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