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.logging.log4j.core.helpers; 018 019 import org.apache.logging.log4j.Logger; 020 import org.apache.logging.log4j.status.StatusLogger; 021 022 import java.io.InputStream; 023 import java.io.InterruptedIOException; 024 import java.lang.reflect.InvocationTargetException; 025 import java.net.URL; 026 027 /** 028 * Load resources (or images) from various sources. 029 */ 030 public final class Loader { 031 032 private static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous."; 033 034 private static boolean ignoreTCL = false; 035 036 private static final Logger LOGGER = StatusLogger.getLogger(); 037 038 static { 039 String ignoreTCLProp = OptionConverter.getSystemProperty("log4j.ignoreTCL", null); 040 if (ignoreTCLProp != null) { 041 ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true); 042 } 043 } 044 045 private Loader() { 046 } 047 048 /** 049 * This method will search for <code>resource</code> in different 050 * places. The search order is as follows: 051 * <p/> 052 * <ol> 053 * <p/> 054 * <p><li>Search for <code>resource</code> using the thread context 055 * class loader under Java2. If that fails, search for 056 * <code>resource</code> using the class loader that loaded this 057 * class (<code>Loader</code>). Under JDK 1.1, only the the class 058 * loader that loaded this class (<code>Loader</code>) is used. 059 * <p/> 060 * <p><li>Try one last time with 061 * <code>ClassLoader.getSystemResource(resource)</code>, that is is 062 * using the system class loader in JDK 1.2 and virtual machine's 063 * built-in class loader in JDK 1.1. 064 * <p/> 065 * </ol> 066 * @param resource The resource to load. 067 * @param defaultLoader The default ClassLoader. 068 * @return A URL to the resource. 069 */ 070 public static URL getResource(String resource, ClassLoader defaultLoader) { 071 try { 072 ClassLoader classLoader = getTCL(); 073 if (classLoader != null) { 074 LOGGER.trace("Trying to find [" + resource + "] using context classloader " 075 + classLoader + '.'); 076 URL url = classLoader.getResource(resource); 077 if (url != null) { 078 return url; 079 } 080 } 081 082 // We could not find resource. Let us now try with the classloader that loaded this class. 083 classLoader = Loader.class.getClassLoader(); 084 if (classLoader != null) { 085 LOGGER.trace("Trying to find [" + resource + "] using " + classLoader + " class loader."); 086 URL url = classLoader.getResource(resource); 087 if (url != null) { 088 return url; 089 } 090 } 091 // We could not find resource. Finally try with the default ClassLoader. 092 if (defaultLoader != null) { 093 LOGGER.trace("Trying to find [" + resource + "] using " + defaultLoader + " class loader."); 094 URL url = defaultLoader.getResource(resource); 095 if (url != null) { 096 return url; 097 } 098 } 099 } catch (IllegalAccessException t) { 100 LOGGER.warn(TSTR, t); 101 } catch (InvocationTargetException t) { 102 if (t.getTargetException() instanceof InterruptedException 103 || t.getTargetException() instanceof InterruptedIOException) { 104 Thread.currentThread().interrupt(); 105 } 106 LOGGER.warn(TSTR, t); 107 } catch (Throwable t) { 108 // 109 // can't be InterruptedException or InterruptedIOException 110 // since not declared, must be error or RuntimeError. 111 LOGGER.warn(TSTR, t); 112 } 113 114 // Last ditch attempt: get the resource from the class path. It 115 // may be the case that clazz was loaded by the Extentsion class 116 // loader which the parent of the system class loader. Hence the 117 // code below. 118 LOGGER.trace("Trying to find [" + resource + "] using ClassLoader.getSystemResource()."); 119 return ClassLoader.getSystemResource(resource); 120 } 121 122 /** 123 * This method will search for <code>resource</code> in different 124 * places. The search order is as follows: 125 * <p/> 126 * <ol> 127 * <p/> 128 * <p><li>Search for <code>resource</code> using the thread context 129 * class loader under Java2. If that fails, search for 130 * <code>resource</code> using the class loader that loaded this 131 * class (<code>Loader</code>). Under JDK 1.1, only the the class 132 * loader that loaded this class (<code>Loader</code>) is used. 133 * <p/> 134 * <p><li>Try one last time with 135 * <code>ClassLoader.getSystemResource(resource)</code>, that is is 136 * using the system class loader in JDK 1.2 and virtual machine's 137 * built-in class loader in JDK 1.1. 138 * <p/> 139 * </ol> 140 * @param resource The resource to load. 141 * @param defaultLoader The default ClassLoader. 142 * @return An InputStream to read the resouce. 143 */ 144 public static InputStream getResourceAsStream(String resource, ClassLoader defaultLoader) { 145 ClassLoader classLoader; 146 InputStream is; 147 148 try { 149 classLoader = getTCL(); 150 if (classLoader != null) { 151 LOGGER.trace("Trying to find [" + resource + "] using context classloader " + classLoader + '.'); 152 is = classLoader.getResourceAsStream(resource); 153 if (is != null) { 154 return is; 155 } 156 } 157 158 // We could not find resource. Let us now try with the classloader that loaded this class. 159 classLoader = Loader.class.getClassLoader(); 160 if (classLoader != null) { 161 LOGGER.trace("Trying to find [" + resource + "] using " + classLoader + " class loader."); 162 is = classLoader.getResourceAsStream(resource); 163 if (is != null) { 164 return is; 165 } 166 } 167 168 // We could not find resource. Finally try with the default ClassLoader. 169 if (defaultLoader != null) { 170 LOGGER.trace("Trying to find [" + resource + "] using " + defaultLoader + " class loader."); 171 is = defaultLoader.getResourceAsStream(resource); 172 if (is != null) { 173 return is; 174 } 175 } 176 } catch (IllegalAccessException t) { 177 LOGGER.warn(TSTR, t); 178 } catch (InvocationTargetException t) { 179 if (t.getTargetException() instanceof InterruptedException 180 || t.getTargetException() instanceof InterruptedIOException) { 181 Thread.currentThread().interrupt(); 182 } 183 LOGGER.warn(TSTR, t); 184 } catch (Throwable t) { 185 // 186 // can't be InterruptedException or InterruptedIOException 187 // since not declared, must be error or RuntimeError. 188 LOGGER.warn(TSTR, t); 189 } 190 191 // Last ditch attempt: get the resource from the class path. It 192 // may be the case that clazz was loaded by the Extentsion class 193 // loader which the parent of the system class loader. Hence the 194 // code below. 195 LOGGER.trace("Trying to find [" + resource + "] using ClassLoader.getSystemResource()."); 196 return ClassLoader.getSystemResourceAsStream(resource); 197 } 198 199 /** 200 * Load a Class by name. 201 * @param className The class name. 202 * @return The Class. 203 * @throws ClassNotFoundException if the Class could not be found. 204 */ 205 public static Class<?> loadClass(String className) throws ClassNotFoundException { 206 // Just call Class.forName(className) if we are instructed to ignore the TCL. 207 if (ignoreTCL) { 208 return Class.forName(className); 209 } else { 210 try { 211 return getTCL().loadClass(className); 212 } catch (Throwable e) { 213 return Class.forName(className); 214 } 215 } 216 } 217 218 public static ClassLoader getClassLoader(Class<?> class1, Class<?> class2) { 219 220 ClassLoader loader1 = null; 221 try { 222 loader1 = getTCL(); 223 } catch (Exception ex) { 224 LOGGER.warn("Caught exception locating thread ClassLoader {}", ex.getMessage()); 225 } 226 ClassLoader loader2 = class1 == null ? null : class1.getClassLoader(); 227 ClassLoader loader3 = class2 == null ? null : class2.getClass().getClassLoader(); 228 229 if (isChild(loader1, loader2)) { 230 return isChild(loader1, loader3) ? loader1 : loader3; 231 } else { 232 return isChild(loader2, loader3) ? loader2 : loader3; 233 } 234 } 235 236 private static boolean isChild(ClassLoader loader1, ClassLoader loader2) { 237 if (loader1 != null && loader2 != null) { 238 ClassLoader parent = loader1.getParent(); 239 while (parent != null && parent != loader2) { 240 parent = parent.getParent(); 241 } 242 return parent != null; 243 } 244 return loader1 != null; 245 } 246 247 /** 248 * Returns the ClassLoader to use. 249 * @return the ClassLoader. 250 */ 251 public static ClassLoader getClassLoader() { 252 253 return getClassLoader(Loader.class, null); 254 } 255 256 private static ClassLoader getTCL() throws IllegalAccessException, InvocationTargetException { 257 ClassLoader cl; 258 if (System.getSecurityManager() == null) { 259 cl = Thread.currentThread().getContextClassLoader(); 260 } else { 261 cl = java.security.AccessController.doPrivileged( 262 new java.security.PrivilegedAction<ClassLoader>() { 263 public ClassLoader run() { 264 return Thread.currentThread().getContextClassLoader(); 265 } 266 } 267 ); 268 } 269 270 return cl; 271 } 272 }