From d2fbb5a929bb6c82bc55b3f8b1a8e55ba7584083 Mon Sep 17 00:00:00 2001 From: lprimak Date: Wed, 27 Nov 2024 17:04:27 -0700 Subject: [PATCH] bugfix: fix EAR deployment failure when multiple WARs use multible CDI-enabled library JARs - correctly copy BDA sets for each war in EAR - Make WAR's CDI beans available in EAR-libs - read web-fragment.xml from EAR-libs - processing ear-lib manifest - de-duplicate BDAs in CDI processing by using LinkedHashSet intead of ArrayList - made some structures final (cleanup) - fixed ear and concurrent classloader leaks --- .../runtime/ContextSetupProviderImpl.java | 6 +- .../javaee/full/deployment/EarDeployer.java | 17 +- appserver/web/war-util/pom.xml | 16 + .../web/loader/WebappClassLoader.java | 20 +- .../deployment/archivist/WebArchivist.java | 109 +++-- .../glassfish/weld/ACLSingletonProvider.java | 8 +- .../weld/BeanDeploymentArchiveImpl.java | 148 ++++-- .../weld/BeanManagerNamingProxy.java | 10 +- .../org/glassfish/weld/DeploymentImpl.java | 451 ++++++++++-------- .../glassfish/weld/GlassFishWeldProvider.java | 48 +- .../weld/RootBeanDeploymentArchive.java | 28 +- .../glassfish/weld/ValidationNamingProxy.java | 6 +- .../java/org/glassfish/weld/WeldDeployer.java | 302 +++++++----- .../weld/services/JCDIServiceImpl.java | 13 +- .../weld/services/JCDIServiceImplTest.java | 10 +- .../enterprise/loader/ASURLClassLoader.java | 21 +- .../sun/enterprise/loader/CacheCleaner.java | 66 +++ .../loader/CachingReflectionUtil.java | 6 +- .../com/sun/enterprise/loader/DirWatcher.java | 4 +- .../common/DeploymentContextImpl.java | 15 +- 20 files changed, 822 insertions(+), 482 deletions(-) create mode 100644 nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/CacheCleaner.java rename {appserver/web/war-util/src/main/java/org/glassfish/web => nucleus/common/common-util/src/main/java/com/sun/enterprise}/loader/CachingReflectionUtil.java (96%) diff --git a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ContextSetupProviderImpl.java b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ContextSetupProviderImpl.java index 98d633bacc3..f53bad9ef16 100644 --- a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ContextSetupProviderImpl.java +++ b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ContextSetupProviderImpl.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2016-2023] [Payara Foundation and/or its affiliates] +// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates] package org.glassfish.concurrent.runtime; @@ -378,9 +378,7 @@ public void reset(ContextHandle contextHandle) { restorer.endContext(); } - if (handle.getContextClassLoader() != null) { - Utility.setContextClassLoader(handle.getContextClassLoader()); - } + Utility.setContextClassLoader(handle.getContextClassLoader()); if (handle.getSecurityContext() != null) { SecurityContext.setCurrent(handle.getSecurityContext()); } diff --git a/appserver/deployment/javaee-full/src/main/java/org/glassfish/javaee/full/deployment/EarDeployer.java b/appserver/deployment/javaee-full/src/main/java/org/glassfish/javaee/full/deployment/EarDeployer.java index ac8567bdd46..66f93f89b78 100644 --- a/appserver/deployment/javaee-full/src/main/java/org/glassfish/javaee/full/deployment/EarDeployer.java +++ b/appserver/deployment/javaee-full/src/main/java/org/glassfish/javaee/full/deployment/EarDeployer.java @@ -37,6 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ +// Portions Copyright [2024] [Payara Foundation and/or its affiliates] package org.glassfish.javaee.full.deployment; @@ -101,7 +102,7 @@ @Service @PerLookup public class EarDeployer implements Deployer { - + public static final String PER_BDA_METADATA_KEY = "[PerBDA]"; // private static final Class GLASSFISH_APPCLIENT_GROUP_FACADE_CLASS = // org.glassfish.appclient.client.AppClientGroupFacade.class; // Currently using a string instead of a Class constant to avoid a circular @@ -457,15 +458,21 @@ public U getCommandParameters(Class commandParametersTy @Override public void addTransientAppMetaData(String metaDataKey, Object metaData) { - context.addTransientAppMetaData(metaDataKey, - metaData); + if (metaDataKey.startsWith(PER_BDA_METADATA_KEY)) { + super.addTransientAppMetaData(metaDataKey, metaData); + } else { + context.addTransientAppMetaData(metaDataKey, metaData); + } } @Override public T getTransientAppMetaData(String metaDataKey, Class metadataType) { - return context.getTransientAppMetaData(metaDataKey, - metadataType); + if (metaDataKey.startsWith(PER_BDA_METADATA_KEY)) { + return super.getTransientAppMetaData(metaDataKey, metadataType); + } else { + return context.getTransientAppMetaData(metaDataKey, metadataType); + } } @Override diff --git a/appserver/web/war-util/pom.xml b/appserver/web/war-util/pom.xml index 007ba3bc40a..aab8c38659f 100755 --- a/appserver/web/war-util/pom.xml +++ b/appserver/web/war-util/pom.xml @@ -120,4 +120,20 @@ glassfish + + + + + com.github.siom79.japicmp + japicmp-maven-plugin + + + + org.glassfish.web.loader.CachingReflectionUtil + + + + + + diff --git a/appserver/web/war-util/src/main/java/org/glassfish/web/loader/WebappClassLoader.java b/appserver/web/war-util/src/main/java/org/glassfish/web/loader/WebappClassLoader.java index 93578a1a19a..72e3e16851c 100644 --- a/appserver/web/war-util/src/main/java/org/glassfish/web/loader/WebappClassLoader.java +++ b/appserver/web/war-util/src/main/java/org/glassfish/web/loader/WebappClassLoader.java @@ -65,6 +65,7 @@ import com.sun.enterprise.deployment.Application; import com.sun.enterprise.deployment.util.DOLUtils; import com.sun.enterprise.glassfish.bootstrap.MainHelper.HotSwapHelper; +import com.sun.enterprise.loader.CacheCleaner; import com.sun.enterprise.security.integration.DDPermissionsLoader; import com.sun.enterprise.security.integration.PermsHolder; import com.sun.enterprise.util.io.FileUtils; @@ -2051,7 +2052,7 @@ public void stop() throws Exception { // START SJSAS 6258619 ClassLoaderUtil.releaseLoader(this); // END SJSAS 6258619 - clearJaxRSCache(); + CacheCleaner.clearJaxRSCache(this); synchronized(jarFilesLock) { started = false; @@ -2658,23 +2659,6 @@ private void clearReferencesRmiTargets() { } } - private void clearJaxRSCache() { - try { - Class cdiComponentProvider = CachingReflectionUtil - .getClassFromCache("org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider", this); - if (cdiComponentProvider != null) { - Field runtimeSpecificsField = CachingReflectionUtil.getFieldFromCache(cdiComponentProvider, - "runtimeSpecifics", true); - Object runtimeSpecifics = runtimeSpecificsField.get(null); - CachingReflectionUtil.getMethodFromCache(runtimeSpecifics.getClass(), - "clearJaxRsResource", true, ClassLoader.class) - .invoke(runtimeSpecifics, this); - } - } catch (Exception e) { - logger.log(Level.WARNING, "Error clearing Jax-Rs cache", e); - } - } - /** * Clear the {@link ResourceBundle} cache of any bundles loaded by this * class loader or any class loader where this loader is a parent class diff --git a/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java b/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java index 83498d21c09..3ea9a8e0965 100644 --- a/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java +++ b/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java @@ -37,11 +37,12 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2014-2021] [Payara Foundation and/or its affiliates] +// Portions Copyright [2014-2024] [Payara Foundation and/or its affiliates] package org.glassfish.web.deployment.archivist; import com.sun.enterprise.deployment.Application; +import com.sun.enterprise.deployment.EarType; import org.glassfish.deployment.common.RootDeploymentDescriptor; import com.sun.enterprise.deployment.EjbBundleDescriptor; import com.sun.enterprise.deployment.EjbDescriptor; @@ -75,9 +76,10 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Vector; +import java.util.Set; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; @@ -296,24 +298,33 @@ protected String getArchiveExtension() { /** * @return a list of libraries included in the archivist */ - public Vector getLibraries(Archive archive) { + public Set getLibraries(ReadableArchive archive) throws IOException { + Set libraries = new LinkedHashSet<>(); + // WAR libraries + extractLibraries(archive, true, libraries); + ReadableArchive parentArchive = archive.getParentArchive(); + if (parentArchive != null && parentArchive.getExtraData(ArchiveType.class).toString().equals(EarType.ARCHIVE_TYPE)) { + // EAR shared libraries + extractLibraries(parentArchive.getSubArchive("lib"), false, libraries); + } + return libraries; + } - Enumeration entries = archive.entries(); + private static void extractLibraries(Archive archive, boolean hasWebInfPrefix, Set libs) { + Enumeration entries = archive != null ? archive.entries() : null; if (entries==null) - return null; + return; - Vector libs = new Vector(); while (entries.hasMoreElements()) { String entryName = entries.nextElement(); - if (!entryName.startsWith("WEB-INF/lib")) { - continue; // not in WEB-INF... + if (hasWebInfPrefix && !entryName.startsWith("WEB-INF/lib")) { + continue; // not in prefix (i.e. WEB-INF)... } if (entryName.endsWith(".jar")) { libs.add(entryName); } } - return libs; } @Override @@ -381,54 +392,50 @@ private List readStandardFragments(WebBundleDescriptorImp ReadableArchive archive) throws IOException { List wfList = new ArrayList(); - Vector libs = getLibraries(archive); - if (libs != null && libs.size() > 0) { - - for (int i = 0; i < libs.size(); i++) { - String lib = (String)libs.get(i); - Archivist wfArchivist = new WebFragmentArchivist(this, habitat); - wfArchivist.setRuntimeXMLValidation(this.getRuntimeXMLValidation()); - wfArchivist.setRuntimeXMLValidationLevel( - this.getRuntimeXMLValidationLevel()); - wfArchivist.setAnnotationProcessingRequested(false); - - WebFragmentDescriptor wfDesc = null; - ReadableArchive embeddedArchive = archive.getSubArchive(lib); - try { - if (embeddedArchive != null && - wfArchivist.hasStandardDeploymentDescriptor(embeddedArchive)) { - try { - wfDesc = (WebFragmentDescriptor)wfArchivist.open(embeddedArchive); - } catch(SAXParseException ex) { - IOException ioex = new IOException(); - ioex.initCause(ex); - throw ioex; - } - } else { - wfDesc = new WebFragmentDescriptor(); - wfDesc.setExists(false); - } - } finally { - if (embeddedArchive != null) { - embeddedArchive.close(); + for (String lib : getLibraries(archive)) { + Archivist wfArchivist = new WebFragmentArchivist(this, habitat); + wfArchivist.setRuntimeXMLValidation(this.getRuntimeXMLValidation()); + wfArchivist.setRuntimeXMLValidationLevel( + this.getRuntimeXMLValidationLevel()); + wfArchivist.setAnnotationProcessingRequested(false); + + WebFragmentDescriptor wfDesc = null; + ReadableArchive embeddedArchive = lib.startsWith("WEB-INF") + ? archive.getSubArchive(lib) : archive.getParentArchive().getSubArchive("lib").getSubArchive(lib); + try { + if (embeddedArchive != null && + wfArchivist.hasStandardDeploymentDescriptor(embeddedArchive)) { + try { + wfDesc = (WebFragmentDescriptor)wfArchivist.open(embeddedArchive); + } catch(SAXParseException ex) { + IOException ioex = new IOException(); + ioex.initCause(ex); + throw ioex; } + } else { + wfDesc = new WebFragmentDescriptor(); + wfDesc.setExists(false); + } + } finally { + if (embeddedArchive != null) { + embeddedArchive.close(); } - wfDesc.setJarName(lib.substring(lib.lastIndexOf('/') + 1)); - wfList.add(wfDesc); + } + wfDesc.setJarName(lib.substring(lib.lastIndexOf('/') + 1)); + wfList.add(wfDesc); - descriptor.putJarNameWebFragmentNamePair(wfDesc.getJarName(), wfDesc.getName()); + descriptor.putJarNameWebFragmentNamePair(wfDesc.getJarName(), wfDesc.getName()); - } + } - if (((WebBundleDescriptorImpl)descriptor).getAbsoluteOrderingDescriptor() != null) { - wfList = ((WebBundleDescriptorImpl)descriptor).getAbsoluteOrderingDescriptor().order(wfList); - } else { - OrderingDescriptor.sort(wfList); - } + if (((WebBundleDescriptorImpl)descriptor).getAbsoluteOrderingDescriptor() != null) { + wfList = ((WebBundleDescriptorImpl)descriptor).getAbsoluteOrderingDescriptor().order(wfList); + } else { + OrderingDescriptor.sort(wfList); + } - for (WebFragmentDescriptor wf : wfList) { - descriptor.addOrderedLib(wf.getJarName()); - } + for (WebFragmentDescriptor wf : wfList) { + descriptor.addOrderedLib(wf.getJarName()); } return wfList; diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/ACLSingletonProvider.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/ACLSingletonProvider.java index 184a492b006..79f89f969a9 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/ACLSingletonProvider.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/ACLSingletonProvider.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. * - * Portions Copyright [2017-2019] Payara Foundation and/or affiliates + * Portions Copyright [2017-2024] Payara Foundation and/or affiliates */ package org.glassfish.weld; @@ -108,11 +108,11 @@ public ClassLoader run() @Override public T get( String id ) { - ClassLoader acl = getClassLoader(); - T instance = store.get(acl); + T instance = storeById.get(id); if (instance == null) { - instance = storeById.get(id); + ClassLoader acl = getClassLoader(); + instance = store.get(acl); if (instance == null) { throw new IllegalStateException("Singleton not set for " + acl); } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanDeploymentArchiveImpl.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanDeploymentArchiveImpl.java index b61dcc8a2b9..235ed40151a 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanDeploymentArchiveImpl.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanDeploymentArchiveImpl.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2016-2022] [Payara Foundation and/or its affiliates] +// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates] package org.glassfish.weld; @@ -62,9 +62,12 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.*; @@ -79,37 +82,37 @@ import static org.glassfish.weld.WeldDeployer.WELD_BOOTSTRAP; import static org.glassfish.weld.connector.WeldUtils.*; - - /* * The means by which Weld Beans are discovered on the classpath. */ -public class BeanDeploymentArchiveImpl implements BeanDeploymentArchive { +public class BeanDeploymentArchiveImpl implements BeanDeploymentArchive, Serializable { + private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(BeanDeploymentArchiveImpl.class.getName()); - private ReadableArchive archive; - private String id; - private List moduleClassNames = null; // Names of classes in the module - private List beanClassNames = null; // Names of bean classes in the module - private List> moduleClasses = null; // Classes in the module - private List> beanClasses = null; // Classes identified as Beans through Weld SPI - private List beansXmlURLs = null; - private final Collection> ejbDescImpls; - private List beanDeploymentArchives; + private transient ReadableArchive archive; + private final String id; + private final List moduleClassNames; // Names of classes in the module + private final List beanClassNames; // Names of bean classes in the module + private transient List> moduleClasses; // Classes in the module + private transient List> beanClasses; // Classes identified as Beans through Weld SPI + private final List beansXmlURLs; + private transient Collection> ejbDescImpls; + private transient Set beanDeploymentArchives; + private transient List deserializedBDAs; - private SimpleServiceRegistry simpleServiceRegistry = null; + private transient SimpleServiceRegistry simpleServiceRegistry = null; + private int originalIdentity; private BDAType bdaType = BDAType.UNKNOWN; - private DeploymentContext context; - - private WeldBootstrap weldBootstrap; + transient DeploymentContext context; + transient WeldBootstrap weldBootstrap; - private final Map, InjectionTarget> itMap = new HashMap<>(); + private transient Map, InjectionTarget> itMap = new HashMap<>(); //workaround: WELD-781 - private ClassLoader moduleClassLoaderForBDA = null; + private transient ClassLoader moduleClassLoaderForBDA; private String friendlyId = ""; @@ -147,8 +150,8 @@ public BeanDeploymentArchiveImpl(ReadableArchive archive, } this.friendlyId = this.id; - this.ejbDescImpls = new HashSet<>(); - this.beanDeploymentArchives = new ArrayList<>(); + this.ejbDescImpls = new LinkedHashSet<>(); + this.beanDeploymentArchives = new LinkedHashSet<>(); this.context = ctx; this.weldBootstrap = context.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); @@ -184,8 +187,8 @@ public BeanDeploymentArchiveImpl(String } this.beansXmlURLs = beansXmlUrls; - this.ejbDescImpls = new HashSet<>(); - this.beanDeploymentArchives = new ArrayList<>(); + this.ejbDescImpls = new LinkedHashSet<>(); + this.beanDeploymentArchives = new LinkedHashSet<>(); this.context = ctx; this.weldBootstrap = context.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); populateEJBsForThisBDA(ejbs); @@ -194,6 +197,39 @@ public BeanDeploymentArchiveImpl(String getClassLoader(); } + public BeanDeploymentArchiveImpl(BeanDeploymentArchiveImpl beanDeploymentArchive) { + this.id = beanDeploymentArchive.id; + this.originalIdentity = beanDeploymentArchive.originalIdentity; + this.moduleClassNames = new ArrayList<>(beanDeploymentArchive.moduleClassNames); + this.beanClassNames = new ArrayList<>(beanDeploymentArchive.beanClassNames); + this.beansXmlURLs = new CopyOnWriteArrayList<>(beanDeploymentArchive.beansXmlURLs); + this.deserializedBDAs = beanDeploymentArchive.deserializedBDAs; + this.friendlyId = beanDeploymentArchive.friendlyId; + this.bdaType = beanDeploymentArchive.bdaType; + this.deploymentComplete = beanDeploymentArchive.deploymentComplete; + + initializeFromOriginal(); + } + + void initializeFromOriginal() { + if (context == null) { + this.context = DeploymentImpl.currentDeploymentContext.get(); + this.weldBootstrap = context.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); + this.moduleClasses = getOriginal().moduleClasses; + this.beanClasses = getOriginal().beanClasses; + getServices().addAll(getOriginal().getServices().entrySet()); + this.moduleClassLoaderForBDA = getOriginal().moduleClassLoaderForBDA; + this.ejbDescImpls = new LinkedHashSet<>(getOriginal().ejbDescImpls); + if (this.itMap == null) { + this.itMap = new HashMap<>(); + } + this.itMap.putAll(getOriginal().itMap); + } + } + + BeanDeploymentArchiveImpl getOriginal() { + return DeploymentImpl.currentBDAs.get().get(originalIdentity); + } private void populateEJBsForThisBDA(Collection ejbs) { for (com.sun.enterprise.deployment.EjbDescriptor next : ejbs) { @@ -208,11 +244,15 @@ private void populateEJBsForThisBDA(Collection getBeanDeploymentArchives() { + if (beanDeploymentArchives == null && deserializedBDAs != null) { + beanDeploymentArchives = new LinkedHashSet<>(deserializedBDAs); + } return beanDeploymentArchives; } @Override public Collection getBeanClasses() { + initializeFromOriginal(); //This method is called during BeanDeployment.deployBeans, so this would //be the right time to place the module classloader for the BDA as the TCL if (logger.isLoggable(FINER)) { @@ -230,6 +270,7 @@ public Collection getBeanClasses() { } public Collection> getBeanClassObjects() { + initializeFromOriginal(); return beanClasses; } @@ -238,6 +279,7 @@ public Collection getModuleBeanClasses() { } public Collection> getModuleBeanClassObjects() { + initializeFromOriginal(); return moduleClasses; } @@ -272,7 +314,7 @@ public BeansXml getBeansXml() { if (beansXmlURLs.size() == 1) { result = weldBootstrap.parse(beansXmlURLs.get(0)); } else { - // This method attempts to performs a merge, but loses some + // This method attempts to perform a merge, but loses some // information (e.g., version, bean-discovery-mode) result = weldBootstrap.parse(beansXmlURLs); } @@ -287,11 +329,12 @@ public BeansXml getBeansXml() { */ @Override public Collection> getEjbs() { - + initializeFromOriginal(); return ejbDescImpls; } public EjbDescriptor getEjbDescriptor(String ejbName) { + initializeFromOriginal(); EjbDescriptor match = null; for (EjbDescriptor next : ejbDescImpls) { @@ -306,6 +349,7 @@ public EjbDescriptor getEjbDescriptor(String ejbName) { @Override public ServiceRegistry getServices() { + initializeFromOriginal(); if (simpleServiceRegistry == null) { simpleServiceRegistry = new SimpleServiceRegistry(); } @@ -328,10 +372,36 @@ public Collection getKnownClasses() { @Override public Collection> getLoadedBeanClasses() { + initializeFromOriginal(); return beanClasses; } + Object readResolve() throws ObjectStreamException { + return new BeanDeploymentArchiveImpl(this); + } + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + originalIdentity = System.identityHashCode(this); + if (DeploymentImpl.currentBDAs.get().put(originalIdentity, this) != null) { + throw new IllegalStateException("Duplicate BDA detected: " + this); + } + out.writeInt(originalIdentity); + out.writeInt(beanDeploymentArchives.size()); + for (BeanDeploymentArchive bda : beanDeploymentArchives) { + out.writeObject(bda); + } + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + originalIdentity = in.readInt(); + int size = in.readInt(); + deserializedBDAs = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + deserializedBDAs.add((BeanDeploymentArchive) in.readObject()); + } + } //A graphical representation of the BDA hierarchy to aid in debugging //and to provide a better representation of how Weld treats the deployed @@ -601,14 +671,13 @@ private void ensureWebLibJarVisibility(List webLibBDA } //update modified BDA if (modified) { - int idx = this.beanDeploymentArchives.indexOf(firstBDA); if (logger.isLoggable(FINE)) { logger.log(FINE, CDILoggerInfo.ENSURE_WEB_LIB_JAR_VISIBILITY_ASSOCIATION_UPDATING, new Object[]{firstBDA.getFriendlyId()}); } - if (idx >= 0) { - this.beanDeploymentArchives.set(idx, firstBDA); + if (this.beanDeploymentArchives.remove(firstBDA)) { + this.beanDeploymentArchives.add(firstBDA); } } } @@ -622,9 +691,8 @@ private void ensureWebLibJarVisibility(List webLibBDA CDILoggerInfo.ENSURE_WEB_LIB_JAR_VISIBILITY_ASSOCIATION_INCLUDING, new Object[]{subBDA.getId(), this.getId()}); } - int idx = this.beanDeploymentArchives.indexOf(subBDA); - if (idx >= 0) { - this.beanDeploymentArchives.set(idx, subBDA); + if (this.beanDeploymentArchives.remove(subBDA)) { + this.beanDeploymentArchives.add(subBDA); } } } @@ -741,14 +809,17 @@ private ClassLoader getClassLoader() { } public InjectionTarget getInjectionTarget(AnnotatedType annotatedType) { + initializeFromOriginal(); return itMap.get(annotatedType); } void putInjectionTarget(AnnotatedType annotatedType, InjectionTarget it) { + initializeFromOriginal(); itMap.put(annotatedType, it); } public ClassLoader getModuleClassLoaderForBDA() { + initializeFromOriginal(); return moduleClassLoaderForBDA; } @@ -853,4 +924,17 @@ static String stripMavenVersion(String name) { } return name; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BeanDeploymentArchiveImpl)) return false; + BeanDeploymentArchiveImpl that = (BeanDeploymentArchiveImpl) o; + return Objects.equals(id, that.id) && Objects.equals(beanClasses, that.beanClasses); + } + + @Override + public int hashCode() { + return Objects.hash(id, beanClasses); + } } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanManagerNamingProxy.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanManagerNamingProxy.java index b9974012c6d..f156f38e081 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanManagerNamingProxy.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanManagerNamingProxy.java @@ -37,6 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ +// Portions Copyright [2024] [Payara Foundation and/or its affiliates] package org.glassfish.weld; @@ -93,7 +94,9 @@ public Object handle(String name) throws NamingException { if( inv != null ) { - JndiNameEnvironment componentEnv = compEnvManager.getJndiNameEnvironment(inv.getComponentId()); + JndiNameEnvironment componentEnv = inv.getComponentId() != null + ? compEnvManager.getJndiNameEnvironment(inv.getComponentId()) + : null; if( componentEnv != null ) { @@ -112,7 +115,7 @@ public Object handle(String name) throws NamingException { if( bundle != null ) { BeanDeploymentArchive bda = weldDeployer.getBeanDeploymentArchiveForBundle(bundle); if( bda != null ) { - WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(bundle.getApplication()); + WeldBootstrap bootstrap = weldDeployer.getBootstrapForArchive(bda); //System.out.println("BeanManagerNamingProxy:: getting BeanManagerImpl for" + bda); beanManager = bootstrap.getManager(bda); } @@ -122,7 +125,6 @@ public Object handle(String name) throws NamingException { throw new IllegalStateException("Cannot resolve bean manager"); } - } else { throw new IllegalStateException("No invocation context found"); } @@ -137,6 +139,4 @@ public Object handle(String name) throws NamingException { return beanManager; } - - } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java index caaae19ab44..7012319103c 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2016-2022] [Payara Foundation and/or its affiliates] +// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates] package org.glassfish.weld; @@ -45,9 +45,15 @@ import static java.util.logging.Level.FINE; import static java.util.logging.Level.WARNING; import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; import static org.glassfish.weld.connector.WeldUtils.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -62,9 +68,11 @@ import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.cdi.CDILoggerInfo; +import org.glassfish.common.util.ObjectInputStreamWithLoader; import org.glassfish.deployment.common.DeploymentContextImpl; import org.glassfish.deployment.common.InstalledLibrariesResolver; import org.glassfish.hk2.classmodel.reflect.Types; +import org.glassfish.internal.data.ApplicationInfo; import org.glassfish.javaee.core.deployment.ApplicationHolder; import org.glassfish.weld.connector.WeldUtils; import org.glassfish.weld.connector.WeldUtils.BDAType; @@ -85,46 +93,50 @@ import jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; import org.jboss.weld.lite.extension.translator.LiteExtensionTranslator; import java.security.PrivilegedAction; +import java.util.stream.Stream; import static java.lang.System.getSecurityManager; import static java.security.AccessController.doPrivileged; import jakarta.enterprise.inject.build.compatible.spi.SkipIfPortableExtensionPresent; - /* * Represents a deployment of a CDI (Weld) application. */ -public class DeploymentImpl implements CDI11Deployment { +public class DeploymentImpl implements CDI11Deployment, Serializable { + private static final long serialVersionUID = 1L; + static final ThreadLocal currentDeployment = new ThreadLocal<>(); + static final ThreadLocal> currentBDAs = new ThreadLocal<>(); + static final ThreadLocal currentDeploymentContext = new ThreadLocal<>(); // Keep track of our BDAs for this deployment - private List rarRootBdas; - private List ejbRootBdas; - private List warRootBdas; - private List libJarRootBdas = null; + private final Set rarRootBdas = new LinkedHashSet<>(); + final Set ejbRootBdas = new LinkedHashSet<>(); + private final Set warRootBdas = new LinkedHashSet<>(); + private final Set libJarRootBdas = new LinkedHashSet<>(); - private List beanDeploymentArchives = new ArrayList<>(); - private DeploymentContext context; + private final Set beanDeploymentArchives = new LinkedHashSet<>(); + final transient DeploymentContext context; // A convenience Map to get BDA for a given BDA ID - private Map idToBeanDeploymentArchive = new HashMap<>(); - private SimpleServiceRegistry simpleServiceRegistry = null; + final Map idToBeanDeploymentArchive = new HashMap<>(); + private transient SimpleServiceRegistry simpleServiceRegistry = null; - private Logger logger = CDILoggerInfo.getLogger(); + private final transient Logger logger; // holds BDA's created for extensions - private Map extensionBDAMap = new HashMap<>(); + private final Map extensionBDAMap = new HashMap<>(); - private Iterable> extensions; + private final List> extensions = new ArrayList<>(); - private List> dynamicExtensions = new ArrayList<>(); + private final List> dynamicExtensions = new ArrayList<>(); - private Collection deployedEjbs = new LinkedList<>(); - private ArchiveFactory archiveFactory; + private final transient Collection deployedEjbs; + private final transient ArchiveFactory archiveFactory; private boolean earContextAppLibBdasProcessed = false; private String appName; private String contextId; - final InjectionManager injectionManager; + final transient InjectionManager injectionManager; /** * Produce BeanDeploymentArchives for this Deployment @@ -136,6 +148,8 @@ public DeploymentImpl(ReadableArchive archive, ArchiveFactory archiveFactory, String moduleName, InjectionManager injectionManager) { + logger = CDILoggerInfo.getLogger(); + deployedEjbs = new LinkedList<>(); if ( logger.isLoggable( FINE ) ) { logger.log(FINE, CDILoggerInfo.CREATING_DEPLOYMENT_ARCHIVE, new Object[]{ archive.getName()}); } @@ -146,8 +160,8 @@ public DeploymentImpl(ReadableArchive archive, // Collect /lib Jar BDAs (if any) from the parent module. // If we've produced BDA(s) from any /lib jars, return as // additional BDA(s) will be produced for any subarchives (war/jar). - libJarRootBdas = scanForLibJars(archive, ejbs, context); - if ((libJarRootBdas != null) && !libJarRootBdas.isEmpty()) { + libJarRootBdas.addAll(scanForLibJars(archive, ejbs, context)); + if (!libJarRootBdas.isEmpty()) { return; } @@ -164,24 +178,112 @@ public DeploymentImpl(ReadableArchive archive, createModuleBda(archive, ejbs, context, contextId); } + DeploymentImpl(DeploymentImpl deployment) { + this.rarRootBdas.addAll(deployment.rarRootBdas); + this.ejbRootBdas.addAll(deployment.ejbRootBdas); + this.warRootBdas.addAll(deployment.warRootBdas); + this.libJarRootBdas.addAll(deployment.libJarRootBdas); + this.beanDeploymentArchives.addAll(deployment.beanDeploymentArchives); + this.appName = deployment.appName; + this.contextId = deployment.contextId; + this.earContextAppLibBdasProcessed = deployment.earContextAppLibBdasProcessed; + + this.context = currentDeploymentContext.get(); + this.archiveFactory = currentDeployment.get().archiveFactory; + getServices().addAll(currentDeployment.get().getServices().entrySet()); + this.injectionManager = currentDeployment.get().injectionManager; + this.logger = currentDeployment.get().logger; + this.deployedEjbs = currentDeployment.get().deployedEjbs; + } + + DeploymentImpl filter(RootBeanDeploymentArchive rootBDA, ApplicationInfo applicationInfo) { + DeploymentImpl filteredDeployment; + try { + filteredDeployment = serializeAndDeserialize(this, applicationInfo.getAppClassLoader()); + } catch (IOException | ClassNotFoundException e) { + throw new IllegalStateException(e); + } + + List nonRooIDs = List.of(rootBDA.getId(), rootBDA.getModuleBda().getId()); + filteredDeployment.clearAndAddAll(filteredDeployment.warRootBdas, filterBDAs(filteredDeployment.warRootBdas, nonRooIDs)); + filteredDeployment.clearAndAddAll(filteredDeployment.beanDeploymentArchives, + filterBDAs(filteredDeployment.beanDeploymentArchives, nonRooIDs, filteredDeployment.rarRootBdas, + filteredDeployment.ejbRootBdas, filteredDeployment.libJarRootBdas)); + filteredDeployment.contextId = rootBDA.getId() + ".bda"; + return filteredDeployment; + } + + private void clearAndAddAll(Set originalBdas, Set bdas) { + originalBdas.clear(); + originalBdas.addAll(bdas); + } + + Set getRootBDAs() { + if (!warRootBdas.isEmpty()) { + return warRootBdas; + } else if (!ejbRootBdas.isEmpty()) { + return ejbRootBdas; + } else if (!rarRootBdas.isEmpty()) { + return rarRootBdas; + } else if (!libJarRootBdas.isEmpty()) { + return libJarRootBdas; + } else { + return Collections.emptySet(); + } + } + + @SuppressWarnings("unchecked") + private TT serializeAndDeserialize(TT original, ClassLoader classLoader) + throws IOException, ClassNotFoundException { + // serialize + var byteArrayOutputStream = new ByteArrayOutputStream(); + try (var outputStream = new ObjectOutputStream(byteArrayOutputStream)) { + outputStream.writeObject(original); + } + + // deserialize + try (var inputStream = new ObjectInputStreamWithLoader( + new ByteArrayInputStream(byteArrayOutputStream.toByteArray()), classLoader)) { + return (TT) inputStream.readObject(); + } + } + + Object readResolve() throws ObjectStreamException { + return new DeploymentImpl(this); + } + + @SafeVarargs + private Set filterBDAs(Set bdas, List bda, + Set... include) { + if (bdas == null) { + return null; + } + List includeRootList = Arrays.stream(include) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(toList()); + List includeList = includeRootList.stream() + .flatMap(list -> Stream.of(list, list.getModuleBda())) + .collect(toList()); + return bdas.stream() + .filter(b -> bda.stream().anyMatch(b.getId()::startsWith) || includeList.contains(b)) + .collect(toSet()); + } + private void addBeanDeploymentArchives(RootBeanDeploymentArchive bda) { + rootBDAs(bda).add(bda); + } + + private Set rootBDAs(RootBeanDeploymentArchive bda) { BDAType moduleBDAType = bda.getModuleBDAType(); if (moduleBDAType.equals(BDAType.WAR)) { - if (warRootBdas == null) { - warRootBdas = new ArrayList<>(); - } - warRootBdas.add(bda); + return warRootBdas; } else if (moduleBDAType.equals(BDAType.JAR)) { - if (ejbRootBdas == null) { - ejbRootBdas = new ArrayList<>(); - } - ejbRootBdas.add(bda); + return ejbRootBdas; } else if (moduleBDAType.equals(BDAType.RAR)) { - if (rarRootBdas == null) { - rarRootBdas = new ArrayList<>(); - } - rarRootBdas.add(bda); + return rarRootBdas; } + throw new IllegalArgumentException("Unknown BDAType: " + moduleBDAType); } /** @@ -191,14 +293,13 @@ private void addBeanDeploymentArchives(RootBeanDeploymentArchive bda) { * been created. */ public void scanArchive(ReadableArchive archive, Collection ejbs, DeploymentContext context, String moduleName) { - if (libJarRootBdas == null) { - libJarRootBdas = scanForLibJars(archive, ejbs, context); - if ((libJarRootBdas != null) && !libJarRootBdas.isEmpty()) { + if (libJarRootBdas.isEmpty()) { + libJarRootBdas.addAll(scanForLibJars(archive, ejbs, context)); + if (!libJarRootBdas.isEmpty()) { return; } } - this.context = context; createModuleBda(archive, ejbs, context, moduleName); } @@ -213,52 +314,44 @@ public void buildDeploymentGraph() { // /ejb1.jar <----> /ejb2.jar // If there are any application (/lib) jars, make them accessible - if (ejbRootBdas != null) { - for (RootBeanDeploymentArchive ejbRootBda : ejbRootBdas) { - BeanDeploymentArchive ejbModuleBda = ejbRootBda.getModuleBda(); + for (RootBeanDeploymentArchive ejbRootBda : ejbRootBdas) { + BeanDeploymentArchive ejbModuleBda = ejbRootBda.getModuleBda(); - boolean modifiedArchive = false; - for (RootBeanDeploymentArchive otherEjbRootBda : ejbRootBdas) { - BeanDeploymentArchive otherEjbModuleBda = otherEjbRootBda.getModuleBda(); - if (otherEjbModuleBda.getId().equals(ejbModuleBda.getId())) { - continue; - } - ejbRootBda.getBeanDeploymentArchives().add(otherEjbRootBda); - ejbRootBda.getBeanDeploymentArchives().add(otherEjbModuleBda); - ejbModuleBda.getBeanDeploymentArchives().add(otherEjbModuleBda); - modifiedArchive = true; + boolean modifiedArchive = false; + for (RootBeanDeploymentArchive otherEjbRootBda : ejbRootBdas) { + BeanDeploymentArchive otherEjbModuleBda = otherEjbRootBda.getModuleBda(); + if (otherEjbModuleBda.getId().equals(ejbModuleBda.getId())) { + continue; } + ejbRootBda.getBeanDeploymentArchives().add(otherEjbRootBda); + ejbRootBda.getBeanDeploymentArchives().add(otherEjbModuleBda); + ejbModuleBda.getBeanDeploymentArchives().add(otherEjbModuleBda); + modifiedArchive = true; + } - // Make /lib jars accessible to the ejbs. - if (libJarRootBdas != null) { - for (RootBeanDeploymentArchive libJarRootBda : libJarRootBdas) { - BeanDeploymentArchive libJarModuleBda = libJarRootBda.getModuleBda(); - ejbRootBda.getBeanDeploymentArchives().add(libJarRootBda); - ejbRootBda.getBeanDeploymentArchives().add(libJarModuleBda); - ejbModuleBda.getBeanDeploymentArchives().add(libJarRootBda); - ejbModuleBda.getBeanDeploymentArchives().add(libJarModuleBda); - modifiedArchive = true; - } - } + // Make /lib jars accessible to the ejbs. + for (RootBeanDeploymentArchive libJarRootBda : libJarRootBdas) { + BeanDeploymentArchive libJarModuleBda = libJarRootBda.getModuleBda(); + ejbRootBda.getBeanDeploymentArchives().add(libJarRootBda); + ejbRootBda.getBeanDeploymentArchives().add(libJarModuleBda); + ejbModuleBda.getBeanDeploymentArchives().add(libJarRootBda); + ejbModuleBda.getBeanDeploymentArchives().add(libJarModuleBda); + modifiedArchive = true; + } - // Make rars accessible to ejbs - if (rarRootBdas != null) { - for (RootBeanDeploymentArchive rarRootBda : rarRootBdas) { - BeanDeploymentArchive rarModuleBda = rarRootBda.getModuleBda(); - ejbRootBda.getBeanDeploymentArchives().add(rarRootBda); - ejbRootBda.getBeanDeploymentArchives().add(rarModuleBda); - ejbModuleBda.getBeanDeploymentArchives().add(rarRootBda); - ejbModuleBda.getBeanDeploymentArchives().add(rarModuleBda); - modifiedArchive = true; - } - } + // Make rars accessible to ejbs + for (RootBeanDeploymentArchive rarRootBda : rarRootBdas) { + BeanDeploymentArchive rarModuleBda = rarRootBda.getModuleBda(); + ejbRootBda.getBeanDeploymentArchives().add(rarRootBda); + ejbRootBda.getBeanDeploymentArchives().add(rarModuleBda); + ejbModuleBda.getBeanDeploymentArchives().add(rarRootBda); + ejbModuleBda.getBeanDeploymentArchives().add(rarModuleBda); + modifiedArchive = true; + } - if (modifiedArchive) { - int idx = getBeanDeploymentArchives().indexOf(ejbModuleBda); - if (idx >= 0) { - getBeanDeploymentArchives().remove(idx); - getBeanDeploymentArchives().add(ejbModuleBda); - } + if (modifiedArchive) { + if (getBeanDeploymentArchives().remove(ejbModuleBda)) { + getBeanDeploymentArchives().add(ejbModuleBda); } } } @@ -267,73 +360,75 @@ public void buildDeploymentGraph() { // /web.war ----> /ejb.jar // If there are any application (/lib) jars, make them accessible - if (warRootBdas != null) { - ListIterator warIter = warRootBdas.listIterator(); - boolean modifiedArchive = false; - while (warIter.hasNext()) { - RootBeanDeploymentArchive warRootBda = warIter.next(); - BeanDeploymentArchive warModuleBda = warRootBda.getModuleBda(); - if (ejbRootBdas != null) { - for (RootBeanDeploymentArchive ejbRootBda : ejbRootBdas) { - BeanDeploymentArchive ejbModuleBda = ejbRootBda.getModuleBda(); - warRootBda.getBeanDeploymentArchives().add(ejbRootBda); - warRootBda.getBeanDeploymentArchives().add(ejbModuleBda); - warModuleBda.getBeanDeploymentArchives().add(ejbRootBda); - warModuleBda.getBeanDeploymentArchives().add(ejbModuleBda); - - for ( BeanDeploymentArchive oneBda : warModuleBda.getBeanDeploymentArchives() ) { - oneBda.getBeanDeploymentArchives().add( ejbRootBda ); - oneBda.getBeanDeploymentArchives().add( ejbModuleBda ); - } - - modifiedArchive = true; - } + Iterator warIter = warRootBdas.iterator(); + boolean modifiedArchive = false; + while (warIter.hasNext()) { + RootBeanDeploymentArchive warRootBda = warIter.next(); + BeanDeploymentArchive warModuleBda = warRootBda.getModuleBda(); + for (RootBeanDeploymentArchive ejbRootBda : ejbRootBdas) { + BeanDeploymentArchive ejbModuleBda = ejbRootBda.getModuleBda(); + warRootBda.getBeanDeploymentArchives().add(ejbRootBda); + warRootBda.getBeanDeploymentArchives().add(ejbModuleBda); + warModuleBda.getBeanDeploymentArchives().add(ejbRootBda); + warModuleBda.getBeanDeploymentArchives().add(ejbModuleBda); + + for ( BeanDeploymentArchive oneBda : warModuleBda.getBeanDeploymentArchives() ) { + oneBda.getBeanDeploymentArchives().add( ejbRootBda ); + oneBda.getBeanDeploymentArchives().add( ejbModuleBda ); } - // Make /lib jars accessible to the war and it's sub bdas - if (libJarRootBdas != null) { - for (RootBeanDeploymentArchive libJarRootBda : libJarRootBdas) { - BeanDeploymentArchive libJarModuleBda = libJarRootBda.getModuleBda(); - warRootBda.getBeanDeploymentArchives().add(libJarRootBda); - warRootBda.getBeanDeploymentArchives().add(libJarModuleBda); - warModuleBda.getBeanDeploymentArchives().add(libJarRootBda); - warModuleBda.getBeanDeploymentArchives().add(libJarModuleBda); - - for ( BeanDeploymentArchive oneBda : warModuleBda.getBeanDeploymentArchives() ) { - oneBda.getBeanDeploymentArchives().add( libJarRootBda ); - oneBda.getBeanDeploymentArchives().add( libJarModuleBda ); - } + modifiedArchive = true; + } - modifiedArchive = true; - } + // Make /lib jars accessible to the war and it's sub bdas + for (RootBeanDeploymentArchive libJarRootBda : libJarRootBdas) { + BeanDeploymentArchive libJarModuleBda = libJarRootBda.getModuleBda(); + warRootBda.getBeanDeploymentArchives().add(libJarRootBda); + warRootBda.getBeanDeploymentArchives().add(libJarModuleBda); + warModuleBda.getBeanDeploymentArchives().add(libJarRootBda); + warModuleBda.getBeanDeploymentArchives().add(libJarModuleBda); + + // make WAR's BDAs accessible to libJar BDAs + Set seen = Collections.newSetFromMap(new IdentityHashMap<>()); + beanDeploymentArchives.stream() + .filter(RootBeanDeploymentArchive.class::isInstance) + .map(RootBeanDeploymentArchive.class::cast) + .forEach(bda -> recursivelyAdd(bda.getBeanDeploymentArchives(), warModuleBda, seen)); + recursivelyAdd(beanDeploymentArchives, warModuleBda, seen); + libJarRootBda.getBeanDeploymentArchives().add(warRootBda); + libJarModuleBda.getBeanDeploymentArchives().add(warRootBda); + libJarRootBda.getBeanDeploymentArchives().add(warModuleBda); + libJarModuleBda.getBeanDeploymentArchives().add(warModuleBda); + + for ( BeanDeploymentArchive oneBda : warModuleBda.getBeanDeploymentArchives() ) { + oneBda.getBeanDeploymentArchives().add( libJarRootBda ); + oneBda.getBeanDeploymentArchives().add( libJarModuleBda ); } - // Make rars accessible to wars and it's sub bdas - if (rarRootBdas != null) { - for (RootBeanDeploymentArchive rarRootBda : rarRootBdas) { - BeanDeploymentArchive rarModuleBda = rarRootBda.getModuleBda(); - warRootBda.getBeanDeploymentArchives().add(rarRootBda); - warRootBda.getBeanDeploymentArchives().add(rarModuleBda); - warModuleBda.getBeanDeploymentArchives().add(rarRootBda); - warModuleBda.getBeanDeploymentArchives().add(rarModuleBda); - - for ( BeanDeploymentArchive oneBda : warModuleBda.getBeanDeploymentArchives() ) { - oneBda.getBeanDeploymentArchives().add( rarRootBda ); - oneBda.getBeanDeploymentArchives().add( rarModuleBda ); - } - - modifiedArchive = true; - } + modifiedArchive = true; + } + + // Make rars accessible to wars and it's sub bdas + for (RootBeanDeploymentArchive rarRootBda : rarRootBdas) { + BeanDeploymentArchive rarModuleBda = rarRootBda.getModuleBda(); + warRootBda.getBeanDeploymentArchives().add(rarRootBda); + warRootBda.getBeanDeploymentArchives().add(rarModuleBda); + warModuleBda.getBeanDeploymentArchives().add(rarRootBda); + warModuleBda.getBeanDeploymentArchives().add(rarModuleBda); + + for ( BeanDeploymentArchive oneBda : warModuleBda.getBeanDeploymentArchives() ) { + oneBda.getBeanDeploymentArchives().add( rarRootBda ); + oneBda.getBeanDeploymentArchives().add( rarModuleBda ); } - if (modifiedArchive) { - int idx = getBeanDeploymentArchives().indexOf(warModuleBda); - if (idx >= 0) { - getBeanDeploymentArchives().remove(idx); - getBeanDeploymentArchives().add(warModuleBda); - } - modifiedArchive = false; + modifiedArchive = true; + } + + if (modifiedArchive) { + if (getBeanDeploymentArchives().remove(warModuleBda)) { + getBeanDeploymentArchives().add(warModuleBda); } + modifiedArchive = false; } } @@ -360,8 +455,17 @@ private void addDependentBdas() { } } + private void recursivelyAdd(Collection bdas, BeanDeploymentArchive bda, Set seen) { + for (BeanDeploymentArchive subBda : new LinkedHashSet<>(bdas)) { + if (seen.add(subBda)) { + subBda.getBeanDeploymentArchives().add(bda); + recursivelyAdd(subBda.getBeanDeploymentArchives(), bda, seen); + } + } + } + @Override - public List getBeanDeploymentArchives() { + public Set getBeanDeploymentArchives() { if ( logger.isLoggable( FINE ) ) { logger.log(FINE, CDILoggerInfo.GET_BEAN_DEPLOYMENT_ARCHIVES, new Object[] {beanDeploymentArchives}); } @@ -373,9 +477,9 @@ public BeanDeploymentArchive loadBeanDeploymentArchive(Class beanClass) { if ( logger.isLoggable( FINE ) ) { logger.log(FINE, CDILoggerInfo.LOAD_BEAN_DEPLOYMENT_ARCHIVE, new Object[] { beanClass }); } - List beanDeploymentArchives = getBeanDeploymentArchives(); + Set beanDeploymentArchives = getBeanDeploymentArchives(); - ListIterator lIter = beanDeploymentArchives.listIterator(); + Iterator lIter = beanDeploymentArchives.iterator(); while (lIter.hasNext()) { BeanDeploymentArchive bda = lIter.next(); if ( logger.isLoggable( FINE ) ) { @@ -445,7 +549,7 @@ public BeanDeploymentArchive loadBeanDeploymentArchive(Class beanClass) { CDILoggerInfo.LOAD_BEAN_DEPLOYMENT_ARCHIVE_ADD_NEW_BDA_TO_ROOTS, new Object[] {} ); } - lIter = beanDeploymentArchives.listIterator(); + lIter = beanDeploymentArchives.iterator(); while (lIter.hasNext()) { BeanDeploymentArchive bda = lIter.next(); bda.getBeanDeploymentArchives().add(newBda); @@ -478,11 +582,11 @@ public ServiceRegistry getServices() { @Override public Iterable> getExtensions() { - if (extensions != null) { + if (!extensions.isEmpty()) { return extensions; } - List bdas = getBeanDeploymentArchives(); + Set bdas = getBeanDeploymentArchives(); ArrayList> extnList = new ArrayList<>(); //registering the org.jboss.weld.lite.extension.translator.LiteExtensionTranslator @@ -515,14 +619,12 @@ public LiteExtensionTranslator run() { ClassLoader moduleClassLoader = ((BeanDeploymentArchiveImpl)bda).getModuleClassLoaderForBDA(); if (!scannedClassLoaders.contains(moduleClassLoader)) { scannedClassLoaders.add(moduleClassLoader); - extensions = context.getTransientAppMetaData(WeldDeployer.WELD_BOOTSTRAP, - WeldBootstrap.class).loadExtensions(moduleClassLoader); - if (extensions != null) { - for (Metadata bdaExtn : extensions) { - if (loadedExtensions.get(bdaExtn.getValue().getClass()) == null) { - extnList.add(bdaExtn); - loadedExtensions.put(bdaExtn.getValue().getClass(), bdaExtn); - } + var extensions = context.getTransientAppMetaData(WeldDeployer.WELD_BOOTSTRAP, + WeldBootstrap.class).loadExtensions(moduleClassLoader); + for (Metadata bdaExtn : extensions) { + if (loadedExtensions.get(bdaExtn.getValue().getClass()) == null) { + extnList.add(bdaExtn); + loadedExtensions.put(bdaExtn.getValue().getClass(), bdaExtn); } } } @@ -542,7 +644,7 @@ public LiteExtensionTranslator run() { } extnList.addAll(dynamicExtensions); - extensions = extnList; + extensions.addAll(extnList); return extnList; } @@ -561,10 +663,8 @@ public void clearDynamicExtensions() { @Override public String toString() { StringBuilder valBuff = new StringBuilder(); - List beanDeploymentArchives = getBeanDeploymentArchives(); - ListIterator lIter = beanDeploymentArchives.listIterator(); - while (lIter.hasNext()) { - BeanDeploymentArchive bda = lIter.next(); + Set beanDeploymentArchives = getBeanDeploymentArchives(); + for(BeanDeploymentArchive bda : beanDeploymentArchives) { valBuff.append(bda.toString()); } return valBuff.toString(); @@ -575,23 +675,11 @@ public BeanDeploymentArchive getBeanDeploymentArchiveForArchive(String archiveId } public void cleanup() { - if (ejbRootBdas != null) { - ejbRootBdas.clear(); - } - if (warRootBdas != null) { - warRootBdas.clear(); - } - if (libJarRootBdas != null) { - libJarRootBdas.clear(); - } - - if ( rarRootBdas != null ) { - rarRootBdas.clear(); - } - - if (idToBeanDeploymentArchive != null) { - idToBeanDeploymentArchive.clear(); - } + ejbRootBdas.clear(); + warRootBdas.clear(); + libJarRootBdas.clear(); + rarRootBdas.clear(); + idToBeanDeploymentArchive.clear(); } private List> getBuildCompatibleExtensions() { @@ -599,14 +687,14 @@ private List> getBuildCompatibleExtens ServiceLoader.load(BuildCompatibleExtension.class, Thread.currentThread().getContextClassLoader()) .stream() .map(java.util.ServiceLoader.Provider::get) - .map(e -> e.getClass()) + .map(BuildCompatibleExtension::getClass) .filter(e -> !e.isAnnotationPresent(SkipIfPortableExtensionPresent.class)) .collect(toList()); } // This method creates and returns a List of BeanDeploymentArchives for each // Weld enabled jar under /lib of an existing Archive. - private List scanForLibJars( ReadableArchive archive, + private Set scanForLibJars( ReadableArchive archive, Collection ejbs, DeploymentContext context) { List libJars = null; @@ -662,9 +750,6 @@ private void createLibJarBda(RootBeanDeploymentArchive rootLibBda) { if (moduleBeansXml == null || !moduleBeansXml.getBeanDiscoveryMode().equals(BeanDiscoveryMode.NONE)) { addBdaToDeploymentBdas(rootLibBda); addBdaToDeploymentBdas(libModuleBda); - if (libJarRootBdas == null) { - libJarRootBdas = new ArrayList<>(); - } for ( RootBeanDeploymentArchive existingLibJarRootBda : libJarRootBdas) { rootLibBda.getBeanDeploymentArchives().add( existingLibJarRootBda ); @@ -765,9 +850,9 @@ public BeanDeploymentArchive getBeanDeploymentArchive(Class beanClass) { return null; } - for ( BeanDeploymentArchive oneBda : beanDeploymentArchives ) { + for (BeanDeploymentArchive oneBda : beanDeploymentArchives) { BeanDeploymentArchiveImpl beanDeploymentArchiveImpl = (BeanDeploymentArchiveImpl) oneBda; - if ( beanDeploymentArchiveImpl.getKnownClasses().contains(beanClass.getName()) ) { + if (beanDeploymentArchiveImpl.getKnownClasses().contains(beanClass.getName())) { return oneBda; } } @@ -789,7 +874,7 @@ public BeanDeploymentArchive getBeanDeploymentArchive(Class beanClass) { return rootBda; } - private RootBeanDeploymentArchive findRootBda( ClassLoader classLoader, List rootBdas ) { + private RootBeanDeploymentArchive findRootBda( ClassLoader classLoader, Set rootBdas ) { if ( rootBdas == null || classLoader == null ) { return null; } @@ -835,16 +920,10 @@ private void createModuleBda( ReadableArchive archive, public Iterator getLibJarRootBdas() { - if ( libJarRootBdas == null ) { - return null; - } return libJarRootBdas.iterator(); } public Iterator getRarRootBdas() { - if ( rarRootBdas == null ) { - return null; - } return rarRootBdas.iterator(); } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/GlassFishWeldProvider.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/GlassFishWeldProvider.java index 0d7d7282572..94ffbb866da 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/GlassFishWeldProvider.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/GlassFishWeldProvider.java @@ -37,9 +37,15 @@ * only if the new code is made subject to such option by the copyright * holder. */ +// Portions Copyright [2024] [Payara Foundation and/or its affiliates] package org.glassfish.weld; +import com.sun.enterprise.deployment.BundleDescriptor; +import com.sun.enterprise.deployment.EjbDescriptor; +import com.sun.enterprise.deployment.WebBundleDescriptor; +import org.glassfish.api.invocation.InvocationManager; +import org.glassfish.internal.api.Globals; import org.jboss.weld.Container; import org.jboss.weld.SimpleCDI; import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive; @@ -54,7 +60,16 @@ * @author JJ Snyder */ public class GlassFishWeldProvider implements CDIProvider { + private static final WeldDeployer weldDeployer = Globals.get(WeldDeployer.class); + private static final InvocationManager invocationManager = Globals.get(InvocationManager.class); + private static class GlassFishEnhancedWeld extends SimpleCDI { + GlassFishEnhancedWeld() { + } + + GlassFishEnhancedWeld(String contextId) { + super(contextId == null ? Container.instance() : Container.instance(contextId)); + } @Override protected BeanManagerImpl unsatisfiedBeanManager(String callerClassName) { @@ -92,15 +107,30 @@ protected BeanManagerImpl unsatisfiedBeanManager(String callerClassName) { @Override public CDI getCDI() { - try { - return new GlassFishEnhancedWeld(); - } catch ( Throwable throwable ) { - Throwable cause = throwable.getCause(); - if ( cause instanceof IllegalStateException ) { - return null; + try { + BundleDescriptor bundle = null; + Object componentEnv = invocationManager.getCurrentInvocation().getJNDIEnvironment(); + if( componentEnv instanceof EjbDescriptor) { + bundle = (BundleDescriptor) + ((EjbDescriptor) componentEnv).getEjbBundleDescriptor(). + getModuleDescriptor().getDescriptor(); + + } else if( componentEnv instanceof WebBundleDescriptor) { + bundle = (BundleDescriptor) componentEnv; + } + + BeanDeploymentArchive bda = weldDeployer.getBeanDeploymentArchiveForBundle(bundle); + if (bda == null) { + return new GlassFishEnhancedWeld(); + } else { + return new GlassFishEnhancedWeld(weldDeployer.getContextIdForArchive(bda)); + } + } catch ( Throwable throwable ) { + Throwable cause = throwable.getCause(); + if ( cause instanceof IllegalStateException ) { + return null; + } + throw throwable; } - throw throwable; - } } - } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/RootBeanDeploymentArchive.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/RootBeanDeploymentArchive.java index 861813ec04d..9d5c526eb9c 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/RootBeanDeploymentArchive.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/RootBeanDeploymentArchive.java @@ -38,7 +38,7 @@ * holder. */ -// Portions Copyright [2016-2017] [Payara Foundation and/or its affiliates] +// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates] package org.glassfish.weld; @@ -49,10 +49,12 @@ import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive; import org.jboss.weld.bootstrap.spi.BeansXml; +import java.io.ObjectStreamException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Objects; /** * A root BDA represents the root of a module where a module is a war, ejb, rar, ear lib @@ -70,7 +72,7 @@ * @author JJ Snyder */ public class RootBeanDeploymentArchive extends BeanDeploymentArchiveImpl { - private BeanDeploymentArchiveImpl moduleBda; + BeanDeploymentArchiveImpl moduleBda; public RootBeanDeploymentArchive(ReadableArchive archive, Collection ejbs, @@ -90,6 +92,11 @@ public RootBeanDeploymentArchive(ReadableArchive archive, createModuleBda(archive, ejbs, deploymentContext, moduleBdaID); } + public RootBeanDeploymentArchive(RootBeanDeploymentArchive rootBeanDeploymentArchive) { + super(rootBeanDeploymentArchive); + moduleBda = rootBeanDeploymentArchive.moduleBda; + } + private void createModuleBda(ReadableArchive archive, Collection ejbs, DeploymentContext deploymentContext, @@ -150,4 +157,21 @@ public BeanDeploymentArchive getModuleBda() { public WeldUtils.BDAType getModuleBDAType() { return moduleBda.getBDAType(); } + + Object readResolve() throws ObjectStreamException { + return new RootBeanDeploymentArchive(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RootBeanDeploymentArchive)) return false; + RootBeanDeploymentArchive that = (RootBeanDeploymentArchive) o; + return Objects.equals(moduleBda, that.moduleBda); + } + + @Override + public int hashCode() { + return Objects.hashCode(moduleBda); + } } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/ValidationNamingProxy.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/ValidationNamingProxy.java index 1e4f1e1780c..345ddfe2950 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/ValidationNamingProxy.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/ValidationNamingProxy.java @@ -37,6 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ +// Portions Copyright [2024] [Payara Foundation and/or its affiliates] package org.glassfish.weld; @@ -48,7 +49,6 @@ import org.glassfish.api.invocation.ComponentInvocation; import org.glassfish.api.invocation.InvocationManager; import org.glassfish.api.naming.NamedNamingObjectProxy; -import org.glassfish.api.naming.NamespacePrefixes; import org.glassfish.hk2.api.ServiceLocator; import org.jboss.weld.bootstrap.WeldBootstrap; import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive; @@ -59,9 +59,7 @@ import jakarta.inject.Inject; import jakarta.inject.Named; import javax.naming.NamingException; -import jakarta.validation.Validation; import jakarta.validation.Validator; -import jakarta.validation.ValidatorContext; import jakarta.validation.ValidatorFactory; import java.util.Set; @@ -189,7 +187,7 @@ private synchronized BeanManager obtainBeanManager() throws NamingException { if( bundle != null ) { BeanDeploymentArchive bda = weldDeployer.getBeanDeploymentArchiveForBundle(bundle); if( bda != null ) { - WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(bundle.getApplication()); + WeldBootstrap bootstrap = weldDeployer.getBootstrapForArchive(bda); beanManager = bootstrap.getManager(bda); } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/WeldDeployer.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/WeldDeployer.java index cfb0a6c9c14..1c60b68f10d 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/WeldDeployer.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/WeldDeployer.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2016-2022] [Payara Foundation and/or its affiliates] +// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates] package org.glassfish.weld; @@ -67,6 +67,7 @@ import static org.jboss.weld.manager.BeanManagerLookupService.lookupBeanManager; import java.security.AccessController; +import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; @@ -124,7 +125,6 @@ import org.jboss.weld.ejb.spi.EjbServices; import org.jboss.weld.exceptions.WeldException; import org.jboss.weld.injection.spi.InjectionServices; -import org.jboss.weld.injection.spi.ResourceInjectionServices; import org.jboss.weld.probe.ProbeExtension; import org.jboss.weld.resources.spi.ResourceLoader; import org.jboss.weld.security.NewInstanceAction; @@ -156,7 +156,7 @@ public class WeldDeployer extends SimpleDeployer appToBootstrap = new HashMap<>(); - private Map bundleToBeanDeploymentArchive = new HashMap<>(); private static final Class[] NON_CONTEXT_CLASSES = { @@ -277,11 +275,7 @@ public WeldApplicationContainer load(WeldContainer container, DeploymentContext ReadableArchive archive = context.getSource(); - boolean[] setTransientAppMetaData = {false}; - - // See if a WeldBootsrap has already been created - only want one per app. - WeldBootstrap bootstrap = getWeldBootstrap(context, applicationInfo, setTransientAppMetaData); - + ensureWeldBootstrapCreated(context, applicationInfo); EjbBundleDescriptor ejbBundle = getEjbBundleFromContext(context); EjbServices ejbServices = null; @@ -296,7 +290,7 @@ public WeldApplicationContainer load(WeldContainer container, DeploymentContext // If the archive is a composite, or has version numbers per maven conventions, strip them out String archiveName = getArchiveName(context, applicationInfo, archive); - DeploymentImpl deploymentImpl = context.getTransientAppMetaData(WELD_DEPLOYMENT, DeploymentImpl.class); + DeploymentImpl deploymentImpl = applicationInfo.getTransientAppMetaData(WELD_DEPLOYMENT, DeploymentImpl.class); if (deploymentImpl == null) { deploymentImpl = new DeploymentImpl(archive, ejbs, context, archiveFactory, archiveName, services.getService(InjectionManager.class)); @@ -338,12 +332,6 @@ public WeldApplicationContainer load(WeldContainer container, DeploymentContext BeanDeploymentArchive beanDeploymentArchive = deploymentImpl.getBeanDeploymentArchiveForArchive(archiveName); if (beanDeploymentArchive != null && !beanDeploymentArchive.getBeansXml().getBeanDiscoveryMode().equals(NONE)) { - if (setTransientAppMetaData[0]) { - // Do this only if we have a root BDA - appToBootstrap.put(context.getModuleMetaData(Application.class), bootstrap); - applicationInfo.addTransientAppMetaData(WELD_BOOTSTRAP, bootstrap); - } - WebBundleDescriptor webBundleDescriptor = context.getModuleMetaData(WebBundleDescriptor.class); boolean developmentMode = isDevelopmentMode(context); if (webBundleDescriptor != null) { @@ -417,7 +405,6 @@ public WeldApplicationContainer load(WeldContainer container, DeploymentContext } } - context.addTransientAppMetaData(WELD_DEPLOYMENT, deploymentImpl); applicationInfo.addTransientAppMetaData(WELD_DEPLOYMENT, deploymentImpl); return new WeldApplicationContainer(); @@ -467,139 +454,192 @@ public boolean is299Enabled(BundleDescriptor bundle) { return bundleToBeanDeploymentArchive.containsKey(bundle); } - public WeldBootstrap getBootstrapForApp(Application app) { - return appToBootstrap.get(app); + public WeldBootstrap getBootstrapForArchive(BeanDeploymentArchive archive) { + return ((BeanDeploymentArchiveImpl) archive).weldBootstrap; } - + public String getContextIdForArchive(BeanDeploymentArchive archive) { + var impl = (BeanDeploymentArchiveImpl) archive; + String rootContextId = impl.getBeanDeploymentArchives().stream() + .filter(RootBeanDeploymentArchive.class::isInstance) + .map(RootBeanDeploymentArchive.class::cast) + .filter(bda -> bda.moduleBda.getBDAType() != WeldUtils.BDAType.UNKNOWN) + .findFirst().map(BeanDeploymentArchive::getId).orElse(null); + return rootContextId == null ? null : rootContextId + ".bda"; + } // ### Private methods + private WeldBootstrap ensureWeldBootstrapCreated(DeploymentContext context, ApplicationInfo applicationInfo) { + @SuppressWarnings("unchecked") + List toShutdown = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP, List.class); + if (toShutdown == null) { + toShutdown = new ArrayList<>(); + applicationInfo.addTransientAppMetaData(WELD_BOOTSTRAP, toShutdown); + } - private WeldBootstrap getWeldBootstrap(DeploymentContext context, ApplicationInfo appInfo, boolean[] setTransientAppMetaData) { - // See if a WeldBootsrap has already been created - only want one per app. + // See if a WeldBootstrap has already been created - only want one per context. WeldBootstrap bootstrap = context.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); - if (bootstrap != null && appInfo.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class) == null) { - // No bootstrap if no CDI BDAs exist yet - bootstrap = null; - } - if (bootstrap == null) { bootstrap = new WeldBootstrap(); - setTransientAppMetaData[0] = true; - // Stash the WeldBootstrap instance, so we may access the WeldManager later.. + // Stash the WeldBootstrap instance, so we may access the WeldManager later... context.addTransientAppMetaData(WELD_BOOTSTRAP, bootstrap); + toShutdown.add(bootstrap); // Making sure that if WeldBootstrap is added, shutdown is set to false, as it is/would not have // been called. - appInfo.addTransientAppMetaData(WELD_BOOTSTRAP_SHUTDOWN, "false"); + applicationInfo.addTransientAppMetaData(WELD_BOOTSTRAP_SHUTDOWN, "false"); } - return bootstrap; } private void processApplicationLoaded(ApplicationInfo applicationInfo) { - WeldBootstrap bootstrap = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); - - if (bootstrap != null) { - DeploymentImpl deploymentImpl = applicationInfo.getTransientAppMetaData(WELD_DEPLOYMENT, DeploymentImpl.class); - deploymentImpl.buildDeploymentGraph(); - - List archives = deploymentImpl.getBeanDeploymentArchives(); - - addResourceLoaders(archives); - addCdiServicesToNonModuleBdas(deploymentImpl.getLibJarRootBdas(), services.getService(InjectionManager.class)); - addCdiServicesToNonModuleBdas(deploymentImpl.getRarRootBdas(), services.getService(InjectionManager.class)); + DeploymentImpl deploymentImpl = applicationInfo.getTransientAppMetaData(WELD_DEPLOYMENT, DeploymentImpl.class); + if (deploymentImpl == null) { + return; + } - // Get current TCL - ClassLoader oldTCL = Thread.currentThread().getContextClassLoader(); + // Get current TCL + ClassLoader oldTCL = Thread.currentThread().getContextClassLoader(); - invocationManager.pushAppEnvironment(applicationInfo::getName); + invocationManager.pushAppEnvironment(applicationInfo::getName); - ComponentInvocation componentInvocation = createComponentInvocation(applicationInfo); + ComponentInvocation componentInvocation = createComponentInvocation(applicationInfo); - try { - invocationManager.preInvoke(componentInvocation); - bootstrap.startExtensions(postProcessExtensions(deploymentImpl.getExtensions(), archives)); - bootstrap.startContainer(deploymentImpl.getContextId() + ".bda", SERVLET, deploymentImpl); - - //This changes added to pass the following test - // CreateBeanAttributesTest#testBeanAttributesForSessionBean - if(!deploymentImpl.getBeanDeploymentArchives().isEmpty()) { - BeanDeploymentArchive rootArchive = deploymentImpl.getBeanDeploymentArchives().get(0); - ServiceRegistry rootServices = bootstrap.getManager(rootArchive).getServices(); - EjbSupport originalEjbSupport = rootServices.get(EjbSupport.class); - if (originalEjbSupport != null) { - // We need to create a proxy instead of a simple wrapper - EjbSupport proxyEjbSupport = (EjbSupport) java.lang.reflect.Proxy.newProxyInstance(EjbSupport.class.getClassLoader(), - new Class[]{EjbSupport.class}, new java.lang.reflect.InvocationHandler() { - @Override - public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable { - if (method.getName().equals("isEjb")) { - - EjbSupport targetEjbSupport = getTargetEjbSupport((Class) args[0]); - - if (targetEjbSupport != null) { - return method.invoke(targetEjbSupport, args); - } - - } else if (method.getName().equals("createSessionBeanAttributes")) { - Object enhancedAnnotated = args[0]; - - Class beanClass = (Class) - enhancedAnnotated.getClass() - .getMethod("getJavaClass") - .invoke(enhancedAnnotated); - - EjbSupport targetEjbSupport = getTargetEjbSupport(beanClass); - if (targetEjbSupport != null) { - return method.invoke(targetEjbSupport, args); - } - } - - return method.invoke(originalEjbSupport, args); - } - - private EjbSupport getTargetEjbSupport(Class beanClass) { - BeanDeploymentArchive ejbArchive = deploymentImpl.getBeanDeploymentArchive(beanClass); - if (ejbArchive == null) { - return null; - } - - BeanManagerImpl ejbBeanManager = lookupBeanManager(beanClass, bootstrap.getManager(ejbArchive)); - - return ejbBeanManager.getServices().get(EjbSupport.class); - } - }); - rootServices.add(EjbSupport.class, proxyEjbSupport); + try { + invocationManager.preInvoke(componentInvocation); + // Modern, multiple WARs in an EAR scenario + if (deploymentImpl.ejbRootBdas.isEmpty()) { + for (RootBeanDeploymentArchive rootBDA : deploymentImpl.getRootBDAs()) { + DeploymentImpl.currentDeployment.set(deploymentImpl); + DeploymentImpl.currentBDAs.set(new HashMap<>()); + DeploymentImpl.currentDeploymentContext.set(rootBDA.context); + try { + DeploymentImpl filtered = deploymentImpl.filter(rootBDA, applicationInfo); + completeDeployment(filtered); + WeldBootstrap bootstrap = filtered.context.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); + startWeldBootstrap(applicationInfo, rootBDA, bootstrap, filtered, componentInvocation); + } finally { + DeploymentImpl.currentDeployment.remove(); + DeploymentImpl.currentBDAs.remove(); + DeploymentImpl.currentDeploymentContext.remove(); } } - bootstrap.startInitialization(); - fireProcessInjectionTargetEvents(bootstrap, applicationInfo, deploymentImpl); - bootstrap.deployBeans(); - bootstrap.validateBeans(); - bootstrap.endInitialization(); + } else if (!deploymentImpl.getRootBDAs().isEmpty()) { + completeDeployment(deploymentImpl); + // Legacy EJB-Jar scenario, one Weld instance per EAR + RootBeanDeploymentArchive bda = deploymentImpl.getRootBDAs().iterator().next(); + WeldBootstrap bootstrap = unifyBootstrap(bda, applicationInfo); + startWeldBootstrap(applicationInfo, bda, bootstrap, deploymentImpl, componentInvocation); + } + } catch (Throwable t) { + doBootstrapShutdown(applicationInfo); + + throw new DeploymentException(getDeploymentErrorMsgPrefix(t) + t.getMessage(), t); + } finally { + try { + invocationManager.postInvoke(componentInvocation); + invocationManager.popAppEnvironment(); + deploymentComplete(deploymentImpl); } catch (Throwable t) { - doBootstrapShutdown(applicationInfo); + logger.log(SEVERE, "Exception dispatching post deploy event", t); + } - throw new DeploymentException(getDeploymentErrorMsgPrefix(t) + t.getMessage(), t); - } finally { - try { - invocationManager.postInvoke(componentInvocation); - invocationManager.popAppEnvironment(); - deploymentComplete(deploymentImpl); - } catch (Throwable t) { - logger.log(SEVERE, "Exception dispatching post deploy event", t); - } + // The TCL is originally the EAR classloader and is reset during Bean deployment to the + // corresponding module classloader in BeanDeploymentArchiveImpl.getBeans + // for Bean classloading to succeed. + // The TCL is reset to its old value here. + Thread.currentThread().setContextClassLoader(oldTCL); + } + } - // The TCL is originally the EAR classloader and is reset during Bean deployment to the - // corresponding module classloader in BeanDeploymentArchiveImpl.getBeans - // for Bean classloading to succeed. - // The TCL is reset to its old value here. - Thread.currentThread().setContextClassLoader(oldTCL); - } + private void completeDeployment(DeploymentImpl deploymentImpl) { + deploymentImpl.buildDeploymentGraph(); + + Set archives = deploymentImpl.getBeanDeploymentArchives(); + + addResourceLoaders(archives); + addCdiServicesToNonModuleBdas(deploymentImpl.getLibJarRootBdas(), services.getService(InjectionManager.class)); + addCdiServicesToNonModuleBdas(deploymentImpl.getRarRootBdas(), services.getService(InjectionManager.class)); + } + + private WeldBootstrap unifyBootstrap(BeanDeploymentArchiveImpl rootArchive, ApplicationInfo applicationInfo) { + WeldBootstrap bootstrap = ensureWeldBootstrapCreated(rootArchive.context, applicationInfo); + rootArchive.getBeanDeploymentArchives().stream().map(BeanDeploymentArchiveImpl.class::cast) + .forEach(bda -> bda.weldBootstrap = bootstrap); + return bootstrap; + } + + private void startWeldBootstrap(ApplicationInfo applicationInfo, RootBeanDeploymentArchive rootBDA, + WeldBootstrap bootstrap, DeploymentImpl deploymentImpl, + ComponentInvocation componentInvocation) { + bootstrap.startExtensions(postProcessExtensions(deploymentImpl.getExtensions(), + deploymentImpl.getBeanDeploymentArchives())); + bootstrap.startContainer(deploymentImpl.getContextId(), SERVLET, deploymentImpl); + + //This changes added to pass the following test + // CreateBeanAttributesTest#testBeanAttributesForSessionBean + if (!rootBDA.getBeanDeploymentArchives().isEmpty()) { + createProxyEJBs(rootBDA, bootstrap, componentInvocation, deploymentImpl); + } + bootstrap.startInitialization(); + fireProcessInjectionTargetEvents(bootstrap, applicationInfo, deploymentImpl); + bootstrap.deployBeans(); + bootstrap.validateBeans(); + bootstrap.endInitialization(); + } + + private static void createProxyEJBs(RootBeanDeploymentArchive warRootBDA, WeldBootstrap bootstrap, + ComponentInvocation componentInvocation, DeploymentImpl deploymentImpl) { + BeanManagerImpl beanManager = bootstrap.getManager(warRootBDA); + componentInvocation.setInstance(beanManager); + ServiceRegistry rootServices = beanManager.getServices(); + EjbSupport originalEjbSupport = rootServices.get(EjbSupport.class); + if (originalEjbSupport != null) { + // We need to create a proxy instead of a simple wrapper + EjbSupport proxyEjbSupport = (EjbSupport) java.lang.reflect.Proxy.newProxyInstance(EjbSupport.class.getClassLoader(), + new Class[]{EjbSupport.class}, new java.lang.reflect.InvocationHandler() { + @Override + public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable { + if (method.getName().equals("isEjb")) { + + EjbSupport targetEjbSupport = getTargetEjbSupport((Class) args[0]); + + if (targetEjbSupport != null) { + return method.invoke(targetEjbSupport, args); + } + + } else if (method.getName().equals("createSessionBeanAttributes")) { + Object enhancedAnnotated = args[0]; + + Class beanClass = (Class) + enhancedAnnotated.getClass() + .getMethod("getJavaClass") + .invoke(enhancedAnnotated); + + EjbSupport targetEjbSupport = getTargetEjbSupport(beanClass); + if (targetEjbSupport != null) { + return method.invoke(targetEjbSupport, args); + } + } + + return method.invoke(originalEjbSupport, args); + } + + private EjbSupport getTargetEjbSupport(Class beanClass) { + BeanDeploymentArchive ejbArchive = deploymentImpl.getBeanDeploymentArchive(beanClass); + if (ejbArchive == null) { + return null; + } + + BeanManagerImpl ejbBeanManager = lookupBeanManager(beanClass, bootstrap.getManager(ejbArchive)); + + return ejbBeanManager.getServices().get(EjbSupport.class); + } + }); + rootServices.add(EjbSupport.class, proxyEjbSupport); } } @@ -608,7 +648,6 @@ private void processApplicationStopped(ApplicationInfo applicationInfo) { Application application = applicationInfo.getMetaData(Application.class); if (application != null) { removeBundleDescriptors(application); - appToBootstrap.remove(application); } String shutdown = applicationInfo.getTransientAppMetaData(WELD_SHUTDOWN, String.class); @@ -620,8 +659,6 @@ private void processApplicationStopped(ApplicationInfo applicationInfo) { Thread.currentThread().setContextClassLoader(applicationInfo.getAppClassLoader()); try { - WeldBootstrap bootstrap = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); - if (bootstrap != null) { invocationManager.pushAppEnvironment(applicationInfo::getName); try { @@ -633,7 +670,6 @@ private void processApplicationStopped(ApplicationInfo applicationInfo) { } applicationInfo.addTransientAppMetaData(WELD_SHUTDOWN, "true"); - } } finally { Thread.currentThread().setContextClassLoader(currentContextClassLoader); } @@ -645,7 +681,7 @@ private void processApplicationStopped(ApplicationInfo applicationInfo) { } - private void addResourceLoaders(List archives) { + private void addResourceLoaders(Set archives) { for (BeanDeploymentArchive archive : archives) { archive.getServices().add( ResourceLoader.class, @@ -670,7 +706,7 @@ private ComponentInvocation createComponentInvocation(ApplicationInfo applicatio return componentInvocation; } - private Iterable> postProcessExtensions(Iterable> extensions, List archives) { + private Iterable> postProcessExtensions(Iterable> extensions, Set archives) { // See if the Jersey extension that scans all classes in the bean archives is present. // Normally this should always be the case as this extension is statically included with Jersey, @@ -713,7 +749,7 @@ private Optional> findJerseyProcessAll(Iterable e.getValue().getClass().getName().equals(JERSEY_PROCESS_ALL_CLASS_NAME)).findAny(); } - private boolean hasJerseyHk2Provider(List archives, ClassLoader jaxRsClassLoader) + private boolean hasJerseyHk2Provider(Set archives, ClassLoader jaxRsClassLoader) throws ClassNotFoundException { Class hk2Provider = Class.forName(JERSEY_HK2_CLASS_NAME, false, jaxRsClassLoader); @@ -759,11 +795,13 @@ private void deploymentComplete(DeploymentImpl deploymentImpl) { } private void doBootstrapShutdown(ApplicationInfo applicationInfo) { - WeldBootstrap bootstrap = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); + List bootstrap = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP, List.class); String bootstrapShutdown = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP_SHUTDOWN, String.class); if (bootstrapShutdown == null || Boolean.valueOf(bootstrapShutdown).equals(FALSE)) { - bootstrap.shutdown(); + if (bootstrap != null) { + bootstrap.forEach(WeldBootstrap::shutdown); + } applicationInfo.addTransientAppMetaData(WELD_BOOTSTRAP_SHUTDOWN, "true"); } } @@ -810,7 +848,7 @@ private String getDeploymentErrorMsgPrefix(Throwable t) { */ private void fireProcessInjectionTargetEvents(WeldBootstrap bootstrap, ApplicationInfo applicationInfo, DeploymentImpl deploymentImpl) { - List beanDeploymentArchives = deploymentImpl.getBeanDeploymentArchives(); + Set beanDeploymentArchives = deploymentImpl.getBeanDeploymentArchives(); Class messageListenerClass = getMessageListenerClass(); diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/JCDIServiceImpl.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/JCDIServiceImpl.java index a29bf9be94e..1447d3de0a1 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/JCDIServiceImpl.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/JCDIServiceImpl.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2016-2022] [Payara Foundation and/or its affiliates] +// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates] package org.glassfish.weld.services; @@ -213,7 +213,7 @@ private JCDIInjectionContext _createJCDIInjectionContext(EjbDescriptor ej // First get BeanDeploymentArchive for this ejb BeanDeploymentArchive bda = getBDAForBeanClass(topLevelBundleDesc, ejb.getEjbClassName()); - WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(ejb.getEjbBundleDescriptor().getApplication()); + WeldBootstrap bootstrap = weldDeployer.getBootstrapForArchive(bda); WeldManager weldManager = bootstrap.getManager(bda); //sanitizing the null reference of weldManager and returning null //when calling _createJCDIInjectionContext @@ -350,9 +350,8 @@ public void injectManagedObject(T managedObject, BundleDescriptor bundle) { BundleDescriptor topLevelBundleDesc = (BundleDescriptor) bundle.getModuleDescriptor().getDescriptor(); // First get BeanDeploymentArchive for this ejb - BeanDeploymentArchive bda = weldDeployer.getBeanDeploymentArchiveForBundle(topLevelBundleDesc); - //BeanDeploymentArchive bda = getBDAForBeanClass(topLevelBundleDesc, managedObject.getClass().getName()); - WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(bundle.getApplication()); + BeanDeploymentArchive bda = getBDAForBeanClass(topLevelBundleDesc, managedObject.getClass().getName()); + WeldBootstrap bootstrap = weldDeployer.getBootstrapForArchive(bda); BeanManager beanManager = bootstrap.getManager(bda); @SuppressWarnings("unchecked") AnnotatedType annotatedType = beanManager.createAnnotatedType((Class) managedObject.getClass()); @@ -400,7 +399,7 @@ public T createInterceptorInstance(Class interceptorClass, // First get BeanDeploymentArchive for this ejb BeanDeploymentArchive bda = getBDAForBeanClass(topLevelBundleDesc, ejb.getEjbClassName()); - WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(ejb.getEjbBundleDescriptor().getApplication()); + WeldBootstrap bootstrap = weldDeployer.getBootstrapForArchive(bda); BeanManagerImpl beanManager = bootstrap.getManager(bda); org.jboss.weld.ejb.spi.EjbDescriptor ejbDesc = beanManager.getEjbDescriptor( ejb.getName()); @@ -481,7 +480,7 @@ public JCDIInjectionContext createManagedObject(Class managedClass, Bu // First get BeanDeploymentArchive for this ejb BeanDeploymentArchive bda = weldDeployer.getBeanDeploymentArchiveForBundle(topLevelBundleDesc); - WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(bundle.getApplication()); + WeldBootstrap bootstrap = weldDeployer.getBootstrapForArchive(bda); BeanManager beanManager = bootstrap.getManager(bda); diff --git a/appserver/web/weld-integration/src/test/java/org/glassfish/weld/services/JCDIServiceImplTest.java b/appserver/web/weld-integration/src/test/java/org/glassfish/weld/services/JCDIServiceImplTest.java index b0600055c20..d63a137c465 100644 --- a/appserver/web/weld-integration/src/test/java/org/glassfish/weld/services/JCDIServiceImplTest.java +++ b/appserver/web/weld-integration/src/test/java/org/glassfish/weld/services/JCDIServiceImplTest.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) [2021] Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) [2021-2024] Payara Foundation and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -96,26 +96,24 @@ public void createJCDIInjectionContextWithoutNullPointerException() { Collection emptyListNames = Collections.emptyList(); Collection emptyListOfArchives = Collections.emptyList(); when(ejbDescriptor.getEjbBundleDescriptor()).thenReturn(ejbBundleDescriptor); - when(ejbBundleDescriptor.getApplication()).thenReturn(application); when(ejbBundleDescriptor.getModuleDescriptor()).thenReturn(moduleDescriptor); when(moduleDescriptor.getDescriptor()).thenReturn(bundleDescriptor); when(ejbDescriptor.getEjbClassName()).thenReturn("EjbName"); when(weldDeployer.getBeanDeploymentArchiveForBundle(bundleDescriptor)).thenReturn(beanDeploymentArchive); - when(weldDeployer.getBootstrapForApp(application)).thenReturn(bootstrap); + when(weldDeployer.getBootstrapForArchive(beanDeploymentArchive)).thenReturn(bootstrap); when(beanDeploymentArchive.getBeanClasses()).thenReturn(emptyListNames); when(beanDeploymentArchive.getBeanDeploymentArchives()).thenReturn(emptyListOfArchives); Object obj = jcdiServiceImpl.createJCDIInjectionContext(ejbDescriptor, ejbInfo); assertNull(obj); - verify(ejbDescriptor, times(2)).getEjbBundleDescriptor(); + verify(ejbDescriptor, times(1)).getEjbBundleDescriptor(); verify(ejbBundleDescriptor, times(1)).getModuleDescriptor(); verify(moduleDescriptor, times(1)).getDescriptor(); verify(weldDeployer, times(1)).getBeanDeploymentArchiveForBundle(bundleDescriptor); verify(beanDeploymentArchive, times(1)).getBeanClasses(); verify(beanDeploymentArchive, times(1)).getBeanDeploymentArchives(); - verify(ejbBundleDescriptor, times(1)).getApplication(); - verify(weldDeployer, times(1)).getBootstrapForApp(application); + verify(weldDeployer, times(1)).getBootstrapForArchive(beanDeploymentArchive); verify(bootstrap, times(1)).getManager(beanDeploymentArchive); } } \ No newline at end of file diff --git a/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/ASURLClassLoader.java b/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/ASURLClassLoader.java index 1f9b249c51f..043eba8e07a 100644 --- a/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/ASURLClassLoader.java +++ b/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/ASURLClassLoader.java @@ -208,6 +208,8 @@ public void done() { // because we've taken the snapshot. doneCalled = true; + CacheCleaner.clearJaxRSCache(this); + // closes the jar handles and sets the url entries to null for (URLEntry u : this.urlSet) { u.close(); @@ -725,9 +727,14 @@ protected Class findClass(String name) throws ClassNotFoundException { // set all spec and impl data for the package, // so just use null. This is consistent will the // JDK code that does the same. - definePackage(packageName, null, null, null, - null, null, null, null); - } catch(IllegalArgumentException iae) { + var manifest = classData.jarFile == null ? null : classData.jarFile.getManifest(); + if (manifest == null) { + definePackage(packageName, null, null, null, + null, null, null, null); + } else { + definePackage(packageName, manifest, classData.pd.getCodeSource().getLocation()); + } + } catch(IllegalArgumentException | IOException iae) { // duplicate attempt to define same package. // safe to ignore. _logger.log(Level.FINE, "duplicate package " + @@ -802,14 +809,14 @@ protected synchronized ClassData findClassData(String name) throws ClassNotFound byte[] result = loadClassData0(u, entryName); if (result != null) { if (System.getSecurityManager() == null) { - return new ClassData(result, u.pd); + return new ClassData(result, u.pd, u.zip); } else { //recreate the pd to include the declared permissions CodeSource cs = u.pd.getCodeSource(); PermissionCollection pc = this.getPermissions(cs); ProtectionDomain pdWithPemissions = new ProtectionDomain(u.pd.getCodeSource(), pc, u.pd.getClassLoader(), u.pd.getPrincipals()); - return new ClassData(result, pdWithPemissions); + return new ClassData(result, pdWithPemissions, u.zip); } } } @@ -1321,10 +1328,12 @@ private static final class ClassData { /** must be 'final' to ensure thread visibility */ private final ProtectionDomain pd; + private final JarFile jarFile; - ClassData(byte[] classBytes, ProtectionDomain pd) { + ClassData(byte[] classBytes, ProtectionDomain pd, JarFile jarFile) { this.classBytes = classBytes; this.pd = pd; + this.jarFile = jarFile; } private synchronized byte[] getClassBytes() { return classBytes; diff --git a/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/CacheCleaner.java b/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/CacheCleaner.java new file mode 100644 index 00000000000..afe5a54fb2e --- /dev/null +++ b/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/CacheCleaner.java @@ -0,0 +1,66 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2024] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/main/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package com.sun.enterprise.loader; + +import com.sun.enterprise.util.CULoggerInfo; +import java.lang.reflect.Field; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class CacheCleaner { + private static final Logger logger = CULoggerInfo.getLogger(); + + public static void clearJaxRSCache(ClassLoader classLoader) { + try { + Class cdiComponentProvider = CachingReflectionUtil + .getClassFromCache("org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider", classLoader); + if (cdiComponentProvider != null) { + Field runtimeSpecificsField = CachingReflectionUtil.getFieldFromCache(cdiComponentProvider, + "runtimeSpecifics", true); + Object runtimeSpecifics = runtimeSpecificsField.get(null); + CachingReflectionUtil.getMethodFromCache(runtimeSpecifics.getClass(), + "clearJaxRsResource", true, ClassLoader.class) + .invoke(runtimeSpecifics, classLoader); + } + } catch (Exception e) { + logger.log(Level.WARNING, "Error clearing Jax-Rs cache", e); + } + } +} diff --git a/appserver/web/war-util/src/main/java/org/glassfish/web/loader/CachingReflectionUtil.java b/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/CachingReflectionUtil.java similarity index 96% rename from appserver/web/war-util/src/main/java/org/glassfish/web/loader/CachingReflectionUtil.java rename to nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/CachingReflectionUtil.java index e43996df5ea..71eac944562 100644 --- a/appserver/web/war-util/src/main/java/org/glassfish/web/loader/CachingReflectionUtil.java +++ b/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/CachingReflectionUtil.java @@ -37,9 +37,10 @@ * only if the new code is made subject to such option by the copyright * holder. */ -package org.glassfish.web.loader; +package com.sun.enterprise.loader; +import com.sun.enterprise.util.CULoggerInfo; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Map; @@ -48,7 +49,8 @@ import java.util.logging.Logger; public class CachingReflectionUtil { - private static final Logger logger = LogFacade.getLogger(); + private static final Logger logger = CULoggerInfo.getLogger(); + private static final Map> classCache = new ConcurrentHashMap<>(); private static final Map methodCache = new ConcurrentHashMap<>(); private static final Map fieldCache = new ConcurrentHashMap<>(); diff --git a/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/DirWatcher.java b/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/DirWatcher.java index d6599566f67..d060653b2dd 100644 --- a/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/DirWatcher.java +++ b/nucleus/common/common-util/src/main/java/com/sun/enterprise/loader/DirWatcher.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) [2019] Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) [2019-2024] Payara Foundation and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -208,7 +208,7 @@ protected void register() { try (Stream stream = Files.list(root)){ stream.forEach(this::registerSubProcessor); } catch (IOException e) { - LOGGER.log(Level.INFO, "Error when listing directory",e); + LOGGER.log(Level.FINE, "Error when listing directory",e); } } diff --git a/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentContextImpl.java b/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentContextImpl.java index f35a5bc88ca..0942d72ec63 100644 --- a/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentContextImpl.java +++ b/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentContextImpl.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2019-2022] Payara Foundation and/or affiliates +// Portions Copyright [2019-2024] Payara Foundation and/or affiliates package org.glassfish.deployment.common; @@ -55,6 +55,7 @@ import org.glassfish.internal.deployment.*; import org.glassfish.loader.util.ASClassLoaderUtil; +import java.lang.ref.WeakReference; import java.util.*; import java.util.logging.Logger; import java.io.File; @@ -117,7 +118,7 @@ public class DeploymentContextImpl implements ExtendedDeploymentContext, PreDest Map modulesMetaData = new HashMap(); List transformers = new ArrayList(); Phase phase = Phase.UNKNOWN; - ClassLoader sharableTemp = null; + WeakReference sharableTemp = null; Map modulePropsMap = new HashMap(); Map transientAppMetaData = new HashMap(); Map moduleArchiveHandlers = new HashMap(); @@ -184,7 +185,7 @@ public synchronized void preDestroy() { boolean hotDeploy = getCommandParameters(DeployCommandParameters.class).hotDeploy; if (!hotDeploy) { try { - PreDestroy.class.cast(sharableTemp).preDestroy(); + PreDestroy.class.cast(sharableTemp.get()).preDestroy(); } catch (Exception e) { // ignore, the classloader does not need to be destroyed } @@ -249,9 +250,9 @@ public synchronized void createDeploymentClassLoader(ClassLoaderHierarchy clh, A this.addTransientAppMetaData(ExtendedDeploymentContext.IS_TEMP_CLASSLOADER, Boolean.TRUE); boolean hotDeploy = getCommandParameters(DeployCommandParameters.class).hotDeploy; if (hotDeploy && this.cloader != null) { - this.sharableTemp = this.cloader; + this.sharableTemp = new WeakReference<>(this.cloader); } else { - this.sharableTemp = createClassLoader(clh, handler, null); + this.sharableTemp = new WeakReference<>(createClassLoader(clh, handler, null)); } } @@ -280,7 +281,7 @@ public synchronized ClassLoader getClassLoader(boolean sharable) { // otherwise, we return the final one. if (phase == Phase.PREPARE) { if (sharable) { - return sharableTemp; + return sharableTemp.get(); } else { InstrumentableClassLoader cl = InstrumentableClassLoader.class.cast(sharableTemp); return cl.copy(); @@ -288,7 +289,7 @@ public synchronized ClassLoader getClassLoader(boolean sharable) { } else { // we are out of the prepare phase, destroy the shareableTemp and // return the final classloader - if (sharableTemp != null && sharableTemp != cloader) { + if (sharableTemp != null && sharableTemp.get() != cloader) { try { PreDestroy.class.cast(sharableTemp).preDestroy(); } catch (Exception e) {