001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2026, 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 v2.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.util.Enumeration; 019import java.util.Set; 020import java.util.HashSet; 021 022import ch.qos.logback.core.Context; 023 024/** 025 * Load resources (or images) from various sources. 026 * 027 * @author Ceki Gülcü 028 */ 029public class Loader { 030 static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous."; 031 032 private static boolean ignoreTCL = false; 033 public static final String IGNORE_TCL_PROPERTY_NAME = "logback.ignoreTCL"; 034 035 static { 036 String ignoreTCLProp = OptionHelper.getSystemProperty(IGNORE_TCL_PROPERTY_NAME, null); 037 038 if (ignoreTCLProp != null) { 039 ignoreTCL = OptionHelper.toBoolean(ignoreTCLProp, true); 040 } 041 } 042 043 /** 044 * This method is used to sanitize the <code>cl</code> argument in case it is null. 045 * 046 * @param cl a class loader, may be null 047 * @return the system class loader if the <code>cl</code> argument is null, return <code>cl</code> otherwise. 048 * 049 * @since 1.4.12 050 */ 051 public static ClassLoader systemClassloaderIfNull(ClassLoader cl) { 052 if(cl == null) 053 return ClassLoader.getSystemClassLoader(); 054 else 055 return cl; 056 } 057 058 /** 059 * Compute the number of occurrences a resource can be found by a class loader. 060 * 061 * @param resource 062 * @param classLoader 063 * @return 064 * @throws IOException 065 */ 066 public static Set<URL> getResources(String resource, ClassLoader classLoader) throws IOException { 067 // See LBCLASSIC-159 068 Set<URL> urlSet = new HashSet<URL>(); 069 Enumeration<URL> urlEnum = classLoader.getResources(resource); 070 while (urlEnum.hasMoreElements()) { 071 URL url = urlEnum.nextElement(); 072 urlSet.add(url); 073 } 074 return urlSet; 075 } 076 077 /** 078 * Search for a resource using the classloader passed as parameter. 079 * 080 * @param resource the resource name to look for 081 * @param classLoader the classloader used for the search 082 */ 083 public static URL getResource(String resource, ClassLoader classLoader) { 084 try { 085 return classLoader.getResource(resource); 086 } catch (Throwable t) { 087 return null; 088 } 089 } 090 091 /** 092 * Attempt to find a resource by using the classloader that loaded this class, 093 * namely Loader.class. 094 * 095 * @param resource 096 * @return 097 */ 098 public static URL getResourceBySelfClassLoader(String resource) { 099 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}