Fixed #23616 by refactoring - cleanup around leaky api of generateAndLoad which relied on consistency of it's parameters - the anchor class was moved to the generator to keep JDK rules - removeRedundantMethods was and is slow -> TODO: optimize + test - ServiceInterfaceGenerator changed output class name and package, because original addition of jaxws.internal is forbidden in JDK11+ - tests were enhanced to be able to compare loading of cached classes.
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EJBUtils.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EJBUtils.java index ec4daf1..1ba97fa 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EJBUtils.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EJBUtils.java
@@ -54,6 +54,7 @@ import org.glassfish.pfl.dynamic.codegen.spi.Wrapper; +import static com.sun.ejb.codegen.GenericHomeGenerator.GENERIC_HOME_CLASSNAME; import static java.util.logging.Level.FINE; 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; @@ -177,48 +178,61 @@ private static String getClassPackageName(String intf) { int dot = intf.lastIndexOf('.'); - return (dot == -1) ? null : intf.substring(0, dot); + return dot == -1 ? null : intf.substring(0, dot); } + /** @return the simple name of the class. For included classes returns includes dollar and wrapper class */ private static String getClassSimpleName(String intf) { int dot = intf.lastIndexOf('.'); - return (dot == -1) ? intf : intf.substring(dot+1); + return dot == -1 ? intf : intf.substring(dot + 1); } + /** + * Prepends __EJB31_Generated__ and adds _Intf__ to the simple class name. + * + * @param ejbClassName full class name + */ public static String getGeneratedOptionalInterfaceName(String ejbClassName) { String packageName = getClassPackageName(ejbClassName); String simpleName = getClassSimpleName(ejbClassName); String optionalIntfName = "__EJB31_Generated__" + simpleName + "__Intf__"; - return (packageName != null) ? - packageName + "." + optionalIntfName : optionalIntfName; + return packageName == null ? optionalIntfName : packageName + "." + optionalIntfName; } + /** + * Adds _Serializable to the original name. + * + * @param beanClass full class name + */ public static String getGeneratedSerializableClassName(String beanClass) { String packageName = getClassPackageName(beanClass); String simpleName = getClassSimpleName(beanClass); String generatedSimpleName = "_" + simpleName + "_Serializable"; - return (packageName != null) ? - packageName + "." + generatedSimpleName : generatedSimpleName; + return packageName == null ? generatedSimpleName : packageName + "." + generatedSimpleName; } + /** + * Adds _Remote to the original name. + * + * @param businessIntf full class name + */ public static String getGeneratedRemoteIntfName(String businessIntf) { String packageName = getClassPackageName(businessIntf); String simpleName = getClassSimpleName(businessIntf); String generatedSimpleName = "_" + simpleName + "_Remote"; - return (packageName != null) ? - packageName + "." + generatedSimpleName : generatedSimpleName; + return packageName == null ? generatedSimpleName : packageName + "." + generatedSimpleName; } + /** + * Adds _Wrapper to the original name. + * + * @param businessIntf full class name + */ public static String getGeneratedRemoteWrapperName(String businessIntf) { String packageName = getClassPackageName(businessIntf); String simpleName = getClassSimpleName(businessIntf); String generatedSimpleName = "_" + simpleName + "_Wrapper"; - return (packageName != null) ? - packageName + "." + generatedSimpleName : generatedSimpleName; - } - - public static String getGenericEJBHomeClassName() { - return "com.sun.ejb.codegen.GenericEJBHome_Generated"; + return packageName == null ? generatedSimpleName : packageName + "." + generatedSimpleName; } /** @@ -340,100 +354,49 @@ } - public static Object resolveEjbRefObject(EjbReferenceDescriptor refDesc, - Object jndiObj) - throws NamingException { - - Object returnObject = jndiObj; - - if( refDesc.isLocal() ) { - + public static Object resolveEjbRefObject(EjbReferenceDescriptor refDesc, Object jndiObj) throws NamingException { + if (refDesc.isLocal()) { EjbDescriptor target = refDesc.getEjbDescriptor(); - BaseContainer container = EjbContainerUtilImpl.getInstance().getContainer(target.getUniqueId()); - - if( refDesc.isEJB30ClientView() ) { - GenericEJBLocalHome genericLocalHome = - container.getEJBLocalBusinessHome(refDesc.getEjbInterface()); - returnObject = genericLocalHome.create(refDesc.getEjbInterface()); - } else { - returnObject = container.getEJBLocalHome(); + if (refDesc.isEJB30ClientView()) { + GenericEJBLocalHome genericLocalHome = container.getEJBLocalBusinessHome(refDesc.getEjbInterface()); + return genericLocalHome.create(refDesc.getEjbInterface()); } - - } else { - - // For the Remote case, the only time we have to do - // something extra with the given jndiObj is if the lookup - // is for a Remote 3.0 object and it was made through a - // corba interoperable name. In that case, - // the jndiObj refers to the internal Remote 3.0 Home so we - // still need to create a remote 30 client wrapper object. - - if ( refDesc.isEJB30ClientView() && - !(jndiObj instanceof RemoteBusinessWrapperBase) ) { - returnObject = EJBUtils.lookupRemote30BusinessObject - (jndiObj, refDesc.getEjbInterface()); - } - + return container.getEJBLocalHome(); } - return returnObject; - + if (refDesc.isEJB30ClientView() && !(jndiObj instanceof RemoteBusinessWrapperBase)) { + return EJBUtils.lookupRemote30BusinessObject(jndiObj, refDesc.getEjbInterface()); + } + return jndiObj; } - public static Object lookupRemote30BusinessObject(Object jndiObj, - String businessInterface) - throws NamingException - { - Object returnObject = null; - + public static Object lookupRemote30BusinessObject(Object jndiObj, String businessInterface) throws NamingException { try { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - - Class genericEJBHome = loadGeneratedGenericEJBHomeClass - (loader); - - final Object genericHomeObj = - PortableRemoteObject.narrow(jndiObj, genericEJBHome); + Class<?> genericEJBHome = loadGeneratedGenericEJBHomeClass(loader); + final Object genericHomeObj = PortableRemoteObject.narrow(jndiObj, genericEJBHome); // The generated remote business interface and the // client wrapper for the business interface are produced - // dynamically. The following call must be made before + // dynamically. The following call must be made before // any EJB 3.0 Remote business interface runtime behavior // is needed in a given JVM. loadGeneratedRemoteBusinessClasses(businessInterface); - String generatedRemoteIntfName = EJBUtils. - getGeneratedRemoteIntfName(businessInterface); + String generatedRemoteIntfName = EJBUtils.getGeneratedRemoteIntfName(businessInterface); + Method createMethod = genericEJBHome.getMethod("create", String.class); + java.rmi.Remote delegate = (java.rmi.Remote) createMethod.invoke(genericHomeObj, generatedRemoteIntfName); - Method createMethod = genericEJBHome.getMethod - ("create", String.class); - - java.rmi.Remote delegate = (java.rmi.Remote) - createMethod.invoke(genericHomeObj, - generatedRemoteIntfName); - - - returnObject = createRemoteBusinessObject - (loader, businessInterface, delegate); - - - // TODO Bring over appclient security exception retry logic CR 6620388 - - } catch(Exception e) { - NamingException ne = new NamingException - ("ejb ref resolution error for remote business interface" - + businessInterface); - - ne.initCause(e instanceof InvocationTargetException ? - e.getCause() : e); + // TODO Bring over appclient security exception retry logic CR 6620388 + return createRemoteBusinessObject(loader, businessInterface, delegate); + } catch (Exception e) { + NamingException ne = new NamingException( + "ejb ref resolution error for remote business interface" + businessInterface); + ne.initCause(e instanceof InvocationTargetException ? e.getCause() : e); throw ne; } - - return returnObject; - } @@ -452,6 +415,10 @@ } + /** + * @param appClassLoader - used to verify existence of classes and for generating too. + * @param businessInterfaceName - this class must exist + */ public static void loadGeneratedRemoteBusinessClasses(ClassLoader appClassLoader, String businessInterfaceName) throws Exception { String generatedRemoteIntfName = EJBUtils.getGeneratedRemoteIntfName(businessInterfaceName); @@ -465,17 +432,13 @@ Wrapper._setClassLoader(appClassLoader); try { if (generatedRemoteIntf == null) { - RemoteGenerator gen = new RemoteGenerator(appClassLoader, businessInterfaceName); - Class<?> developerClass = appClassLoader.loadClass(businessInterfaceName); - generateAndLoad(gen, generatedRemoteIntfName, appClassLoader, developerClass); - + RemoteGenerator generator = new RemoteGenerator(appClassLoader, businessInterfaceName); + generateAndLoad(generator, appClassLoader); } if (generatedRemoteWrapper == null) { - Remote30WrapperGenerator gen = new Remote30WrapperGenerator(appClassLoader, businessInterfaceName, - generatedRemoteIntfName); - - Class<?> developerClass = appClassLoader.loadClass(businessInterfaceName); - generateAndLoad(gen, wrapperClassName, appClassLoader, developerClass); + Remote30WrapperGenerator generator + = new Remote30WrapperGenerator(appClassLoader, businessInterfaceName, generatedRemoteIntfName); + generateAndLoad(generator, appClassLoader); } } finally { // Make sure no classloader is bound to threadlocal: avoid possible classloader leak. @@ -484,36 +447,38 @@ } - public static Class<?> loadGeneratedGenericEJBHomeClass(ClassLoader appClassLoader) throws Exception { - String className = getGenericEJBHomeClassName(); - Class<?> generatedGenericEJBHomeClass = loadClassIgnoringExceptions(appClassLoader, className); + public static Class<?> loadGeneratedGenericEJBHomeClass(final ClassLoader appClassLoader) throws Exception { + final Class<?> generatedGenericEJBHomeClass = loadClassIgnoringExceptions(appClassLoader, GENERIC_HOME_CLASSNAME); if (generatedGenericEJBHomeClass != null) { return generatedGenericEJBHomeClass; } - GenericHomeGenerator gen = new GenericHomeGenerator(appClassLoader); - return generateAndLoad(gen, className, appClassLoader, GenericHomeGenerator.class); + final GenericHomeGenerator generator = new GenericHomeGenerator(); + return generateAndLoad(generator, appClassLoader); } - public static Class generateSEI(ClassGeneratorFactory cgf, ClassLoader loader, Class beanClass) { - Class<?> clazz = loadClassIgnoringExceptions(loader, cgf.className()); + public static Class<?> generateSEI(ClassGeneratorFactory cgf, ClassLoader loader) { + Class<?> clazz = loadClassIgnoringExceptions(loader, cgf.getGeneratedClassName()); if (clazz != null) { return clazz; } - return generateAndLoad(cgf, cgf.className(), loader, beanClass); + return generateAndLoad(cgf, loader); } - private synchronized static Class<?> generateAndLoad( - final ClassGeneratorFactory factory, final String requestedClassName, - final ClassLoader loader, final Class<?> anchorClass) { - - Class<?> clazz = loadClassIgnoringExceptions(loader, requestedClassName); + /** + * Checks if the class wasn't already generated by another thread and if not, generates it. + * The class name is retrieved from {@link ClassGeneratorFactory#getGeneratedClassName()} + * and if it wasn't found, generator knows it's definition. + */ + // made package visible just for tests + static synchronized Class<?> generateAndLoad(final ClassGeneratorFactory generator, final ClassLoader loader) { + Class<?> clazz = loadClassIgnoringExceptions(loader, generator.getGeneratedClassName()); if (clazz != null) { return clazz; } - factory.evaluate(); + generator.evaluate(); final Properties props = new Properties(); if (_logger.isLoggable(Level.FINEST)) { @@ -531,9 +496,9 @@ } if (System.getSecurityManager() == null) { - return Wrapper._generate(anchorClass, props); + return Wrapper._generate(generator.getAnchorClass(), props); } - PrivilegedAction<Class<?>> action = () -> Wrapper._generate(anchorClass, props); + PrivilegedAction<Class<?>> action = () -> Wrapper._generate(generator.getAnchorClass(), props); return AccessController.doPrivileged(action); }
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGeneratorFactory.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGeneratorFactory.java index 22eba45..84a1263 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGeneratorFactory.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGeneratorFactory.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -16,14 +17,26 @@ package com.sun.ejb.codegen; +import org.glassfish.pfl.dynamic.codegen.spi.Wrapper; -/** Convenience interface that defines a factory for ClassGenerator instances. +/** + * Convenience interface that defines a factory for ClassGenerator instances. * It puts the class name of the generated class in a single place. - * It must always be the case that evaluate().name().equals( className() ). */ -public interface ClassGeneratorFactory -{ - String className() ; +public interface ClassGeneratorFactory { + /** + * @return name of the generated class or interface + */ + String getGeneratedClassName(); + + /** + * @return loadable class of the same package as {@link #getGeneratedClassName()} + */ + Class<?> getAnchorClass(); + + /** + * Calls {@link Wrapper} methods to configure the class definition. + */ void evaluate(); }
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 7ea2959..84fdca6 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
@@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -17,246 +18,102 @@ package com.sun.ejb.codegen; import java.lang.reflect.Method; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.Set; -import java.util.Vector; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.sun.enterprise.deployment.MethodDescriptor; -import com.sun.logging.LogDomains; -import org.glassfish.api.deployment.DeploymentContext; -import org.glassfish.ejb.deployment.descriptor.ContainerTransaction; -import org.glassfish.ejb.deployment.descriptor.EjbDescriptor; -import org.glassfish.ejb.deployment.descriptor.EjbSessionDescriptor; +import java.util.ArrayList; +import java.util.List; /** * The base class for all code generators. */ -public abstract class Generator { - - protected static final Logger _logger = LogDomains.getLogger(Generator.class, LogDomains.EJB_LOGGER); - - protected String ejbClassSymbol; - - public abstract String getGeneratedClass(); - +public abstract class Generator implements ClassGeneratorFactory { /** * Get the package name from the class name. + * * @param className class name. * @return the package name. */ protected String getPackageName(String className) { int dot = className.lastIndexOf('.'); - if (dot == -1) + if (dot == -1) { return null; + } return className.substring(0, dot); } - protected String getBaseName(String className) { - int dot = className.lastIndexOf('.'); - if (dot == -1) - return className; - return className.substring(dot+1); - } - - protected String printType(Class cls) { - if (cls.isArray()) { - return printType(cls.getComponentType()) + "[]"; - } else { - return cls.getName(); - } - } - - protected Method[] removeDups(Method[] orig) { - // Remove duplicates from method array. - // Duplicates will arise if a class/intf and super-class/intf - // define methods with the same signature. Potentially the - // throws clauses of the methods may be different (note Java - // requires that the superclass/intf method have a superset of the - // exceptions in the derived method). - Vector nodups = new Vector(); - for ( int i=0; i<orig.length; i++ ) { - Method m1 = orig[i]; - boolean dup = false; - for ( Enumeration e=nodups.elements(); e.hasMoreElements(); ) { - Method m2 = (Method)e.nextElement(); - - // m1 and m2 are duplicates if they have the same signature - // (name and same parameters). - if ( !m1.getName().equals(m2.getName()) ) - continue; - - Class[] m1parms = m1.getParameterTypes(); - Class[] m2parms = m2.getParameterTypes(); - if ( m1parms.length != m2parms.length ) - continue; - - boolean parmsDup = true; - for ( int j=0; j<m2parms.length; j++ ) { - if ( m1parms[j] != m2parms[j] ) { - parmsDup = false; - break; - } - } - if ( parmsDup ) { - dup = true; - // Select which of the duplicate methods to generate - // code for: choose the one that is lower in the - // inheritance hierarchy: this ensures that the generated - // method will compile. - if ( m2.getDeclaringClass().isAssignableFrom( - m1.getDeclaringClass()) ) { - // m2 is a superclass/intf of m1, so replace m2 with m1 - nodups.remove(m2); - nodups.add(m1); - } - break; - } - } - - if ( !dup ) - nodups.add(m1); - } - return (Method[])nodups.toArray(new Method[nodups.size()]); - } /** - * Return true if method is on a jakarta.ejb.EJBObject/EJBLocalObject/ - * jakarta.ejb.EJBHome,jakarta.ejb.EJBLocalHome interface. + * @param className + * @return simple class name (including wrapper class and dollar sign if it is internal class) */ - protected boolean isEJBIntfMethod(Class ejbIntfClz, Method methodToCheck) { - boolean isEJBIntfMethod = false; - - Method[] ejbIntfMethods = ejbIntfClz.getMethods(); - for(int i = 0; i < ejbIntfMethods.length; i++) { - Method next = ejbIntfMethods[i]; - if(methodCompare(methodToCheck, next)) { - isEJBIntfMethod = true; - - String ejbIntfClzName = ejbIntfClz.getName(); - Class methodToCheckClz = methodToCheck.getDeclaringClass(); - if( !methodToCheckClz.getName().equals(ejbIntfClzName) ) { - String[] logParams = {next.toString(), methodToCheck.toString()}; - _logger.log(Level.WARNING, - "ejb.illegal_ejb_interface_override", - logParams); - } - - break; - } + protected String getBaseName(String className) { + int dot = className.lastIndexOf('.'); + if (dot == -1) { + return className; } - - return isEJBIntfMethod; + return className.substring(dot + 1); } - private boolean methodCompare(Method factoryMethod, Method homeMethod) { + /** + * Remove duplicates from method array. + * <p> + * Duplicates will arise if a class/intf and super-class/intf + * define methods with the same signature. Potentially the + * throws clauses of the methods may be different (note Java + * requires that the superclass/intf method have a superset of the + * exceptions in the derived method). + * + * @param methods + * @return methods which can be generated in an interface + */ + protected Method[] removeRedundantMethods(Method[] methods) { + final List<Method> nodups = new ArrayList<>(); + for (Method method : methods) { + boolean duplicationDetected = false; + final List<Method> previousResult = new ArrayList<>(nodups); + for (Method alreadyProcessed : previousResult) { + // m1 and m2 are duplicates if they have the same signature + // (name and same parameters). + if (!method.getName().equals(alreadyProcessed.getName())) { + continue; + } + if (!haveSameParams(method, alreadyProcessed)) { + continue; + } + duplicationDetected = true; + // Select which of the duplicate methods to generate + // code for: choose the one that is lower in the + // inheritance hierarchy: this ensures that the generated + // method will compile. + if (alreadyProcessed.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) { + // alreadyProcessedMethod is a superclass/intf of method, + // so replace it with more concrete method + nodups.remove(alreadyProcessed); + nodups.add(method); + } + break; + } - if (!factoryMethod.getName().equals(homeMethod.getName())) { + if (!duplicationDetected) { + nodups.add(method); + } + } + return nodups.toArray(new Method[nodups.size()]); + } + + + private boolean haveSameParams(final Method method1, final Method method2) { + Class<?>[] m1parms = method1.getParameterTypes(); + Class<?>[] m2parms = method2.getParameterTypes(); + if (m1parms.length != m2parms.length) { return false; } - - Class[] factoryParamTypes = factoryMethod.getParameterTypes(); - Class[] beanParamTypes = homeMethod.getParameterTypes(); - if (factoryParamTypes.length != beanParamTypes.length) { - return false; - } - for(int i = 0; i < factoryParamTypes.length; i++) { - if (factoryParamTypes[i] != beanParamTypes[i]) { + for (int i = 0; i < m2parms.length; i++) { + if (m1parms[i] != m2parms[i]) { return false; } } - - // NOTE : Exceptions and return types are not part of equality check return true; } - - - protected String getUniqueClassName(DeploymentContext context, String origName, String origSuffix, - Vector existingClassNames) { - String newClassName = null; - boolean foundUniqueName = false; - int count = 0; - while (!foundUniqueName) { - String suffix = origSuffix; - if (count > 0) { - suffix = origSuffix + count; - } - newClassName = origName + suffix; - if (!existingClassNames.contains(newClassName)) { - foundUniqueName = true; - existingClassNames.add(newClassName); - } else { - count++; - } - } - return newClassName; - } - - - protected String getTxAttribute(EjbDescriptor dd, Method method) { - // The TX_* strings returned MUST match the TX_* constants in - // com.sun.ejb.Container. - if (dd instanceof EjbSessionDescriptor && ((EjbSessionDescriptor) dd).getTransactionType().equals("Bean")) { - return "TX_BEAN_MANAGED"; - } - - String txAttr = null; - MethodDescriptor mdesc = new MethodDescriptor(method, ejbClassSymbol); - ContainerTransaction ct = dd.getContainerTransactionFor(mdesc); - if (ct != null) { - String attr = ct.getTransactionAttribute(); - if (attr.equals(ContainerTransaction.NOT_SUPPORTED)) { - txAttr = "TX_NOT_SUPPORTED"; - } else if (attr.equals(ContainerTransaction.SUPPORTS)) { - txAttr = "TX_SUPPORTS"; - } else if (attr.equals(ContainerTransaction.REQUIRED)) { - txAttr = "TX_REQUIRED"; - } else if (attr.equals(ContainerTransaction.REQUIRES_NEW)) { - txAttr = "TX_REQUIRES_NEW"; - } else if (attr.equals(ContainerTransaction.MANDATORY)) { - txAttr = "TX_MANDATORY"; - } else if (attr.equals(ContainerTransaction.NEVER)) { - txAttr = "TX_NEVER"; - } - } - - if (txAttr == null) { - throw new RuntimeException("Transaction Attribute not found for method " + method); - } - return txAttr; - } - - protected String getSecurityAttribute(EjbDescriptor dd, Method m) { - // The SEC_* strings returned MUST match the SEC_* constants in - // com.sun.ejb.Container. - MethodDescriptor thisMethodDesc = new MethodDescriptor(m, ejbClassSymbol); - Set unchecked = dd.getUncheckedMethodDescriptors(); - if (unchecked != null) { - Iterator i = unchecked.iterator(); - while (i.hasNext()) { - MethodDescriptor md = (MethodDescriptor) i.next(); - if (thisMethodDesc.equals(md)) { - return "SEC_UNCHECKED"; - } - } - } - - Set excluded = dd.getExcludedMethodDescriptors(); - if (excluded != null) { - Iterator i = excluded.iterator(); - while (i.hasNext()) { - MethodDescriptor md = (MethodDescriptor) i.next(); - if (thisMethodDesc.equals(md)) { - return "SEC_EXCLUDED"; - } - } - } - - return "SEC_CHECKED"; - } }
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/GenericHomeGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/GenericHomeGenerator.java index 256b8dd..789dc91 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/GenericHomeGenerator.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/GenericHomeGenerator.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -16,74 +17,70 @@ package com.sun.ejb.codegen; +import com.sun.ejb.containers.GenericEJBHome; -import com.sun.ejb.EJBUtils; +import java.rmi.Remote; +import java.rmi.RemoteException; -import com.sun.enterprise.util.LocalStringManagerImpl; - -import static java.lang.reflect.Modifier.*; - -import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.*; +import static java.lang.reflect.Modifier.ABSTRACT; +import static java.lang.reflect.Modifier.PUBLIC; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._String; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._arg; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._classGenerator; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._clear; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._end; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._interface; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._method; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._package; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._t; /** * This class is used to generate a sub-interface of the * GenericEJBHome interface that will be loaded within each * application. */ +public class GenericHomeGenerator extends Generator { -public class GenericHomeGenerator extends Generator - implements ClassGeneratorFactory { - - private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(GenericHomeGenerator.class); - - private String genericEJBHomeClassName; - private ClassLoader loader; + /** + * This class name is relative to the classloader used, but has always the same name. + */ + public static final String GENERIC_HOME_CLASSNAME = GenericHomeGenerator.class.getPackageName() + + ".GenericEJBHome_Generated"; /** * Get the fully qualified name of the generated class. * @return the name of the generated class. */ - public String getGeneratedClass() { - return genericEJBHomeClassName; - } - - // For corba codegen infrastructure - public String className() { - return getGeneratedClass(); + @Override + public final String getGeneratedClassName() { + return GENERIC_HOME_CLASSNAME; } - public GenericHomeGenerator(ClassLoader cl) throws GeneratorException { - super(); - - genericEJBHomeClassName = EJBUtils.getGenericEJBHomeClassName(); - loader = cl; + @Override + public Class<?> getAnchorClass() { + return GenericHomeGenerator.class; } + @Override public void evaluate() { - _clear(); - String packageName = getPackageName(genericEJBHomeClassName); - String simpleName = getBaseName (genericEJBHomeClassName); + String packageName = getPackageName(getGeneratedClassName()); + String simpleName = getBaseName(getGeneratedClassName()); _package(packageName); - _interface(PUBLIC, simpleName, - _t("com.sun.ejb.containers.GenericEJBHome")); + _interface(PUBLIC, simpleName, _t(GenericEJBHome.class.getName())); - // Create method - _method(PUBLIC | ABSTRACT, _t("java.rmi.Remote"), - "create", _t("java.rmi.RemoteException")); + _method(PUBLIC | ABSTRACT, _t(Remote.class.getName()), "create", _t(RemoteException.class.getName())); _arg(_String(), "generatedBusinessIntf"); _end(); _classGenerator() ; - - return; } }
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Remote30WrapperGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Remote30WrapperGenerator.java index 66b1ce8..d288bc7 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Remote30WrapperGenerator.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Remote30WrapperGenerator.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -16,85 +17,104 @@ package com.sun.ejb.codegen; -import java.lang.reflect.Method; -import java.util.*; - - -import static java.lang.reflect.Modifier.*; - -import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.*; -import org.glassfish.pfl.dynamic.codegen.spi.Type ; -import org.glassfish.pfl.dynamic.codegen.spi.Expression ; - import com.sun.ejb.EJBUtils; +import com.sun.ejb.containers.InternalEJBContainerException; +import com.sun.ejb.containers.InternalRemoteException; +import com.sun.ejb.containers.RemoteBusinessWrapperBase; import com.sun.enterprise.util.LocalStringManagerImpl; -public class Remote30WrapperGenerator extends Generator - implements ClassGeneratorFactory { +import java.lang.reflect.Method; +import java.rmi.AccessException; +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; - private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(Remote30WrapperGenerator.class); +import org.glassfish.pfl.dynamic.codegen.spi.Expression; +import org.glassfish.pfl.dynamic.codegen.spi.Type; +import org.omg.CORBA.SystemException; - private String remoteInterfaceName; - private Class businessInterface; - private String remoteClientClassName; - private String remoteClientPackageName; - private String remoteClientSimpleName; - private Method[] bizMethods; +import jakarta.ejb.EJBAccessException; +import jakarta.ejb.EJBException; +import jakarta.ejb.EJBTransactionRequiredException; +import jakarta.ejb.EJBTransactionRolledbackException; +import jakarta.ejb.NoSuchEJBException; +import jakarta.transaction.TransactionRequiredException; +import jakarta.transaction.TransactionRolledbackException; - private ClassLoader loader; +import static java.lang.reflect.Modifier.PRIVATE; +import static java.lang.reflect.Modifier.PUBLIC; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.*; - public String getGeneratedClass() { - return remoteClientClassName; - } +public final class Remote30WrapperGenerator extends Generator { - // For corba codegen infrastructure - public String className() { - return getGeneratedClass(); - } + private static final LocalStringManagerImpl localStrings = new LocalStringManagerImpl(Remote30WrapperGenerator.class); + private static final Logger LOG = Logger.getLogger(Remote30WrapperGenerator.class.getName()); + + private final String remoteInterfaceName; + private final Class<?> businessInterface; + private final String remoteClientClassName; + private final String remoteClientPackageName; + private final String remoteClientSimpleName; + private final Method[] methodsToGenerate; + + private final ClassLoader loader; /** * Construct the Wrapper generator with the specified deployment * descriptor and class loader. * - * @exception GeneratorException + * @param loader + * @param businessIntfName must already exist and be loadable by the loader + * @param remoteInterfaceName generated class will implement this + * + * @throws GeneratorException */ - public Remote30WrapperGenerator(ClassLoader cl, String businessIntfName, String remoteIntfName) + public Remote30WrapperGenerator(ClassLoader loader, String businessIntfName, String remoteInterfaceName) throws GeneratorException { - super(); - remoteInterfaceName = remoteIntfName; - loader = cl; + this.loader = loader; + this.remoteInterfaceName = remoteInterfaceName; try { - this.businessInterface = cl.loadClass(businessIntfName); + businessInterface = loader.loadClass(businessIntfName); } catch (ClassNotFoundException ex) { - throw new InvalidBean( - localStrings.getLocalString( - "generator.remote_interface_not_found", - "Business interface " + businessInterface + " not found ")); + throw new InvalidBean(localStrings.getLocalString( + "generator.remote_interface_not_found", + "Business interface " + businessIntfName + " not found ")); } if (jakarta.ejb.EJBObject.class.isAssignableFrom(businessInterface)) { - throw new GeneratorException("Invalid Remote Business Interface " + - businessInterface + ". A Remote Business interface MUST " + - "not extend jakarta.ejb.EJBObject."); + throw new GeneratorException("Invalid Remote Business Interface " + businessInterface + + ". A Remote Business interface MUST not extend jakarta.ejb.EJBObject."); } - remoteClientClassName = EJBUtils. - getGeneratedRemoteWrapperName(businessInterface.getName()); - + remoteClientClassName = EJBUtils.getGeneratedRemoteWrapperName(businessIntfName); remoteClientPackageName = getPackageName(remoteClientClassName); remoteClientSimpleName = getBaseName(remoteClientClassName); - bizMethods = removeDups(businessInterface.getMethods()); + methodsToGenerate = removeRedundantMethods(businessInterface.getMethods()); // NOTE : no need to remove ejb object methods because EJBObject // is only visible through the RemoteHome view. - } + @Override + public String getGeneratedClassName() { + return remoteClientClassName; + } + @Override + public Class<?> getAnchorClass() { + return businessInterface; + } + + @Override public void evaluate() { _clear(); @@ -107,7 +127,7 @@ } _class(PUBLIC, remoteClientSimpleName, - _t("com.sun.ejb.containers.RemoteBusinessWrapperBase"), + _t(RemoteBusinessWrapperBase.class.getName()), _t(businessInterface.getName())); _data(PRIVATE, _t(remoteInterfaceName), "delegate_"); @@ -117,45 +137,42 @@ _arg(_String(), "busIntf"); _body(); - _expr(_super(_s(_void(), _t("java.rmi.Remote"), _String()), _v("stub"), _v("busIntf"))); + _expr(_super(_s(_void(), _t(Remote.class.getName()), _String()), _v("stub"), _v("busIntf"))); _assign(_v("delegate_"), _v("stub")); _end(); - for(int i = 0; i < bizMethods.length; i++) { - printMethodImpl(bizMethods[i]); + for (Method method : methodsToGenerate) { + printMethodImpl(method); } _end(); try { - java.util.Properties p = new java.util.Properties(); + Properties p = new Properties(); p.put("Wrapper.DUMP_AFTER_SETUP_VISITOR", "true"); p.put("Wrapper.TRACE_BYTE_CODE_GENERATION", "true"); p.put("Wrapper.USE_ASM_VERIFIER", "true"); _byteCode(loader, p); } catch(Exception e) { - System.out.println("Got exception when generating byte code"); - e.printStackTrace(); + LOG.log(Level.WARNING, "Got exception when generating byte code", e); } _classGenerator() ; - - return; } private void printMethodImpl(Method m) { - List<Type> exceptionList = new LinkedList<Type>(); - for (Class exception : m.getExceptionTypes()) { + List<Type> exceptionList = new LinkedList<>(); + for (Class<?> exception : m.getExceptionTypes()) { exceptionList.add(Type.type(exception)); } _method(PUBLIC, Type.type(m.getReturnType()), m.getName(), exceptionList); int i = 0; - List<Type> expressionListTypes = new LinkedList<Type>(); - List<Expression> expressionList = new LinkedList<Expression>(); - for (Class param : m.getParameterTypes()) { + List<Type> expressionListTypes = new LinkedList<>(); + List<Expression> expressionList = new LinkedList<>(); + for (Class<?> param : m.getParameterTypes()) { String paramName = "param" + i; _arg(Type.type(param), paramName); i++; @@ -167,7 +184,7 @@ _try(); - Class returnType = m.getReturnType(); + Class<?> returnType = m.getReturnType(); if (returnType == void.class) { _expr( @@ -177,76 +194,93 @@ _call(_v("delegate_"), m.getName(), _s(Type.type(returnType), expressionListTypes), expressionList)); } - boolean doExceptionTranslation = !java.rmi.Remote.class.isAssignableFrom(businessInterface); + boolean doExceptionTranslation = !Remote.class.isAssignableFrom(businessInterface); if (doExceptionTranslation) { + _catch(_t(TransactionRolledbackException.class.getName()), "trex"); - _catch(_t("jakarta.transaction.TransactionRolledbackException"), "trex"); - - _define( _t("java.lang.RuntimeException"), "r", - _new( _t("jakarta.ejb.EJBTransactionRolledbackException"), _s(_void()))); + _define(_t(RuntimeException.class.getName()), "r", + _new(_t(EJBTransactionRolledbackException.class.getName()), _s(_void()))); _expr( - _call( _v("r"), "initCause", _s(_t("java.lang.Throwable"), _t("java.lang.Throwable")), _v("trex")) + _call( + _v("r"), "initCause", + _s(_t(Throwable.class.getName()), _t(Throwable.class.getName())), + _v("trex") + ) ); _throw(_v("r")); - _catch(_t("jakarta.transaction.TransactionRequiredException"), "treqex"); + _catch(_t(TransactionRequiredException.class.getName()), "treqex"); - _define( _t("java.lang.RuntimeException"), "r", - _new( _t("jakarta.ejb.EJBTransactionRequiredException"), _s(_void()))); + _define(_t(RuntimeException.class.getName()), "r", + _new(_t(EJBTransactionRequiredException.class.getName()), _s(_void()))); + _expr( - _call( _v("r"), "initCause", _s(_t("java.lang.Throwable"), _t("java.lang.Throwable")), _v("treqex")) + _call( + _v("r"), "initCause", + _s(_t(Throwable.class.getName()), _t(Throwable.class.getName())), + _v("treqex") + ) ); _throw(_v("r")); - _catch(_t("java.rmi.NoSuchObjectException"), "nsoe"); + _catch(_t(NoSuchObjectException.class.getName()), "nsoe"); - _define( _t("java.lang.RuntimeException"), "r", - _new( _t("jakarta.ejb.NoSuchEJBException"), _s(_void()))); + _define(_t(RuntimeException.class.getName()), "r", + _new(_t(NoSuchEJBException.class.getName()), _s(_void()))); _expr( - _call( _v("r"), "initCause", _s(_t("java.lang.Throwable"), _t("java.lang.Throwable")), _v("nsoe")) + _call( + _v("r"), "initCause", + _s(_t(Throwable.class.getName()), _t(Throwable.class.getName())), + _v("nsoe") + ) ); _throw(_v("r")); - _catch(_t("java.rmi.AccessException"), "accex"); + _catch(_t(AccessException.class.getName()), "accex"); - _define( _t("java.lang.RuntimeException"), "r", - _new( _t("jakarta.ejb.EJBAccessException"), _s(_void()))); + _define(_t(RuntimeException.class.getName()), "r", + _new(_t(EJBAccessException.class.getName()), _s(_void()))); _expr( - _call( _v("r"), "initCause", _s(_t("java.lang.Throwable"), _t("java.lang.Throwable")), _v("accex")) + _call( + _v("r"), "initCause", + _s(_t(Throwable.class.getName()), _t(Throwable.class.getName())), + _v("accex") + ) ); _throw(_v("r")); - _catch(_t("com.sun.ejb.containers.InternalEJBContainerException"), "iejbcEx"); + _catch(_t(InternalEJBContainerException.class.getName()), "iejbcEx"); - // This wraps an EJBException. Pull out the cause and throw - // it as is. - //_define( _t("java.lang.Throwable"), "r", _null()); - - - // _throw(_cast(_t("jakarta.ejb.EJBException"), _v("r"))); _throw( - _cast(_t("jakarta.ejb.EJBException"), _call( _v("iejbcEx"), "getCause", _s(_t("java.lang.Throwable")))) + _cast( + _t(EJBException.class.getName()), + _call(_v("iejbcEx"), "getCause", _s(_t(Throwable.class.getName()))) + ) ); - _catch(_t("java.rmi.RemoteException"), "re"); + _catch(_t(RemoteException.class.getName()), "re"); - _throw( _new( _t("jakarta.ejb.EJBException"), _s(_void(), _t("java.lang.Exception")), _v("re"))); + _throw( _new( _t(EJBException.class.getName()), _s(_void(), _t(Exception.class.getName())), _v("re"))); - _catch( _t("org.omg.CORBA.SystemException"), "corbaSysEx"); - _define( _t("java.lang.RuntimeException"), "r", _new( _t("jakarta.ejb.EJBException"), _s(_void()))); + _catch( _t(SystemException.class.getName()), "corbaSysEx"); + _define( _t(RuntimeException.class.getName()), "r", _new( _t(EJBException.class.getName()), _s(_void()))); _expr( - _call( _v("r"), "initCause", _s(_t("java.lang.Throwable"), _t("java.lang.Throwable")), _v("corbaSysEx")) + _call( + _v("r"), "initCause", + _s(_t(Throwable.class.getName()), _t(Throwable.class.getName())), + _v("corbaSysEx") + ) ); _throw(_v("r")); _end(); } else { - _catch(_t("com.sun.ejb.containers.InternalEJBContainerException"), "iejbcEx"); + _catch(_t(InternalEJBContainerException.class.getName()), "iejbcEx"); _throw( - _new( _t("com.sun.ejb.containers.InternalRemoteException"), - _s(_void(), _t("com.sun.ejb.containers.InternalEJBContainerException")), + _new( _t(InternalRemoteException.class.getName()), + _s(_void(), _t(InternalEJBContainerException.class.getName())), _v("iejbcEx")) ); _end();
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/RemoteGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/RemoteGenerator.java index 2bb8271..9de52f8 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/RemoteGenerator.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/RemoteGenerator.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -16,80 +17,88 @@ package com.sun.ejb.codegen; -import java.lang.reflect.Method; -import java.io.*; -import java.util.*; import com.sun.ejb.EJBUtils; +import com.sun.ejb.containers.InternalEJBContainerException; +import com.sun.ejb.containers.RemoteBusinessObject; +import com.sun.enterprise.util.LocalStringManagerImpl; -import static java.lang.reflect.Modifier.*; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; -import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.*; import org.glassfish.pfl.dynamic.codegen.spi.Type ; -import com.sun.enterprise.util.LocalStringManagerImpl; +import static java.lang.reflect.Modifier.ABSTRACT; +import static java.lang.reflect.Modifier.PUBLIC; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._arg; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._classGenerator; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._clear; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._end; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._interface; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._method; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._package; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._t; /** * This class is used to generate the RMI-IIOP version of a * remote business interface. */ - -public class RemoteGenerator extends Generator - implements ClassGeneratorFactory { +public final class RemoteGenerator extends Generator { private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(RemoteGenerator.class); + private Class<?> businessInterface; + private final Method[] methodsToGenerate; + private final String remoteInterfacePackageName; + private final String remoteInterfaceSimpleName; + private final String remoteInterfaceName; - private Class businessInterface; - private Method[] bizMethods; - private String remoteInterfacePackageName; - private String remoteInterfaceSimpleName; - private String remoteInterfaceName; - - /** - * Get the fully qualified name of the generated class. - * Note: the remote/local implementation class is in the same package - * as the bean class, NOT the remote/local interface. - * @return the name of the generated class. - */ - public String getGeneratedClass() { - return remoteInterfaceName; - } - - // For corba codegen infrastructure - public String className() { - return getGeneratedClass(); - } /** * Construct the Wrapper generator with the specified deployment * descriptor and class loader. - * @exception GeneratorException + * + * @param classLoader + * @param businessIntf + * @throws InvalidBean if the businessInterface doesn't exist. */ - public RemoteGenerator(ClassLoader cl, String businessIntf) throws GeneratorException { - super(); - + public RemoteGenerator(ClassLoader classLoader, String businessIntf) throws InvalidBean { try { - businessInterface = cl.loadClass(businessIntf); + businessInterface = classLoader.loadClass(businessIntf); } catch (ClassNotFoundException ex) { throw new InvalidBean( - localStrings.getLocalString( - "generator.remote_interface_not_found", - "Remote interface not found ")); + localStrings.getLocalString("generator.remote_interface_not_found", "Remote interface not found ")); } - remoteInterfaceName = EJBUtils.getGeneratedRemoteIntfName - (businessInterface.getName()); - + remoteInterfaceName = EJBUtils.getGeneratedRemoteIntfName(businessInterface.getName()); remoteInterfacePackageName = getPackageName(remoteInterfaceName); remoteInterfaceSimpleName = getBaseName(remoteInterfaceName); - bizMethods = removeDups(businessInterface.getMethods()); + methodsToGenerate = removeRedundantMethods(businessInterface.getMethods()); // NOTE : no need to remove ejb object methods because EJBObject // is only visible through the RemoteHome view. } + /** + * Get the fully qualified name of the generated class. + * <p> + * Note: the remote/local implementation class is in the same package + * as the bean class, NOT the remote/local interface. + * + * @return the name of the generated class. + */ + @Override + public String getGeneratedClassName() { + return remoteInterfaceName; + } + @Override + public Class<?> getAnchorClass() { + return businessInterface; + } + + @Override public void evaluate() { _clear(); @@ -97,51 +106,46 @@ if (remoteInterfacePackageName != null) { _package(remoteInterfacePackageName); } else { - // no-arg _package() call is required for default package _package(); } _interface(PUBLIC, remoteInterfaceSimpleName, - _t("java.rmi.Remote"), - _t("com.sun.ejb.containers.RemoteBusinessObject")); + _t(java.rmi.Remote.class.getName()), + _t(RemoteBusinessObject.class.getName()) + ); - for(int i = 0; i < bizMethods.length; i++) { - printMethod(bizMethods[i]); + for (Method method : methodsToGenerate) { + printMethod(method); } _end(); _classGenerator() ; - - return; - } private void printMethod(Method m) { boolean throwsRemoteException = false; - List<Type> exceptionList = new LinkedList<Type>(); - for(Class exception : m.getExceptionTypes()) { + List<Type> exceptionList = new LinkedList<>(); + for (Class<?> exception : m.getExceptionTypes()) { exceptionList.add(Type.type(exception)); - if( exception.getName().equals("java.rmi.RemoteException") ) { + if (exception.getName().equals("java.rmi.RemoteException")) { throwsRemoteException = true; } } - if( !throwsRemoteException ) { + if (!throwsRemoteException) { exceptionList.add(_t("java.rmi.RemoteException")); } - exceptionList.add(_t("com.sun.ejb.containers.InternalEJBContainerException")); + exceptionList.add(_t(InternalEJBContainerException.class.getName())); _method(PUBLIC | ABSTRACT, Type.type(m.getReturnType()), m.getName(), exceptionList); int i = 0; - for(Class param : m.getParameterTypes()) { + for (Class<?> param : m.getParameterTypes()) { _arg(Type.type(param), "param" + i); i++; } _end(); } - - }
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ServiceInterfaceGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ServiceInterfaceGenerator.java index d639f2a..ed9abd8 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ServiceInterfaceGenerator.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ServiceInterfaceGenerator.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -18,21 +19,23 @@ import java.lang.reflect.Method; -import java.util.List; +import java.rmi.RemoteException; import java.util.ArrayList; import java.util.LinkedList; - -import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.*; +import java.util.List; import org.glassfish.pfl.dynamic.codegen.spi.Type ; -import java.util.logging.Logger; - import jakarta.jws.WebMethod; -import static java.lang.reflect.Modifier.*; - -import com.sun.enterprise.util.LocalStringManagerImpl; -import com.sun.logging.LogDomains; +import static java.lang.reflect.Modifier.ABSTRACT; +import static java.lang.reflect.Modifier.PUBLIC; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._arg; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._clear; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._end; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._interface; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._method; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._package; +import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._t; /** * This class is responsible for generating the SEI when it is not packaged @@ -40,98 +43,52 @@ * * @author Jerome Dochez */ -public class ServiceInterfaceGenerator extends Generator - implements ClassGeneratorFactory { +public class ServiceInterfaceGenerator extends Generator { - private static LocalStringManagerImpl localStrings = - new LocalStringManagerImpl(ServiceInterfaceGenerator.class); - private static Logger _logger=null; - static{ - _logger=LogDomains.getLogger(ServiceInterfaceGenerator.class, LogDomains.DPL_LOGGER); - } - - Class sib=null; - String serviceIntfName; - String packageName; - String serviceIntfSimpleName; - Method[] intfMethods; + private final Class<?> ejbClass; + private final String packageName; + private final String serviceIntfName; + private final String serviceIntfSimpleName; + private final Method[] intfMethods; /** * Construct the Wrapper generator with the specified deployment * descriptor and class loader. - * @exception GeneratorException. */ - public ServiceInterfaceGenerator(ClassLoader cl, Class sib) - throws GeneratorException, ClassNotFoundException - { - super(); - - this.sib = sib; - serviceIntfSimpleName = getServiceIntfName(); - - packageName = getPackageName(); - serviceIntfName = packageName + "." + serviceIntfSimpleName; - - intfMethods = calculateMethods(sib, removeDups(sib.getMethods())); + public ServiceInterfaceGenerator(Class<?> ejbClass) { + this.ejbClass = ejbClass; + packageName = getPackageName(ejbClass.getName()); + serviceIntfSimpleName = getServiceIntfName(ejbClass); + serviceIntfName = (packageName == null ? "" : packageName + ".") + serviceIntfSimpleName; + intfMethods = calculateMethods(ejbClass, removeRedundantMethods(ejbClass.getMethods())); // NOTE : no need to remove ejb object methods because EJBObject // is only visible through the RemoteHome view. } - public String getServiceIntfName() { - String serviceIntfSimpleName = sib.getSimpleName(); - if (serviceIntfSimpleName.endsWith("EJB")) { - return serviceIntfSimpleName.substring(0, serviceIntfSimpleName.length()-3); - } else { - return serviceIntfSimpleName+"SEI"; - } - } - - public String getPackageName() { - return sib.getPackage().getName()+".internal.jaxws"; - } /** * Get the fully qualified name of the generated class. + * <p> * Note: the remote/local implementation class is in the same package * as the bean class, NOT the remote/local interface. + * * @return the name of the generated class. */ - public String getGeneratedClass() { + @Override + public String getGeneratedClassName() { return serviceIntfName; } - // For corba codegen infrastructure - public String className() { - return getGeneratedClass(); + + @Override + public Class<?> getAnchorClass() { + return ejbClass; } - private Method[] calculateMethods(Class sib, Method[] initialList) { - // we start by assuming the @WebMethod was NOT used on this class - boolean webMethodAnnotationUsed = false; - List<Method> list = new ArrayList<Method>(); - - for (Method m : initialList) { - WebMethod wm = m.getAnnotation(WebMethod.class); - if ( (wm != null) && !webMethodAnnotationUsed) { - webMethodAnnotationUsed=true; - // reset the list, this is the first annotated method we find - list.clear(); - } - if (wm!=null) { - list.add(m); - } else { - if (!webMethodAnnotationUsed && !m.getDeclaringClass().equals(java.lang.Object.class)) { - list.add(m); - } - } - } - return list.toArray(new Method[list.size()]); - } - + @Override public void evaluate() { - _clear(); if (packageName != null) { @@ -140,38 +97,31 @@ _interface(PUBLIC, serviceIntfSimpleName); - for(int i = 0; i < intfMethods.length; i++) { - printMethod(intfMethods[i]); + for (Method intfMethod : intfMethods) { + printMethod(intfMethod); } _end(); - - return; - } - private void printMethod(Method m) - { - + private void printMethod(Method m) { boolean throwsRemoteException = false; - List<Type> exceptionList = new LinkedList<Type>(); - for(Class exception : m.getExceptionTypes()) { + List<Type> exceptionList = new LinkedList<>(); + for (Class<?> exception : m.getExceptionTypes()) { exceptionList.add(Type.type(exception)); - if( exception.getName().equals("java.rmi.RemoteException") ) { + if (exception.getName().equals(RemoteException.class.getName())) { throwsRemoteException = true; } - } - if( !throwsRemoteException ) { - exceptionList.add(_t("java.rmi.RemoteException")); + } + if (!throwsRemoteException) { + exceptionList.add(_t(RemoteException.class.getName())); } - _method( PUBLIC | ABSTRACT, Type.type(m.getReturnType()), - m.getName(), exceptionList); + _method(PUBLIC | ABSTRACT, Type.type(m.getReturnType()), m.getName(), exceptionList); int i = 0; - - for(Class param : m.getParameterTypes()) { + for (Class<?> param : m.getParameterTypes()) { _arg(Type.type(param), "param" + i); i++; } @@ -179,4 +129,36 @@ _end(); } + + private static String getServiceIntfName(Class<?> ejbClass) { + String serviceIntfSimpleName = ejbClass.getSimpleName(); + if (serviceIntfSimpleName.endsWith("EJB")) { + return serviceIntfSimpleName.substring(0, serviceIntfSimpleName.length() - 3) + "_GeneratedSEI"; + } + return serviceIntfSimpleName + "_GeneratedSEI"; + } + + + private static Method[] calculateMethods(Class sib, Method[] initialList) { + // we start by assuming the @WebMethod was NOT used on this class + boolean webMethodAnnotationUsed = false; + List<Method> list = new ArrayList<>(); + + for (Method m : initialList) { + WebMethod wm = m.getAnnotation(WebMethod.class); + if (wm != null && !webMethodAnnotationUsed) { + webMethodAnnotationUsed = true; + // reset the list, this is the first annotated method we find + list.clear(); + } + if (wm != null) { + list.add(m); + } else { + if (!webMethodAnnotationUsed && !m.getDeclaringClass().equals(Object.class)) { + list.add(m); + } + } + } + return list.toArray(new Method[list.size()]); + } }
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java index 48b787a..8c89bea 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java
@@ -1103,8 +1103,8 @@ Class serviceEndpointIntfClass = loader.loadClass(webServiceEndpoint.getServiceEndpointInterface()); if (!serviceEndpointIntfClass.isInterface()) { - ServiceInterfaceGenerator generator = new ServiceInterfaceGenerator(loader, ejbClass); - serviceEndpointIntfClass = EJBUtils.generateSEI(generator, loader, this.ejbClass); + ServiceInterfaceGenerator generator = new ServiceInterfaceGenerator(ejbClass); + serviceEndpointIntfClass = EJBUtils.generateSEI(generator, loader); if (serviceEndpointIntfClass == null) { throw new RuntimeException(localStrings.getLocalString("ejb.error_generating_sei", "Error in generating service endpoint interface class for EJB class {0}", this.ejbClass));
diff --git a/appserver/ejb/ejb-container/src/test/java/com/sun/ejb/EJBUtilsTest.java b/appserver/ejb/ejb-container/src/test/java/com/sun/ejb/EJBUtilsTest.java index ab949d8..b81f13d 100644 --- a/appserver/ejb/ejb-container/src/test/java/com/sun/ejb/EJBUtilsTest.java +++ b/appserver/ejb/ejb-container/src/test/java/com/sun/ejb/EJBUtilsTest.java
@@ -18,13 +18,16 @@ import com.sun.ejb.codegen.ClassGeneratorFactory; import com.sun.ejb.codegen.Generator; +import com.sun.ejb.codegen.Remote30WrapperGenerator; import com.sun.ejb.codegen.ServiceInterfaceGenerator; import java.util.Collection; import java.util.concurrent.TimeUnit; -import org.glassfish.pfl.dynamic.codegen.spi.Wrapper; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.results.Result; @@ -34,7 +37,6 @@ import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; -import static java.lang.reflect.Modifier.PUBLIC; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.lessThan; @@ -47,53 +49,71 @@ /** * @author David Matejcek */ +@TestMethodOrder(OrderAnnotation.class) public class EJBUtilsTest { + /** + * The value shall be high enough to pass on all standard environments, + * but lower than when we are generating classes. See warmup results in logs. + */ + private static final double MAX_TIME_PER_OPERATION = 1_000_000d; private static final ClassLoader loader = EJBUtilsTest.class.getClassLoader(); + private static double firstRunScore; @Test - public void generateSEI_Benchmark() throws Exception { + @Order(1) + public void generateAndLoad_firstRun() throws Exception { Options options = new OptionsBuilder() .include(getClass().getName() + ".*") - .mode(Mode.AverageTime) .warmupIterations(0) - .measurementIterations(2) - .measurementTime(TimeValue.seconds(1L)) - .forks(1) - .threads(20) - .shouldFailOnError(true) - .shouldDoGC(true) - .timeout(TimeValue.seconds(5L)) - .timeUnit(TimeUnit.NANOSECONDS) + .measurementIterations(1).forks(1).measurementTime(TimeValue.milliseconds(50L)) + // should be able to detect deadlocks and race conditions when generating classes + .threads(100).timeout(TimeValue.seconds(5L)) + .timeUnit(TimeUnit.MICROSECONDS) + .mode(Mode.SingleShotTime).shouldFailOnError(true) .build(); Collection<RunResult> results = new Runner(options).run(); assertThat(results, hasSize(1)); - Result<?> result = results.iterator().next().getAggregatedResult().getPrimaryResult(); - assertThat(result.getScore(), lessThan(100000d)); + Result<?> primaryResult = results.iterator().next().getPrimaryResult(); + firstRunScore = primaryResult.getScore(); + assertThat(primaryResult.getScore(), lessThan(MAX_TIME_PER_OPERATION)); + } + + + @Test + @Order(2) + public void generateAndLoad_Benchmark() throws Exception { + Options options = new OptionsBuilder() + .include(getClass().getName() + ".*") + .warmupBatchSize(1).warmupForks(0).warmupIterations(1).warmupTime(TimeValue.milliseconds(50L)) + .measurementIterations(1).forks(1).measurementTime(TimeValue.milliseconds(200L)) + // should be able to detect race conditions when loading classes generated in previous test + .threads(100).timeout(TimeValue.seconds(5L)) + .timeUnit(TimeUnit.MICROSECONDS) + .mode(Mode.AverageTime).shouldFailOnError(true) + .build(); + + Collection<RunResult> results = new Runner(options).run(); + assertThat(results, hasSize(1)); + Result<?> primaryResult = results.iterator().next().getPrimaryResult(); + assertThat(primaryResult.getScore(), lessThan(firstRunScore / 4)); } @Benchmark - public void generateSei_Benchmark() throws Exception { - ClassGeneratorFactory generator = new CustomGenerator(); - Class<?> newClass = EJBUtils.generateSEI(generator, loader, EJbUtilsEjbTestClass.class); + public void generateAndLoad() throws Exception { + // random interface for the test + String interfaceName = ClassGeneratorFactory.class.getName(); + Generator generator = new Remote30WrapperGenerator(loader, interfaceName, interfaceName); + Class<?> newClass = EJBUtils.generateAndLoad(generator, loader); assertNotNull(newClass); - assertEquals(generator.className(), newClass.getName()); + assertEquals(generator.getGeneratedClassName(), newClass.getName()); } @Test - public void generateSei_ServiceInterfaceGenerator() throws Exception { - ServiceInterfaceGenerator generator = new ServiceInterfaceGenerator(loader, EJbUtilsEjbTestClass.class); - // FIXME: com.sun.ejb.EJBUtilsTest$EJbUtilsEjbTestClass doesn't have expected package com.sun.ejb.internal.jaxws - Class<?> newClass = EJBUtils.generateSEI(generator, loader, EJbUtilsEjbTestClass.class); - assertNotNull(newClass); - assertEquals(generator.className(), newClass.getName()); - } - - - @Test + @Order(10) public void loadGeneratedRemoteBusinessClasses() throws Exception { EJBUtils.loadGeneratedRemoteBusinessClasses(EjbUtilsTestInterface.class.getName()); Class<?> ifaceRemote = loader.loadClass("com.sun.ejb._EJBUtilsTest$EjbUtilsTestInterface_Remote"); @@ -105,6 +125,7 @@ @Test + @Order(20) public void loadGeneratedGenericEJBHomeClass() throws Exception { Class<?> newClass = EJBUtils.loadGeneratedGenericEJBHomeClass(loader); assertNotNull(newClass); @@ -113,34 +134,18 @@ assertSame(newClass, EJBUtils.loadGeneratedGenericEJBHomeClass(loader)); } - private static class CustomGenerator extends Generator implements ClassGeneratorFactory { - @Override - public String getGeneratedClass() { - return "com.sun.ejb.EJBUtilsTestImplFromCustomGenerator"; - } - - @Override - public String className() { - return getGeneratedClass(); - } - - @Override - public void evaluate() { - Wrapper._clear(); - Wrapper._package(getPackageName(className())); - Wrapper._interface(PUBLIC, getBaseName(className())); - Wrapper._classGenerator(); - } + @Test + @Order(30) + public void generateSEI() throws Exception { + Generator generator = new ServiceInterfaceGenerator(ClassGeneratorFactory.class); + Class<?> newClass = EJBUtils.generateSEI(generator, loader); + assertNotNull(newClass); + assertEquals(generator.getGeneratedClassName(), newClass.getName()); } interface EjbUtilsTestInterface { void doSomething(); } - - - public static class EJbUtilsEjbTestClass { - - } }