This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
     new 1bb5cb19b7 Refactor JreCompat support for Subject.callAs() to remove 
Jre18Compat
1bb5cb19b7 is described below

commit 1bb5cb19b77605ca70e91989be4879694b60d56b
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Jul 26 10:11:58 2024 +0100

    Refactor JreCompat support for Subject.callAs() to remove Jre18Compat
    
    We can switch from Subject.doAs() to Subject.callAs() at any point from
    Java 18 to 22 inclusive to switch at Java 21 since it is an LTS version.
---
 .../org/apache/tomcat/util/compat/Jre18Compat.java |  71 ---------------
 .../org/apache/tomcat/util/compat/Jre19Compat.java |   2 +-
 .../org/apache/tomcat/util/compat/Jre21Compat.java |  25 +++++
 java/org/apache/tomcat/util/compat/JreCompat.java  | 101 ++++++++++-----------
 4 files changed, 72 insertions(+), 127 deletions(-)

diff --git a/java/org/apache/tomcat/util/compat/Jre18Compat.java 
b/java/org/apache/tomcat/util/compat/Jre18Compat.java
deleted file mode 100644
index e4c7d58256..0000000000
--- a/java/org/apache/tomcat/util/compat/Jre18Compat.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-package org.apache.tomcat.util.compat;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CompletionException;
-
-import javax.security.auth.Subject;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.res.StringManager;
-
-public class Jre18Compat extends JreCompat {
-
-    private static final Log log = LogFactory.getLog(Jre18Compat.class);
-    private static final StringManager sm = 
StringManager.getManager(Jre18Compat.class);
-
-    private static final Method callAsMethod;
-
-    static {
-        Method m1 = null;
-
-        try {
-            m1 = Subject.class.getMethod("callAs", Subject.class, 
Callable.class);
-        } catch (NoSuchMethodException e) {
-            // Must before-Java 18
-            log.debug(sm.getString("jre18Compat.javaPre18"), e);
-        }
-
-        callAsMethod = m1;
-    }
-
-
-    static boolean isSupported() {
-        return callAsMethod != null;
-    }
-
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <T> T callAs(Subject subject, Callable<T> action) throws 
CompletionException {
-        try {
-            return (T) callAsMethod.invoke(null, subject, action);
-        } catch (IllegalAccessException e) {
-            throw new CompletionException(e);
-        } catch (InvocationTargetException e) {
-            Throwable cause = e.getCause();
-            if (cause instanceof CompletionException) {
-                throw (CompletionException) cause;
-            }
-            throw new CompletionException(e);
-        }
-    }
-}
diff --git a/java/org/apache/tomcat/util/compat/Jre19Compat.java 
b/java/org/apache/tomcat/util/compat/Jre19Compat.java
index fd9b85c515..60ee0c2dc1 100644
--- a/java/org/apache/tomcat/util/compat/Jre19Compat.java
+++ b/java/org/apache/tomcat/util/compat/Jre19Compat.java
@@ -22,7 +22,7 @@ import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.res.StringManager;
 
