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    package org.apache.commons.discovery.log;
018    
019    import java.lang.reflect.Method;
020    import java.util.Enumeration;
021    import java.util.Hashtable;
022    
023    import org.apache.commons.discovery.DiscoveryException;
024    import org.apache.commons.discovery.tools.ClassUtils;
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    
028    
029    /**
030     * <p>Simple implementation of Log that sends all enabled log messages,
031     * for all defined loggers, to System.err.
032     * </p>
033     * 
034     * <p>Hacked from commons-logging SimpleLog for use in discovery.
035     * This is intended to be enough of a Log implementation to bootstrap
036     * Discovery.
037     * </p>
038     * 
039     * <p>One property: <code>org.apache.commons.discovery.log.level</code>.
040     * valid values: all, trace, debug, info, warn, error, fatal, off.
041     * </p>
042     * 
043     * @author Richard A. Sitze
044     * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
045     * @author Rod Waldhoff
046     * @author Robert Burrell Donkin
047     *
048     * @version $Id: DiscoveryLogFactory.java 480374 2006-11-29 03:33:25Z niallp $
049     */
050    public class DiscoveryLogFactory {
051        private static LogFactory logFactory = null;
052        private static final Hashtable  classRegistry = new Hashtable();
053        private static final Class[] setLogParamClasses = new Class[] { Log.class };
054    
055        /**
056         * Above fields must be initialied before this one..
057         */
058        private static Log log = DiscoveryLogFactory._newLog(DiscoveryLogFactory.class);
059    
060        /**
061         */    
062        public static Log newLog(Class clazz) {
063            /**
064             * Required to implement 'public static void setLog(Log)'
065             */
066            try {
067                Method setLog = ClassUtils.findPublicStaticMethod(clazz,
068                                                                  void.class,
069                                                                  "setLog",
070                                                                  setLogParamClasses);
071                
072                if (setLog == null) {
073                    String msg = "Internal Error: " + clazz.getName() + " required to implement 'public static void setLog(Log)'";
074                    log.fatal(msg);
075                    throw new DiscoveryException(msg);
076                }
077            } catch (SecurityException se) {
078                String msg = "Required Security Permissions not present";
079                log.fatal(msg, se);
080                throw new DiscoveryException(msg, se);
081            }
082    
083            if (log.isDebugEnabled())
084                log.debug("Class meets requirements: " + clazz.getName());
085    
086            return _newLog(clazz);
087        }
088    
089        /**
090         * This method MUST not invoke any logging..
091         */
092        public static Log _newLog(Class clazz) {
093            classRegistry.put(clazz, clazz);
094    
095            return (logFactory == null)
096                   ? new SimpleLog(clazz.getName())
097                   : logFactory.getInstance(clazz.getName());
098        }
099        
100        public static void setLog(Log _log) {
101            log = _log;
102        }
103    
104        /**
105         * Set logFactory, works ONLY on first call.
106         */
107        public static void setFactory(LogFactory factory) {
108            if (logFactory == null) {
109                // for future generations.. if any
110                logFactory = factory;
111                
112                // now, go back and reset loggers for all current classes..
113                Enumeration elements = classRegistry.elements();
114                while (elements.hasMoreElements()) {
115                    Class clazz = (Class)elements.nextElement();
116    
117                    if (log.isDebugEnabled())
118                        log.debug("Reset Log for: " + clazz.getName());
119                    
120                    Method setLog = null;
121                    
122                    // invoke 'setLog(Log)'.. we already know it's 'public static',
123                    // have verified parameters, and return type..
124                    try {
125                        setLog = clazz.getMethod("setLog", setLogParamClasses);
126                    } catch(Exception e) {
127                        String msg = "Internal Error: pre-check for " + clazz.getName() + " failed?!";
128                        log.fatal(msg, e);
129                        throw new DiscoveryException(msg, e);
130                    }
131        
132                    Object[] setLogParam = new Object[] { factory.getInstance(clazz.getName()) };
133                    
134                    try {
135                        setLog.invoke(null, setLogParam);
136                    } catch(Exception e) {
137                        String msg = "Internal Error: setLog failed for " + clazz.getName();
138                        log.fatal(msg, e);
139                        throw new DiscoveryException(msg, e);
140                    }
141                }
142            }
143        }
144    }