View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.util;
15  
16  import java.io.IOException;
17  import java.net.URL;
18  import java.security.AccessController;
19  import java.security.PrivilegedAction;
20  import java.util.Enumeration;
21  import java.util.Set;
22  import java.util.HashSet;
23  
24  import ch.qos.logback.core.Context;
25  
26  /**
27   * Load resources (or images) from various sources.
28   *
29   * @author Ceki Gülcü
30   */
31  public class Loader {
32      static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
33  
34      private static boolean ignoreTCL = false;
35      public static final String IGNORE_TCL_PROPERTY_NAME = "logback.ignoreTCL";
36      private static boolean HAS_GET_CLASS_LOADER_PERMISSION = false;
37  
38      static {
39          String ignoreTCLProp = OptionHelper.getSystemProperty(IGNORE_TCL_PROPERTY_NAME, null);
40  
41          if (ignoreTCLProp != null) {
42              ignoreTCL = OptionHelper.toBoolean(ignoreTCLProp, true);
43          }
44  
45          HAS_GET_CLASS_LOADER_PERMISSION = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
46              public Boolean run() {
47                  try {
48                      AccessController.checkPermission(new RuntimePermission("getClassLoader"));
49                      return true;
50                  } catch (SecurityException e) {
51                      // Using SecurityException instead of AccessControlException.
52                      // See bug LOGBACK-760.
53                      return false;
54                  }
55              }
56          });
57      }
58  
59      /**
60       * This method is used to sanitize the <code>cl</code> argument in case it is null.
61       *
62       * @param cl a class loader, may be null
63       * @return the system class loader if the <code>cl</code> argument is null, return <code>cl</code> otherwise.
64       *
65       * @since 1.4.12
66       */
67      public static ClassLoader systemClassloaderIfNull(ClassLoader cl) {
68          if(cl == null)
69              return ClassLoader.getSystemClassLoader();
70          else
71              return cl;
72      }
73  
74      /**
75       * Compute the number of occurrences a resource can be found by a class loader.
76       *
77       * @param resource
78       * @param classLoader
79       * @return
80       * @throws IOException
81       */
82      public static Set<URL> getResources(String resource, ClassLoader classLoader) throws IOException {
83          // See LBCLASSIC-159
84          Set<URL> urlSet = new HashSet<URL>();
85          Enumeration<URL> urlEnum = classLoader.getResources(resource);
86          while (urlEnum.hasMoreElements()) {
87              URL url = urlEnum.nextElement();
88              urlSet.add(url);
89          }
90          return urlSet;
91      }
92  
93      /**
94       * Search for a resource using the classloader passed as parameter.
95       *
96       * @param resource    the resource name to look for
97       * @param classLoader the classloader used for the search
98       */
99      public static URL getResource(String resource, ClassLoader classLoader) {
100         try {
101             return classLoader.getResource(resource);
102         } catch (Throwable t) {
103             return null;
104         }
105     }
106 
107     /**
108      * Attempt to find a resource by using the classloader that loaded this class,
109      * namely Loader.class.
110      *
111      * @param resource
112      * @return
113      */
114     public static URL getResourceBySelfClassLoader(String resource) {
115         return getResource(resource, getClassLoaderOfClass(Loader.class));
116     }
117 
118     // private static URL getResourceByTCL(String resource) {
119     // return getResource(resource, getTCL());
120     // }
121 
122     /**
123      * Get the Thread Context Loader which is a JDK 1.2 feature. If we are running
124      * under JDK 1.1 or anything else goes wrong the method returns {@code null}.
125      */
126     public static ClassLoader getTCL() {
127         return Thread.currentThread().getContextClassLoader();
128     }
129 
130     public static Class<?> loadClass(String clazz, Context context) throws ClassNotFoundException {
131         ClassLoader cl = getClassLoaderOfObject(context);
132         return cl.loadClass(clazz);
133     }
134 
135     /**
136      * Get the class loader of the object passed as argument. Return the system
137      * class loader if appropriate.
138      *
139      * @param o
140      * @return
141      */
142     public static ClassLoader getClassLoaderOfObject(Object o) {
143         if (o == null) {
144             throw new NullPointerException("Argument cannot be null");
145         }
146         return getClassLoaderOfClass(o.getClass());
147     }
148 
149     /**
150      * Returns the class loader of clazz in an access privileged section.
151      *
152      * @param clazz
153      * @return
154      */
155     public static ClassLoader getClassLoaderAsPrivileged(final Class<?> clazz) {
156         if (!HAS_GET_CLASS_LOADER_PERMISSION)
157             return null;
158         else
159             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
160                 public ClassLoader run() {
161                     return clazz.getClassLoader();
162                 }
163             });
164     }
165 
166     /**
167      * Return the class loader which loaded the class passed as argument. Return the
168      * system class loader if the class loader of 'clazz' argument is null.
169      *
170      * @param clazz
171      * @return
172      */
173     public static ClassLoader getClassLoaderOfClass(final Class<?> clazz) {
174         ClassLoader cl = clazz.getClassLoader();
175         return systemClassloaderIfNull(cl);
176     }
177 
178     /**
179      * If running under JDK 1.2 load the specified class using the
180      * <code>Thread</code> <code>contextClassLoader</code> if that fails try
181      * Class.forname. Under JDK 1.1 only Class.forName is used.
182      */
183     public static Class<?> loadClass(String clazz) throws ClassNotFoundException {
184         // Just call Class.forName(clazz) if we are running under JDK 1.1
185         // or if we are instructed to ignore the TCL.
186         if (ignoreTCL) {
187             return Class.forName(clazz);
188         } else {
189             try {
190                 return getTCL().loadClass(clazz);
191             } catch (Throwable e) {
192                 // we reached here because tcl was null or because of a
193                 // security exception, or because clazz could not be loaded...
194                 // In any case we now try one more time
195                 return Class.forName(clazz);
196             }
197         }
198     }
199 }