    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}