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.lang.reflect.Constructor;
021import java.util.Hashtable;
022
023import 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 915605 2014-07-09 20:22:43Z tn $
054 */
055public 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}