Skip to content

Commit 5475ead

Browse files
committed
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, including refactored reflection caching
1 parent 45dff37 commit 5475ead

File tree

21 files changed

+986
-530
lines changed

21 files changed

+986
-530
lines changed

appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ContextSetupProviderImpl.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* only if the new code is made subject to such option by the copyright
3838
* holder.
3939
*/
40-
// Portions Copyright [2016-2023] [Payara Foundation and/or its affiliates]
40+
// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates]
4141

4242
package org.glassfish.concurrent.runtime;
4343

@@ -378,9 +378,7 @@ public void reset(ContextHandle contextHandle) {
378378
restorer.endContext();
379379
}
380380

381-
if (handle.getContextClassLoader() != null) {
382-
Utility.setContextClassLoader(handle.getContextClassLoader());
383-
}
381+
Utility.setContextClassLoader(handle.getContextClassLoader());
384382
if (handle.getSecurityContext() != null) {
385383
SecurityContext.setCurrent(handle.getSecurityContext());
386384
}

appserver/deployment/javaee-full/src/main/java/org/glassfish/javaee/full/deployment/EarDeployer.java

+12-5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* only if the new code is made subject to such option by the copyright
3838
* holder.
3939
*/
40+
// Portions Copyright [2024] [Payara Foundation and/or its affiliates]
4041

4142
package org.glassfish.javaee.full.deployment;
4243

