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 }