001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.common.logging; 017 018import org.modeshape.common.CommonI18n; 019import org.modeshape.common.logging.jdk.JdkLoggerFactory; 020import org.modeshape.common.logging.log4j.Log4jLoggerFactory; 021import org.modeshape.common.logging.slf4j.SLF4JLoggerFactory; 022 023/** 024 * The abstract class for the LogFactory, which is called to create a specific implementation of the {@link Logger}. 025 * <p> 026 * ModeShape provides out of the box several LogFactory implementations that work with common log frameworks: 027 * <ol> 028 * <li>SLF4J (which sits atop several logging frameworks)</li> 029 * <li>Log4J</li> 030 * <li>JDK Util Logging</li> 031 * </ol> 032 * The static initializer for this class checks the classpath for the availability of these frameworks, and as soon as one is 033 * found the LogFactory implementation for that framework is instantiated and used for all ModeShape logging. 034 * </p> 035 * <p> 036 * However, since ModeShape can be embedded into any application, it is possible that applications use a logging framework other 037 * than those listed above. So before falling back to the JDK logging, ModeShape looks for the 038 * <code>org.modeshape.common.logging.CustomLoggerFactory</code> class, and if found attempts to instantiate and use it. But 039 * ModeShape does not provide this class out of the box; rather an application that is embedding ModeShape can provide its own 040 * version of that class that should extend {@link LogFactory} and create an appropriate implementation of {@link Logger} that 041 * forwards ModeShape log messages to the application's logging framework. 042 * </p> 043 */ 044public abstract class LogFactory { 045 046 /** 047 * The name of the {@link LogFactory} implementation that is not provided out of the box but can be created, implemented, and 048 * placed on the classpath to have ModeShape send log messages to a custom framework. 049 */ 050 public static final String CUSTOM_LOG_FACTORY_CLASSNAME = "org.modeshape.common.logging.CustomLoggerFactory"; 051 052 private static LogFactory LOGFACTORY; 053 054 static { 055 Throwable customLoggingError = null; 056 boolean customLogging = false; 057 boolean slf4jLogging = false; 058 boolean log4jLogging = false; 059 060 if (isCustomLoggerAvailable()) { 061 try { 062 @SuppressWarnings( "unchecked" ) 063 Class<LogFactory> customClass = (Class<LogFactory>)Class.forName(CUSTOM_LOG_FACTORY_CLASSNAME); 064 LOGFACTORY = customClass.newInstance(); 065 customLogging = true; 066 } catch (Throwable throwable) { 067 customLoggingError = throwable; 068 } 069 } 070 071 if (LOGFACTORY == null) { 072 if (isSLF4JAvailable()) { 073 LOGFACTORY = new SLF4JLoggerFactory(); 074 slf4jLogging = true; 075 } else if (isLog4jAvailable()) { 076 LOGFACTORY = new Log4jLoggerFactory(); 077 log4jLogging = true; 078 } else { 079 LOGFACTORY = new JdkLoggerFactory(); 080 } 081 } 082 083 Logger logger = LOGFACTORY.getLogger(LogFactory.class.getName()); 084 085 if (customLogging) { 086 logger.info(CommonI18n.customLoggingAvailable, CUSTOM_LOG_FACTORY_CLASSNAME); 087 } else if (slf4jLogging) { 088 logger.info(CommonI18n.slf4jAvailable); 089 } else if (log4jLogging) { 090 logger.info(CommonI18n.log4jAvailable); 091 } else { 092 logger.info(CommonI18n.jdkFallback); 093 } 094 095 if (customLoggingError != null) { 096 // log the problem related to the custom logger 097 logger.warn(customLoggingError, 098 CommonI18n.errorInitializingCustomLoggerFactory, 099 CUSTOM_LOG_FACTORY_CLASSNAME); 100 } 101 } 102 103 private static boolean isSLF4JAvailable() { 104 try { 105 // check if the api is in the classpath and initialize the classes 106 Class.forName("org.slf4j.Logger"); 107 Class.forName("org.slf4j.LoggerFactory"); 108 109 // check if there's at least one implementation and initialize the classes 110 Class.forName("org.slf4j.impl.StaticLoggerBinder"); 111 return true; 112 } catch (ClassNotFoundException e) { 113 return false; 114 } 115 } 116 117 private static boolean isLog4jAvailable() { 118 try { 119 // Check if the Log4J main interface is in the classpath and initialize the class 120 Class.forName("org.apache.log4j.Logger"); 121 return true; 122 } catch (ClassNotFoundException e) { 123 return false; 124 } 125 } 126 127 private static boolean isCustomLoggerAvailable() { 128 try { 129 // Check if a custom log factory implementation is in the classpath and initialize the class 130 Class.forName(CUSTOM_LOG_FACTORY_CLASSNAME); 131 return true; 132 } catch (ClassNotFoundException e) { 133 return false; 134 } 135 } 136 137 static LogFactory getLogFactory() { 138 return LOGFACTORY; 139 } 140 141 /** 142 * Return a logger named corresponding to the class passed as parameter. 143 * 144 * @param clazz the returned logger will be named after clazz 145 * @return logger 146 */ 147 Logger getLogger( Class<?> clazz ) { 148 return Logger.getLogger(clazz.getName()); 149 } 150 151 /** 152 * Return a logger named according to the name parameter. 153 * 154 * @param name The name of the logger. 155 * @return logger 156 */ 157 protected abstract Logger getLogger( String name ); 158 159}