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    
018    package org.apache.commons.logging;
019    
020    import java.lang.reflect.Constructor;
021    import java.util.Hashtable;
022    
023    import org.apache.commons.logging.impl.NoOpLog;
024    
025    /**
026     * Factory for creating {@link Log} instances.  Applications should call
027     * the <code>makeNewLogInstance()</code> method to instantiate new instances
028     * of the configured {@link Log} implementation class.
029     * <p>
030     * By default, calling <code>getInstance()</code> will use the following
031     * algorithm:
032     * <ul>
033     * <li>If Log4J is available, return an instance of
034     *     <code>org.apache.commons.logging.impl.Log4JLogger</code>.</li>
035     * <li>If JDK 1.4 or later is available, return an instance of
036     *     <code>org.apache.commons.logging.impl.Jdk14Logger</code>.</li>
037     * <li>Otherwise, return an instance of
038     *     <code>org.apache.commons.logging.impl.NoOpLog</code>.</li>
039     * </ul>
040     * <p>
041     * You can change the default behavior in one of two ways:
042     * <ul>
043     * <li>On the startup command line, set the system property
044     *     <code>org.apache.commons.logging.log</code> to the name of the
045     *     <code>org.apache.commons.logging.Log</code> implementation class
046     *     you want to use.</li>
047     * <li>At runtime, call <code>LogSource.setLogImplementation()</code>.</li>
048     * </ul>
049     *
050     * @deprecated Use {@link LogFactory} instead - The default factory
051     *  implementation performs exactly the same algorithm as this class did
052     *
053     * @version $Id: LogSource.html 862526 2013-05-20 17:07:42Z tn $
054     */
055    public class LogSource {
056    
057        // ------------------------------------------------------- Class Attributes
058    
059        static protected Hashtable logs = new Hashtable();
060    
061        /** Is log4j available (in the current classpath) */
062        static protected boolean log4jIsAvailable = false;
063    
064        /** Is JDK 1.4 logging available */
065        static protected boolean jdk14IsAvailable = false;
066    
067        /** Constructor for current log class */
068        static protected Constructor logImplctor = null;
069    
070        // ----------------------------------------------------- Class Initializers
071    
072        static {
073    
074            // Is Log4J Available?
075            try {
076                log4jIsAvailable = null != Class.forName("org.apache.log4j.Logger");
077            } catch (Throwable t) {
078                log4jIsAvailable = false;
079            }
080    
081            // Is JDK 1.4 Logging Available?
082            try {
083                jdk14IsAvailable = null != Class.forName("java.util.logging.Logger") &&
084                                   null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger");
085            } catch (Throwable t) {
086                jdk14IsAvailable = false;
087            }
088    
089            // Set the default Log implementation
090            String name = null;
091            try {
092                name = System.getProperty("org.apache.commons.logging.log");
093                if (name == null) {
094                    name = System.getProperty("org.apache.commons.logging.Log");
095                }
096            } catch (Throwable t) {
097            }
098            if (name != null) {
099                try {
100                    setLogImplementation(name);
101                } catch (Throwable t) {
102                    try {
103                        setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
104                    } catch (Throwable u) {
105                        // ignored
106                    }
107                }
108            } else {
109                try {
110                    if (log4jIsAvailable) {
111                        setLogImplementation("org.apache.commons.logging.impl.Log4JLogger");
112                    } else if (jdk14IsAvailable) {
113                        setLogImplementation("org.apache.commons.logging.impl.Jdk14Logger");
114                    } else {
115                        setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
116                    }
117                } catch (Throwable t) {
118                    try {
119                        setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
120                    } catch (Throwable u) {
121                        // ignored
122                    }
123                }
124            }
125    
126        }
127    
128        // ------------------------------------------------------------ Constructor
129    
130        /** Don't allow others to create instances. */
131        private LogSource() {
132        }
133    
134        // ---------------------------------------------------------- Class Methods
135    
136        /**
137         * Set the log implementation/log implementation factory
138         * by the name of the class.  The given class must implement {@link Log},
139         * and provide a constructor that takes a single {@link String} argument
140         * (containing the name of the log).
141         */
142        static public void setLogImplementation(String classname)
143            throws LinkageError, NoSuchMethodException, SecurityException, ClassNotFoundException {
144            try {
145                Class logclass = Class.forName(classname);
146                Class[] argtypes = new Class[1];
147                argtypes[0] = "".getClass();
148                logImplctor = logclass.getConstructor(argtypes);
149            } catch (Throwable t) {
150                logImplctor = null;
151            }
152        }
153    
154        /**
155         * Set the log implementation/log implementation factory by class.
156         * The given class must implement {@link Log}, and provide a constructor
157         * that takes a single {@link String} argument (containing the name of the log).
158         */
159        static public void setLogImplementation(Class logclass)
160            throws LinkageError, ExceptionInInitializerError, NoSuchMethodException, SecurityException {
161            Class[] argtypes = new Class[1];
162            argtypes[0] = "".getClass();
163            logImplctor = logclass.getConstructor(argtypes);
164        }
165    
166        /** Get a <code>Log</code> instance by class name. */
167        static public Log getInstance(String name) {
168            Log log = (Log) logs.get(name);
169            if (null == log) {
170                log = makeNewLogInstance(name);
171                logs.put(name, log);
172            }
173            return log;
174        }
175    
176        /** Get a <code>Log</code> instance by class. */
177        static public Log getInstance(Class clazz) {
178            return getInstance(clazz.getName());
179        }
180    
181        /**
182         * Create a new {@link Log} implementation, based on the given <i>name</i>.
183         * <p>
184         * The specific {@link Log} implementation returned is determined by the
185         * value of the <tt>org.apache.commons.logging.log</tt> property. The value
186         * of <tt>org.apache.commons.logging.log</tt> may be set to the fully specified
187         * name of a class that implements the {@link Log} interface. This class must
188         * also have a public constructor that takes a single {@link String} argument
189         * (containing the <i>name</i> of the {@link Log} to be constructed.
190         * <p>
191         * When <tt>org.apache.commons.logging.log</tt> is not set, or when no corresponding
192         * class can be found, this method will return a Log4JLogger if the log4j Logger
193         * class is available in the {@link LogSource}'s classpath, or a Jdk14Logger if we
194         * are on a JDK 1.4 or later system, or NoOpLog if neither of the above conditions is true.
195         *
196         * @param name the log name (or category)
197         */
198        static public Log makeNewLogInstance(String name) {
199            Log log;
200            try {
201                Object[] args = { name };
202                log = (Log) logImplctor.newInstance(args);
203            } catch (Throwable t) {
204                log = null;
205            }
206            if (null == log) {
207                log = new NoOpLog(name);
208            }
209            return log;
210        }
211    
212        /**
213         * Returns a {@link String} array containing the names of
214         * all logs known to me.
215         */
216        static public String[] getLogNames() {
217            return (String[]) logs.keySet().toArray(new String[logs.size()]);
218        }
219    }