Skip to content

Commit c4904d9

Browse files
avpinchukdmatej
authored andcommitted
Fixes WebappClassLoader race condition on definePackage
Signed-off-by: Alexander Pinčuk <[email protected]>
1 parent 500d30b commit c4904d9

File tree

1 file changed

+43
-6
lines changed

1 file changed

+43
-6
lines changed

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

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation
2+
* Copyright (c) 2022, 2025 Contributors to the Eclipse Foundation.
33
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
44
* Copyright 2004 The Apache Software Foundation
55
*
@@ -47,10 +47,13 @@
4747
import java.util.Collections;
4848
import java.util.Enumeration;
4949
import java.util.List;
50+
import java.util.Map;
5051
import java.util.Set;
5152
import java.util.concurrent.ConcurrentHashMap;
5253
import java.util.concurrent.ConcurrentLinkedQueue;
5354
import java.util.concurrent.CopyOnWriteArrayList;
55+
import java.util.concurrent.locks.Lock;
56+
import java.util.concurrent.locks.ReentrantLock;
5457
import java.util.function.Function;
5558
import java.util.jar.Attributes;
5659
import java.util.jar.Attributes.Name;
@@ -171,6 +174,9 @@ public final class WebappClassLoader extends GlassfishUrlClassLoader
171174
/** Associated directory context giving access to the resources in this webapp. */
172175
private DirContext jndiResources;
173176

177+
/** Maps package name to the corresponding lock object. */
178+
private final Map<String, Lock> packageLocks = new ConcurrentHashMap<>();
179+
174180
/**
175181
* Should this class loader delegate to the parent class loader
176182
* <strong>before</strong> searching its own repositories (i.e. the
@@ -1147,6 +1153,8 @@ public void close() throws IOException {
11471153
LOG.log(WARNING, "Parent close method failed.", e);
11481154
}
11491155

1156+
packageLocks.clear();
1157+
11501158
notFoundResources.clear();
11511159
resourceEntryCache.clear();
11521160
pathTimestamps.clear();
@@ -1244,18 +1252,23 @@ private ResourceEntry findClassInternal(String name) throws ClassNotFoundExcepti
12441252
// Looking up the package
12451253
final int pos = name.lastIndexOf('.');
12461254
final String packageName = pos == -1 ? null : name.substring(0, pos);
1247-
final Package pkg;
1255+
Package pkg;
12481256
if (packageName == null) {
12491257
pkg = null;
12501258
} else {
12511259
pkg = getDefinedPackage(packageName);
12521260

12531261
// Define the package (if null)
12541262
if (pkg == null) {
1255-
if (entry.manifest == null) {
1256-
definePackage(packageName, null, null, null, null, null, null, null);
1257-
} else {
1258-
definePackage(packageName, entry.manifest, entry.codeBase);
1263+
Lock packageLock = getPackageDefinigLock(packageName);
1264+
packageLock.lock();
1265+
try {
1266+
pkg = getDefinedPackage(packageName);
1267+
if (pkg == null) {
1268+
definePackage(packageName, entry);
1269+
}
1270+
} finally {
1271+
packageLock.unlock();
12591272
}
12601273
}
12611274
}
@@ -1279,6 +1292,30 @@ private ResourceEntry findClassInternal(String name) throws ClassNotFoundExcepti
12791292
}
12801293
}
12811294

1295+
/**
1296+
* Defines a Package of the given name.
1297+
*
1298+
* @param packageName the name of the to-be-defined package
1299+
* @param resourceEntry the resource entry
1300+
*/
1301+
private void definePackage(String packageName, ResourceEntry resourceEntry) {
1302+
if (resourceEntry.manifest == null) {
1303+
definePackage(packageName, null, null, null, null, null, null, null);
1304+
} else {
1305+
definePackage(packageName, resourceEntry.manifest, resourceEntry.codeBase);
1306+
}
1307+
}
1308+
1309+
/**
1310+
* Returns the lock object for package defining operations.
1311+
*
1312+
* @param packageName the name of the to-be-defined package
1313+
* @return the lock for package defining operations
1314+
*/
1315+
private Lock getPackageDefinigLock(String packageName) {
1316+
return packageLocks.computeIfAbsent(packageName, key -> new ReentrantLock());
1317+
}
1318+
12821319

12831320
/**
12841321
* Attempts to find the specified resource in local repositories.

0 commit comments

Comments
 (0)