5858import hudson .security .ACLContext ;
5959import hudson .security .Permission ;
6060import hudson .security .PermissionScope ;
61+ import hudson .util .AbstractCachingClassLoader ;
6162import hudson .util .CyclicGraphDetector ;
6263import hudson .util .CyclicGraphDetector .CycleDetectedException ;
6364import hudson .util .FormValidation ;
106107import java .util .Locale ;
107108import java .util .Map ;
108109import java .util .Objects ;
109- import java .util .Optional ;
110110import java .util .ServiceLoader ;
111111import java .util .Set ;
112112import java .util .TreeMap ;
113113import java .util .UUID ;
114114import java .util .concurrent .ConcurrentHashMap ;
115- import java .util .concurrent .ConcurrentMap ;
116115import java .util .concurrent .CopyOnWriteArrayList ;
117116import java .util .concurrent .Future ;
118117import java .util .function .Supplier ;
@@ -2396,49 +2395,60 @@ public <T> T of(String key, Class<T> type, Supplier<T> func) {
23962395 /**
23972396 * {@link ClassLoader} that can see all plugins.
23982397 */
2399- public static final class UberClassLoader extends ClassLoader {
2398+ public static final class UberClassLoader extends AbstractCachingClassLoader {
2399+ // 100k entries is a reasonable default. ~20MB of memory.
2400+ private static final int MISSED_CLASS_CACHE_SIZE = Integer .parseInt (
2401+ System .getProperty (UberClassLoader .class .getName () + ".MISSED_CLASS_CACHE_SIZE" , "100000" ));
2402+
24002403 private final List <PluginWrapper > activePlugins ;
24012404
24022405 /** Cache of loaded, or known to be unloadable, classes. */
2403- private final ConcurrentMap <String , Optional <Class <?>>> loaded = new ConcurrentHashMap <>();
2404-
2405- static {
2406- registerAsParallelCapable ();
2407- }
2408-
24092406 public UberClassLoader (List <PluginWrapper > activePlugins ) {
2410- super ("UberClassLoader" , PluginManager .class .getClassLoader ());
2407+ super ("UberClassLoader" , PluginManager .class .getClassLoader (), MISSED_CLASS_CACHE_SIZE );
24112408 this .activePlugins = activePlugins ;
24122409 }
24132410
24142411 @ Override
2415- protected Class <?> findClass (String name ) throws ClassNotFoundException {
2416- if (name .startsWith ("SimpleTemplateScript" )) { // cf. groovy.text.SimpleTemplateEngine
2417- throw new ClassNotFoundException ("ignoring " + name );
2412+ protected boolean isClassKnownAsMissed (String name ) {
2413+ if (name .startsWith ("SimpleTemplateScript" ) || // cf. groovy.text.SimpleTemplateEngine
2414+ name .startsWith ("groovy.tmp." )) {
2415+ return true ;
24182416 }
2419- return loaded .computeIfAbsent (name , this ::computeValue ).orElseThrow (() -> new ClassNotFoundException (name ));
2417+
2418+ return super .isClassKnownAsMissed (name );
24202419 }
24212420
2422- private Optional <Class <?>> computeValue (String name ) {
2421+ @ Override
2422+ protected Class <?> doLoadClass (String name ) {
2423+ try {
2424+ return getParent ().loadClass (name );
2425+ } catch (ClassNotFoundException e ) {
2426+ // Not found. Try the next class loader.
2427+ }
2428+
24232429 for (PluginWrapper p : activePlugins ) {
24242430 try {
24252431 if (FAST_LOOKUP ) {
2426- return Optional . of ( ClassLoaderReflectionToolkit .loadClass (p .classLoader , name ) );
2432+ return ClassLoaderReflectionToolkit .loadClass (p .classLoader , name );
24272433 } else {
2428- return Optional . of ( p .classLoader .loadClass (name ) );
2434+ return p .classLoader .loadClass (name );
24292435 }
24302436 } catch (ClassNotFoundException e ) {
24312437 // Not found. Try the next class loader.
24322438 }
24332439 }
24342440 // Not found in any of the class loaders. Delegate.
2435- return Optional . empty () ;
2441+ return null ;
24362442 }
24372443
24382444 @ Override
2439- protected URL findResource (String name ) {
2445+ public URL getResource (String name ) {
2446+ URL url = getParent ().getResource (name );
2447+ if (url != null ) {
2448+ return url ;
2449+ }
2450+
24402451 for (PluginWrapper p : activePlugins ) {
2441- URL url ;
24422452 if (FAST_LOOKUP ) {
24432453 url = ClassLoaderReflectionToolkit ._findResource (p .classLoader , name );
24442454 } else {
@@ -2452,8 +2462,10 @@ protected URL findResource(String name) {
24522462 }
24532463
24542464 @ Override
2455- protected Enumeration <URL > findResources (String name ) throws IOException {
2465+ public Enumeration <URL > getResources (String name ) throws IOException {
24562466 List <URL > resources = new ArrayList <>();
2467+ resources .addAll (Collections .list (getParent ().getResources (name )));
2468+
24572469 for (PluginWrapper p : activePlugins ) {
24582470 if (FAST_LOOKUP ) {
24592471 resources .addAll (Collections .list (ClassLoaderReflectionToolkit ._findResources (p .classLoader , name )));
@@ -2464,10 +2476,6 @@ protected Enumeration<URL> findResources(String name) throws IOException {
24642476 return Collections .enumeration (resources );
24652477 }
24662478
2467- void clearCacheMisses () {
2468- loaded .values ().removeIf (Optional ::isEmpty );
2469- }
2470-
24712479 @ Override
24722480 public String toString () {
24732481 // only for debugging purpose
0 commit comments