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 * This method is used to sanitize the <code>cl</code> argument in case it is null. 061 * 062 * @param cl a class loader, may be null 063 * @return the system class loader if the <code>cl</code> argument is null, return <code>cl</code> otherwise. 064 * 065 * @since 1.4.12 066 */ 067 public static ClassLoader systemClassloaderIfNull(ClassLoader cl) { 068 if(cl == null) 069 return ClassLoader.getSystemClassLoader(); 070 else 071 return cl; 072 } 073 074 /** 075 * Compute the number of occurrences a resource can be found by a class loader. 076 * 077 * @param resource 078 * @param classLoader 079 * @return 080 * @throws IOException 081 */ 082 public static Set<URL> getResources(String resource, ClassLoader classLoader) throws IOException { 083 // See LBCLASSIC-159 084 Set<URL> urlSet = new HashSet<URL>(); 085 Enumeration<URL> urlEnum = classLoader.getResources(resource); 086 while (urlEnum.hasMoreElements()) { 087 URL url = urlEnum.nextElement(); 088 urlSet.add(url); 089 } 090 return urlSet; 091 } 092 093 /** 094 * Search for a resource using the classloader passed as parameter. 095 * 096 * @param resource the resource name to look for 097 * @param classLoader the classloader used for the search 098 */ 099 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}