001    package org.apache.ojb.broker.util.logging;
002    
003    /* Copyright 2002-2005 The Apache Software Foundation
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * 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    
018    import java.util.HashMap;
019    import java.util.Map;
020    
021    import org.apache.ojb.broker.util.ClassHelper;
022    import org.apache.commons.lang.SystemUtils;
023    
024    /**
025     * The factory class <code>LoggerFactory</code> can be used
026     * to create <code>Logger</code> instances.
027     * The <code>Logger</code>-implementation class served
028     * by the factory is configured by settings in the
029     * OJB.properties file.
030     *
031     * @author Thomas Mahler
032     * @author <a href="leandro@ibnetwork.com.br">Leandro Rodrigo Saad Cruz</a>
033     * @version $Id: LoggerFactoryImpl.java,v 1.1 2007-08-24 22:17:32 ewestfal Exp $
034     * @see <a href="http://jakarta.apache.org/log4j/docs/index.html">jakarta-log4j</a>
035     */
036    public class LoggerFactoryImpl
037    {
038        public static final String BOOT_LOG_LEVEL_STR = "OJB.bootLogLevel";
039        protected static final String BOOT_STR = "BOOT";
040        protected static final String DEFAULT_STR = "DEFAULT";
041        protected static final LoggerFactoryImpl INSTANCE = new LoggerFactoryImpl();
042    
043        private Logger defaultLogger = null;
044    
045        private Logger bootLogger = null;
046    
047        private boolean bootLoggerIsReassigned = false;
048    
049        /** Used for caching logger instances */
050        private Map cache = new HashMap();
051        /** The configuration */
052        private LoggingConfiguration conf;
053    
054        // yes. it's a singleton !
055        private LoggerFactoryImpl()
056        {
057        }
058    
059        public static LoggerFactoryImpl getInstance()
060        {
061            return INSTANCE;
062        }
063    
064        private LoggingConfiguration getConfiguration()
065        {
066            if(conf == null)
067            {
068                // this will load the configuration
069                conf = new LoggingConfiguration();
070            }
071            return conf;
072        }
073    
074        /**
075         * returns a minimal logger that needs no configuration
076         * and can thus be safely used during OJB boot phase
077         * (i.e. when OJB.properties have not been loaded).
078         *
079         * @return Logger the OJB BootLogger
080         */
081        public Logger getBootLogger()
082        {
083            if(bootLogger == null)
084            {
085                // create a StringBuffer based Logger for boot log operations
086                bootLogger = createStringBufferLogger_Boot();
087            }
088            return bootLogger;
089        }
090    
091    
092        /**
093         * returns the default logger. This Logger can
094         * be used when it is not appropriate to use a
095         * dedicated fresh Logger instance.
096         *
097         * @return default Logger
098         */
099        public Logger getDefaultLogger()
100        {
101            if(defaultLogger == null)
102            {
103                defaultLogger = getLogger(DEFAULT_STR);
104            }
105            return defaultLogger;
106        }
107    
108    
109        /**
110         * returns a Logger. The Logger is named
111         * after the full qualified name of input parameter clazz
112         *
113         * @param clazz the Class which name is to be used as name
114         * @return Logger the returned Logger
115         */
116        public Logger getLogger(Class clazz)
117        {
118            return getLogger(clazz.getName());
119        }
120    
121    
122        /**
123         * returns a Logger.
124         *
125         * @param loggerName the name of the Logger
126         * @return Logger the returned Logger
127         */
128        public Logger getLogger(String loggerName)
129        {
130            Logger logger;
131            //lookup in the cache first
132            logger = (Logger) cache.get(loggerName);
133    
134            if(logger == null)
135            {
136                try
137                {
138                    // get the configuration (not from the configurator because this is independent)
139                    logger = createLoggerInstance(loggerName);
140                    if(getBootLogger().isDebugEnabled())
141                    {
142                        getBootLogger().debug("Using logger class '"
143                                + (getConfiguration() != null ? getConfiguration().getLoggerClass() : null)
144                                + "' for " + loggerName);
145                    }
146                    // configure the logger
147                    getBootLogger().debug("Initializing logger instance " + loggerName);
148                    logger.configure(conf);
149                }
150                catch(Throwable t)
151                {
152                    // do reassign check and signal logger creation failure
153                    reassignBootLogger(true);
154                    logger = getBootLogger();
155                    getBootLogger().error("[" + this.getClass().getName()
156                                + "] Could not initialize logger " + (conf != null ? conf.getLoggerClass() : null), t);
157                }
158                //cache it so we can get it faster the next time
159                cache.put(loggerName, logger);
160                // do reassign check
161                reassignBootLogger(false);
162            }
163            return logger;
164        }
165    
166        /**
167         * Creates a new Logger instance for the specified name.
168         */
169        private Logger createLoggerInstance(String loggerName) throws Exception
170        {
171            Class loggerClass = getConfiguration().getLoggerClass();
172            Logger log = (Logger) ClassHelper.newInstance(loggerClass, String.class, loggerName);
173            log.configure(getConfiguration());
174            return log;
175        }
176    
177        /**
178         *
179         * @param forceError
180         */
181        protected synchronized void reassignBootLogger(boolean forceError)
182        {
183            // if the boot logger was already reassigned do nothing
184            if(!bootLoggerIsReassigned)
185            {
186                Logger newBootLogger = null;
187                String name = getBootLogger().getName();
188                try
189                {
190                    // 1. try to use a Logger instance based on the configuration files
191                    newBootLogger = createLoggerInstance(name);
192                }
193                catch(Exception e) {/*ignore*/}
194                if(newBootLogger == null)
195                {
196                    // 2. if no logging library can be found, use OJB's console logger
197                    newBootLogger = createPoorMansLogger_Boot();
198                }
199                if(getBootLogger() instanceof StringBufferLoggerImpl)
200                {
201                    /*
202                    if the StringBuffer based Logger was used for OJB bootstrap process
203                    get the logging statement string and log it on the "real" Logger instance
204                    */
205                    StringBufferLoggerImpl strLogger = (StringBufferLoggerImpl) getBootLogger();
206                    String bootMessage = strLogger.flushLogBuffer();
207                    String eol = SystemUtils.LINE_SEPARATOR;
208                    if(forceError || strLogger.isErrorLog())
209                    {
210                        newBootLogger.error("-- boot log messages -->" + eol + bootMessage);
211                    }
212                    else
213                    {
214                        newBootLogger.info("-- boot log messages -->" + eol + bootMessage);
215                    }
216                }
217                bootLogger = newBootLogger;
218                bootLoggerIsReassigned = true;
219            }
220        }
221    
222        protected Logger createPoorMansLogger_Boot()
223        {
224            Logger bootLogger = new PoorMansLoggerImpl(BOOT_STR);
225            // allow user to set boot log level via system property
226            String level = System.getProperty(BOOT_LOG_LEVEL_STR, LoggingConfiguration.OJB_DEFAULT_BOOT_LOG_LEVEL);
227            ((PoorMansLoggerImpl) bootLogger).setLevel(level);
228            return bootLogger;
229        }
230    
231        protected Logger createStringBufferLogger_Boot()
232        {
233            Logger bootLogger = new StringBufferLoggerImpl(BOOT_STR);
234            // allow user to set boot log level via system property
235            String level = System.getProperty(BOOT_LOG_LEVEL_STR, LoggingConfiguration.OJB_DEFAULT_BOOT_LOG_LEVEL);
236            ((PoorMansLoggerImpl) bootLogger).setLevel(level);
237            return bootLogger;
238        }
239    }