-public class Jre19Compat extends Jre18Compat {
+public class Jre19Compat extends JreCompat {
 
     private static final Log log = LogFactory.getLog(Jre19Compat.class);
     private static final StringManager sm = 
StringManager.getManager(Jre19Compat.class);
diff --git a/java/org/apache/tomcat/util/compat/Jre21Compat.java 
b/java/org/apache/tomcat/util/compat/Jre21Compat.java
index d06c8519a7..c534ea4e2d 100644
--- a/java/org/apache/tomcat/util/compat/Jre21Compat.java
+++ b/java/org/apache/tomcat/util/compat/Jre21Compat.java
@@ -18,6 +18,10 @@ package org.apache.tomcat.util.compat;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionException;
+
+import javax.security.auth.Subject;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -31,6 +35,7 @@ public class Jre21Compat extends Jre19Compat {
     private static final Method nameMethod;
     private static final Method startMethod;
     private static final Method ofVirtualMethod;
+    private static final Method callAsMethod;
 
 
     static {
@@ -38,12 +43,14 @@ public class Jre21Compat extends Jre19Compat {
         Method m1 = null;
         Method m2 = null;
         Method m3 = null;
+        Method m4 = null;
 
         try {
             c1 = Class.forName("java.lang.Thread$Builder");
             m1 = c1.getMethod("name", String.class, long.class);
             m2 = c1.getMethod("start", Runnable.class);
             m3 = Thread.class.getMethod("ofVirtual", (Class<?>[]) null);
+            m4 = Subject.class.getMethod("callAs", Subject.class, 
Callable.class);
         } catch (ClassNotFoundException e) {
             // Must be pre-Java 21
             log.debug(sm.getString("jre21Compat.javaPre21"), e);
@@ -54,6 +61,7 @@ public class Jre21Compat extends Jre19Compat {
         nameMethod = m1;
         startMethod = m2;
         ofVirtualMethod = m3;
+        callAsMethod = m4;
     }
 
     static boolean isSupported() {
@@ -79,4 +87,21 @@ public class Jre21Compat extends Jre19Compat {
             throw new UnsupportedOperationException(e);
         }
     }
+
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T callAs(Subject subject, Callable<T> action) throws 
CompletionException {
+        try {
+            return (T) callAsMethod.invoke(null, subject, action);
+        } catch (IllegalAccessException e) {
+            throw new CompletionException(e);
+        } catch (InvocationTargetException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof CompletionException) {
+                throw (CompletionException) cause;
+            }
+            throw new CompletionException(e);
+        }
+    }
 }
diff --git a/java/org/apache/tomcat/util/compat/JreCompat.java 
b/java/org/apache/tomcat/util/compat/JreCompat.java
index 9227c2deac..001ce82546 100644
--- a/java/org/apache/tomcat/util/compat/JreCompat.java
+++ b/java/org/apache/tomcat/util/compat/JreCompat.java
@@ -26,15 +26,13 @@ import javax.security.auth.Subject;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
- * This is the base implementation class for JRE compatibility and provides an
- * implementation based on Java 17. Sub-classes may extend this class and 
provide
- * alternative implementations for later JRE versions
+ * This is the base implementation class for JRE compatibility and provides an 
implementation based on Java 17.
+ * Sub-classes may extend this class and provide alternative implementations 
for later JRE versions
  */
 public class JreCompat {
 
     private static final JreCompat instance;
     private static final boolean graalAvailable;
-    private static final boolean jre18Available;
     private static final boolean jre19Available;
     private static final boolean jre21Available;
     private static final boolean jre22Available;
@@ -59,31 +57,21 @@ public class JreCompat {
             jre22Available = true;
             jre21Available = true;
             jre19Available = true;
-            jre18Available = true;
         } else if (Jre21Compat.isSupported()) {
             instance = new Jre21Compat();
             jre22Available = false;
             jre21Available = true;
             jre19Available = true;
-            jre18Available = true;
         } else if (Jre19Compat.isSupported()) {
             instance = new Jre19Compat();
             jre22Available = false;
             jre21Available = false;
             jre19Available = true;
-            jre18Available = true;
-        } else if (Jre18Compat.isSupported()) {
-            instance = new Jre19Compat();
-            jre22Available = false;
-            jre21Available = false;
-            jre19Available = false;
-            jre18Available = true;
         } else {
             instance = new JreCompat();
             jre22Available = false;
             jre21Available = false;
             jre19Available = false;
-            jre18Available = false;
         }
     }
 
@@ -98,11 +86,6 @@ public class JreCompat {
     }
 
 
-    public static boolean isJre18Available() {
-        return jre18Available;
-    }
-
-
     public static boolean isJre19Available() {
         return jre19Available;
     }
@@ -118,44 +101,20 @@ public class JreCompat {
     }
 
 
-    // Java 17 implementations of Java 18 methods
-
-    @SuppressWarnings("removal")
-    public <T> T callAs(Subject subject, Callable<T> action) throws 
CompletionException {
-        try {
-            return Subject.doAs(subject, new PrivilegedExceptionAction<T>() {
-
-                @Override
-                public T run() throws Exception {
-                    return action.call();
-                }
-            });
-        } catch (Exception e) {
-            throw new CompletionException(e);
-        }
-    }
-
-
     // Java 17 implementations of Java 19 methods
 
     /**
      * Obtains the executor, if any, used to create the provided thread.
      *
-     * @param thread    The thread to examine
+     * @param thread The thread to examine
      *
-     * @return  The executor, if any, that created the provided thread
+     * @return The executor, if any, that created the provided thread
      *
-     * @throws NoSuchFieldException
-     *              If a field used via reflection to obtain the executor 
cannot
-     *              be found
-     * @throws SecurityException
-     *              If a security exception occurs while trying to identify the
-     *              executor
-     * @throws IllegalArgumentException
-     *              If the instance object does not match the class of the 
field
-     *              when obtaining a field value via reflection
-     * @throws IllegalAccessException
-     *              If a field is not accessible due to access restrictions
+     * @throws NoSuchFieldException     If a field used via reflection to 
obtain the executor cannot be found
+     * @throws SecurityException        If a security exception occurs while 
trying to identify the executor
+     * @throws IllegalArgumentException If the instance object does not match 
the class of the field when obtaining a
+     *                                      field value via reflection
+     * @throws IllegalAccessException   If a field is not accessible due to 
access restrictions
      */
     public Object getExecutor(Thread thread)
             throws NoSuchFieldException, SecurityException, 
IllegalArgumentException, IllegalAccessException {
@@ -181,11 +140,9 @@ public class JreCompat {
         // "java.util.concurrent" code is in public domain,
         // so all implementations are similar including our
         // internal fork.
-        if (target != null && target.getClass().getCanonicalName() != null &&
-                (target.getClass().getCanonicalName().equals(
-                        
"org.apache.tomcat.util.threads.ThreadPoolExecutor.Worker") ||
-                        target.getClass().getCanonicalName().equals(
-                                
"java.util.concurrent.ThreadPoolExecutor.Worker"))) {
+        if (target != null && target.getClass().getCanonicalName() != null && 
(target.getClass().getCanonicalName()
+                
.equals("org.apache.tomcat.util.threads.ThreadPoolExecutor.Worker") ||
+                
target.getClass().getCanonicalName().equals("java.util.concurrent.ThreadPoolExecutor.Worker")))
 {
             Field executorField = target.getClass().getDeclaredField("this$0");
             executorField.setAccessible(true);
             result = executorField.get(target);
@@ -218,4 +175,38 @@ public class JreCompat {
     public void threadBuilderStart(Object threadBuilder, Runnable command) {
         throw new 
UnsupportedOperationException(sm.getString("jreCompat.noVirtualThreads"));
     }
+
+
+    /*
+     * This is a slightly different usage of JreCompat.
+     *
+     * Subject.doAs() was deprecated in Java 18 and replaced with 
Subject.callAs(). As of Java 23, calling
+     * Subject.doAs() will trigger an UnsupportedOperationException unless the 
java.security.manager system property is
+     * set. To avoid Tomcat installations using Spnego authentication having 
to set this value, JreCompat is used to
+     * call Subject.callAs() instead.
+     *
+     * Because Java versions 18 to 22 inclusive support both the old and the 
new method, the switch over can occur at
+     * any Java version from 18 to 22 inclusive. Java 21 onwards was selected 
as it as an LTS version and that removes
+     * the need to add a Jre18Compat class.
+     *
+     * So, the slightly longer description for this method is:
+     *
+     * Java 17 implementation of a method replaced between Java 18 and 22 with 
the replacement method being used by
+     * Tomcat when running on Java 21 onwards.
+     */
+
+    @SuppressWarnings("removal")
+    public <T> T callAs(Subject subject, Callable<T> action) throws 
CompletionException {
+        try {
+            return Subject.doAs(subject, new PrivilegedExceptionAction<T>() {
+
+                @Override
+                public T run() throws Exception {
+                    return action.call();
+                }
+            });
+        } catch (Exception e) {
+            throw new CompletionException(e);
+        }
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to