001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.logging; 019 020import java.io.FileOutputStream; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.PrintStream; 024import java.lang.ref.WeakReference; 025import java.net.URL; 026import java.net.URLConnection; 027import java.nio.charset.StandardCharsets; 028import java.security.AccessController; 029import java.security.PrivilegedAction; 030import java.util.Enumeration; 031import java.util.Hashtable; 032import java.util.Iterator; 033import java.util.Objects; 034import java.util.Properties; 035import java.util.ServiceConfigurationError; 036import java.util.ServiceLoader; 037 038/** 039 * Factory for creating {@link Log} instances, with discovery and 040 * configuration features similar to that employed by standard Java APIs 041 * such as JAXP. 042 * <p> 043 * <strong>IMPLEMENTATION NOTE</strong> - This implementation is heavily 044 * based on the SAXParserFactory and DocumentBuilderFactory implementations 045 * (corresponding to the JAXP pluggability APIs) found in Apache Xerces. 046 * </p> 047 */ 048public abstract class LogFactory { 049 // Implementation note re AccessController usage 050 // 051 // It is important to keep code invoked via an AccessController to small 052 // auditable blocks. Such code must carefully evaluate all user input 053 // (parameters, system properties, configuration file contents, etc). As an 054 // example, a Log implementation should not write to its log file 055 // with an AccessController anywhere in the call stack, otherwise an 056 // insecure application could configure the log implementation to write 057 // to a protected file using the privileges granted to JCL rather than 058 // to the calling application. 059 // 060 // Under no circumstance should a non-private method return data that is 061 // retrieved via an AccessController. That would allow an insecure application 062 // to invoke that method and obtain data that it is not permitted to have. 063 // 064 // Invoking user-supplied code with an AccessController set is not a major 065 // issue (for example, invoking the constructor of the class specified by 066 // HASHTABLE_IMPLEMENTATION_PROPERTY). That class will be in a different 067 // trust domain, and therefore must have permissions to do whatever it 068 // is trying to do regardless of the permissions granted to JCL. There is 069 // a slight issue in that untrusted code may point that environment variable 070 // to another trusted library, in which case the code runs if both that 071 // library and JCL have the necessary permissions even when the untrusted 072 // caller does not. That's a pretty hard route to exploit though. 073 074 /** 075 * The name ({@code priority}) of the key in the configuration file used to 076 * specify the priority of that particular configuration file. The associated value 077 * is a floating-point number; higher values take priority over lower values. 078 */ 079 public static final String PRIORITY_KEY = "priority"; 080 081 /** 082 * The name ({@code use_tccl}) of the key in the configuration file used 083 * to specify whether logging classes should be loaded via the thread 084 * context class loader (TCCL), or not. By default, the TCCL is used. 085 */ 086 public static final String TCCL_KEY = "use_tccl"; 087 088 /** 089 * The name ({@code org.apache.commons.logging.LogFactory}) of the property 090 * used to identify the LogFactory implementation 091 * class name. This can be used as a system property, or as an entry in a 092 * configuration properties file. 093 */ 094 public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory"; 095 096 private static final String FACTORY_LOG4J_API = "org.apache.commons.logging.impl.Log4jApiLogFactory"; 097 private static final String LOG4J_API_LOGGER = "org.apache.logging.log4j.Logger"; 098 private static final String LOG4J_TO_SLF4J_BRIDGE = "org.apache.logging.slf4j.SLF4JProvider"; 099 100 private static final String FACTORY_SLF4J = "org.apache.commons.logging.impl.Slf4jLogFactory"; 101 private static final String SLF4J_API_LOGGER = "org.slf4j.Logger"; 102 103 /** 104 * The fully qualified class name of the fallback {@code LogFactory} 105 * implementation class to use, if no other can be found. 106 */ 107 public static final String FACTORY_DEFAULT = "org.apache.commons.logging.impl.LogFactoryImpl"; 108 109 /** 110 * The name ({@code commons-logging.properties}) of the properties file to search for. 111 */ 112 public static final String FACTORY_PROPERTIES = "commons-logging.properties"; 113 114 /** 115 * JDK 1.3+ <a href="https://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider"> 116 * 'Service Provider' specification</a>. 117 */ 118 protected static final String SERVICE_ID = 119 "META-INF/services/org.apache.commons.logging.LogFactory"; 120 121 /** 122 * The name ({@code org.apache.commons.logging.diagnostics.dest}) 123 * of the property used to enable internal commons-logging 124 * diagnostic output, in order to get information on what logging 125 * implementations are being discovered, what class loaders they 126 * are loaded through, etc. 127 * <p> 128 * If a system property of this name is set then the value is 129 * assumed to be the name of a file. The special strings 130 * STDOUT or STDERR (case-sensitive) indicate output to 131 * System.out and System.err respectively. 132 * <p> 133 * Diagnostic logging should be used only to debug problematic 134 * configurations and should not be set in normal production use. 135 */ 136 public static final String DIAGNOSTICS_DEST_PROPERTY = 137 "org.apache.commons.logging.diagnostics.dest"; 138 139 /** 140 * When null (the usual case), no diagnostic output will be 141 * generated by LogFactory or LogFactoryImpl. When non-null, 142 * interesting events will be written to the specified object. 143 */ 144 private static final PrintStream DIAGNOSTICS_STREAM; 145 146 /** 147 * A string that gets prefixed to every message output by the 148 * logDiagnostic method, so that users can clearly see which 149 * LogFactory class is generating the output. 150 */ 151 private static final String diagnosticPrefix; 152 153 /** 154 * Setting this system property 155 * ({@code org.apache.commons.logging.LogFactory.HashtableImpl}) 156 * value allows the {@code Hashtable} used to store 157 * class loaders to be substituted by an alternative implementation. 158 * <p> 159 * <strong>Note:</strong> {@code LogFactory} will print: 160 * </p> 161 * <pre> 162 * [ERROR] LogFactory: Load of custom hashtable failed 163 * </pre> 164 * <p> 165 * to system error and then continue using a standard Hashtable. 166 * </p> 167 * <p> 168 * <strong>Usage:</strong> Set this property when Java is invoked 169 * and {@code LogFactory} will attempt to load a new instance 170 * of the given implementation class. 171 * For example, running the following ant scriplet: 172 * </p> 173 * <pre> 174 * <java classname="${test.runner}" fork="yes" failonerror="${test.failonerror}"> 175 * ... 176 * <sysproperty 177 * key="org.apache.commons.logging.LogFactory.HashtableImpl" 178 * value="org.apache.commons.logging.AltHashtable"/> 179 * </java> 180 * </pre> 181 * <p> 182 * will mean that {@code LogFactory} will load an instance of 183 * {@code org.apache.commons.logging.AltHashtable}. 184 * </p> 185 * <p> 186 * A typical use case is to allow a custom 187 * Hashtable implementation using weak references to be substituted. 188 * This will allow class loaders to be garbage collected without 189 * the need to release them (on 1.3+ JVMs only, of course ;). 190 * </p> 191 */ 192 public static final String HASHTABLE_IMPLEMENTATION_PROPERTY = 193 "org.apache.commons.logging.LogFactory.HashtableImpl"; 194 195 /** Name used to load the weak hashtable implementation by names. */ 196 private static final String WEAK_HASHTABLE_CLASSNAME = 197 "org.apache.commons.logging.impl.WeakHashtable"; 198 199 /** 200 * A reference to the class loader that loaded this class. This is the 201 * same as LogFactory.class.getClassLoader(). However computing this 202 * value isn't quite as simple as that, as we potentially need to use 203 * AccessControllers etc. It's more efficient to compute it once and 204 * cache it here. 205 */ 206 private static final WeakReference<ClassLoader> thisClassLoaderRef; 207 208 /** 209 * Maximum number of {@link ServiceLoader} errors to ignore, while 210 * looking for an implementation. 211 */ 212 private static final int MAX_BROKEN_SERVICES = 3; 213 214 /** 215 * The previously constructed {@code LogFactory} instances, keyed by 216 * the {@code ClassLoader} with which it was created. 217 */ 218 protected static Hashtable<ClassLoader, LogFactory> factories; 219 220 /** 221 * Previously constructed {@code LogFactory} instance as in the 222 * {@code factories} map, but for the case where 223 * {@code getClassLoader} returns {@code null}. 224 * This can happen when: 225 * <ul> 226 * <li>using JDK1.1 and the calling code is loaded via the system 227 * class loader (very common)</li> 228 * <li>using JDK1.2+ and the calling code is loaded via the boot 229 * class loader (only likely for embedded systems work).</li> 230 * </ul> 231 * Note that {@code factories} is a <i>Hashtable</i> (not a HashMap), 232 * and hashtables don't allow null as a key. 233 * @deprecated since 1.1.2 234 */ 235 @Deprecated 236 protected static volatile LogFactory nullClassLoaderFactory; 237 238 static { 239 // note: it's safe to call methods before initDiagnostics (though 240 // diagnostic output gets discarded). 241 final ClassLoader thisClassLoader = getClassLoader(LogFactory.class); 242 thisClassLoaderRef = new WeakReference<>(thisClassLoader); 243 // In order to avoid confusion where multiple instances of JCL are 244 // being used via different class loaders within the same app, we 245 // ensure each logged message has a prefix of form 246 // [LogFactory from class loader OID] 247 // 248 // Note that this prefix should be kept consistent with that 249 // in LogFactoryImpl. However here we don't need to output info 250 // about the actual *instance* of LogFactory, as all methods that 251 // output diagnostics from this class are static. 252 String classLoaderName; 253 try { 254 if (thisClassLoader == null) { 255 classLoaderName = "BOOTLOADER"; 256 } else { 257 classLoaderName = objectId(thisClassLoader); 258 } 259 } catch (final SecurityException e) { 260 classLoaderName = "UNKNOWN"; 261 } 262 diagnosticPrefix = "[LogFactory from " + classLoaderName + "] "; 263 DIAGNOSTICS_STREAM = initDiagnostics(); 264 logClassLoaderEnvironment(LogFactory.class); 265 factories = createFactoryStore(); 266 if (isDiagnosticsEnabled()) { 267 logDiagnostic("BOOTSTRAP COMPLETED"); 268 } 269 } 270 271 /** 272 * Remember this factory, so later calls to LogFactory.getCachedFactory 273 * can return the previously created object (together with all its 274 * cached Log objects). 275 * 276 * @param classLoader should be the current context class loader. Note that 277 * this can be null under some circumstances; this is ok. 278 * @param factory should be the factory to cache. This should never be null. 279 */ 280 private static void cacheFactory(final ClassLoader classLoader, final LogFactory factory) { 281 // Ideally we would assert(factory != null) here. However reporting 282 // errors from within a logging implementation is a little tricky! 283 284 if (factory != null) { 285 if (classLoader == null) { 286 nullClassLoaderFactory = factory; 287 } else { 288 factories.put(classLoader, factory); 289 } 290 } 291 } 292 293 /** 294 * Implements the operations described in the Javadoc for newFactory. 295 * 296 * @param factoryClassName Factory class. 297 * @param classLoader used to load the specified factory class. This is expected to be either the TCCL or the class loader which loaded this class. 298 * Note that the class loader which loaded this class might be "null" (for example, the boot loader) for embedded systems. 299 * @return either a LogFactory object or a LogConfigurationException object. 300 * @since 1.1 301 */ 302 protected static Object createFactory(final String factoryClassName, final ClassLoader classLoader) { 303 // This will be used to diagnose bad configurations 304 // and allow a useful message to be sent to the user 305 Class<?> logFactoryClass = null; 306 try { 307 if (classLoader != null) { 308 try { 309 // First the given class loader param (thread class loader) 310 311 // Warning: must typecast here & allow exception 312 // to be generated/caught & recast properly. 313 logFactoryClass = classLoader.loadClass(factoryClassName); 314 if (LogFactory.class.isAssignableFrom(logFactoryClass)) { 315 if (isDiagnosticsEnabled()) { 316 logDiagnostic("Loaded class " + logFactoryClass.getName() + " from class loader " + objectId(classLoader)); 317 } 318 } else // 319 // This indicates a problem with the ClassLoader tree. 320 // An incompatible ClassLoader was used to load the 321 // implementation. 322 // As the same classes 323 // must be available in multiple class loaders, 324 // it is very likely that multiple JCL jars are present. 325 // The most likely fix for this 326 // problem is to remove the extra JCL jars from the 327 // ClassLoader hierarchy. 328 // 329 if (isDiagnosticsEnabled()) { 330 logDiagnostic("Factory class " + logFactoryClass.getName() + " loaded from class loader " + objectId(logFactoryClass.getClassLoader()) 331 + " does not extend '" + LogFactory.class.getName() + "' as loaded by this class loader."); 332 logHierarchy("[BAD CL TREE] ", classLoader); 333 } 334 335 return logFactoryClass.getConstructor().newInstance(); 336 337 } catch (final ClassNotFoundException ex) { 338 if (classLoader == thisClassLoaderRef.get()) { 339 // Nothing more to try, onwards. 340 if (isDiagnosticsEnabled()) { 341 logDiagnostic("Unable to locate any class called '" + factoryClassName + "' via class loader " + objectId(classLoader)); 342 } 343 throw ex; 344 } 345 // ignore exception, continue 346 } catch (final NoClassDefFoundError e) { 347 if (classLoader == thisClassLoaderRef.get()) { 348 // Nothing more to try, onwards. 349 if (isDiagnosticsEnabled()) { 350 logDiagnostic("Class '" + factoryClassName + "' cannot be loaded" + " via class loader " + objectId(classLoader) 351 + " - it depends on some other class that cannot be found."); 352 } 353 throw e; 354 } 355 // ignore exception, continue 356 } catch (final ClassCastException e) { 357 if (classLoader == thisClassLoaderRef.get()) { 358 // There's no point in falling through to the code below that 359 // tries again with thisClassLoaderRef, because we've just tried 360 // loading with that loader (not the TCCL). Just throw an 361 // appropriate exception here. 362 363 final boolean implementsLogFactory = implementsLogFactory(logFactoryClass); 364 365 // 366 // Construct a good message: users may not actual expect that a custom implementation 367 // has been specified. Several well known containers use this mechanism to adapt JCL 368 // to their native logging system. 369 // 370 final StringBuilder msg = new StringBuilder(); 371 msg.append("The application has specified that a custom LogFactory implementation "); 372 msg.append("should be used but Class '"); 373 msg.append(factoryClassName); 374 msg.append("' cannot be converted to '"); 375 msg.append(LogFactory.class.getName()); 376 msg.append("'. "); 377 if (implementsLogFactory) { 378 msg.append("The conflict is caused by the presence of multiple LogFactory classes "); 379 msg.append("in incompatible class loaders. "); 380 msg.append("Background can be found in https://commons.apache.org/logging/tech.html. "); 381 msg.append("If you have not explicitly specified a custom LogFactory then it is likely "); 382 msg.append("that the container has set one without your knowledge. "); 383 msg.append("In this case, consider using the commons-logging-adapters.jar file or "); 384 msg.append("specifying the standard LogFactory from the command line. "); 385 } else { 386 msg.append("Please check the custom implementation. "); 387 } 388 msg.append("Help can be found at https://commons.apache.org/logging/troubleshooting.html."); 389 390 if (isDiagnosticsEnabled()) { 391 logDiagnostic(msg.toString()); 392 } 393 394 throw new ClassCastException(msg.toString()); 395 } 396 397 // Ignore exception, continue. Presumably the class loader was the 398 // TCCL; the code below will try to load the class via thisClassLoaderRef. 399 // This will handle the case where the original calling class is in 400 // a shared classpath but the TCCL has a copy of LogFactory and the 401 // specified LogFactory implementation; we will fall back to using the 402 // LogFactory implementation from the same class loader as this class. 403 // 404 // Issue: this doesn't handle the reverse case, where this LogFactory 405 // is in the webapp, and the specified LogFactory implementation is 406 // in a shared classpath. In that case: 407 // (a) the class really does implement LogFactory (bad log msg above) 408 // (b) the fallback code will result in exactly the same problem. 409 } 410 } 411 412 /* 413 * At this point, either classLoader == null, OR classLoader was unable to load factoryClass. 414 * 415 * In either case, we call Class.forName, which is equivalent to LogFactory.class.getClassLoader().load(name), that is, we ignore the class loader 416 * parameter the caller passed, and fall back to trying the class loader associated with this class. See the Javadoc for the newFactory method for 417 * more info on the consequences of this. 418 * 419 * Notes: * LogFactory.class.getClassLoader() may return 'null' if LogFactory is loaded by the bootstrap class loader. 420 */ 421 // Warning: must typecast here & allow exception 422 // to be generated/caught & recast properly. 423 if (isDiagnosticsEnabled()) { 424 logDiagnostic( 425 "Unable to load factory class via class loader " + objectId(classLoader) + " - trying the class loader associated with this LogFactory."); 426 } 427 logFactoryClass = Class.forName(factoryClassName); 428 return logFactoryClass.newInstance(); 429 } catch (final Exception e) { 430 // Check to see if we've got a bad configuration 431 if (isDiagnosticsEnabled()) { 432 logDiagnostic("Unable to create LogFactory instance."); 433 } 434 if (logFactoryClass != null && !LogFactory.class.isAssignableFrom(logFactoryClass)) { 435 return new LogConfigurationException("The chosen LogFactory implementation does not extend LogFactory." + " Please check your configuration.", 436 e); 437 } 438 return new LogConfigurationException(e); 439 } 440 } 441 442 /** 443 * Create the hashtable which will be used to store a map of 444 * (context class loader -> logfactory-object). Version 1.2+ of Java 445 * supports "weak references", allowing a custom Hashtable class 446 * to be used which uses only weak references to its keys. Using weak 447 * references can fix memory leaks on webapp unload in some cases (though 448 * not all). Version 1.1 of Java does not support weak references, so we 449 * must dynamically determine which we are using. And just for fun, this 450 * code also supports the ability for a system property to specify an 451 * arbitrary Hashtable implementation name. 452 * <p> 453 * Note that the correct way to ensure no memory leaks occur is to ensure 454 * that LogFactory.release(contextClassLoader) is called whenever a 455 * webapp is undeployed. 456 * </p> 457 */ 458 private static Hashtable<ClassLoader, LogFactory> createFactoryStore() { 459 Hashtable<ClassLoader, LogFactory> result = null; 460 String storeImplementationClass; 461 try { 462 storeImplementationClass = getSystemProperty(HASHTABLE_IMPLEMENTATION_PROPERTY, null); 463 } catch (final SecurityException ex) { 464 // Permissions don't allow this to be accessed. Default to the "modern" 465 // weak hashtable implementation if it is available. 466 storeImplementationClass = null; 467 } 468 469 if (storeImplementationClass == null) { 470 storeImplementationClass = WEAK_HASHTABLE_CLASSNAME; 471 } 472 try { 473 final Class<Hashtable<ClassLoader, LogFactory>> implementationClass = (Class<Hashtable<ClassLoader, LogFactory>>) Class 474 .forName(storeImplementationClass); 475 result = implementationClass.getConstructor().newInstance(); 476 } catch (final Throwable t) { 477 handleThrowable(t); // may re-throw t 478 479 // ignore 480 if (!WEAK_HASHTABLE_CLASSNAME.equals(storeImplementationClass)) { 481 // if the user's trying to set up a custom implementation, give a clue 482 if (isDiagnosticsEnabled()) { 483 // use internal logging to issue the warning 484 logDiagnostic("[ERROR] LogFactory: Load of custom Hashtable failed"); 485 } else { 486 // we *really* want this output, even if diagnostics weren't 487 // explicitly enabled by the user. 488 System.err.println("[ERROR] LogFactory: Load of custom Hashtable failed"); 489 } 490 } 491 } 492 if (result == null) { 493 result = new Hashtable<>(); 494 } 495 return result; 496 } 497 498 /** 499 * Gets the thread context class loader if available; otherwise return null. 500 * <p> 501 * Most/all code should call getContextClassLoaderInternal rather than 502 * calling this method directly. 503 * </p> 504 * <p> 505 * The thread context class loader is available for JDK 1.2 506 * or later, if certain security conditions are met. 507 * </p> 508 * <p> 509 * Note that no internal logging is done within this method because 510 * this method is called every time LogFactory.getLogger() is called, 511 * and we don't want too much output generated here. 512 * </p> 513 * 514 * @throws LogConfigurationException if a suitable class loader 515 * cannot be identified. 516 * @return the thread's context class loader or {@code null} if the Java security 517 * policy forbids access to the context class loader from one of the classes 518 * in the current call stack. 519 * @since 1.1 520 */ 521 protected static ClassLoader directGetContextClassLoader() throws LogConfigurationException { 522 ClassLoader classLoader = null; 523 try { 524 classLoader = Thread.currentThread().getContextClassLoader(); 525 } catch (final SecurityException ignore) { 526 // getContextClassLoader() throws SecurityException when 527 // the context class loader isn't an ancestor of the 528 // calling class's class loader, or if security 529 // permissions are restricted. 530 // 531 // We ignore this exception to be consistent with the previous 532 // behavior (e.g. 1.1.3 and earlier). 533 } 534 // Return the selected class loader 535 return classLoader; 536 } 537 538 /** 539 * Check cached factories (keyed by contextClassLoader) 540 * 541 * @param contextClassLoader is the context class loader associated 542 * with the current thread. This allows separate LogFactory objects 543 * per component within a container, provided each component has 544 * a distinct context class loader set. This parameter may be null 545 * in JDK1.1, and in embedded systems where jcl-using code is 546 * placed in the bootclasspath. 547 * 548 * @return the factory associated with the specified class loader if 549 * one has previously been created, or null if this is the first time 550 * we have seen this particular class loader. 551 */ 552 private static LogFactory getCachedFactory(final ClassLoader contextClassLoader) { 553 if (contextClassLoader == null) { 554 // We have to handle this specially, as factories is a Hashtable 555 // and those don't accept null as a key value. 556 // 557 // nb: nullClassLoaderFactory might be null. That's ok. 558 return nullClassLoaderFactory; 559 } 560 return factories.get(contextClassLoader); 561 } 562 563 /** 564 * Safely get access to the class loader for the specified class. 565 * <p> 566 * Theoretically, calling getClassLoader can throw a security exception, 567 * and so should be done under an AccessController in order to provide 568 * maximum flexibility. However in practice people don't appear to use 569 * security policies that forbid getClassLoader calls. So for the moment 570 * all code is written to call this method rather than Class.getClassLoader, 571 * so that we could put AccessController stuff in this method without any 572 * disruption later if we need to. 573 * </p> 574 * <p> 575 * Even when using an AccessController, however, this method can still 576 * throw SecurityException. Commons Logging basically relies on the 577 * ability to access class loaders. A policy that forbids all 578 * class loader access will also prevent commons-logging from working: 579 * currently this method will throw an exception preventing the entire app 580 * from starting up. Maybe it would be good to detect this situation and 581 * just disable all commons-logging? Not high priority though - as stated 582 * above, security policies that prevent class loader access aren't common. 583 * </p> 584 * <p> 585 * Note that returning an object fetched via an AccessController would 586 * technically be a security flaw anyway; untrusted code that has access 587 * to a trusted JCL library could use it to fetch the class loader for 588 * a class even when forbidden to do so directly. 589 * </p> 590 * 591 * @param clazz Class. 592 * @return a ClassLoader. 593 * 594 * @since 1.1 595 */ 596 protected static ClassLoader getClassLoader(final Class<?> clazz) { 597 try { 598 return clazz.getClassLoader(); 599 } catch (final SecurityException ex) { 600 if (isDiagnosticsEnabled()) { 601 logDiagnostic("Unable to get class loader for class '" + clazz + "' due to security restrictions - " + ex.getMessage()); 602 } 603 throw ex; 604 } 605 } 606 607 /** 608 * Locate a user-provided configuration file. 609 * <p> 610 * The classpath of the specified classLoader (usually the context class loader) 611 * is searched for properties files of the specified name. If none is found, 612 * null is returned. If more than one is found, then the file with the greatest 613 * value for its PRIORITY property is returned. If multiple files have the 614 * same PRIORITY value then the first in the classpath is returned. 615 * </p> 616 * <p> 617 * This differs from the 1.0.x releases; those always use the first one found. 618 * However as the priority is a new field, this change is backwards compatible. 619 * </p> 620 * <p> 621 * The purpose of the priority field is to allow a webserver administrator to 622 * override logging settings in all webapps by placing a commons-logging.properties 623 * file in a shared classpath location with a priority > 0; this overrides any 624 * commons-logging.properties files without priorities which are in the 625 * webapps. Webapps can also use explicit priorities to override a configuration 626 * file in the shared classpath if needed. 627 * </p> 628 */ 629 private static Properties getConfigurationFile(final ClassLoader classLoader, final String fileName) { 630 Properties props = null; 631 double priority = 0.0; 632 URL propsUrl = null; 633 try { 634 final Enumeration<URL> urls = getResources(classLoader, fileName); 635 636 if (urls == null) { 637 return null; 638 } 639 640 while (urls.hasMoreElements()) { 641 final URL url = urls.nextElement(); 642 643 final Properties newProps = getProperties(url); 644 if (newProps != null) { 645 if (props == null) { 646 propsUrl = url; 647 props = newProps; 648 final String priorityStr = props.getProperty(PRIORITY_KEY); 649 priority = 0.0; 650 if (priorityStr != null) { 651 priority = Double.parseDouble(priorityStr); 652 } 653 654 if (isDiagnosticsEnabled()) { 655 logDiagnostic("[LOOKUP] Properties file found at '" + url + "'" + " with priority " + priority); 656 } 657 } else { 658 final String newPriorityStr = newProps.getProperty(PRIORITY_KEY); 659 double newPriority = 0.0; 660 if (newPriorityStr != null) { 661 newPriority = Double.parseDouble(newPriorityStr); 662 } 663 664 if (newPriority > priority) { 665 if (isDiagnosticsEnabled()) { 666 logDiagnostic("[LOOKUP] Properties file at '" + url + "'" + " with priority " + newPriority + " overrides file at '" + propsUrl 667 + "'" + " with priority " + priority); 668 } 669 670 propsUrl = url; 671 props = newProps; 672 priority = newPriority; 673 } else if (isDiagnosticsEnabled()) { 674 logDiagnostic("[LOOKUP] Properties file at '" + url + "'" + " with priority " + newPriority + " does not override file at '" 675 + propsUrl + "'" + " with priority " + priority); 676 } 677 } 678 679 } 680 } 681 } catch (final SecurityException e) { 682 if (isDiagnosticsEnabled()) { 683 logDiagnostic("SecurityException thrown while trying to find/read config files."); 684 } 685 } 686 687 if (isDiagnosticsEnabled()) { 688 if (props == null) { 689 logDiagnostic("[LOOKUP] No properties file of name '" + fileName + "' found."); 690 } else { 691 logDiagnostic("[LOOKUP] Properties file of name '" + fileName + "' found at '" + propsUrl + '"'); 692 } 693 } 694 695 return props; 696 } 697 698 /** 699 * Returns the current context class loader. 700 * <p> 701 * In versions prior to 1.1, this method did not use an AccessController. 702 * In version 1.1, an AccessController wrapper was incorrectly added to 703 * this method, causing a minor security flaw. 704 * </p> 705 * <p> 706 * In version 1.1.1 this change was reverted; this method no longer uses 707 * an AccessController. User code wishing to obtain the context class loader 708 * must invoke this method via AccessController.doPrivileged if it needs 709 * support for that. 710 * </p> 711 * 712 * @return the context class loader associated with the current thread, 713 * or null if security doesn't allow it. 714 * @throws LogConfigurationException if there was some weird error while 715 * attempting to get the context class loader. 716 */ 717 protected static ClassLoader getContextClassLoader() throws LogConfigurationException { 718 return directGetContextClassLoader(); 719 } 720 721 /** 722 * Calls LogFactory.directGetContextClassLoader under the control of an 723 * AccessController class. This means that Java code running under a 724 * security manager that forbids access to ClassLoaders will still work 725 * if this class is given appropriate privileges, even when the caller 726 * doesn't have such privileges. Without using an AccessController, the 727 * the entire call stack must have the privilege before the call is 728 * allowed. 729 * 730 * @return the context class loader associated with the current thread, 731 * or null if security doesn't allow it. 732 * @throws LogConfigurationException if there was some weird error while 733 * attempting to get the context class loader. 734 */ 735 private static ClassLoader getContextClassLoaderInternal() throws LogConfigurationException { 736 return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) LogFactory::directGetContextClassLoader); 737 } 738 739 /** 740 * Constructs (if necessary) and return a {@code LogFactory} instance, using the following ordered lookup procedure to determine the name of the 741 * implementation class to be loaded. 742 * <ul> 743 * <li>The {@code org.apache.commons.logging.LogFactory} system property.</li> 744 * <li>The JDK 1.3 Service Discovery mechanism</li> 745 * <li>Use the properties file {@code commons-logging.properties} file, if found in the class path of this class. The configuration file is in standard 746 * {@link java.util.Properties} format and contains the fully qualified name of the implementation class with the key being the system property defined 747 * above.</li> 748 * <li>Fall back to a default implementation class ({@code org.apache.commons.logging.impl.LogFactoryImpl}).</li> 749 * </ul> 750 * <p> 751 * <em>NOTE</em> - If the properties file method of identifying the {@code LogFactory} implementation class is utilized, all of the properties defined in 752 * this file will be set as configuration attributes on the corresponding {@code LogFactory} instance. 753 * </p> 754 * <p> 755 * <em>NOTE</em> - In a multi-threaded environment it is possible that two different instances will be returned for the same class loader environment. 756 * </p> 757 * 758 * @return a {@code LogFactory}. 759 * @throws LogConfigurationException if the implementation class is not available or cannot be instantiated. 760 */ 761 public static LogFactory getFactory() throws LogConfigurationException { 762 // Identify the class loader we will be using 763 final ClassLoader contextClassLoader = getContextClassLoaderInternal(); 764 765 // This is an odd enough situation to report about. This 766 // output will be a nuisance on JDK1.1, as the system 767 // class loader is null in that environment. 768 if (contextClassLoader == null && isDiagnosticsEnabled()) { 769 logDiagnostic("Context class loader is null."); 770 } 771 772 // Return any previously registered factory for this class loader 773 LogFactory factory = getCachedFactory(contextClassLoader); 774 if (factory != null) { 775 return factory; 776 } 777 778 if (isDiagnosticsEnabled()) { 779 logDiagnostic( 780 "[LOOKUP] LogFactory implementation requested for the first time for context class loader " + 781 objectId(contextClassLoader)); 782 logHierarchy("[LOOKUP] ", contextClassLoader); 783 } 784 785 // Load properties file. 786 // 787 // If the properties file exists, then its contents are used as 788 // "attributes" on the LogFactory implementation class. One particular 789 // property may also control which LogFactory concrete subclass is 790 // used, but only if other discovery mechanisms fail.. 791 // 792 // As the properties file (if it exists) will be used one way or 793 // another in the end we may as well look for it first. 794 795 final Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES); 796 797 // Determine whether we will be using the thread context class loader to 798 // load logging classes or not by checking the loaded properties file (if any). 799 ClassLoader baseClassLoader = contextClassLoader; 800 if (props != null) { 801 final String useTCCLStr = props.getProperty(TCCL_KEY); 802 // The Boolean.valueOf(useTCCLStr).booleanValue() formulation 803 // is required for Java 1.2 compatibility. 804 if (useTCCLStr != null && !Boolean.parseBoolean(useTCCLStr)) { 805 // Don't use current context class loader when locating any 806 // LogFactory or Log classes, just use the class that loaded 807 // this abstract class. When this class is deployed in a shared 808 // classpath of a container, it means webapps cannot deploy their 809 // own logging implementations. It also means that it is up to the 810 // implementation whether to load library-specific config files 811 // from the TCCL or not. 812 baseClassLoader = thisClassLoaderRef.get(); 813 } 814 } 815 816 // Determine which concrete LogFactory subclass to use. 817 // First, try a global system property 818 if (isDiagnosticsEnabled()) { 819 logDiagnostic("[LOOKUP] Looking for system property [" + FACTORY_PROPERTY + 820 "] to define the LogFactory subclass to use..."); 821 } 822 823 try { 824 final String factoryClass = getSystemProperty(FACTORY_PROPERTY, null); 825 if (factoryClass != null) { 826 if (isDiagnosticsEnabled()) { 827 logDiagnostic("[LOOKUP] Creating an instance of LogFactory class '" + factoryClass + 828 "' as specified by system property " + FACTORY_PROPERTY); 829 } 830 factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); 831 } else if (isDiagnosticsEnabled()) { 832 logDiagnostic("[LOOKUP] No system property [" + FACTORY_PROPERTY + "] defined."); 833 } 834 } catch (final SecurityException e) { 835 if (isDiagnosticsEnabled()) { 836 logDiagnostic("[LOOKUP] A security exception occurred while trying to create an" + 837 " instance of the custom factory class" + ": [" + trim(e.getMessage()) + 838 "]. Trying alternative implementations..."); 839 } 840 // ignore 841 } catch (final RuntimeException e) { 842 // This is not consistent with the behavior when a bad LogFactory class is 843 // specified in a services file. 844 // 845 // One possible exception that can occur here is a ClassCastException when 846 // the specified class wasn't castable to this LogFactory type. 847 if (isDiagnosticsEnabled()) { 848 logDiagnostic("[LOOKUP] An exception occurred while trying to create an" + 849 " instance of the custom factory class" + ": [" + 850 trim(e.getMessage()) + 851 "] as specified by a system property."); 852 } 853 throw e; 854 } 855 856 // Second, try to find a service by using the JDK 1.3 class 857 // discovery mechanism, which involves putting a file with the name 858 // of an interface class in the META-INF/services directory, where the 859 // contents of the file is a single line specifying a concrete class 860 // that implements the desired interface. 861 862 if (factory == null) { 863 if (isDiagnosticsEnabled()) { 864 logDiagnostic("[LOOKUP] Using ServiceLoader to define the LogFactory subclass to use..."); 865 } 866 try { 867 final ServiceLoader<LogFactory> serviceLoader = ServiceLoader.load(LogFactory.class); 868 final Iterator<LogFactory> iterator = serviceLoader.iterator(); 869 870 int i = MAX_BROKEN_SERVICES; 871 while (factory == null && i-- > 0) { 872 try { 873 if (iterator.hasNext()) { 874 factory = iterator.next(); 875 } 876 } catch (final ServiceConfigurationError | LinkageError ex) { 877 if (isDiagnosticsEnabled()) { 878 logDiagnostic("[LOOKUP] An exception occurred while trying to find an" + 879 " instance of LogFactory" + 880 ": [" + trim(ex.getMessage()) + 881 "]. Trying alternative implementations..."); 882 } 883 } 884 } 885 } catch (final Exception ex) { 886 // note: if the specified LogFactory class wasn't compatible with LogFactory 887 // for some reason, a ClassCastException will be caught here, and attempts will 888 // continue to find a compatible class. 889 if (isDiagnosticsEnabled()) { 890 logDiagnostic( 891 "[LOOKUP] A security exception occurred while trying to create an" + 892 " instance of the custom factory class" + 893 ": [" + trim(ex.getMessage()) + 894 "]. Trying alternative implementations..."); 895 } 896 // ignore 897 } 898 } 899 900 // Third try looking into the properties file read earlier (if found) 901 902 if (factory == null) { 903 if (props != null) { 904 if (isDiagnosticsEnabled()) { 905 logDiagnostic( 906 "[LOOKUP] Looking in properties file for entry with key '" + FACTORY_PROPERTY + 907 "' to define the LogFactory subclass to use..."); 908 } 909 final String factoryClass = props.getProperty(FACTORY_PROPERTY); 910 if (factoryClass != null) { 911 if (isDiagnosticsEnabled()) { 912 logDiagnostic( 913 "[LOOKUP] Properties file specifies LogFactory subclass '" + factoryClass + "'"); 914 } 915 factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); 916 917 // TODO: think about whether we need to handle exceptions from newFactory 918 } else if (isDiagnosticsEnabled()) { 919 logDiagnostic("[LOOKUP] Properties file has no entry specifying LogFactory subclass."); 920 } 921 } else if (isDiagnosticsEnabled()) { 922 logDiagnostic("[LOOKUP] No properties file available to determine" + " LogFactory subclass from.."); 923 } 924 } 925 926 // Fourth, try one of the 3 provided factories 927 928 try { 929 // We prefer Log4j API, since it does not stringify objects. 930 if (factory == null && isClassAvailable(LOG4J_API_LOGGER, baseClassLoader)) { 931 // If the Log4j API is redirected to SLF4J, we use SLF4J directly. 932 if (isClassAvailable(LOG4J_TO_SLF4J_BRIDGE, baseClassLoader)) { 933 logDiagnostic( 934 "[LOOKUP] Log4j API to SLF4J redirection detected. Loading the SLF4J LogFactory implementation '" + FACTORY_SLF4J + "'."); 935 factory = newFactory(FACTORY_SLF4J, baseClassLoader, contextClassLoader); 936 } else { 937 logDiagnostic("[LOOKUP] Log4j API detected. Loading the Log4j API LogFactory implementation '" + FACTORY_LOG4J_API + "'."); 938 factory = newFactory(FACTORY_LOG4J_API, baseClassLoader, contextClassLoader); 939 } 940 } 941 942 if (factory == null && isClassAvailable(SLF4J_API_LOGGER, baseClassLoader)) { 943 logDiagnostic("[LOOKUP] SLF4J detected. Loading the SLF4J LogFactory implementation '" + FACTORY_SLF4J + "'."); 944 factory = newFactory(FACTORY_SLF4J, baseClassLoader, contextClassLoader); 945 } 946 } catch (final Exception e) { 947 logDiagnostic("[LOOKUP] An exception occurred while creating LogFactory: " + e.getMessage()); 948 } 949 950 if (factory == null) { 951 if (isDiagnosticsEnabled()) { 952 logDiagnostic( 953 "[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT + 954 "' via the same class loader that loaded this LogFactory" + 955 " class (ie not looking in the context class loader)."); 956 } 957 958 // Note: unlike the above code which can try to load custom LogFactory 959 // implementations via the TCCL, we don't try to load the default LogFactory 960 // implementation via the context class loader because: 961 // * that can cause problems (see comments in newFactory method) 962 // * no-one should be customising the code of the default class 963 // Yes, we do give up the ability for the child to ship a newer 964 // version of the LogFactoryImpl class and have it used dynamically 965 // by an old LogFactory class in the parent, but that isn't 966 // necessarily a good idea anyway. 967 factory = newFactory(FACTORY_DEFAULT, thisClassLoaderRef.get(), contextClassLoader); 968 } 969 970 if (factory != null) { 971 /** 972 * Always cache using context class loader. 973 */ 974 cacheFactory(contextClassLoader, factory); 975 976 if (props != null) { 977 final Enumeration<?> names = props.propertyNames(); 978 while (names.hasMoreElements()) { 979 final String name = Objects.toString(names.nextElement(), null); 980 final String value = props.getProperty(name); 981 factory.setAttribute(name, value); 982 } 983 } 984 } 985 986 return factory; 987 } 988 989 /** 990 * Convenience method to return a named logger, without the application having to care about factories. 991 * 992 * @param clazz Class from which a log name will be derived 993 * @return a named logger. 994 * @throws LogConfigurationException if a suitable {@code Log} instance cannot be returned 995 */ 996 public static Log getLog(final Class<?> clazz) throws LogConfigurationException { 997 return getFactory().getInstance(clazz); 998 } 999 1000 /** 1001 * Convenience method to return a named logger, without the application having to care about factories. 1002 * 1003 * @param name Logical name of the {@code Log} instance to be returned (the meaning of this name is only known to the underlying logging implementation that 1004 * is being wrapped) 1005 * @return a named logger. 1006 * @throws LogConfigurationException if a suitable {@code Log} instance cannot be returned 1007 */ 1008 public static Log getLog(final String name) throws LogConfigurationException { 1009 return getFactory().getInstance(name); 1010 } 1011 1012 /** 1013 * Given a URL that refers to a .properties file, load that file. 1014 * This is done under an AccessController so that this method will 1015 * succeed when this jarfile is privileged but the caller is not. 1016 * This method must therefore remain private to avoid security issues. 1017 * <p> 1018 * {@code Null} is returned if the URL cannot be opened. 1019 * </p> 1020 */ 1021 private static Properties getProperties(final URL url) { 1022 return AccessController.doPrivileged((PrivilegedAction<Properties>) () -> { 1023 // We must ensure that useCaches is set to false, as the 1024 // default behavior of java is to cache file handles, and 1025 // this "locks" files, preventing hot-redeploy on windows. 1026 try { 1027 final URLConnection connection = url.openConnection(); 1028 connection.setUseCaches(false); 1029 try (InputStream stream = connection.getInputStream()) { 1030 if (stream != null) { 1031 final Properties props = new Properties(); 1032 props.load(stream); 1033 return props; 1034 } 1035 } catch (final IOException e) { 1036 if (isDiagnosticsEnabled()) { 1037 logDiagnostic("Unable to close stream for URL " + url); 1038 } 1039 } 1040 } catch (final IOException e) { 1041 if (isDiagnosticsEnabled()) { 1042 logDiagnostic("Unable to read URL " + url); 1043 } 1044 } 1045 1046 return null; 1047 }); 1048 } 1049 1050 /** 1051 * Given a file name, return an enumeration of URLs pointing to 1052 * all the occurrences of that file name in the classpath. 1053 * <p> 1054 * This is just like ClassLoader.getResources except that the 1055 * operation is done under an AccessController so that this method will 1056 * succeed when this jarfile is privileged but the caller is not. 1057 * This method must therefore remain private to avoid security issues. 1058 * </p> 1059 * <p> 1060 * If no instances are found, an Enumeration is returned whose 1061 * hasMoreElements method returns false (ie an "empty" enumeration). 1062 * If resources could not be listed for some reason, null is returned. 1063 * </p> 1064 */ 1065 private static Enumeration<URL> getResources(final ClassLoader loader, final String name) { 1066 return AccessController.doPrivileged((PrivilegedAction<Enumeration<URL>>) () -> { 1067 try { 1068 if (loader != null) { 1069 return loader.getResources(name); 1070 } 1071 return ClassLoader.getSystemResources(name); 1072 } catch (final IOException e) { 1073 if (isDiagnosticsEnabled()) { 1074 logDiagnostic("Exception while trying to find configuration file " + name + ":" + e.getMessage()); 1075 } 1076 return null; 1077 } catch (final NoSuchMethodError e) { 1078 // we must be running on a 1.1 JVM which doesn't support 1079 // ClassLoader.getSystemResources; just return null in 1080 // this case. 1081 return null; 1082 } 1083 }); 1084 } 1085 1086 /** 1087 * Read the specified system property, using an AccessController so that 1088 * the property can be read if JCL has been granted the appropriate 1089 * security rights even if the calling code has not. 1090 * <p> 1091 * Take care not to expose the value returned by this method to the 1092 * calling application in any way; otherwise the calling app can use that 1093 * info to access data that should not be available to it. 1094 * </p> 1095 */ 1096 private static String getSystemProperty(final String key, final String def) 1097 throws SecurityException { 1098 return AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty(key, def)); 1099 } 1100 1101 /** 1102 * Checks whether the supplied Throwable is one that needs to be 1103 * re-thrown and ignores all others. 1104 * 1105 * The following errors are re-thrown: 1106 * <ul> 1107 * <li>ThreadDeath</li> 1108 * <li>VirtualMachineError</li> 1109 * </ul> 1110 * 1111 * @param t the Throwable to check 1112 */ 1113 protected static void handleThrowable(final Throwable t) { 1114 if (t instanceof ThreadDeath) { 1115 throw (ThreadDeath) t; 1116 } 1117 if (t instanceof VirtualMachineError) { 1118 throw (VirtualMachineError) t; 1119 } 1120 // All other instances of Throwable will be silently ignored 1121 } 1122 1123 /** 1124 * Determines whether the given class actually implements {@code LogFactory}. 1125 * Diagnostic information is also logged. 1126 * <p> 1127 * <strong>Usage:</strong> to diagnose whether a class loader conflict is the cause 1128 * of incompatibility. The test used is whether the class is assignable from 1129 * the {@code LogFactory} class loaded by the class's class loader. 1130 * @param logFactoryClass {@code Class} which may implement {@code LogFactory} 1131 * @return true if the {@code logFactoryClass} does extend 1132 * {@code LogFactory} when that class is loaded via the same 1133 * class loader that loaded the {@code logFactoryClass}. 1134 * </p> 1135 */ 1136 private static boolean implementsLogFactory(final Class<?> logFactoryClass) { 1137 boolean implementsLogFactory = false; 1138 if (logFactoryClass != null) { 1139 try { 1140 final ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader(); 1141 if (logFactoryClassLoader == null) { 1142 logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot class loader"); 1143 } else { 1144 logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader); 1145 final Class<?> factoryFromCustomLoader = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader); 1146 implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass); 1147 final String logFactoryClassName = logFactoryClass.getName(); 1148 if (implementsLogFactory) { 1149 logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClassName + " implements LogFactory but was loaded by an incompatible class loader."); 1150 } else { 1151 logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClassName + " does not implement LogFactory."); 1152 } 1153 } 1154 } catch (final SecurityException e) { 1155 // 1156 // The application is running within a hostile security environment. 1157 // This will make it very hard to diagnose issues with JCL. 1158 // Consider running less securely whilst debugging this issue. 1159 // 1160 logDiagnostic("[CUSTOM LOG FACTORY] SecurityException caught trying to determine whether " 1161 + "the compatibility was caused by a class loader conflict: " + e.getMessage()); 1162 } catch (final LinkageError e) { 1163 // 1164 // This should be an unusual circumstance. 1165 // LinkageError's usually indicate that a dependent class has incompatibly changed. 1166 // Another possibility may be an exception thrown by an initializer. 1167 // Time for a clean rebuild? 1168 // 1169 logDiagnostic("[CUSTOM LOG FACTORY] LinkageError caught trying to determine whether " 1170 + "the compatibility was caused by a class loader conflict: " + e.getMessage()); 1171 } catch (final ClassNotFoundException e) { 1172 // 1173 // LogFactory cannot be loaded by the class loader which loaded the custom factory implementation. 1174 // The custom implementation is not viable until this is corrected. 1175 // Ensure that the JCL jar and the custom class are available from the same class loader. 1176 // Running with diagnostics on should give information about the class loaders used 1177 // to load the custom factory. 1178 // 1179 logDiagnostic("[CUSTOM LOG FACTORY] LogFactory class cannot be loaded by the class loader which loaded " 1180 + "the custom LogFactory implementation. Is the custom factory in the right class loader?"); 1181 } 1182 } 1183 return implementsLogFactory; 1184 } 1185 1186 /** 1187 * Determines whether the user wants internal diagnostic output. If so, 1188 * returns an appropriate writer object. Users can enable diagnostic 1189 * output by setting the system property named {@link #DIAGNOSTICS_DEST_PROPERTY} to 1190 * a file name, or the special values STDOUT or STDERR. 1191 */ 1192 private static PrintStream initDiagnostics() { 1193 String dest; 1194 try { 1195 dest = getSystemProperty(DIAGNOSTICS_DEST_PROPERTY, null); 1196 if (dest == null) { 1197 return null; 1198 } 1199 } catch (final SecurityException ex) { 1200 // We must be running in some very secure environment. 1201 // We just have to assume output is not wanted.. 1202 return null; 1203 } 1204 1205 if (dest.equals("STDOUT")) { 1206 return System.out; 1207 } 1208 if (dest.equals("STDERR")) { 1209 return System.err; 1210 } 1211 try { 1212 // open the file in append mode 1213 final FileOutputStream fos = new FileOutputStream(dest, true); 1214 return new PrintStream(fos, false, StandardCharsets.UTF_8.name()); 1215 } catch (final IOException ex) { 1216 // We should report this to the user - but how? 1217 return null; 1218 } 1219 } 1220 1221 private static boolean isClassAvailable(final String className, final ClassLoader classLoader) { 1222 final ClassLoader loader = LogFactory.class.getClassLoader(); 1223 logDiagnostic("Checking if class '" + className + "' is available in class loader " + objectId(loader)); 1224 try { 1225 Class.forName(className, true, classLoader); 1226 return true; 1227 } catch (final ClassNotFoundException | LinkageError e) { 1228 logDiagnostic("Failed to load class '" + className + "' from class loader " + objectId(loader) + ": " + e.getMessage()); 1229 } 1230 return false; 1231 } 1232 1233 /** 1234 * Indicates true if the user has enabled internal logging. 1235 * <p> 1236 * By the way, sorry for the incorrect grammar, but calling this method 1237 * areDiagnosticsEnabled just isn't Java beans style. 1238 * </p> 1239 * 1240 * @return true if calls to logDiagnostic will have any effect. 1241 * @since 1.1 1242 */ 1243 protected static boolean isDiagnosticsEnabled() { 1244 return DIAGNOSTICS_STREAM != null; 1245 } 1246 1247 /** 1248 * Generates useful diagnostics regarding the class loader tree for 1249 * the specified class. 1250 * <p> 1251 * As an example, if the specified class was loaded via a webapp's 1252 * class loader, then you may get the following output: 1253 * </p> 1254 * <pre> 1255 * Class com.acme.Foo was loaded via class loader 11111 1256 * ClassLoader tree: 11111 -> 22222 (SYSTEM) -> 33333 -> BOOT 1257 * </pre> 1258 * <p> 1259 * This method returns immediately if isDiagnosticsEnabled() 1260 * returns false. 1261 * </p> 1262 * 1263 * @param clazz is the class whose class loader + tree are to be 1264 * output. 1265 */ 1266 private static void logClassLoaderEnvironment(final Class<?> clazz) { 1267 if (!isDiagnosticsEnabled()) { 1268 return; 1269 } 1270 1271 try { 1272 // Deliberately use System.getProperty here instead of getSystemProperty; if 1273 // the overall security policy for the calling application forbids access to 1274 // these variables then we do not want to output them to the diagnostic stream. 1275 logDiagnostic("[ENV] Extension directories (java.ext.dir): " + System.getProperty("java.ext.dir")); 1276 logDiagnostic("[ENV] Application classpath (java.class.path): " + System.getProperty("java.class.path")); 1277 } catch (final SecurityException ex) { 1278 logDiagnostic("[ENV] Security setting prevent interrogation of system classpaths."); 1279 } 1280 1281 final String className = clazz.getName(); 1282 ClassLoader classLoader; 1283 1284 try { 1285 classLoader = getClassLoader(clazz); 1286 } catch (final SecurityException ex) { 1287 // not much useful diagnostics we can print here! 1288 logDiagnostic("[ENV] Security forbids determining the class loader for " + className); 1289 return; 1290 } 1291 1292 logDiagnostic("[ENV] Class " + className + " was loaded via class loader " + objectId(classLoader)); 1293 logHierarchy("[ENV] Ancestry of class loader which loaded " + className + " is ", classLoader); 1294 } 1295 1296 /** 1297 * Write the specified message to the internal logging destination. 1298 * <p> 1299 * Note that this method is private; concrete subclasses of this class 1300 * should not call it because the diagnosticPrefix string this 1301 * method puts in front of all its messages is LogFactory@...., 1302 * while subclasses should put SomeSubClass@... 1303 * </p> 1304 * <p> 1305 * Subclasses should instead compute their own prefix, then call 1306 * logRawDiagnostic. Note that calling isDiagnosticsEnabled is 1307 * fine for subclasses. 1308 * </p> 1309 * <p> 1310 * Note that it is safe to call this method before initDiagnostics 1311 * is called; any output will just be ignored (as isDiagnosticsEnabled 1312 * will return false). 1313 * </p> 1314 * 1315 * @param msg is the diagnostic message to be output. 1316 */ 1317 private static void logDiagnostic(final String msg) { 1318 if (DIAGNOSTICS_STREAM != null) { 1319 DIAGNOSTICS_STREAM.print(diagnosticPrefix); 1320 DIAGNOSTICS_STREAM.println(msg); 1321 DIAGNOSTICS_STREAM.flush(); 1322 } 1323 } 1324 1325 /** 1326 * Logs diagnostic messages about the given class loader 1327 * and it's hierarchy. The prefix is prepended to the message 1328 * and is intended to make it easier to understand the logs. 1329 * @param prefix 1330 * @param classLoader 1331 */ 1332 private static void logHierarchy(final String prefix, ClassLoader classLoader) { 1333 if (!isDiagnosticsEnabled()) { 1334 return; 1335 } 1336 ClassLoader systemClassLoader; 1337 if (classLoader != null) { 1338 final String classLoaderString = classLoader.toString(); 1339 logDiagnostic(prefix + objectId(classLoader) + " == '" + classLoaderString + "'"); 1340 } 1341 1342 try { 1343 systemClassLoader = ClassLoader.getSystemClassLoader(); 1344 } catch (final SecurityException ex) { 1345 logDiagnostic(prefix + "Security forbids determining the system class loader."); 1346 return; 1347 } 1348 if (classLoader != null) { 1349 final StringBuilder buf = new StringBuilder(prefix + "ClassLoader tree:"); 1350 for(;;) { 1351 buf.append(objectId(classLoader)); 1352 if (classLoader == systemClassLoader) { 1353 buf.append(" (SYSTEM) "); 1354 } 1355 1356 try { 1357 classLoader = classLoader.getParent(); 1358 } catch (final SecurityException ex) { 1359 buf.append(" --> SECRET"); 1360 break; 1361 } 1362 1363 buf.append(" --> "); 1364 if (classLoader == null) { 1365 buf.append("BOOT"); 1366 break; 1367 } 1368 } 1369 logDiagnostic(buf.toString()); 1370 } 1371 } 1372 1373 /** 1374 * Writes the specified message to the internal logging destination. 1375 * 1376 * @param msg is the diagnostic message to be output. 1377 * @since 1.1 1378 */ 1379 protected static final void logRawDiagnostic(final String msg) { 1380 if (DIAGNOSTICS_STREAM != null) { 1381 DIAGNOSTICS_STREAM.println(msg); 1382 DIAGNOSTICS_STREAM.flush(); 1383 } 1384 } 1385 1386 /** 1387 * Method provided for backwards compatibility; see newFactory version that 1388 * takes 3 parameters. 1389 * <p> 1390 * This method would only ever be called in some rather odd situation. 1391 * Note that this method is static, so overriding in a subclass doesn't 1392 * have any effect unless this method is called from a method in that 1393 * subclass. However this method only makes sense to use from the 1394 * getFactory method, and as that is almost always invoked via 1395 * LogFactory.getFactory, any custom definition in a subclass would be 1396 * pointless. Only a class with a custom getFactory method, then invoked 1397 * directly via CustomFactoryImpl.getFactory or similar would ever call 1398 * this. Anyway, it's here just in case, though the "managed class loader" 1399 * value output to the diagnostics will not report the correct value. 1400 * </p> 1401 * 1402 * @param factoryClass factory class. 1403 * @param classLoader class loader. 1404 * @return a LogFactory. 1405 */ 1406 protected static LogFactory newFactory(final String factoryClass, 1407 final ClassLoader classLoader) { 1408 return newFactory(factoryClass, classLoader, null); 1409 } 1410 1411 /** 1412 * Gets a new instance of the specified {@code LogFactory} implementation class, loaded by the specified class loader. If that fails, try the class loader 1413 * used to load this (abstract) LogFactory. 1414 * <p> 1415 * <b>ClassLoader conflicts</b> 1416 * </p> 1417 * <p> 1418 * Note that there can be problems if the specified ClassLoader is not the same as the class loader that loaded this class, that is, when loading a concrete 1419 * LogFactory subclass via a context class loader. 1420 * </p> 1421 * <p> 1422 * The problem is the same one that can occur when loading a concrete Log subclass via a context class loader. 1423 * </p> 1424 * <p> 1425 * The problem occurs when code running in the context class loader calls class X which was loaded via a parent class loader, and class X then calls 1426 * LogFactory.getFactory (either directly or via LogFactory.getLog). Because class X was loaded via the parent, it binds to LogFactory loaded via the 1427 * parent. When the code in this method finds some LogFactoryYYYY class in the child (context) class loader, and there also happens to be a LogFactory class 1428 * defined in the child class loader, then LogFactoryYYYY will be bound to LogFactory@childloader. It cannot be cast to LogFactory@parentloader, that is, 1429 * this method cannot return the object as the desired type. Note that it doesn't matter if the LogFactory class in the child class loader is identical to 1430 * the LogFactory class in the parent class loader, they are not compatible. 1431 * </p> 1432 * <p> 1433 * The solution taken here is to simply print out an error message when this occurs then throw an exception. The deployer of the application must ensure 1434 * they remove all occurrences of the LogFactory class from the child class loader in order to resolve the issue. Note that they do not have to move the 1435 * custom LogFactory subclass; that is ok as long as the only LogFactory class it can find to bind to is in the parent class loader. 1436 * </p> 1437 * 1438 * @param factoryClass Fully qualified name of the {@code LogFactory} implementation class 1439 * @param classLoader ClassLoader from which to load this class 1440 * @param contextClassLoader is the context that this new factory will manage logging for. 1441 * @return a new instance of the specified {@code LogFactory}. 1442 * @throws LogConfigurationException if a suitable instance cannot be created 1443 * @since 1.1 1444 */ 1445 protected static LogFactory newFactory(final String factoryClass, 1446 final ClassLoader classLoader, 1447 final ClassLoader contextClassLoader) 1448 throws LogConfigurationException { 1449 // Note that any unchecked exceptions thrown by the createFactory 1450 // method will propagate out of this method; in particular a 1451 // ClassCastException can be thrown. 1452 final Object result = AccessController.doPrivileged((PrivilegedAction<?>) () -> createFactory(factoryClass, classLoader)); 1453 1454 if (result instanceof LogConfigurationException) { 1455 final LogConfigurationException ex = (LogConfigurationException) result; 1456 if (isDiagnosticsEnabled()) { 1457 logDiagnostic("An error occurred while loading the factory class:" + ex.getMessage()); 1458 } 1459 throw ex; 1460 } 1461 if (isDiagnosticsEnabled()) { 1462 logDiagnostic("Created object " + objectId(result) + " to manage class loader " + objectId(contextClassLoader)); 1463 } 1464 return (LogFactory) result; 1465 } 1466 1467 /** 1468 * Returns a string that uniquely identifies the specified object, including 1469 * its class. 1470 * <p> 1471 * The returned string is of form "className@hashCode", that is, is the same as 1472 * the return value of the Object.toString() method, but works even when 1473 * the specified object's class has overridden the toString method. 1474 * </p> 1475 * 1476 * @param o may be null. 1477 * @return a string of form className@hashCode, or "null" if param o is null. 1478 * @since 1.1 1479 */ 1480 public static String objectId(final Object o) { 1481 if (o == null) { 1482 return "null"; 1483 } 1484 return o.getClass().getName() + "@" + System.identityHashCode(o); 1485 } 1486 1487 /** 1488 * Releases any internal references to previously created {@link LogFactory} 1489 * instances that have been associated with the specified class loader 1490 * (if any), after calling the instance method {@code release()} on 1491 * each of them. 1492 * 1493 * @param classLoader ClassLoader for which to release the LogFactory 1494 */ 1495 public static void release(final ClassLoader classLoader) { 1496 if (isDiagnosticsEnabled()) { 1497 logDiagnostic("Releasing factory for class loader " + objectId(classLoader)); 1498 } 1499 // factories is not final and could be replaced in this block. 1500 final Hashtable<ClassLoader, LogFactory> factories = LogFactory.factories; 1501 synchronized (factories) { 1502 if (classLoader == null) { 1503 if (nullClassLoaderFactory != null) { 1504 nullClassLoaderFactory.release(); 1505 nullClassLoaderFactory = null; 1506 } 1507 } else { 1508 final LogFactory factory = factories.get(classLoader); 1509 if (factory != null) { 1510 factory.release(); 1511 factories.remove(classLoader); 1512 } 1513 } 1514 } 1515 } 1516 1517 /** 1518 * Release any internal references to previously created {@link LogFactory} 1519 * instances, after calling the instance method {@code release()} on 1520 * each of them. This is useful in environments like servlet containers, 1521 * which implement application reloading by throwing away a ClassLoader. 1522 * Dangling references to objects in that class loader would prevent 1523 * garbage collection. 1524 */ 1525 public static void releaseAll() { 1526 if (isDiagnosticsEnabled()) { 1527 logDiagnostic("Releasing factory for all class loaders."); 1528 } 1529 // factories is not final and could be replaced in this block. 1530 final Hashtable<ClassLoader, LogFactory> factories = LogFactory.factories; 1531 synchronized (factories) { 1532 factories.values().forEach(LogFactory::release); 1533 factories.clear(); 1534 1535 if (nullClassLoaderFactory != null) { 1536 nullClassLoaderFactory.release(); 1537 nullClassLoaderFactory = null; 1538 } 1539 } 1540 } 1541 1542 /** Utility method to safely trim a string. */ 1543 private static String trim(final String src) { 1544 if (src == null) { 1545 return null; 1546 } 1547 return src.trim(); 1548 } 1549 1550 /** 1551 * Protected constructor that is not available for public use. 1552 */ 1553 protected LogFactory() { 1554 } 1555 1556 /** 1557 * Gets the configuration attribute with the specified name (if any), 1558 * or {@code null} if there is no such attribute. 1559 * 1560 * @param name Name of the attribute to return 1561 * @return the configuration attribute with the specified name. 1562 */ 1563 public abstract Object getAttribute(String name); 1564 1565 /** 1566 * Gets an array containing the names of all currently defined configuration attributes. If there are no such attributes, a zero length array is returned. 1567 * 1568 * @return an array containing the names of all currently defined configuration attributes 1569 */ 1570 public abstract String[] getAttributeNames(); 1571 1572 /** 1573 * Convenience method to derive a name from the specified class and call {@code getInstance(String)} with it. 1574 * 1575 * @param clazz Class for which a suitable Log name will be derived 1576 * @return a name from the specified class. 1577 * @throws LogConfigurationException if a suitable {@code Log} instance cannot be returned 1578 */ 1579 public abstract Log getInstance(Class<?> clazz) throws LogConfigurationException; 1580 1581 /** 1582 * Constructs (if necessary) and return a {@code Log} instance, using the factory's current set of configuration attributes. 1583 * <p> 1584 * <strong>NOTE</strong> - Depending upon the implementation of the {@code LogFactory} you are using, the {@code Log} instance you are returned may or may 1585 * not be local to the current application, and may or may not be returned again on a subsequent call with the same name argument. 1586 * </p> 1587 * 1588 * @param name Logical name of the {@code Log} instance to be returned (the meaning of this name is only known to the underlying logging implementation that 1589 * is being wrapped) 1590 * @return a {@code Log} instance. 1591 * @throws LogConfigurationException if a suitable {@code Log} instance cannot be returned 1592 */ 1593 public abstract Log getInstance(String name) 1594 throws LogConfigurationException; 1595 1596 /** 1597 * Releases any internal references to previously created {@link Log} 1598 * instances returned by this factory. This is useful in environments 1599 * like servlet containers, which implement application reloading by 1600 * throwing away a ClassLoader. Dangling references to objects in that 1601 * class loader would prevent garbage collection. 1602 */ 1603 public abstract void release(); 1604 1605 /** 1606 * Removes any configuration attribute associated with the specified name. 1607 * If there is no such attribute, no action is taken. 1608 * 1609 * @param name Name of the attribute to remove 1610 */ 1611 public abstract void removeAttribute(String name); 1612 1613 // 1614 // We can't do this in the class constructor, as there are many 1615 // static methods on this class that can be called before any 1616 // LogFactory instances are created, and they depend upon this 1617 // stuff having been set up. 1618 // 1619 // Note that this block must come after any variable declarations used 1620 // by any methods called from this block, as we want any static initializer 1621 // associated with the variable to run first. If static initializers for 1622 // variables run after this code, then (a) their value might be needed 1623 // by methods called from here, and (b) they might *override* any value 1624 // computed here! 1625 // 1626 // So the wisest thing to do is just to place this code at the very end 1627 // of the class file. 1628 1629 /** 1630 * Sets the configuration attribute with the specified name. Calling 1631 * this with a {@code null} value is equivalent to calling 1632 * {@code removeAttribute(name)}. 1633 * 1634 * @param name Name of the attribute to set 1635 * @param value Value of the attribute to set, or {@code null} 1636 * to remove any setting for this attribute 1637 */ 1638 public abstract void setAttribute(String name, Object value); 1639 1640}