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 }