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.logging.log4j.core.helpers;
18  
19  import org.apache.logging.log4j.Logger;
20  import org.apache.logging.log4j.status.StatusLogger;
21  
22  import java.io.InputStream;
23  import java.io.InterruptedIOException;
24  import java.lang.reflect.InvocationTargetException;
25  import java.net.URL;
26  
27  /**
28   * Load resources (or images) from various sources.
29   */
30  public final class Loader {
31  
32      private static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
33  
34      private static boolean ignoreTCL = false;
35  
36      private static final Logger LOGGER = StatusLogger.getLogger();
37  
38      static {
39          String ignoreTCLProp = OptionConverter.getSystemProperty("log4j.ignoreTCL", null);
40          if (ignoreTCLProp != null) {
41              ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true);
42          }
43      }
44  
45      private Loader() {
46      }
47  
48      /**
49       * This method will search for <code>resource</code> in different
50       * places. The search order is as follows:
51       * <p/>
52       * <ol>
53       * <p/>
54       * <p><li>Search for <code>resource</code> using the thread context
55       * class loader under Java2. If that fails, search for
56       * <code>resource</code> using the class loader that loaded this
57       * class (<code>Loader</code>). Under JDK 1.1, only the the class
58       * loader that loaded this class (<code>Loader</code>) is used.
59       * <p/>
60       * <p><li>Try one last time with
61       * <code>ClassLoader.getSystemResource(resource)</code>, that is is
62       * using the system class loader in JDK 1.2 and virtual machine's
63       * built-in class loader in JDK 1.1.
64       * <p/>
65       * </ol>
66       * @param resource The resource to load.
67       * @param defaultLoader The default ClassLoader.
68       * @return A URL to the resource.
69       */
70      public static URL getResource(String resource, ClassLoader defaultLoader) {
71          try {
72              ClassLoader classLoader = getTCL();
73              if (classLoader != null) {
74                  LOGGER.trace("Trying to find [" + resource + "] using context classloader "
75                          + classLoader + '.');
76                  URL url = classLoader.getResource(resource);
77                  if (url != null) {
78                      return url;
79                  }
80              }
81  
82              // We could not find resource. Let us now try with the classloader that loaded this class.
83              classLoader = Loader.class.getClassLoader();
84              if (classLoader != null) {
85                  LOGGER.trace("Trying to find [" + resource + "] using " + classLoader + " class loader.");
86                  URL url = classLoader.getResource(resource);
87                  if (url != null) {
88                      return url;
89                  }
90              }
91              // We could not find resource. Finally try with the default ClassLoader.
92              if (defaultLoader != null) {
93                  LOGGER.trace("Trying to find [" + resource + "] using " + defaultLoader + " class loader.");
94                  URL url = defaultLoader.getResource(resource);
95                  if (url != null) {
96                      return url;
97                  }
98              }
99          } 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 }