001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.util;
015
016import java.io.IOException;
017import java.net.URL;
018import java.security.AccessController;
019import java.security.PrivilegedAction;
020import java.util.Enumeration;
021import java.util.Set;
022import java.util.HashSet;
023
024import ch.qos.logback.core.Context;
025
026/**
027 * Load resources (or images) from various sources.
028 *
029 * @author Ceki Gülcü
030 */
031public class Loader {
032    static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
033
034    private static boolean ignoreTCL = false;
035    public static final String IGNORE_TCL_PROPERTY_NAME = "logback.ignoreTCL";
036    private static boolean HAS_GET_CLASS_LOADER_PERMISSION = false;
037
038    static {
039        String ignoreTCLProp = OptionHelper.getSystemProperty(IGNORE_TCL_PROPERTY_NAME, null);
040
041        if (ignoreTCLProp != null) {
042            ignoreTCL = OptionHelper.toBoolean(ignoreTCLProp, true);
043        }
044
045        HAS_GET_CLASS_LOADER_PERMISSION = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
046            public Boolean run() {
047                try {
048                    AccessController.checkPermission(new RuntimePermission("getClassLoader"));
049                    return true;
050                } catch (SecurityException e) {
051                    // Using SecurityException instead of AccessControlException.
052                    // See bug LOGBACK-760.
053                    return false;
054                }
055            }
056        });
057    }
058
059    /**
060     * Compute the number of occurrences a resource can be found by a class loader.
061     *
062     * @param resource
063     * @param classLoader
064     * @return
065     * @throws IOException
066     */
067
068    public static Set<URL> getResources(String resource, ClassLoader classLoader) throws IOException {
069        // See LBCLASSIC-159
070        Set<URL> urlSet = new HashSet<URL>();
071        Enumeration<URL> urlEnum = classLoader.getResources(resource);
072        while (urlEnum.hasMoreElements()) {
073            URL url = urlEnum.nextElement();
074            urlSet.add(url);
075        }
076        return urlSet;
077    }
078
079    /**
080     * Search for a resource using the classloader passed as parameter.
081     *
082     * @param resource    the resource name to look for
083     * @param classLoader the classloader used for the search
084     */
085    public static URL getResource(String resource, ClassLoader classLoader) {
086        try {
087            return classLoader.getResource(resource);
088        } catch (Throwable t) {
089            return null;
090        }
091    }
092
093    /**
094     * Attempt to find a resource by using the classloader that loaded this class,
095     * namely Loader.class.
096     *
097     * @param resource
098     * @return
099     */
100    public static URL getResourceBySelfClassLoader(String resource) {
101        return getResource(resource, getClassLoaderOfClass(Loader.class));
102    }
103
104    // private static URL getResourceByTCL(String resource) {
105    // return getResource(resource, getTCL());
106    // }
107
108    /**
109     * Get the Thread Context Loader which is a JDK 1.2 feature. If we are running
110     * under JDK 1.1 or anything else goes wrong the method returns {@code null}.
111     */
112    public static ClassLoader getTCL() {
113        return Thread.currentThread().getContextClassLoader();
114    }
115
116    public static Class<?> loadClass(String clazz, Context context) throws ClassNotFoundException {
117        ClassLoader cl = getClassLoaderOfObject(context);
118        return cl.loadClass(clazz);
119    }
120
121    /**
122     * Get the class loader of the object passed as argument. Return the system
123     * class loader if appropriate.
124     *
125     * @param o
126     * @return
127     */
128    public static ClassLoader getClassLoaderOfObject(Object o) {
129        if (o == null) {
130            throw new NullPointerException("Argument cannot be null");
131        }
132        return getClassLoaderOfClass(o.getClass());
133    }
134
135    /**
136     * Returns the class loader of clazz in an access privileged section.
137     *
138     * @param clazz
139     * @return
140     */
141    public static ClassLoader getClassLoaderAsPrivileged(final Class<?> clazz) {
142        if (!HAS_GET_CLASS_LOADER_PERMISSION)
143            return null;
144        else
145            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
146                public ClassLoader run() {
147                    return clazz.getClassLoader();
148                }
149            });
150    }
151
152    /**
153     * Return the class loader which loaded the class passed as argument. Return the
154     * system class loader if appropriate.
155     *
156     * @param clazz
157     * @return
158     */
159    public static ClassLoader getClassLoaderOfClass(final Class<?> clazz) {
160        ClassLoader cl = clazz.getClassLoader();
161        if (cl == null) {
162            return ClassLoader.getSystemClassLoader();
163        } else {
164            return cl;
165        }
166    }
167
168    /**
169     * If running under JDK 1.2 load the specified class using the
170     * <code>Thread</code> <code>contextClassLoader</code> if that fails try
171     * Class.forname. Under JDK 1.1 only Class.forName is used.
172     */
173    public static Class<?> loadClass(String clazz) throws ClassNotFoundException {
174        // Just call Class.forName(clazz) if we are running under JDK 1.1
175        // or if we are instructed to ignore the TCL.
176        if (ignoreTCL) {
177            return Class.forName(clazz);
178        } else {
179            try {
180                return getTCL().loadClass(clazz);
181            } catch (Throwable e) {
182                // we reached here because tcl was null or because of a
183                // security exception, or because clazz could not be loaded...
184                // In any case we now try one more time
185                return Class.forName(clazz);
186            }
187        }
188    }
189}