#23628 Fixed TCK tests - issues with the SecurityManager
- now ClassGenerator is responsible for everything around this.
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGenerator.java
index 14289c3..fef5136 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGenerator.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGenerator.java
@@ -16,22 +16,29 @@
package com.sun.ejb.codegen;
+import com.sun.enterprise.loader.ASURLClassLoader;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
+import java.util.Objects;
import java.util.logging.Logger;
import static java.util.logging.Level.CONFIG;
/**
- * This class serves to generate classes, which cannot be generated by the
- * {@link java.lang.invoke.MethodHandles.Lookup} class, because it restricts
+ * This class serves to generate classes, because ...
+ * <p>
+ * {@link java.lang.invoke.MethodHandles.Lookup} class restricts
* the generated class to use an already existing class as a source of the package
* and {@link ProtectionDomain}.
* <p>
- * Also {@link Proxy#newProxyInstance(ClassLoader, Class[], java.lang.reflect.InvocationHandler)}
+ * {@link Proxy#newProxyInstance(ClassLoader, Class[], java.lang.reflect.InvocationHandler)}
* has another requirements, ie. all referred classes must be loadable by used classloader.
*
* @author David Matejcek
@@ -68,6 +75,56 @@
/**
+ * Decides which method is suitable to define the new class and then uses it.
+ *
+ * @param loader the classloader instance used to generate the class
+ * @param anchorClass the class used as an "orientation" class. See the {@link Lookup} class for
+ * more info.
+ * @param targetPackageName the name is used in decision logic; if the anchor class is from
+ * a different package, the {@link Lookup}'s method is not usable.
+ * @param className expected binary name or null
+ * @param classData the valid bytes that make up the class data.
+ * @return the new generated class
+ * @throws ClassDefinitionException invalid data, missing dependency, or another error related
+ * to the class generation
+ */
+ public static Class<?> defineClass(final ClassLoader loader, final Class<?> anchorClass,
+ final String targetPackageName, final String className, final byte[] classData) {
+ if (useMethodHandles(loader, anchorClass, targetPackageName)) {
+ return defineClass(anchorClass, className, classData);
+ } else if (System.getSecurityManager() == null) {
+ return defineClass(loader, className, classData, anchorClass.getProtectionDomain());
+ } else {
+ return defineClass(loader, className, classData);
+ }
+ }
+
+
+ /**
+ * Calls the {@link Lookup}'s defineClass method to create a new class
+ *
+ * @param anchorClass the class used as an "orientation" class. See the {@link Lookup} class for more info.
+ * @param className expected binary name or null
+ * @param classData the valid bytes that make up the class data.
+ * @return the new generated class
+ * @throws ClassDefinitionException invalid data, missing dependency, or another error related
+ * to the class generation
+ */
+ public static Class<?> defineClass(final Class<?> anchorClass, final String className, final byte[] classData) {
+ LOG.log(CONFIG, "Defining class: {0} with anchorClass: {1}", new Object[] {className, anchorClass});
+ final PrivilegedAction<Class<?>> action = () -> {
+ try {
+ final Lookup lookup = MethodHandles.privateLookupIn(anchorClass, MethodHandles.lookup());
+ return lookup.defineClass(classData);
+ } catch (IllegalAccessException e) {
+ throw new ClassDefinitionException(className,anchorClass, e);
+ }
+ };
+ return AccessController.doPrivileged(action);
+ }
+
+
+ /**
* Calls the {@link ClassLoader}'s protected defineClass method to create a new class
*
* @param loader the classloader instance used to generate the class
@@ -95,15 +152,17 @@
* @throws ClassDefinitionException invalid data, missing dependency, or another error related
* to the class generation
*/
- public static Class<?> defineClass(
- final ClassLoader loader, final String className,
- final byte[] classData, final int offset, final int length) throws ClassDefinitionException {
+ public static Class<?> defineClass(final ClassLoader loader, final String className, final byte[] classData,
+ final int offset, final int length) throws ClassDefinitionException {
LOG.log(CONFIG, "Defining class: {0} by loader: {1}", new Object[] {className, loader});
- try {
- return (Class<?>) defineClassMethod.invoke(loader, className, classData, 0, length);
- } catch (final Exception | NoClassDefFoundError | ClassFormatError e) {
- throw new ClassDefinitionException(className, loader, e);
- }
+ final PrivilegedAction<Class<?>> action = () -> {
+ try {
+ return (Class<?>) defineClassMethod.invoke(loader, className, classData, 0, length);
+ } catch (final Exception | NoClassDefFoundError | ClassFormatError e) {
+ throw new ClassDefinitionException(className, loader, e);
+ }
+ };
+ return AccessController.doPrivileged(action);
}
@@ -142,11 +201,14 @@
final byte[] classData, final int offset, final int length,
final ProtectionDomain protectionDomain) throws ClassDefinitionException {
LOG.log(CONFIG, "Defining class: {0} by loader: {1}", new Object[] {className, loader});
- try {
- return (Class<?>) defineClassMethodSM.invoke(loader, className, classData, 0, length, protectionDomain);
- } catch (final Exception | NoClassDefFoundError | ClassFormatError e) {
- throw new ClassDefinitionException(className, loader, e);
- }
+ final PrivilegedAction<Class<?>> action = () -> {
+ try {
+ return (Class<?>) defineClassMethodSM.invoke(loader, className, classData, 0, length, protectionDomain);
+ } catch (final Exception | NoClassDefFoundError | ClassFormatError e) {
+ throw new ClassDefinitionException(className, loader, e);
+ }
+ };
+ return AccessController.doPrivileged(action);
}
@@ -159,5 +221,24 @@
ClassDefinitionException(final String className, final ClassLoader loader, final Throwable cause) {
super("Could not define class '" + className + "' by the class loader: " + loader, cause);
}
+
+ ClassDefinitionException(final String className, final Class<?> anchorClass, final Throwable cause) {
+ super("Could not define class '" + className + "' using the anchor " + anchorClass, cause);
+ }
+
+ }
+
+
+ private static boolean useMethodHandles(final ClassLoader loader, final Class<?> anchorClass,
+ final String targetPackageName) {
+ if (loader == null) {
+ return true;
+ }
+ // The bootstrap CL used by embedded glassfish doesn't remember generated classes
+ // Further ClassLoader.findClass calls will fail.
+ if (anchorClass == null || loader.getParent() == null || loader.getClass() == ASURLClassLoader.class) {
+ return false;
+ }
+ return Objects.equals(targetPackageName, anchorClass.getPackageName());
}
}
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Generator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Generator.java
index 6acfb2f..caf1b43 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Generator.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Generator.java
@@ -17,15 +17,10 @@
package com.sun.ejb.codegen;
-import com.sun.enterprise.loader.ASURLClassLoader;
-
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Method;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -37,6 +32,7 @@
import org.glassfish.pfl.dynamic.codegen.spi.ImportList;
import org.glassfish.pfl.dynamic.codegen.spi.Wrapper;
+import static com.sun.ejb.codegen.ClassGenerator.defineClass;
import static org.glassfish.pfl.dynamic.codegen.impl.CodeGenerator.generateBytecode;
import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.DUMP_AFTER_SETUP_VISITOR;
import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.TRACE_BYTE_CODE_GENERATION;
@@ -128,31 +124,7 @@
final ClassGeneratorImpl codeGenerator = (ClassGeneratorImpl) _classGenerator();
final byte[] bytecode = generateBytecode(codeGenerator, getClassLoader(), imports, props, System.out);
-
- if (useMethodHandles()) {
- LOG.log(Level.FINEST, "Using MethodHandles to define {0}, anchorClass: {1}",
- new Object[] {getGeneratedClassName(), getAnchorClass()});
- final Lookup lookup = MethodHandles.privateLookupIn(getAnchorClass(), MethodHandles.lookup());
- return lookup.defineClass(bytecode);
- }
-
- if (System.getSecurityManager() == null) {
- return ClassGenerator.defineClass(getClassLoader(), getGeneratedClassName(), bytecode,
- getAnchorClass().getProtectionDomain());
- }
- final PrivilegedAction<Class<?>> action = () -> ClassGenerator.defineClass(getClassLoader(),
- getGeneratedClassName(), bytecode);
- return AccessController.doPrivileged(action);
- }
-
-
- private boolean useMethodHandles() {
- // The bootstrap CL used by embedded glassfish doesn't remember generated classes
- // Further ClassLoader.findClass calls will fail.
- if (loader.getParent() == null || loader.getClass() == ASURLClassLoader.class) {
- return false;
- }
- return Objects.equals(getPackageName(), getAnchorClass().getPackageName());
+ return defineClass(getClassLoader(), getAnchorClass(), getPackageName(), getGeneratedClassName(), bytecode);
}