001    /*
002     * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/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    
032    package org.apache.commons.ssl;
033    
034    import java.io.BufferedOutputStream;
035    import java.io.FileOutputStream;
036    import java.io.IOException;
037    import java.io.OutputStream;
038    import java.io.PrintStream;
039    import java.text.DateFormat;
040    import java.text.SimpleDateFormat;
041    import 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     */
059    public 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    }