diff --git a/.gitignore b/.gitignore index 39fa8643b80..cd33363f8cc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ target/ .vscode/ .idea .DS_Store +.sdkmanrc gfbuild.log nb-configuration.xml /appserver/tests/quicklook/classes/ @@ -26,4 +27,4 @@ appserver/tests/quicklook/quicklook_summary.txt **/nbproject .flattened-pom.xml **/__pycache__ -appserver/packager/legal/src/main/resources/glassfish/legal/3RD-PARTY-LICENSE.txt \ No newline at end of file +appserver/packager/legal/src/main/resources/glassfish/legal/3RD-PARTY-LICENSE.txt diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EjbInvocation.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EjbInvocation.java index 1f55e463a7d..94cbc6743ab 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EjbInvocation.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EjbInvocation.java @@ -269,7 +269,7 @@ public class EjbInvocation // EjbInvocation(String compEnvId, Container container) { super.componentId = compEnvId; - super.container = container; + setContainer(container); super.setComponentInvocationType(ComponentInvocation.ComponentInvocationType.EJB_INVOCATION); EjbBundleDescriptor ejbBundleDesc = container.getEjbDescriptor().getEjbBundleDescriptor(); @@ -371,6 +371,7 @@ public EjbInvocation clone() { @Override public Object getJaccEjb() { Object bean = null; + Object container = getContainer(); if( container != null ) { bean = ((Container) container).getJaccEjb(this); } @@ -452,7 +453,7 @@ public void setTransactionOperationsManager(TransactionOperationsManager transac */ @Override public boolean userTransactionMethodsAllowed() { - return ((Container) container).userTransactionMethodsAllowed(this); + return ((Container) getContainer()).userTransactionMethodsAllowed(this); } /** @@ -461,7 +462,7 @@ public boolean userTransactionMethodsAllowed() { */ @Override public void userTransactionLookupAllowed() throws NameNotFoundException { - ((BaseContainer) container).checkUserTransactionLookup(this); + ((BaseContainer) getContainer()).checkUserTransactionLookup(this); } /** @@ -469,7 +470,7 @@ public void userTransactionLookupAllowed() throws NameNotFoundException { */ @Override public void doAfterUtxBegin() { - ((Container) container).doAfterBegin(this); + ((Container) getContainer()).doAfterBegin(this); } public InterceptorManager.InterceptorChain getInterceptorChain() { @@ -650,11 +651,11 @@ public Object[] getInterceptorInstances() { @Override public Object invokeBeanMethod() throws Throwable { - return ((BaseContainer) container).invokeBeanMethod(this); + return ((BaseContainer) getContainer()).invokeBeanMethod(this); } public com.sun.enterprise.security.SecurityManager getEjbSecurityManager() { - return ((BaseContainer)container).getSecurityManager(); + return ((BaseContainer) getContainer()).getSecurityManager(); } @Override @@ -684,7 +685,7 @@ public boolean authorizeWebService(Method m) throws Exception { private Exception authorizeWebServiceAndSetMethod(Method m) { try { this.method = m; - if (((com.sun.ejb.Container) container).authorize(this)) { + if (((com.sun.ejb.Container) getContainer()).authorize(this)) { // Record the method on which the successful // authorization check was performed. setWebServiceMethod(m); diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EjbInvocationFactory.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EjbInvocationFactory.java index 8864e94ee60..7efc472a9d5 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EjbInvocationFactory.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EjbInvocationFactory.java @@ -58,7 +58,7 @@ public EjbInvocationFactory(String compEnvId, Container container) { public EjbInvocation create() { EjbInvocation ejbInv = new EjbInvocation(compEnvId, container); - ejbInv.jndiEnvironment = container.getEjbDescriptor(); + ejbInv.setJNDIEnvironment(container.getEjbDescriptor()); return ejbInv; } @@ -67,7 +67,7 @@ public EjbInvocation create(Object ejb, C ctx) { ejbInv.ejb = ejb; ejbInv.instance = ejb; ejbInv.context = ctx; - ejbInv.jndiEnvironment = container.getEjbDescriptor(); + ejbInv.setJNDIEnvironment(container.getEjbDescriptor()); return ejbInv; } diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java index 693490e7a21..cf117612345 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java @@ -2002,7 +2002,7 @@ public void preInvoke(EjbInvocation inv) { } inv.transactionAttribute = inv.invocationInfo.txAttr; - inv.container = this; + inv.setContainer(this); if (inv.mustInvokeAsynchronously()) { return; diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbAsyncInvocationManager.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbAsyncInvocationManager.java index 2f65813fdb7..c72ee61e872 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbAsyncInvocationManager.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbAsyncInvocationManager.java @@ -158,7 +158,7 @@ public void cleanupContainerTasks(Container container) { Map.Entry next = iterator.next(); EjbAsyncTask task = next.getValue().getEjbAsyncTask(); - if( task.getEjbInvocation().container == container ) { + if( task.getEjbInvocation().getContainer() == container ) { removedTasks.add(task.getInvId()); diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbAsyncTask.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbAsyncTask.java index 670fc6f5b39..b6ce48e50b1 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbAsyncTask.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbAsyncTask.java @@ -88,7 +88,7 @@ EjbInvocation getEjbInvocation() { public V call() throws Exception { V returnValue = null; - BaseContainer container = (BaseContainer) inv.container; + BaseContainer container = (BaseContainer) inv.getContainer(); ClassLoader prevCL = Thread.currentThread().getContextClassLoader(); try { Utility.setContextClassLoader(container.getClassLoader()); diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbEndpointFacadeImpl.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbEndpointFacadeImpl.java index f6f7e81a043..c655ba234ec 100644 --- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbEndpointFacadeImpl.java +++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/EjbEndpointFacadeImpl.java @@ -89,7 +89,7 @@ public ComponentInvocation startInvocation() { // Do the portions of preInvoke that don't need a Method object. inv.isWebService = true; - inv.container = container_; + inv.setContainer(container_); inv.transactionAttribute = Container.TX_NOT_INITIALIZED; // AS per latest spec change, the MessageContext object in WebSvcCtxt diff --git a/appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanContainer.java b/appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanContainer.java index 37ee49d0365..84f3c1952c2 100644 --- a/appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanContainer.java +++ b/appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanContainer.java @@ -216,7 +216,7 @@ public final class MessageBeanContainer extends BaseContainer implements Message messageBeanClient_ = clientFactory.createMessageBeanClient(msgBeanDesc); componentInvocation = createComponentInvocation(); - componentInvocation.container = this; + componentInvocation.setContainer(this); invocationManager.preInvoke(componentInvocation); messageBeanClient_.setup(this); @@ -1135,7 +1135,7 @@ public void beforeMessageDelivery(Method method, MessageDeliveryType deliveryTyp invocation.context = context; invocation.instance = context.getEJB(); invocation.ejb = context.getEJB(); - invocation.container = this; + invocation.setContainer(this); // Message Bean Container only starts a new transaction if // there is no imported transaction and the message listener diff --git a/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/OpenTelemetryApplicationEventListener.java b/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/OpenTelemetryApplicationEventListener.java index f8fe1d7565e..207b2db9c5f 100644 --- a/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/OpenTelemetryApplicationEventListener.java +++ b/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/OpenTelemetryApplicationEventListener.java @@ -79,6 +79,12 @@ public void postConstruct() { @Override public void onEvent(final ApplicationEvent event) { + switch (event.getType()) { + case DESTROY_FINISHED: + case RELOAD_FINISHED: + openTracingHelper.canTraceCache.clear(event.getResourceConfig().getClassLoader()); + break; + } LOG.config(() -> "onEvent(event.type=" + event.getType() + ")"); } diff --git a/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/OpenTracingHelper.java b/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/OpenTracingHelper.java index ffbd756bdc4..911b8d8a9e6 100644 --- a/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/OpenTracingHelper.java +++ b/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/OpenTracingHelper.java @@ -368,7 +368,7 @@ private Traced computeTracedAnnotation(ResourceInfo resourceInfo, BeanManager be return result == null ? NULL_TRACED : result; } - private static ResourceCache canTraceCache = new ResourceCache<>(); + static ResourceCache canTraceCache = new ResourceCache<>(); /** * Helper method that checks if any specified skip patterns match this method name * diff --git a/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/ResourceCache.java b/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/ResourceCache.java index e3684f9c2b6..46ebaf588ba 100644 --- a/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/ResourceCache.java +++ b/appserver/payara-appserver-modules/microprofile/telemetry/src/main/java/fish/payara/microprofile/telemetry/tracing/jaxrs/ResourceCache.java @@ -47,7 +47,6 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; -import org.eclipse.microprofile.opentracing.Traced; class ResourceCache { @@ -83,4 +82,12 @@ public int hashCode() { T get(ResourceInfo info, Supplier supplier) { return tracedCache.computeIfAbsent(new ResourceKey(info), k -> supplier.get()); } + + /** + * clear all classes belonging to this class loader + * @param classLoader + */ + void clear(ClassLoader classLoader) { + tracedCache.entrySet().removeIf(entry -> entry.getKey().resourceClass.getClassLoader() == classLoader); + } } diff --git a/appserver/persistence/entitybean-container/src/main/java/org/glassfish/persistence/ejb/entitybean/container/EntityContainer.java b/appserver/persistence/entitybean-container/src/main/java/org/glassfish/persistence/ejb/entitybean/container/EntityContainer.java index 56ece86c7ee..e2f1d4707c0 100644 --- a/appserver/persistence/entitybean-container/src/main/java/org/glassfish/persistence/ejb/entitybean/container/EntityContainer.java +++ b/appserver/persistence/entitybean-container/src/main/java/org/glassfish/persistence/ejb/entitybean/container/EntityContainer.java @@ -1284,7 +1284,7 @@ private void internalRemoveBeanUnchecked(EJBLocalRemoteObject localRemoteObj, bo context.incrementCalls(); inv.instance = inv.ejb = context.getEJB(); - inv.container = this; + inv.setContainer(this); invocationManager.preInvoke(inv); // call ejbLoad if necessary diff --git a/appserver/web/gf-web-connector/src/main/java/fish/payara/appserver/context/JavaEEContextUtilImpl.java b/appserver/web/gf-web-connector/src/main/java/fish/payara/appserver/context/JavaEEContextUtilImpl.java index c70880f3fcd..9db5e7b5e8e 100644 --- a/appserver/web/gf-web-connector/src/main/java/fish/payara/appserver/context/JavaEEContextUtilImpl.java +++ b/appserver/web/gf-web-connector/src/main/java/fish/payara/appserver/context/JavaEEContextUtilImpl.java @@ -214,7 +214,7 @@ private InstanceImpl(ComponentInvocation currentInvocation) { } else if (currentInvocation.getJNDIEnvironment() instanceof JndiNameEnvironment) { componentId = DOLUtils.toEarComponentId( DOLUtils.getApplicationName((JndiNameEnvironment) - currentInvocation.jndiEnvironment)); + currentInvocation.getJNDIEnvironment())); isApplicationComponent = true; } else { // checkState() later should error out due to this condition 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 f053eb33e08..1fed2d1cc71 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 @@ -121,6 +121,7 @@ import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -2036,6 +2037,7 @@ public void stop() throws Exception { // START SJSAS 6258619 ClassLoaderUtil.releaseLoader(this); // END SJSAS 6258619 + clearBeanELResolverCache(); synchronized(jarFilesLock) { started = false; @@ -2642,6 +2644,45 @@ private void clearReferencesRmiTargets() { } } + private void clearBeanELResolverCache() { + try { + Class elUtilsClass = Class.forName("com.sun.faces.el.ELUtils"); + Class elResolverClass = Class.forName("jakarta.el.BeanELResolver"); + Object resolver = elUtilsClass.getField("BEAN_RESOLVER").get(null); + logger.fine(String.format("Fields: %s", Arrays.stream(elResolverClass.getDeclaredFields()) + .map(Field::toString).collect(Collectors.toList()))); + try { + elResolverClass.getMethod("clearProperties", ClassLoader.class).invoke(resolver, this); + } catch (NoSuchMethodException e) { + clearBeanELResolverPropertiesCache(resolver, elResolverClass); + } + } catch (ClassNotFoundException e) { + logger.log(Level.FINE, "BeanELResolver or ELUtils not found", e); + } catch (Exception e) { + logger.log(Level.WARNING, "Error clearing BeanELResolver cache", e); + } + } + + /** + * Workaround until clearProperties() is available in Jakarta EL + * @see Jakarta EL Pull Request + */ + private void clearBeanELResolverPropertiesCache(Object resolver, Class elResolverClass) throws Exception { + Class elResolverCacheClass = Class.forName("jakarta.el.BeanELResolver$SoftConcurrentHashMap"); + var propertiesField = elResolverClass.getDeclaredField("properties"); + propertiesField.setAccessible(true); + ConcurrentHashMap, Object> properties = + (ConcurrentHashMap, Object>) propertiesField.get(resolver); + properties.entrySet().removeIf(entry -> entry.getKey().getClassLoader() == this); + var mapField = elResolverCacheClass.getDeclaredField("map"); + mapField.setAccessible(true); + ConcurrentHashMap, Object> map = + (ConcurrentHashMap, Object>) mapField.get(propertiesField.get(resolver)); + map.entrySet().removeIf(entry -> entry.getKey().getClassLoader() == this); + var cleanupMethod = elResolverCacheClass.getDeclaredMethod("cleanup"); + cleanupMethod.setAccessible(true); + cleanupMethod.invoke(propertiesField.get(resolver)); + } /** * Clear the {@link ResourceBundle} cache of any bundles loaded by this diff --git a/appserver/web/web-core/src/main/java/org/apache/catalina/core/ApplicationFilterConfig.java b/appserver/web/web-core/src/main/java/org/apache/catalina/core/ApplicationFilterConfig.java index 91bd5a0de06..acf8d827ea4 100644 --- a/appserver/web/web-core/src/main/java/org/apache/catalina/core/ApplicationFilterConfig.java +++ b/appserver/web/web-core/src/main/java/org/apache/catalina/core/ApplicationFilterConfig.java @@ -324,8 +324,9 @@ void release() { String msg = rb.getString(LogFacade.DO_AS_PRIVILEGE); log.log(Level.SEVERE, msg, ex); } - } else { + } else { filter.destroy(); + filterDef = null; } if (context != null) { diff --git a/appserver/web/web-glue/src/main/java/com/sun/enterprise/web/WebComponentInvocation.java b/appserver/web/web-glue/src/main/java/com/sun/enterprise/web/WebComponentInvocation.java index 4a134a1a50d..fd567c61cb9 100644 --- a/appserver/web/web-glue/src/main/java/com/sun/enterprise/web/WebComponentInvocation.java +++ b/appserver/web/web-glue/src/main/java/com/sun/enterprise/web/WebComponentInvocation.java @@ -64,8 +64,8 @@ public WebComponentInvocation(WebModule wm, Object instance) { setComponentInvocationType( ComponentInvocation.ComponentInvocationType.SERVLET_INVOCATION); componentId = wm.getComponentId(); - jndiEnvironment = wm.getWebBundleDescriptor(); - container = wm; + setJNDIEnvironment(wm.getWebBundleDescriptor()); + setContainer(wm); this.instance = instance; setResourceTableKey(_getResourceTableKey()); diff --git a/core/core-parent/pom.xml b/core/core-parent/pom.xml index 05d579be794..c6b03ea169e 100644 --- a/core/core-parent/pom.xml +++ b/core/core-parent/pom.xml @@ -642,6 +642,7 @@ io.opentelemetry.extension io.opentelemetry.instrumentation fish.payara.shaded + org.glassfish.api.invocation diff --git a/nucleus/common/glassfish-api/src/main/java/org/glassfish/api/invocation/ComponentInvocation.java b/nucleus/common/glassfish-api/src/main/java/org/glassfish/api/invocation/ComponentInvocation.java index 594ab913dcc..53bc72a4165 100644 --- a/nucleus/common/glassfish-api/src/main/java/org/glassfish/api/invocation/ComponentInvocation.java +++ b/nucleus/common/glassfish-api/src/main/java/org/glassfish/api/invocation/ComponentInvocation.java @@ -43,6 +43,7 @@ import static org.glassfish.api.invocation.ComponentInvocation.ComponentInvocationType.UN_INITIALIZED; +import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; @@ -80,9 +81,9 @@ public enum ComponentInvocationType { /** * ServletContext for servlet, Container for EJB */ - public Object container; + private WeakReference container; - public Object jndiEnvironment; + private WeakReference jndiEnvironment; public String componentId; @@ -117,13 +118,13 @@ public enum ComponentInvocationType { protected String registrationName; public ComponentInvocation() { - + container = new WeakReference<>(null); } public ComponentInvocation(String componentId, ComponentInvocationType invocationType, Object container, String appName, String moduleName, String registrationName) { this.componentId = componentId; this.invocationType = invocationType; - this.container = container; + this.container = new WeakReference<>(container); this.appName = appName; this.moduleName = moduleName; this.registrationName = registrationName; @@ -133,7 +134,7 @@ public ComponentInvocation(String componentId, ComponentInvocationType invocatio this.componentId = componentId; this.invocationType = invocationType; this.instance = instance; - this.container = container; + this.container = new WeakReference<>(container); this.transaction = transaction; } @@ -202,31 +203,34 @@ public void setComponentId(String componentId) { } public Object getJndiEnvironment() { - return jndiEnvironment; + return getJNDIEnvironment(); } public void setJndiEnvironment(Object jndiEnvironment) { - this.jndiEnvironment = jndiEnvironment; + setJNDIEnvironment(jndiEnvironment); } public void setJNDIEnvironment(Object val) { - jndiEnvironment = val; + jndiEnvironment = new WeakReference<>(val); } public Object getJNDIEnvironment() { - return jndiEnvironment; + if (jndiEnvironment == null) { + return null; + } + return jndiEnvironment.get(); } public Object getContainer() { - return container; + return container.get(); } public void setContainer(Object container) { - this.container = container; + this.container = new WeakReference<>(container); } public Object getContainerContext() { - return container; + return getContainer(); } public Object getTransaction() { @@ -391,7 +395,7 @@ public String toString() { str.append("\tcomponentId=").append(componentId).append('\n'); str.append("\ttype=").append(invocationType).append('\n'); str.append("\tinstance=").append(instanceName != null ? instanceName : String.valueOf(instance)).append('\n'); - str.append("\tcontainer=").append(container).append('\n'); + str.append("\tcontainer=").append(getContainer()).append('\n'); str.append("\tappName=").append(appName).append('\n'); return str.toString(); }