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  
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          String ignoreTCLProp = OptionConverter.getSystemProperty("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(String resource, ClassLoader defaultLoader) {
72          ClassLoader classLoader;
73          URL url;
74  
75          try {
76              classLoader = getTCL();
77              if (classLoader != null) {
78                  LOGGER.trace("Trying to find [" + resource + "] using context classloader "
79                          + classLoader + ".");
80                  url = classLoader.getResource(resource);
81                  if (url != null) {
82                      return url;
83                  }
84              }
85  
86              // We could not find resource. Let us now try with the classloader that loaded this class.
87              classLoader = Loader.class.getClassLoader();
88              if (classLoader != null) {
89                  LOGGER.trace("Trying to find [" + resource + "] using " + classLoader + " class loader.");
90                  url = classLoader.getResource(resource);
91                  if (url != null) {
92                      return url;
93                  }
94              }
95              // We could not find resource. Finally try with the default ClassLoader.
96              if (defaultLoader != null) {
97                  LOGGER.trace("Trying to find [" + resource + "] using " + defaultLoader + " class loader.");
98                  url = defaultLoader.getResource(resource);
99                  if (url != null) {
100                     return url;
101                 }
102             }
103         } catch (IllegalAccessException t) {
104             LOGGER.warn(TSTR, t);
105         } catch (InvocationTargetException t) {
106             if (t.getTargetException() instanceof InterruptedException
107                 || t.getTargetException() instanceof InterruptedIOException) {
108                 Thread.currentThread().interrupt();
109             }
110             LOGGER.warn(TSTR, t);
111         } catch (Throwable t) {
112             //
113             //  can't be InterruptedException or InterruptedIOException
114             //    since not declared, must be error or RuntimeError.
115             LOGGER.warn(TSTR, t);
116         }
117 
118         // Last ditch attempt: get the resource from the class path. It
119         // may be the case that clazz was loaded by the Extentsion class
120         // loader which the parent of the system class loader. Hence the
121         // code below.
122         LOGGER.trace("Trying to find [" + resource + "] using ClassLoader.getSystemResource().");
123         return ClassLoader.getSystemResource(resource);
124     }
125 
126     /**
127      * This method will search for <code>resource</code> in different
128      * places. The search order is as follows:
129      * <p/>
130      * <ol>
131      * <p/>
132      * <p><li>Search for <code>resource</code> using the thread context
133      * class loader under Java2. If that fails, search for
134      * <code>resource</code> using the class loader that loaded this
135      * class (<code>Loader</code>). Under JDK 1.1, only the the class
136      * loader that loaded this class (<code>Loader</code>) is used.
137      * <p/>
138      * <p><li>Try one last time with
139      * <code>ClassLoader.getSystemResource(resource)</code>, that is is
140      * using the system class loader in JDK 1.2 and virtual machine's
141      * built-in class loader in JDK 1.1.
142      * <p/>
143      * </ol>
144      * @param resource The resource to load.
145      * @param defaultLoader The default ClassLoader.
146      * @return An InputStream to read the resouce.
147      */
148     public static InputStream getResourceAsStream(String resource, ClassLoader defaultLoader) {
149         ClassLoader classLoader;
150         InputStream is;
151 
152         try {
153             classLoader = getTCL();
154             if (classLoader != null) {
155                 LOGGER.trace("Trying to find [" + resource + "] using context classloader " + classLoader + ".");
156                 is = classLoader.getResourceAsStream(resource);
157                 if (is != null) {
158                     return is;
159                 }
160             }
161 
162             // We could not find resource. Let us now try with the classloader that loaded this class.
163             classLoader = Loader.class.getClassLoader();
164             if (classLoader != null) {
165                 LOGGER.trace("Trying to find [" + resource + "] using " + classLoader + " class loader.");
166                 is = classLoader.getResourceAsStream(resource);
167                 if (is != null) {
168                     return is;
169                 }
170             }
171 
172             // We could not find resource. Finally try with the default ClassLoader.
173             if (defaultLoader != null) {
174                 LOGGER.trace("Trying to find [" + resource + "] using " + defaultLoader + " class loader.");
175                 is = defaultLoader.getResourceAsStream(resource);
176                 if (is != null) {
177                     return is;
178                 }
179             }
180         } catch (IllegalAccessException t) {
181             LOGGER.warn(TSTR, t);
182         } catch (InvocationTargetException t) {
183             if (t.getTargetException() instanceof InterruptedException
184                 || t.getTargetException() instanceof InterruptedIOException) {
185                 Thread.currentThread().interrupt();
186             }
187             LOGGER.warn(TSTR, t);
188         } catch (Throwable t) {
189             //
190             //  can't be InterruptedException or InterruptedIOException
191             //    since not declared, must be error or RuntimeError.
192             LOGGER.warn(TSTR, t);
193         }
194 
195         // Last ditch attempt: get the resource from the class path. It
196         // may be the case that clazz was loaded by the Extentsion class
197         // loader which the parent of the system class loader. Hence the
198         // code below.
199         LOGGER.trace("Trying to find [" + resource + "] using ClassLoader.getSystemResource().");
200         return ClassLoader.getSystemResourceAsStream(resource);
201     }
202 
203     /**
204      * Load a Class by name.
205      * @param clazz The class name.
206      * @return The Class.
207      * @throws ClassNotFoundException if the Class could not be found.
208      */
209     public static Class loadClass(String clazz) throws ClassNotFoundException {
210         // Just call Class.forName(clazz) if we are instructed to ignore the TCL.
211         if (ignoreTCL) {
212             return Class.forName(clazz);
213         } else {
214             try {
215                 return getTCL().loadClass(clazz);
216             } catch (Throwable e) {
217                 return Class.forName(clazz);
218             }
219         }
220     }
221 
222     /**
223      * Return the ClassLoader to use.
224      * @return the ClassLoader.
225      */
226     public static ClassLoader getClassLoader() {
227         ClassLoader cl = null;
228 
229         try {
230             cl = getTCL();
231         } catch (Exception ex) {
232             // Ignore the exception. The ClassLoader will be located.
233         }
234         if (cl == null) {
235             cl = Loader.getClassLoader();
236         }
237         return cl;
238     }
239 
240     private static ClassLoader getTCL() throws IllegalAccessException, InvocationTargetException {
241         ClassLoader cl;
242         if (System.getSecurityManager() == null) {
243             cl = Thread.currentThread().getContextClassLoader();
244         } else {
245             cl = (ClassLoader) java.security.AccessController.doPrivileged(
246                 new java.security.PrivilegedAction() {
247                     public Object run() {
248                         return Thread.currentThread().getContextClassLoader();
249                     }
250                 }
251             );
252         }
253 
254         return cl;
255     }
256 }