@@ -101,7 +102,7 @@
101102
@Service
102103
@PerLookup
103104
public class EarDeployer implements Deployer {
104-
105+
public static final String PER_BDA_METADATA_KEY = "[PerBDA]";
105106
// private static final Class GLASSFISH_APPCLIENT_GROUP_FACADE_CLASS =
106107
// org.glassfish.appclient.client.AppClientGroupFacade.class;
107108
// Currently using a string instead of a Class constant to avoid a circular
@@ -457,15 +458,21 @@ public <U extends OpsParams> U getCommandParameters(Class<U> commandParametersTy
457458
@Override
458459
public void addTransientAppMetaData(String metaDataKey,
459460
Object metaData) {
460-
context.addTransientAppMetaData(metaDataKey,
461-
metaData);
461+
if (metaDataKey.startsWith(PER_BDA_METADATA_KEY)) {
462+
super.addTransientAppMetaData(metaDataKey, metaData);
463+
} else {
464+
context.addTransientAppMetaData(metaDataKey, metaData);
465+
}
462466
}
463467

464468
@Override
465469
public <T> T getTransientAppMetaData(String metaDataKey,
466470
Class<T> metadataType) {
467-
return context.getTransientAppMetaData(metaDataKey,
468-
metadataType);
471+
if (metaDataKey.startsWith(PER_BDA_METADATA_KEY)) {
472+
return super.getTransientAppMetaData(metaDataKey, metadataType);
473+
} else {
474+
return context.getTransientAppMetaData(metaDataKey, metadataType);
475+
}
469476
}
470477

471478
@Override

appserver/web/war-util/src/main/java/org/glassfish/web/loader/CachingReflectionUtil.java

+35-46
Original file line numberDiff line numberDiff line change
@@ -42,60 +42,49 @@
4242

4343
import java.lang.reflect.Field;
4444
import java.lang.reflect.Method;
45-
import java.util.Map;
46-
import java.util.concurrent.ConcurrentHashMap;
47-
import java.util.logging.Level;
48-
import java.util.logging.Logger;
4945

46+
/**
47+
* @deprecated This class is not used and will be removed in a future release.
48+
* Functionality has been moved to {@link com.sun.enterprise.loader.CachingReflectionUtil}.
49+
*/
50+
@Deprecated(forRemoval = true)
5051
public class CachingReflectionUtil {
51-
private static final Logger logger = LogFacade.getLogger();
52-
private static final Map<String, Class<?>> classCache = new ConcurrentHashMap<>();
53-
private static final Map<String, Method> methodCache = new ConcurrentHashMap<>();
54-
private static final Map<String, Field> fieldCache = new ConcurrentHashMap<>();
55-
52+
/**
53+
* @deprecated This method is not used and will be removed in a future release.
54+
* Functionality has been moved to {@link com.sun.enterprise.loader.CachingReflectionUtil}.
55+
* @param className
56+
* @param classLoader
57+
* @return
58+
*/
59+
@Deprecated(forRemoval = true)
5660
public static Class<?> getClassFromCache(String className, ClassLoader classLoader) {
57-
var cls = classCache.computeIfAbsent(className, k -> {
58-
try {
59-
return classLoader.loadClass(className);
60-
} catch (ClassNotFoundException e) {
61-
logger.log(Level.FINE, "Class not found: " + className, e);
62-
return null;
63-
}
64-
});
65-
return cls;
61+
return com.sun.enterprise.loader.CachingReflectionUtil.getClassFromCache(className, classLoader);
6662
}
6763

64+
/**
65+
* @deprecated This method is not used and will be removed in a future release.
66+
* Functionality has been moved to {@link com.sun.enterprise.loader.CachingReflectionUtil}.
67+
* @param cls
68+
* @param methodName
69+
* @param isPrivate
70+
* @param parameterTypes
71+
* @return
72+
*/
73+
@Deprecated(forRemoval = true)
6874
public static Method getMethodFromCache(Class<?> cls, String methodName, boolean isPrivate, Class<?>... parameterTypes) {
69-
return methodCache.computeIfAbsent(methodName, k -> {
70-
try {
71-
if (isPrivate) {
72-
Method method = cls.getDeclaredMethod(methodName, parameterTypes);
73-
method.setAccessible(true);
74-
return method;
75-
} else {
76-
return cls.getMethod(methodName, parameterTypes);
77-
}
78-
} catch (NoSuchMethodException e) {
79-
logger.log(Level.FINE, "Method not found: " + methodName, e);
80-
return null;
81-
}
82-
});
75+
return com.sun.enterprise.loader.CachingReflectionUtil.getMethodFromCache(cls, methodName, isPrivate, parameterTypes);
8376
}
8477

78+
/**
79+
* @deprecated This method is not used and will be removed in a future release.
80+
* Functionality has been moved to {@link com.sun.enterprise.loader.CachingReflectionUtil}.
81+
* @param cls
82+
* @param fieldName
83+
* @param isPrivate
84+
* @return
85+
*/
86+
@Deprecated(forRemoval = true)
8587
public static Field getFieldFromCache(Class<?> cls, String fieldName, boolean isPrivate) {
86-
return fieldCache.computeIfAbsent(fieldName, k -> {
87-
try {
88-
if (isPrivate) {
89-
Field field = cls.getDeclaredField(fieldName);
90-
field.setAccessible(true);
91-
return field;
92-
} else {
93-
return cls.getField(fieldName);
94-
}
95-
} catch (NoSuchFieldException e) {
96-
logger.log(Level.FINE, "Field not found: " + fieldName, e);
97-
return null;
98-
}
99-
});
88+
return com.sun.enterprise.loader.CachingReflectionUtil.getFieldFromCache(cls, fieldName, isPrivate);
10089
}
10190
}

appserver/web/war-util/src/main/java/org/glassfish/web/loader/WebappClassLoader.java

+2-18
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import com.sun.enterprise.deployment.Application;
6666
import com.sun.enterprise.deployment.util.DOLUtils;
6767
import com.sun.enterprise.glassfish.bootstrap.MainHelper.HotSwapHelper;
68+
import com.sun.enterprise.loader.CacheCleaner;
6869
import com.sun.enterprise.security.integration.DDPermissionsLoader;
6970
import com.sun.enterprise.security.integration.PermsHolder;
7071
import com.sun.enterprise.util.io.FileUtils;
@@ -2051,7 +2052,7 @@ public void stop() throws Exception {
20512052
// START SJSAS 6258619
20522053
ClassLoaderUtil.releaseLoader(this);
20532054
// END SJSAS 6258619
2054-
clearJaxRSCache();
2055+
CacheCleaner.clearCaches(this);
20552056

20562057
synchronized(jarFilesLock) {
20572058
started = false;
@@ -2658,23 +2659,6 @@ private void clearReferencesRmiTargets() {
26582659
}
26592660
}
26602661

2661-
private void clearJaxRSCache() {
2662-
try {
2663-
Class<?> cdiComponentProvider = CachingReflectionUtil
2664-
.getClassFromCache("org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider", this);
2665-
if (cdiComponentProvider != null) {
2666-
Field runtimeSpecificsField = CachingReflectionUtil.getFieldFromCache(cdiComponentProvider,
2667-
"runtimeSpecifics", true);
2668-
Object runtimeSpecifics = runtimeSpecificsField.get(null);
2669-
CachingReflectionUtil.getMethodFromCache(runtimeSpecifics.getClass(),
2670-
"clearJaxRsResource", true, ClassLoader.class)
2671-
.invoke(runtimeSpecifics, this);
2672-
}
2673-
} catch (Exception e) {
2674-
logger.log(Level.WARNING, "Error clearing Jax-Rs cache", e);
2675-
}
2676-
}
2677-
26782662
/**
26792663
* Clear the {@link ResourceBundle} cache of any bundles loaded by this
26802664
* class loader or any class loader where this loader is a parent class

appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java

+58-51
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@
3737
* only if the new code is made subject to such option by the copyright
3838
* holder.
3939
*/
40-
// Portions Copyright [2014-2021] [Payara Foundation and/or its affiliates]
40+
// Portions Copyright [2014-2024] [Payara Foundation and/or its affiliates]
4141

4242
package org.glassfish.web.deployment.archivist;
4343

4444
import com.sun.enterprise.deployment.Application;
45+
import com.sun.enterprise.deployment.EarType;
4546
import org.glassfish.deployment.common.RootDeploymentDescriptor;
4647
import com.sun.enterprise.deployment.EjbBundleDescriptor;
4748
import com.sun.enterprise.deployment.EjbDescriptor;
@@ -75,9 +76,10 @@
7576
import java.util.ArrayList;
7677
import java.util.Enumeration;
7778
import java.util.HashMap;
79+
import java.util.LinkedHashSet;
7880
import java.util.List;
7981
import java.util.Map;
80-
import java.util.Vector;
82+
import java.util.Set;
8183
import java.net.URL;
8284
import java.util.logging.Level;
8385
import java.util.logging.Logger;
@@ -296,24 +298,33 @@ protected String getArchiveExtension() {
296298
/**
297299
* @return a list of libraries included in the archivist
298300
*/
299-
public Vector<String> getLibraries(Archive archive) {
301+
public Set<String> getLibraries(ReadableArchive archive) throws IOException {
302+
Set<String> libraries = new LinkedHashSet<>();
303+
// WAR libraries
304+
extractLibraries(archive, true, libraries);
305+
ReadableArchive parentArchive = archive.getParentArchive();
306+
if (parentArchive != null && parentArchive.getExtraData(ArchiveType.class).toString().equals(EarType.ARCHIVE_TYPE)) {
307+
// EAR shared libraries
308+
extractLibraries(parentArchive.getSubArchive("lib"), false, libraries);
309+
}
310+
return libraries;
311+
}
300312

301-
Enumeration<String> entries = archive.entries();
313+
private static void extractLibraries(Archive archive, boolean hasWebInfPrefix, Set<String> libs) {
314+
Enumeration<String> entries = archive != null ? archive.entries() : null;
302315
if (entries==null)
303-
return null;
316+
return;
304317

305-
Vector<String> libs = new Vector<String>();
306318
while (entries.hasMoreElements()) {
307319

308320
String entryName = entries.nextElement();
309-
if (!entryName.startsWith("WEB-INF/lib")) {
310-
continue; // not in WEB-INF...
321+
if (hasWebInfPrefix && !entryName.startsWith("WEB-INF/lib")) {
322+
continue; // not in prefix (i.e. WEB-INF)...
311323
}
312324
if (entryName.endsWith(".jar")) {
313325
libs.add(entryName);
314326
}
315327
}
316-
return libs;
317328
}
318329

319330
@Override
@@ -381,54 +392,50 @@ private List<WebFragmentDescriptor> readStandardFragments(WebBundleDescriptorImp
381392
ReadableArchive archive) throws IOException {
382393

383394
List<WebFragmentDescriptor> wfList = new ArrayList<WebFragmentDescriptor>();
384-
Vector libs = getLibraries(archive);
385-
if (libs != null && libs.size() > 0) {
386-
387-
for (int i = 0; i < libs.size(); i++) {
388-
String lib = (String)libs.get(i);
389-
Archivist wfArchivist = new WebFragmentArchivist(this, habitat);
390-
wfArchivist.setRuntimeXMLValidation(this.getRuntimeXMLValidation());
391-
wfArchivist.setRuntimeXMLValidationLevel(
392-
this.getRuntimeXMLValidationLevel());
393-
wfArchivist.setAnnotationProcessingRequested(false);
394-
395-
WebFragmentDescriptor wfDesc = null;
396-
ReadableArchive embeddedArchive = archive.getSubArchive(lib);
397-
try {
398-
if (embeddedArchive != null &&
399-
wfArchivist.hasStandardDeploymentDescriptor(embeddedArchive)) {
400-
try {
401-
wfDesc = (WebFragmentDescriptor)wfArchivist.open(embeddedArchive);
402-
} catch(SAXParseException ex) {
403-
IOException ioex = new IOException();
404-
ioex.initCause(ex);
405-
throw ioex;
406-
}
407-
} else {
408-
wfDesc = new WebFragmentDescriptor();
409-
wfDesc.setExists(false);
410-
}
411-
} finally {
412-
if (embeddedArchive != null) {
413-
embeddedArchive.close();
395+
for (String lib : getLibraries(archive)) {
396+
Archivist wfArchivist = new WebFragmentArchivist(this, habitat);
397+
wfArchivist.setRuntimeXMLValidation(this.getRuntimeXMLValidation());
398+
wfArchivist.setRuntimeXMLValidationLevel(
399+
this.getRuntimeXMLValidationLevel());
400+
wfArchivist.setAnnotationProcessingRequested(false);
401+
402+
WebFragmentDescriptor wfDesc = null;
403+
ReadableArchive embeddedArchive = lib.startsWith("WEB-INF")
404+
? archive.getSubArchive(lib) : archive.getParentArchive().getSubArchive("lib").getSubArchive(lib);
405+
try {
406+
if (embeddedArchive != null &&
407+
wfArchivist.hasStandardDeploymentDescriptor(embeddedArchive)) {
408+
try {
409+
wfDesc = (WebFragmentDescriptor)wfArchivist.open(embeddedArchive);
410+
} catch(SAXParseException ex) {
411+
IOException ioex = new IOException();
412+
ioex.initCause(ex);
413+
throw ioex;
414414
}
415+
} else {
416+
wfDesc = new WebFragmentDescriptor();
417+
wfDesc.setExists(false);
418+
}
419+
} finally {
420+
if (embeddedArchive != null) {
421+
embeddedArchive.close();
415422
}
416-
wfDesc.setJarName(lib.substring(lib.lastIndexOf('/') + 1));
417-
wfList.add(wfDesc);
423+
}
424+
wfDesc.setJarName(lib.substring(lib.lastIndexOf('/') + 1));
425+
wfList.add(wfDesc);
418426

419-
descriptor.putJarNameWebFragmentNamePair(wfDesc.getJarName(), wfDesc.getName());
427+
descriptor.putJarNameWebFragmentNamePair(wfDesc.getJarName(), wfDesc.getName());
420428

421-
}
429+
}
422430

423-
if (((WebBundleDescriptorImpl)descriptor).getAbsoluteOrderingDescriptor() != null) {
424-
wfList = ((WebBundleDescriptorImpl)descriptor).getAbsoluteOrderingDescriptor().order(wfList);
425-
} else {
426-
OrderingDescriptor.sort(wfList);
427-
}
431+
if (((WebBundleDescriptorImpl)descriptor).getAbsoluteOrderingDescriptor() != null) {
432+
wfList = ((WebBundleDescriptorImpl)descriptor).getAbsoluteOrderingDescriptor().order(wfList);
433+
} else {
434+
OrderingDescriptor.sort(wfList);
435+
}
428436

429-
for (WebFragmentDescriptor wf : wfList) {
430-
descriptor.addOrderedLib(wf.getJarName());
431-
}
437+
for (WebFragmentDescriptor wf : wfList) {
438+
descriptor.addOrderedLib(wf.getJarName());
432439
}
433440

434441
return wfList;

appserver/web/weld-integration/src/main/java/org/glassfish/weld/ACLSingletonProvider.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* only if the new code is made subject to such option by the copyright
3838
* holder.
3939
*
40-
* Portions Copyright [2017-2019] Payara Foundation and/or affiliates
40+
* Portions Copyright [2017-2024] Payara Foundation and/or affiliates
4141
*/
4242

4343
package org.glassfish.weld;
@@ -108,11 +108,11 @@ public ClassLoader run()
108108
@Override
109109
public T get( String id )
110110
{
111-
ClassLoader acl = getClassLoader();
112-
T instance = store.get(acl);
111+
T instance = storeById.get(id);
113112
if (instance == null)
114113
{
115-
instance = storeById.get(id);
114+
ClassLoader acl = getClassLoader();
115+
instance = store.get(acl);
116116
if (instance == null) {
117117
throw new IllegalStateException("Singleton not set for " + acl);
118118
}

0 commit comments

Comments
 (0)