3131import hudson .Plugin .DummyImpl ;
3232import hudson .PluginWrapper .Dependency ;
3333import hudson .model .Hudson ;
34+ import hudson .util .AbstractCachingClassLoader ;
35+ import hudson .util .CompoundEnumeration ;
3436import hudson .util .CyclicGraphDetector ;
3537import hudson .util .CyclicGraphDetector .CycleDetectedException ;
3638import hudson .util .IOUtils ;
5355import java .util .List ;
5456import java .util .Set ;
5557import java .util .UUID ;
58+ import java .util .concurrent .atomic .AtomicReference ;
5659import java .util .jar .Attributes ;
5760import java .util .jar .JarFile ;
5861import java .util .jar .Manifest ;
@@ -559,7 +562,7 @@ private static void unzipExceptClasses(File archive, File destDir, Project prj)
559562 /**
560563 * Used to load classes from dependency plugins.
561564 */
562- static final class DependencyClassLoader extends ClassLoader {
565+ static final class DependencyClassLoader extends AbstractCachingClassLoader {
563566 /**
564567 * This classloader is created for this plugin. Useful during debugging.
565568 */
@@ -572,30 +575,26 @@ static final class DependencyClassLoader extends ClassLoader {
572575 /**
573576 * Topologically sorted list of transitive dependencies. Lazily initialized via double-checked locking.
574577 */
575- private volatile List <PluginWrapper > transitiveDependencies ;
576-
577- static {
578- registerAsParallelCapable ();
579- }
578+ private final AtomicReference <List <PluginWrapper >> transitiveDependencies = new AtomicReference <>();
580579
581580 DependencyClassLoader (ClassLoader parent , File archive , List <Dependency > dependencies , PluginManager pluginManager ) {
582- super ("dependency ClassLoader for " + archive .getPath (), parent );
581+ super ("dependency ClassLoader for " + archive .getPath (), parent , 10 );
583582 this ._for = archive ;
584583 this .dependencies = List .copyOf (dependencies );
585584 this .pluginManager = pluginManager ;
586585 }
587586
588587 private void updateTransitiveDependencies () {
589588 // This will be recalculated at the next time.
590- transitiveDependencies = null ;
589+ transitiveDependencies . set ( null ) ;
591590 }
592591
593592 private List <PluginWrapper > getTransitiveDependencies () {
594- List < PluginWrapper > localTransitiveDependencies = transitiveDependencies ;
595- if (localTransitiveDependencies = = null ) {
596- synchronized ( this ) {
597- localTransitiveDependencies = transitiveDependencies ;
598- if ( localTransitiveDependencies == null ) {
593+ return transitiveDependencies . accumulateAndGet ( null , ( old , ignored ) -> {
594+ if (old ! = null ) {
595+ return old ;
596+ }
597+
599598 CyclicGraphDetector <PluginWrapper > cgd = new CyclicGraphDetector <>() {
600599 @ Override
601600 protected List <PluginWrapper > getEdges (PluginWrapper pw ) {
@@ -619,15 +618,18 @@ protected List<PluginWrapper> getEdges(PluginWrapper pw) {
619618 throw new AssertionError (e ); // such error should have been reported earlier
620619 }
621620
622- transitiveDependencies = localTransitiveDependencies = cgd .getSorted ();
623- }
624- }
625- }
626- return localTransitiveDependencies ;
621+ return cgd .getSorted ();
622+ });
627623 }
628624
629625 @ Override
630- protected Class <?> findClass (String name ) throws ClassNotFoundException {
626+ public Class <?> doLoadClass (String name ) {
627+ try {
628+ return getParent ().loadClass (name );
629+ } catch (ClassNotFoundException ignored ) {
630+ // OK, try next
631+ }
632+
631633 if (PluginManager .FAST_LOOKUP ) {
632634 for (PluginWrapper pw : getTransitiveDependencies ()) {
633635 try {
@@ -649,49 +651,65 @@ protected Class<?> findClass(String name) throws ClassNotFoundException {
649651 }
650652 }
651653
652- throw new ClassNotFoundException ( name ) ;
654+ return null ;
653655 }
654656
655657 @ Override
656658 @ SuppressFBWarnings (value = "DMI_COLLECTION_OF_URLS" ,
657659 justification = "Should not produce network overheads since the URL is local. JENKINS-53793 is a follow-up" )
658- protected Enumeration <URL > findResources (String name ) throws IOException {
659- HashSet <URL > result = new HashSet <>();
660+ public Enumeration <URL > getResources (String name ) throws IOException {
661+ ArrayList <Enumeration <? extends URL >> enumerations = new ArrayList <>();
662+
663+ Enumeration <URL > result ;
660664
661665 if (PluginManager .FAST_LOOKUP ) {
662- for (PluginWrapper pw : getTransitiveDependencies ()) {
663- Enumeration <URL > urls = ClassLoaderReflectionToolkit ._findResources (pw .classLoader , name );
664- while (urls != null && urls .hasMoreElements ())
665- result .add (urls .nextElement ());
666- }
666+ enumerations .add (getParent ().getResources (name ));
667+
668+ for (PluginWrapper pw : getTransitiveDependencies ()) {
669+ enumerations .add (ClassLoaderReflectionToolkit ._findResources (pw .classLoader , name ));
670+ }
671+ result = new CompoundEnumeration <>(enumerations );
667672 } else {
668673 for (Dependency dep : dependencies ) {
669674 PluginWrapper p = pluginManager .getPlugin (dep .shortName );
670675 if (p != null ) {
671- Enumeration <URL > urls = p .classLoader .getResources (name );
672- while (urls != null && urls .hasMoreElements ())
673- result .add (urls .nextElement ());
676+ enumerations .add (p .classLoader .getResources (name ));
674677 }
675678 }
679+ result = new CompoundEnumeration <>(enumerations );
680+ Set <URL > resultSet = new HashSet <>();
681+ while (result .hasMoreElements ()) {
682+ resultSet .add (result .nextElement ());
683+ }
684+
685+ result = Collections .enumeration (resultSet );
676686 }
677687
678- return Collections . enumeration ( result ) ;
688+ return result ;
679689 }
680690
681691 @ Override
682- protected URL findResource (String name ) {
692+ public URL getResource (String name ) {
693+ URL url = getParent ().getResource (name );
694+ if (url != null ) {
695+ return url ;
696+ }
697+
683698 if (PluginManager .FAST_LOOKUP ) {
684- for (PluginWrapper pw : getTransitiveDependencies ()) {
685- URL url = ClassLoaderReflectionToolkit ._findResource (pw .classLoader , name );
686- if (url != null ) return url ;
699+ for (PluginWrapper pw : getTransitiveDependencies ()) {
700+ url = ClassLoaderReflectionToolkit ._findResource (pw .classLoader , name );
701+ if (url != null ) {
702+ return url ;
687703 }
704+ }
688705 } else {
689706 for (Dependency dep : dependencies ) {
690707 PluginWrapper p = pluginManager .getPlugin (dep .shortName );
691708 if (p != null ) {
692- URL url = p .classLoader .getResource (name );
693- if (url != null )
709+ url = p .classLoader .getResource (name );
710+ if (url != null ) {
694711 return url ;
712+ }
695713 }
696714 }
697715 }
0 commit comments