001/*
002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.15/src/java/org/apache/commons/ssl/LogWrapper.java $
003 * $Revision: 121 $
004 * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
005 *
006 * ====================================================================
007 * Licensed to the Apache Software Foundation (ASF) under one
008 * or more contributor license agreements.  See the NOTICE file
009 * distributed with this work for additional information
010 * regarding copyright ownership.  The ASF licenses this file
011 * to you under the Apache License, Version 2.0 (the
012 * "License"); you may not use this file except in compliance
013 * with the License.  You may obtain a copy of the License at
014 *
015 *   http://www.apache.org/licenses/LICENSE-2.0
016 *
017 * Unless required by applicable law or agreed to in writing,
018 * software distributed under the License is distributed on an
019 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020 * KIND, either express or implied.  See the License for the
021 * specific language governing permissions and limitations
022 * under the License.
023 * ====================================================================
024 *
025 * This software consists of voluntary contributions made by many
026 * individuals on behalf of the Apache Software Foundation.  For more
027 * information on the Apache Software Foundation, please see
028 * <http://www.apache.org/>.
029 *
030 */
031
032package org.apache.commons.ssl;
033
034import java.io.BufferedOutputStream;
035import java.io.FileOutputStream;
036import java.io.IOException;
037import java.io.OutputStream;
038import java.io.PrintStream;
039import java.text.DateFormat;
040import java.text.SimpleDateFormat;
041import java.util.Date;
042
043/**
044 * <p/>
045 * LogWrapper can be used for situations where log4j might not be available on
046 * the classpath.  It presents the most basic and critical components of the
047 * log4j API, and passes all log calls through to log4j if possible.  If log4j
048 * is not available, logging is sent to standard-out by default.
049 * <p/>
050 * This default logging to standard-out (which only occurs if log4j is NOT
051 * available) can be disabled or changed via the static setBackupStream() and
052 * setBackupLogFile() methods.
053 *
054 * @author Credit Union Central of British Columbia
055 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
056 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
057 * @since 3-Aug-2006
058 */
059public class LogWrapper {
060
061    // final static String[] LEVELS = {"DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
062    final static String[] LEVELS = {"+", " ", "!", "*", "#"};
063    final static String TIMESTAMP_PATTERN = "zzz:yyyy-MM-dd/HH:mm:ss.SSS";
064    final static int TIMESTAMP_LENGTH = TIMESTAMP_PATTERN.length();
065    final static String LINE_SEPARATOR = System.getProperty("line.separator");
066    final static DateFormat DF = new SimpleDateFormat(TIMESTAMP_PATTERN);
067
068    private final static LogWrapper NOOP = new LogWrapper();
069
070    /** Should we print DEBUG statements if log4j is not available? */
071    private final static boolean DEBUG = true;
072
073    /** true if log4j is available */
074    public final static boolean log4j;
075
076    /**
077     * OutputStream to log to if log4j is not available.  Set it to null to
078     * disable.
079     */
080    private static volatile OutputStream backup = System.out;
081
082    /** The wrappingPrintStream is lazy-initted if we have to log a stacktrace. */
083    private static volatile PrintStream wrappingPrintStream = null;
084
085    private final LogHelper h;
086
087    static {
088        boolean avail = false;
089        try {
090            // LogHelper's constructor will blow up if log4j.jar isn't on the
091            // classpath.
092            LogHelper lh = new LogHelper(LogWrapper.class);
093            lh.hashCode();
094            avail = true;
095        }
096        catch (Throwable t) {
097            avail = false;
098        }
099        finally {
100            log4j = avail;
101        }
102    }
103
104    public static boolean isLog4jAvailable() { return log4j; }
105
106    public static LogWrapper getLogger(Class c) {
107        return log4j ? new LogWrapper(c) : NOOP;
108    }
109
110    public static LogWrapper getLogger(String s) {
111        return log4j ? new LogWrapper(s) : NOOP;
112    }
113
114    private LogWrapper() { this.h = null; }
115
116    private LogWrapper(Class c) { this.h = new LogHelper(c); }
117
118    private LogWrapper(String s) { this.h = new LogHelper(s); }
119
120    public void debug(Object o) {
121        if (t(0, o, null)) {
122            h.debug(o);
123        }
124    }
125
126    public void debug(Object o, Throwable t) {
127        if (t(0, o, t)) {
128            h.debug(o, t);
129        }
130    }
131
132    public void info(Object o) {
133        if (t(1, o, null)) {
134            h.info(o);
135        }
136    }
137
138    public void info(Object o, Throwable t) {
139        if (t(1, o, t)) {
140            h.info(o, t);
141        }
142    }
143
144    public void warn(Object o) {
145        if (t(2, o, null)) {
146            h.warn(o);
147        }
148    }
149
150    public void warn(Object o, Throwable t) {
151        if (t(2, o, t)) {
152            h.warn(o, t);
153        }
154    }
155
156    public void error(Object o) {
157        if (t(3, o, null)) {
158            h.error(o);
159        }
160    }
161
162    public void error(Object o, Throwable t) {
163        if (t(3, o, t)) {
164            h.error(o, t);
165        }
166    }
167
168    public void fatal(Object o) {
169        if (t(4, o, null)) {
170            h.fatal(o);
171        }
172    }
173
174    public void fatal(Object o, Throwable t) {
175        if (t(4, o, t)) {
176            h.fatal(o, t);
177        }
178    }
179
180    public boolean isDebugEnabled() { return log4j ? h.isDebugEnabled() : DEBUG;}
181
182    public boolean isInfoEnabled() { return !log4j || h.isInfoEnabled(); }
183
184    public Object getLog4jLogger() { return log4j ? h.getLog4jLogger() : null; }
185
186
187    /**
188     * Tests if log4j is available.  If not, logs to backup OutputStream (if
189     * backup != null).
190     *
191     * @param level log4j logging level for this statement
192     * @param o     object to log
193     * @param t     throwable to log
194     * @return true if log4j is available, false if log4j is not.  If it returns
195     *         false, as a side-effect, it will also log the statement.
196     */
197    private boolean t(int level, Object o, Throwable t) {
198        if (log4j) {
199            return true;
200        } else {
201            // LogWrapper doesn't log debug statements if Log4j is not available
202            // and DEBUG is false.
203            if (backup != null && (DEBUG || level > 0)) {
204                String s = "";  // log4j allows null
205                if (o != null) {
206                    try {
207                        s = (String) o;
208                    }
209                    catch (ClassCastException cce) {
210                        s = o.toString();
211                    }
212                }
213                int len = s.length() + TIMESTAMP_LENGTH + 9;
214                String timestamp = DF.format(new Date());
215                StringBuffer buf = new StringBuffer(len);
216                buf.append(timestamp);
217                if (LEVELS[level].length() == 1) {
218                    buf.append(LEVELS[level]);
219                } else {
220                    buf.append(' ');
221                    buf.append(LEVELS[level]);
222                    buf.append(' ');
223                }
224                buf.append(s);
225                buf.append(LINE_SEPARATOR);
226                s = buf.toString();
227                byte[] logBytes = s.getBytes();
228                try {
229                    if (t == null) {
230                        backup.write(logBytes);
231                    } else {
232                        synchronized (backup) {
233                            backup.write(logBytes);
234                            if (t != null) {
235                                if (wrappingPrintStream == null) {
236                                    wrappingPrintStream = new PrintStream(backup, false);
237                                }
238                                t.printStackTrace(wrappingPrintStream);
239                                wrappingPrintStream.flush();
240                            }
241                        }
242                    }
243                    backup.flush();   // J2RE 1.5.0 IBM J9 2.3 Linux x86-32 needs this.
244                }
245                catch (IOException ioe) {
246                    throw new RuntimeException(ioe.toString());
247                }
248            }
249            return false;
250        }
251    }
252
253    /**
254     * Set file to log to if log4j is not available.
255     *
256     * @param f path to use for backup log file (if log4j not available)
257     * @throws IOException if we can't write to the given path
258     */
259    public static void setBackupLogFile(String f)
260        throws IOException {
261        if (!log4j) {
262            OutputStream out = new FileOutputStream(f, true);
263            out = new BufferedOutputStream(out);
264            setBackupStream(out);
265        }
266    }
267
268    /**
269     * Set PrintStream to log to if log4j is not available.  Set to null to
270     * disable.  Default value is System.out.
271     *
272     * @param os outputstream to use for backup logging (if log4j not available)
273     */
274    public static void setBackupStream(OutputStream os) {
275        // synchronize on the old backup - don't want to pull the rug out from
276        // under him if he's working on a big stacktrace or something like that.
277        if (backup != null) {
278            synchronized (backup) {
279                wrappingPrintStream = null;
280                backup = os;
281            }
282        } else {
283            wrappingPrintStream = null;
284            backup = os;
285        }
286    }
287
288    /**
289     * Get the PrintStream we're logging to if log4j is not available.
290     *
291     * @return OutputStream we're using as our log4j replacement.
292     */
293    public static OutputStream getBackupStream() { return backup; }
294
295}