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  import org.apache.logging.log4j.util.PropertiesUtil;
22  
23  import java.io.InputStream;
24  import java.io.InterruptedIOException;
25  import java.lang.reflect.InvocationTargetException;
26  import java.net.URL;
27  
28  /**
29   * Load resources (or images) from various sources.
30   */
31  public final class Loader {
32  
33      private static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
34  
35      private static boolean ignoreTCL = false;
36  
37      private static final Logger LOGGER = StatusLogger.getLogger();
38  
39      static {
40          final String ignoreTCLProp = PropertiesUtil.getProperties().getStringProperty("log4j.ignoreTCL", null);
41          if (ignoreTCLProp != null) {
42              ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true);
43          }
44      }
45  
46      private Loader() {
47      }
48  
49      /**
50       * This method will search for <code>resource</code> in different
51       * places. The search order is as follows:
52       * <p/>
53       * <ol>
54       * <p/>
55       * <p><li>Search for <code>resource</code> using the thread context
56       * class loader under Java2. If that fails, search for
57       * <code>resource</code> using the class loader that loaded this
58       * class (<code>Loader</code>). Under JDK 1.1, only the the class
59       * loader that loaded this class (<code>Loader</code>) is used.
60       * <p/>
61       * <p><li>Try one last time with
62       * <code>ClassLoader.getSystemResource(resource)</code>, that is is
63       * using the system class loader in JDK 1.2 and virtual machine's
64       * built-in class loader in JDK 1.1.
65       * <p/>
66       * </ol>
67       * @param resource The resource to load.
68       * @param defaultLoader The default ClassLoader.
69       * @return A URL to the resource.
70       */
71      public static URL getResource(final String resource, final ClassLoader defaultLoader) {
72          try {
73              ClassLoader classLoader = getTCL();
74              if (classLoader != null) {
75                  LOGGER.trace("Trying to find [" + resource + "] using context classloader "
76                          + classLoader + '.');
77                  final URL url = classLoader.getResource(resource);
78                  if (url != null) {
79                      return url;
80                  }
81              }
82  
83              // We could not find resource. Let us now try with the classloader that loaded this class.
84              classLoader = Loader.class.getClassLoader();
85              if (classLoader != null) {
86                  LOGGER.trace("Trying to find [" + resource + "] using " + classLoader + " class loader.");
87                  final URL url = classLoader.getResource(resource);
88                  if (url != null) {
89                      return url;
90                  }
91              }
92              // We could not find resource. Finally try with the default ClassLoader.
93              if (defaultLoader != null) {
94                  LOGGER.trace("Trying to find [" + resource + "] using " + defaultLoader + " class loader.");
95                  final URL url = defaultLoader.getResource(resource);
96                  if (url != null) {
97                      return url;
98                  }
99              }
100         } catch (final IllegalAccessException t) {
101             LOGGER.warn(TSTR, t);
102         } catch (final InvocationTargetException t) {
103             if (t.getTargetException() instanceof InterruptedException
104                 || t.getTargetException() instanceof InterruptedIOException) {
105                 Thread.currentThread().interrupt();
106             }
107             LOGGER.warn(TSTR, t);
108         } catch (final Throwable t) {
109             //
110             //  can't be InterruptedException or InterruptedIOException
111             //    since not declared, must be error or RuntimeError.
112             LOGGER.warn(TSTR, t);
113         }
114 
115         // Last ditch attempt: get the resource from the class path. It
116         // may be the case that clazz was loaded by the Extension class
117         // loader which the parent of the system class loader. Hence the
118         // code below.
119         LOGGER.trace("Trying to find [" + resource + "] using ClassLoader.getSystemResource().");
120         return ClassLoader.getSystemResource(resource);
121     }
122 
123     /**
124      * This method will search for <code>resource</code> in different
125      * places. The search order is as follows:
126      * <p/>
127      * <ol>
128      * <p/>
129      * <p><li>Search for <code>resource</code> using the thread context
130      * class loader under Java2. If that fails, search for
131      * <code>resource</code> using the class loader that loaded this
132      * class (<code>Loader</code>). Under JDK 1.1, only the the class
133      * loader that loaded this class (<code>Loader</code>) is used.
134      * <p/>
135      * <p><li>Try one last time with
136      * <code>ClassLoader.getSystemResource(resource)</code>, that is is
137      * using the system class loader in JDK 1.2 and virtual machine's
138      * built-in class loader in JDK 1.1.
139      * <p/>
140      * </ol>
141      * @param resource The resource to load.
142      * @param defaultLoader The default ClassLoader.
143      * @return An InputStream to read the resouce.
144      */
145     public static InputStream getResourceAsStream(final String resource, final ClassLoader defaultLoader) {
146         ClassLoader classLoader;
147         InputStream is;
148 
149         try {
150             classLoader = getTCL();
151             if (classLoader != null) {
152                 LOGGER.trace("Trying to find [" + resource + "] using context classloader " + classLoader + '.');
153                 is = classLoader.getResourceAsStream(resource);
154                 if (is != null) {
155                     return is;
156                 }
157             }
158 
159             // We could not find resource. Let us now try with the classloader that loaded this class.
160             classLoader = Loader.class.getClassLoader();
161             if (classLoader != null) {
162                 LOGGER.trace("Trying to find [" + resource + "] using " + classLoader + " class loader.");
163                 is = classLoader.getResourceAsStream(resource);
164                 if (is != null) {
165                     return is;
166                 }
167             }
168 
169             // We could not find resource. Finally try with the default ClassLoader.
170             if (defaultLoader != null) {
171                 LOGGER.trace("Trying to find [" + resource + "] using " + defaultLoader + " class loader.");
172                 is = defaultLoader.getResourceAsStream(resource);
173                 if (is != null) {
174                     return is;
175                 }
176             }
177         } catch (final IllegalAccessException t) {
178             LOGGER.warn(TSTR, t);
179         } catch (final InvocationTargetException t) {
180             if (t.getTargetException() instanceof InterruptedException
181                 || t.getTargetException() instanceof InterruptedIOException) {
182                 Thread.currentThread().interrupt();
183             }
184             LOGGER.warn(TSTR, t);
185         } catch (final Throwable t) {
186             //
187             //  can't be InterruptedException or InterruptedIOException
188             //    since not declared, must be error or RuntimeError.
189             LOGGER.warn(TSTR, t);
190         }
191 
192         // Last ditch attempt: get the resource from the class path. It
193         // may be the case that clazz was loaded by the Extension class
194         // loader which the parent of the system class loader. Hence the
195         // code below.
196         LOGGER.trace("Trying to find [" + resource + "] using ClassLoader.getSystemResource().");
197         return ClassLoader.getSystemResourceAsStream(resource);
198     }
199 
200     /**
201      * Load a Class by name.
202      * @param className The class name.
203      * @return The Class.
204      * @throws ClassNotFoundException if the Class could not be found.
205      */
206     public static Class<?> loadClass(final String className) throws ClassNotFoundException {
207         // Just call Class.forName(className) if we are instructed to ignore the TCL.
208         if (ignoreTCL) {
209             return Class.forName(className);
210         } else {
211             try {
212                 return getTCL().loadClass(className);
213             } catch (final Throwable e) {
214                 return Class.forName(className);
215             }
216         }
217     }
218 
219     public static ClassLoader getClassLoader(final Class<?> class1, final Class<?> class2) {
220 
221         ClassLoader loader1 = null;
222         try {
223             loader1 = getTCL();
224         } catch (final Exception ex) {
225             LOGGER.warn("Caught exception locating thread ClassLoader {}", ex.getMessage());
226         }
227         final ClassLoader loader2 = class1 == null ? null : class1.getClassLoader();
228         final ClassLoader loader3 = class2 == null ? null : class2.getClass().getClassLoader();
229 
230         if (isChild(loader1, loader2)) {
231             return isChild(loader1, loader3) ? loader1 : loader3;
232         } else {
233             return isChild(loader2, loader3) ? loader2 : loader3;
234         }
235     }
236 
237     private static boolean isChild(final ClassLoader loader1, final ClassLoader loader2) {
238         if (loader1 != null && loader2 != null) {
239             ClassLoader parent = loader1.getParent();
240             while (parent != null && parent != loader2) {
241                 parent = parent.getParent();
242             }
243             return parent != null;
244         }
245         return loader1 != null;
246     }
247 
248     /**
249      * Returns the ClassLoader to use.
250      * @return the ClassLoader.
251      */
252     public static ClassLoader getClassLoader() {
253 
254         return getClassLoader(Loader.class, null);
255     }
256 
257     private static ClassLoader getTCL() throws IllegalAccessException, InvocationTargetException {
258         ClassLoader cl;
259         if (System.getSecurityManager() == null) {
260             cl = Thread.currentThread().getContextClassLoader();
261         } else {
262             cl = java.security.AccessController.doPrivileged(
263                 new java.security.PrivilegedAction<ClassLoader>() {
264                     public ClassLoader run() {
265                         return Thread.currentThread().getContextClassLoader();
266                     }
267                 }
268             );
269         }
270 
271         return cl;
272     }
273 }