View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.discovery.resource;
18  
19  import java.util.Vector;
20  
21  import org.apache.commons.discovery.jdk.JDKHooks;
22  
23  
24  /***
25   * There are many different contexts in which
26   * loaders can be used.  This provides a holder
27   * for a set of class loaders, so that they
28   * don't have to be build back up everytime...
29   *
30   * @author Richard A. Sitze
31   * @author Craig R. McClanahan
32   * @author Costin Manolache
33   */
34  public class ClassLoaders
35  {
36      protected Vector classLoaders = new Vector();
37      
38      /*** Construct a new class loader set
39       */
40      public ClassLoaders() {
41      }
42      
43      public int size() {
44          return classLoaders.size();
45      }
46      
47      public ClassLoader get(int idx) {
48          return (ClassLoader)classLoaders.elementAt(idx);
49      }
50  
51      /***
52       * Specify a new class loader to be used in searching.
53       * The order of loaders determines the order of the result.
54       * It is recommended to add the most specific loaders first.
55       */
56      public void put(ClassLoader classLoader) {
57          if (classLoader != null) {
58              classLoaders.addElement(classLoader);
59          }
60      }
61      
62  
63      /***
64       * Specify a new class loader to be used in searching.
65       * The order of loaders determines the order of the result.
66       * It is recommended to add the most specific loaders first.
67       * 
68       * @param prune if true, verify that the class loader is
69       *              not an Ancestor (@see isAncestor) before
70       *              adding it to our list.
71       */
72      public void put(ClassLoader classLoader, boolean prune) {
73          if (classLoader != null  &&  !(prune && isAncestor(classLoader))) {
74              classLoaders.addElement(classLoader);
75          }
76      }
77      
78      
79      /***
80       * Check to see if <code>classLoader</code> is an
81       * ancestor of any contained class loader.
82       * 
83       * This can be used to eliminate redundant class loaders
84       * IF all class loaders defer to parent class loaders
85       * before resolving a class.
86       * 
87       * It may be that this is not always true.  Therefore,
88       * this check is not done internally to eliminate
89       * redundant class loaders, but left to the discretion
90       * of the user.
91       */
92      public boolean isAncestor(final ClassLoader classLoader) {
93          /* bootstrap classloader, at root of all trees! */
94          if (classLoader == null)
95              return true;
96  
97          for (int idx = 0; idx < size(); idx++) {
98              for(ClassLoader walker = get(idx);
99                  walker != null;
100                 walker = walker.getParent())
101             {
102                 if (walker == classLoader) {
103                     return true;
104                 }
105             }
106         }
107         return false;
108     }
109 
110 
111     /***
112      * Utility method.  Returns a preloaded ClassLoaders instance
113      * containing the following class loaders, in order:
114      * 
115      * <ul>
116      *   <li>spi.getClassLoader</li>
117      *   <li>seeker.getClassLoader</li>
118      *   <li>System Class Loader</li>
119      * </ul>
120      * 
121      * Note that the thread context class loader is NOT present.
122      * This is a reasonable set of loaders to try if the resource to be found
123      * should be restricted to a libraries containing the SPI and Factory.
124      * 
125      * @param spi WHAT is being looked for (an implementation of this class,
126      *            a default property file related to this class).
127      * @param factory WHO is performing the lookup.
128      * @param prune Determines if ancestors are allowed to be loaded or not.
129      */    
130     public static ClassLoaders getLibLoaders(Class spi, Class factory, boolean prune) {
131         ClassLoaders loaders = new ClassLoaders();
132         
133         if (spi != null) loaders.put(spi.getClassLoader());
134         if (factory != null) loaders.put(factory.getClassLoader(), prune);
135         loaders.put(JDKHooks.getJDKHooks().getSystemClassLoader(), prune);
136         
137         return loaders;
138     }
139     
140     /***
141      * Utility method.  Returns a preloaded ClassLoaders instance
142      * containing the following class loaders, in order:
143      * 
144      * <ul>
145      *   <li>Thread Context Class Loader</li>
146      *   <li>spi.getClassLoader</li>
147      *   <li>seeker.getClassLoader</li>
148      *   <li>System Class Loader</li>
149      * </ul>
150      * 
151      * Note that the thread context class loader IS  present.
152      * This is a reasonable set of loaders to try if the resource to be found
153      * may be provided by an application.
154      * 
155      * @param spi WHAT is being looked for (an implementation of this class,
156      *            a default property file related to this class).
157      * @param factory WHO is performing the lookup (factory).
158      * @param prune Determines if ancestors are allowed to be loaded or not.
159      */    
160     public static ClassLoaders getAppLoaders(Class spi, Class factory, boolean prune) {
161         ClassLoaders loaders = new ClassLoaders();
162 
163         loaders.put(JDKHooks.getJDKHooks().getThreadContextClassLoader());
164         if (spi != null) loaders.put(spi.getClassLoader(), prune);
165         if (factory != null) loaders.put(factory.getClassLoader(), prune);
166         loaders.put(JDKHooks.getJDKHooks().getSystemClassLoader(), prune);
167         
168         return loaders;
169     }
170 }