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.util.Enumeration;
19 import java.util.Set;
20 import java.util.HashSet;
21
22 import ch.qos.logback.core.Context;
23
24 /**
25 * Load resources (or images) from various sources.
26 *
27 * @author Ceki Gülcü
28 */
29 public class Loader {
30 static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
31
32 private static boolean ignoreTCL = false;
33 public static final String IGNORE_TCL_PROPERTY_NAME = "logback.ignoreTCL";
34
35 static {
36 String ignoreTCLProp = OptionHelper.getSystemProperty(IGNORE_TCL_PROPERTY_NAME, null);
37
38 if (ignoreTCLProp != null) {
39 ignoreTCL = OptionHelper.toBoolean(ignoreTCLProp, true);
40 }
41 }
42
43 /**
44 * This method is used to sanitize the <code>cl</code> argument in case it is null.
45 *
46 * @param cl a class loader, may be null
47 * @return the system class loader if the <code>cl</code> argument is null, return <code>cl</code> otherwise.
48 *
49 * @since 1.4.12
50 */
51 public static ClassLoader systemClassloaderIfNull(ClassLoader cl) {
52 if(cl == null)
53 return ClassLoader.getSystemClassLoader();
54 else
55 return cl;
56 }
57
58 /**
59 * Compute the number of occurrences a resource can be found by a class loader.
60 *
61 * @param resource
62 * @param classLoader
63 * @return
64 * @throws IOException
65 */
66 public static Set<URL> getResources(String resource, ClassLoader classLoader) throws IOException {
67 // See LBCLASSIC-159
68 Set<URL> urlSet = new HashSet<URL>();
69 Enumeration<URL> urlEnum = classLoader.getResources(resource);
70 while (urlEnum.hasMoreElements()) {
71 URL url = urlEnum.nextElement();
72 urlSet.add(url);
73 }
74 return urlSet;
75 }
76
77 /**
78 * Search for a resource using the classloader passed as parameter.
79 *
80 * @param resource the resource name to look for
81 * @param classLoader the classloader used for the search
82 */
83 public static URL getResource(String resource, ClassLoader classLoader) {
84 try {
85 return classLoader.getResource(resource);
86 } catch (Throwable t) {
87 return null;
88 }
89 }
90
91 /**
92 * Attempt to find a resource by using the classloader that loaded this class,
93 * namely Loader.class.
94 *
95 * @param resource
96 * @return
97 */
98 public static URL getResourceBySelfClassLoader(String resource) {
99 return getResource(resource, getClassLoaderOfClass(Loader.class));
100 }
101
102 // private static URL getResourceByTCL(String resource) {
103 // return getResource(resource, getTCL());
104 // }
105
106 /**
107 * Get the Thread Context Loader which is a JDK 1.2 feature. If we are running
108 * under JDK 1.1 or anything else goes wrong the method returns {@code null}.
109 */
110 public static ClassLoader getTCL() {
111 return Thread.currentThread().getContextClassLoader();
112 }
113
114 public static Class<?> loadClass(String clazz, Context context) throws ClassNotFoundException {
115 ClassLoader cl = getClassLoaderOfObject(context);
116 return cl.loadClass(clazz);
117 }
118
119 /**
120 * Get the class loader of the object passed as argument. Return the system
121 * class loader if appropriate.
122 *
123 * @param o
124 * @return
125 */
126 public static ClassLoader getClassLoaderOfObject(Object o) {
127 if (o == null) {
128 throw new NullPointerException("Argument cannot be null");
129 }
130 return getClassLoaderOfClass(o.getClass());
131 }
132
133 /**
134 * Check whether a given class is loadable by the class loader that loaded the context parameter.
135 *
136 * @param className the class to check for availability
137 * @param context the context object used to find the class loader
138 * @return true if className is available, false otherwise
139 * @since 1.5.18
140 */
141 public static boolean isClassLoadable(String className, Context context) {
142 try {
143 Class<?> aClass = Loader.loadClass(className, context);
144 return true;
145 } catch (ClassNotFoundException e) {
146 return false;
147 }
148 }
149
150
151 /**
152 * Return the class loader which loaded the class passed as argument. Return the
153 * system class loader if the class loader of 'clazz' argument is null.
154 *
155 * @param clazz
156 * @return
157 */
158 public static ClassLoader getClassLoaderOfClass(final Class<?> clazz) {
159 ClassLoader cl = clazz.getClassLoader();
160 return systemClassloaderIfNull(cl);
161 }
162
163 /**
164 * If running under JDK 1.2 load the specified class using the
165 * <code>Thread</code> <code>contextClassLoader</code> if that fails try
166 * Class.forname. Under JDK 1.1 only Class.forName is used.
167 */
168 public static Class<?> loadClass(String clazz) throws ClassNotFoundException {
169 // Just call Class.forName(clazz) if we are running under JDK 1.1
170 // or if we are instructed to ignore the TCL.
171 if (ignoreTCL) {
172 return Class.forName(clazz);
173 } else {
174 try {
175 return getTCL().loadClass(clazz);
176 } catch (Throwable e) {
177 // we reached here because tcl was null or because of a
178 // security exception, or because clazz could not be loaded...
179 // In any case we now try one more time
180 return Class.forName(clazz);
181 }
182 }
183 }
184 }