001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.discovery.resource;
018
019 import java.util.Vector;
020
021 import org.apache.commons.discovery.jdk.JDKHooks;
022
023
024 /**
025 * There are many different contexts in which
026 * loaders can be used. This provides a holder
027 * for a set of class loaders, so that they
028 * don't have to be build back up everytime...
029 *
030 * @author Richard A. Sitze
031 * @author Craig R. McClanahan
032 * @author Costin Manolache
033 */
034 public class ClassLoaders
035 {
036 protected Vector classLoaders = new Vector();
037
038 /** Construct a new class loader set
039 */
040 public ClassLoaders() {
041 }
042
043 public int size() {
044 return classLoaders.size();
045 }
046
047 public ClassLoader get(int idx) {
048 return (ClassLoader)classLoaders.elementAt(idx);
049 }
050
051 /**
052 * Specify a new class loader to be used in searching.
053 * The order of loaders determines the order of the result.
054 * It is recommended to add the most specific loaders first.
055 */
056 public void put(ClassLoader classLoader) {
057 if (classLoader != null) {
058 classLoaders.addElement(classLoader);
059 }
060 }
061
062
063 /**
064 * Specify a new class loader to be used in searching.
065 * The order of loaders determines the order of the result.
066 * It is recommended to add the most specific loaders first.
067 *
068 * @param prune if true, verify that the class loader is
069 * not an Ancestor (@see isAncestor) before
070 * adding it to our list.
071 */
072 public void put(ClassLoader classLoader, boolean prune) {
073 if (classLoader != null && !(prune && isAncestor(classLoader))) {
074 classLoaders.addElement(classLoader);
075 }
076 }
077
078
079 /**
080 * Check to see if <code>classLoader</code> is an
081 * ancestor of any contained class loader.
082 *
083 * This can be used to eliminate redundant class loaders
084 * IF all class loaders defer to parent class loaders
085 * before resolving a class.
086 *
087 * It may be that this is not always true. Therefore,
088 * this check is not done internally to eliminate
089 * redundant class loaders, but left to the discretion
090 * of the user.
091 */
092 public boolean isAncestor(final ClassLoader classLoader) {
093 /* bootstrap classloader, at root of all trees! */
094 if (classLoader == null)
095 return true;
096
097 for (int idx = 0; idx < size(); idx++) {
098 for(ClassLoader walker = get(idx);
099 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 }