[jboss-svn-commits] JBoss Common SVN: r3328 - jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Jul 3 00:07:47 EDT 2009


Author: david.lloyd at jboss.com
Date: 2009-07-03 00:07:45 -0400 (Fri, 03 Jul 2009)
New Revision: 3328

Added:
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/PeriodicRotatingFileHandler.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/WriterHandler.java
Modified:
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/AsyncHandler.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ExtHandler.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/FileHandler.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/OutputStreamHandler.java
Log:
Handlers: javadoc, cleanup refactor of stream/writer handlers, add periodic rotating file handler

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/AsyncHandler.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/AsyncHandler.java	2009-07-03 01:49:43 UTC (rev 3327)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/AsyncHandler.java	2009-07-03 04:07:45 UTC (rev 3328)
@@ -31,7 +31,11 @@
 import java.util.logging.Handler;
 import java.util.logging.ErrorManager;
 
-public final class AsyncHandler extends ExtHandler {
+/**
+ * An asycnhronous log handler which is used to write to a handler or group of handlers which are "slow" or introduce
+ * some degree of latency.
+ */
+public class AsyncHandler extends ExtHandler {
 
     private final CopyOnWriteArrayList<Handler> handlers = new CopyOnWriteArrayList<Handler>();
     private final ThreadFactory threadFactory;
@@ -43,23 +47,47 @@
 
     private static final int DEFAULT_QUEUE_LENGTH = 512;
 
+    /**
+     * Construct a new instance.
+     *
+     * @param queueLength the queue length
+     * @param threadFactory the thread factory to use to construct the handler thread
+     */
     public AsyncHandler(final int queueLength, final ThreadFactory threadFactory) {
         recordQueue = new ArrayQueue<ExtLogRecord>(queueLength);
         this.threadFactory = threadFactory;
     }
 
+    /**
+     * Construct a new instance.
+     *
+     * @param threadFactory the thread factory to use to construct the handler thread
+     */
     public AsyncHandler(final ThreadFactory threadFactory) {
         this(DEFAULT_QUEUE_LENGTH, threadFactory);
     }
 
+    /**
+     * Construct a new instance.
+     *
+     * @param queueLength the queue length
+     */
     public AsyncHandler(final int queueLength) {
         this(queueLength, Executors.defaultThreadFactory());
     }
 
+    /**
+     * Construct a new instance.
+     */
     public AsyncHandler() {
         this(DEFAULT_QUEUE_LENGTH);
     }
 
+    /**
+     * Add a sub-handler to publish events to.
+     *
+     * @param handler the sub-handler
+     */
     public void addHandler(final Handler handler) {
         checkAccess();
         synchronized (recordQueue) {
@@ -70,6 +98,11 @@
         }
     }
 
+    /**
+     * Remove a sub-handler.
+     *
+     * @param handler the sub-handler
+     */
     public void removeHandler(final Handler handler) {
         checkAccess();
         synchronized (recordQueue) {
@@ -79,6 +112,7 @@
         }
     }
 
+    /** {@inheritDoc} */
     public void publish(final ExtLogRecord record) {
         final Queue<ExtLogRecord> recordQueue = this.recordQueue;
         boolean intr = Thread.interrupted();
@@ -115,12 +149,14 @@
         }
     }
 
+    /** {@inheritDoc} */
     public void flush() {
         for (Handler handler : handlers) {
             handler.flush();
         }
     }
 
+    /** {@inheritDoc} */
     public void close() throws SecurityException {
         checkAccess();
         closed = true;

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ExtHandler.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ExtHandler.java	2009-07-03 01:49:43 UTC (rev 3327)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ExtHandler.java	2009-07-03 04:07:45 UTC (rev 3328)
@@ -62,7 +62,7 @@
      *
      * @throws SecurityException if a security manager is installed and the caller does not have the {@code "control" LoggingPermission}
      */
-    protected void checkAccess() throws SecurityException {
+    protected static void checkAccess() throws SecurityException {
         final SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(CONTROL_PERMISSION);

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/FileHandler.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/FileHandler.java	2009-07-03 01:49:43 UTC (rev 3327)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/FileHandler.java	2009-07-03 04:07:45 UTC (rev 3328)
@@ -26,11 +26,15 @@
 import java.io.FileOutputStream;
 import java.io.FileNotFoundException;
 
+import java.util.logging.Formatter;
+
 /**
  * A simple file handler.
  */
 public class FileHandler extends OutputStreamHandler {
 
+    private File file;
+
     /**
      * Construct a new instance with no formatter and no output file.
      */
@@ -38,22 +42,68 @@
     }
 
     /**
+     * Construct a new instance with the given formatter and no output file.
+     *
+     * @param formatter the formatter
+     */
+    public FileHandler(final Formatter formatter) {
+        super(formatter);
+    }
+
+    /**
+     * Construct a new instance with the given formatter and output file.
+     *
+     * @param formatter the formatter
+     * @param file the file
+     * @throws FileNotFoundException if the file could not be found on open
+     */
+    public FileHandler(final Formatter formatter, final File file) throws FileNotFoundException {
+        super(formatter);
+        setFile(file);
+    }
+
+    /**
      * Set the output file.
      *
      * @param file the file
      * @throws FileNotFoundException if an error occurs opening the file
      */
     public void setFile(File file) throws FileNotFoundException {
-        final File parentFile = file.getParentFile();
-        if (parentFile != null) {
-            parentFile.mkdirs();
+        synchronized (outputLock) {
+            if (file == null) {
+                setOutputStream(null);
+            }
+            final File parentFile = file.getParentFile();
+            if (parentFile != null) {
+                parentFile.mkdirs();
+            }
+            boolean ok = false;
+            final FileOutputStream fos = new FileOutputStream(file, false);
+            try {
+                setOutputStream(fos);
+                this.file = file;
+            } finally {
+                if (! ok) {
+                    safeClose(fos);
+                }
+            }
         }
-        setOutputStream(new FileOutputStream(file, false));
     }
 
     /**
-     * Set the output file.
+     * Get the current output file.
      *
+     * @return the file
+     */
+    public File getFile() {
+        synchronized (outputLock) {
+            return file;
+        }
+    }
+
+    /**
+     * Set the output file by name.
+     *
      * @param fileName the file name
      * @throws FileNotFoundException if an error occurs opening the file
      */

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/OutputStreamHandler.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/OutputStreamHandler.java	2009-07-03 01:49:43 UTC (rev 3327)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/OutputStreamHandler.java	2009-07-03 04:07:45 UTC (rev 3328)
@@ -22,31 +22,22 @@
 
 package org.jboss.logmanager.handlers;
 
-import org.jboss.logmanager.ExtLogRecord;
 import org.jboss.logmanager.formatters.Formatters;
 import java.io.OutputStream;
-import java.io.Writer;
 import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
-import java.io.IOException;
-import java.io.Closeable;
-import java.io.Flushable;
-import java.security.Permission;
+import java.io.Writer;
 
 import java.util.logging.ErrorManager;
 import java.util.logging.Formatter;
-import java.util.logging.LoggingPermission;
 
 /**
- * An output stream handler that supports autoflush and extended log records.  No records will be logged until an
- * output stream is configured.
+ * An output stream handler which supports any {@code OutputStream}, using the specified encoding.  If no encoding is
+ * specified, the platform default is used.
  */
-public class OutputStreamHandler extends ExtHandler {
+public class OutputStreamHandler extends WriterHandler {
 
-    private volatile boolean autoFlush = false;
-    private final Object outputLock = new Object();
     private OutputStream outputStream;
-    private Writer writer;
 
     /**
      * Construct a new instance with no formatter.
@@ -76,173 +67,50 @@
     }
 
     /**
-     * Determine whether autoflush is currently enabled.
-     *
-     * @return {@code true} if autoflush is enabled
-     */
-    public boolean isAutoFlush() {
-        return autoFlush;
-    }
-
-    /**
-     * Change the autoflush status.
-     *
-     * @param autoFlush {@code true} to enable autoflush, {@code false} to disable it
-     * @throws SecurityException if you do not have sufficient permission to invoke this operation
-     */
-    public void setAutoFlush(final boolean autoFlush) throws SecurityException {
-        checkControl();
-        this.autoFlush = autoFlush;
-    }
-
-    /**
      * Set the target encoding.
      *
      * @param encoding the new encoding
      * @throws SecurityException if you do not have sufficient permission to invoke this operation
-     * @throws UnsupportedEncodingException if the specified encoding is not supported
+     * @throws java.io.UnsupportedEncodingException if the specified encoding is not supported
      */
     public void setEncoding(final String encoding) throws SecurityException, UnsupportedEncodingException {
-        checkControl();
+        // superclass checks access
         super.setEncoding(encoding);
         synchronized (outputLock) {
-            final Writer writer = this.writer;
-            if (writer == null) {
-                return;
-            }
-            closeWriter();
-            this.writer = encoding == null ? new OutputStreamWriter(outputStream) : new OutputStreamWriter(outputStream, encoding);
+            final OutputStream outputStream = this.outputStream;
+            updateWriter(outputStream, encoding);
         }
     }
 
+    /** {@inheritDoc}  Setting a writer will replace any target output stream. */
+    public void setWriter(final Writer writer) {
+        synchronized (outputLock) {
+            super.setWriter(writer);
+            outputStream = null;
+        }
+    }
+
     /**
      * Set the output stream to write to.
      *
-     * @param newOutputStream the new output stream or {@code null} for none
+     * @param outputStream the new output stream or {@code null} for none
      */
-    public void setOutputStream(final OutputStream newOutputStream) {
-        checkControl();
-        if (newOutputStream == null) {
-            closeStream();
-            return;
-        }
-        final Writer newWriter;
+    public void setOutputStream(final OutputStream outputStream) {
+        checkAccess();
         try {
-            final String encoding = getEncoding();
-            newWriter = encoding == null ? new OutputStreamWriter(newOutputStream) : new OutputStreamWriter(newOutputStream, encoding);
+            synchronized (outputLock) {
+                this.outputStream = outputStream;
+                updateWriter(outputStream, getEncoding());
+            }
         } catch (UnsupportedEncodingException e) {
             throw new IllegalArgumentException("The specified encoding is invalid");
         } catch (Exception e) {
-            reportError("Error opeing output stream", e, ErrorManager.OPEN_FAILURE);
+            reportError("Error opening output stream", e, ErrorManager.OPEN_FAILURE);
             return;
         }
-        synchronized (outputLock) {
-            closeStream();
-            outputStream = newOutputStream;
-            writer = newWriter;
-            try {
-                writer.write(getFormatter().getHead(this));
-            } catch (Exception e) {
-                reportError("Error writing section header", e, ErrorManager.WRITE_FAILURE);
-            }
-        }
     }
 
-    /**
-     * Publish a log record.
-     *
-     * @param record the log record to publish
-     */
-    public void publish(final ExtLogRecord record) {
-        if (isLoggable(record)) {
-            final String formatted;
-            final Formatter formatter = getFormatter();
-            try {
-                formatted = formatter.format(record);
-            } catch (Exception ex) {
-                reportError("Formatting error", ex, ErrorManager.FORMAT_FAILURE);
-                return;
-            }
-            try {
-                synchronized (outputLock) {
-                    final Writer writer = this.writer;
-                    if (writer == null) {
-                        return;
-                    }
-                    writer.write(formatted);
-                }
-            } catch (Exception ex) {
-                reportError("Error writing log message", ex, ErrorManager.WRITE_FAILURE);
-                return;
-            }
-            if (autoFlush) flush();
-        }
+    private void updateWriter(final OutputStream newOutputStream, final String encoding) throws UnsupportedEncodingException {
+        setWriter(newOutputStream == null ? null : encoding == null ? new OutputStreamWriter(newOutputStream) : new OutputStreamWriter(newOutputStream, encoding));
     }
-
-    /**
-     * Flush this logger.
-     */
-    public void flush() {
-        synchronized (outputLock) {
-            safeFlush(writer);
-        }
-    }
-
-    private void safeClose(Closeable c) {
-        try {
-            if (c != null) c.close();
-        } catch (Exception e) {
-            reportError("Error closing resource", e, ErrorManager.CLOSE_FAILURE);
-        }
-    }
-
-    private void safeFlush(Flushable f) {
-        try {
-            if (f != null) f.flush();
-        } catch (IOException e) {
-            reportError("Error on flush", e, ErrorManager.FLUSH_FAILURE);
-        }
-    }
-
-    private void closeWriter() {
-        safeFlush(writer);
-        writer = null;
-    }
-
-    private void closeStream() {
-        synchronized (outputLock) {
-            final Writer writer = this.writer;
-            if (writer == null) {
-                return;
-            }
-            try {
-                writer.write(getFormatter().getTail(this));
-            } catch (Exception ex) {
-                reportError("Error writing section tail", ex, ErrorManager.WRITE_FAILURE);
-            }
-            safeFlush(writer);
-            safeClose(writer);
-            this.writer = null;
-            outputStream = null;
-        }
-    }
-
-    /**
-     * Close this logger.
-     *
-     * @throws SecurityException if you do not have sufficient permission to invoke this operation
-     */
-    public void close() throws SecurityException {
-        checkControl();
-        closeStream();
-    }
-
-    private static void checkControl() throws SecurityException {
-        final SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkPermission(CONTROL_PERMISSION);
-        }
-    }
-
-    private static final Permission CONTROL_PERMISSION = new LoggingPermission("control", null);
 }

Added: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/PeriodicRotatingFileHandler.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/PeriodicRotatingFileHandler.java	                        (rev 0)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/PeriodicRotatingFileHandler.java	2009-07-03 04:07:45 UTC (rev 3328)
@@ -0,0 +1,182 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.logmanager.handlers;
+
+import org.jboss.logmanager.ExtLogRecord;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Calendar;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import java.util.logging.ErrorManager;
+
+/**
+ * A file handler which rotates the log at a preset time interval.  The interval is determined by the content of the
+ * suffix string which is passed in to {@link #setSuffix(String)}.
+ */
+public class PeriodicRotatingFileHandler extends FileHandler {
+
+    private SimpleDateFormat format;
+    private String nextSuffix;
+    private Period period;
+    private long nextRollover;
+
+    /** {@inheritDoc}  This implementation checks to see if the scheduled rollover time has yet occurred. */
+    protected void preWrite(final ExtLogRecord record) {
+        final long recordMillis = record.getMillis();
+        if (recordMillis >= nextRollover) {
+            rollOver();
+            calcNextRollover(recordMillis);
+        }
+    }
+
+    /**
+     * Set the suffix string.  The string is in a format which can be understood by {@link java.text.SimpleDateFormat}.
+     * The period of the rotation is automatically calculated based on the suffix.
+     *
+     * @param suffix the suffix
+     * @throws IllegalArgumentException if the suffix is not valid
+     */
+    public void setSuffix(String suffix) throws IllegalArgumentException {
+        final SimpleDateFormat format = new SimpleDateFormat(suffix);
+        final int len = suffix.length();
+        Period period = Period.NEVER;
+        for (int i = 0; i < len; i ++) {
+            switch (suffix.charAt(i)) {
+                case 'y': period = min(period, Period.YEAR); break;
+                case 'M': period = min(period, Period.MONTH); break;
+                case 'w':
+                case 'W': period = min(period, Period.WEEK); break;
+                case 'D':
+                case 'd':
+                case 'F':
+                case 'E': period = min(period, Period.DAY); break;
+                case 'a': period = min(period, Period.HALF_DAY); break;
+                case 'H':
+                case 'k':
+                case 'K':
+                case 'h': period = min(period, Period.HOUR); break;
+                case 'm': period = min(period, Period.MINUTE); break;
+                case '\'': while (suffix.charAt(++i) != '\''); break;
+                case 's':
+                case 'S': throw new IllegalArgumentException("Rotating by second or millisecond is not supported");
+            }
+        }
+        synchronized (outputLock) {
+            this.format = format;
+            this.period = period;
+            final long now = System.currentTimeMillis();
+            calcNextRollover(now);
+        }
+    }
+
+    private void rollOver() {
+        try {
+            final File file = getFile();
+            // first, close the original file (some OSes won't let you move/rename a file that is open)
+            setFile(null);
+            // next, rotate it
+            file.renameTo(new File(file.getName() + nextSuffix));
+            // start new file
+            setFile(file);
+        } catch (FileNotFoundException e) {
+            reportError("Unable to rotate log file", e, ErrorManager.OPEN_FAILURE);
+        }
+    }
+
+    private void calcNextRollover(final long fromTime) {
+        if (period == Period.NEVER) {
+            nextRollover = Long.MAX_VALUE;
+            return;
+        }
+        nextSuffix = format.format(new Date(fromTime));
+        final Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(fromTime);
+        final Period period = this.period;
+        // clear out less-significant fields
+        switch (period) {
+            default:
+            case YEAR:
+                calendar.clear(Calendar.MONTH);
+            case MONTH:
+                calendar.clear(Calendar.DAY_OF_MONTH);
+                calendar.clear(Calendar.WEEK_OF_MONTH);
+            case WEEK:
+                calendar.clear(Calendar.DAY_OF_WEEK);
+                calendar.clear(Calendar.DAY_OF_WEEK_IN_MONTH);
+            case DAY:
+                calendar.clear(Calendar.HOUR_OF_DAY);
+            case HALF_DAY:
+                calendar.clear(Calendar.HOUR);
+            case HOUR:
+                calendar.clear(Calendar.MINUTE);
+            case MINUTE:
+                calendar.clear(Calendar.SECOND);
+                calendar.clear(Calendar.MILLISECOND);
+        }
+        // increment the relevant field
+        switch (period) {
+            case YEAR:
+                calendar.add(Calendar.YEAR, 1);
+                break;
+            case MONTH:
+                calendar.add(Calendar.MONTH, 1);
+                break;
+            case WEEK:
+                calendar.add(Calendar.WEEK_OF_YEAR, 1);
+                break;
+            case DAY:
+                calendar.add(Calendar.DAY_OF_MONTH, 1);
+                break;
+            case HALF_DAY:
+                calendar.add(Calendar.AM_PM, 1);
+                break;
+            case HOUR:
+                calendar.add(Calendar.HOUR, 1);
+                break;
+            case MINUTE:
+                calendar.add(Calendar.MINUTE, 1);
+                break;
+        }
+        nextRollover = calendar.getTimeInMillis();
+    }
+
+    private static <T extends Comparable<? super T>> T min(T a, T b) {
+        return a.compareTo(b) <= 0 ? a : b;
+    }
+
+    /**
+     * Possible period values.  Keep in strictly ascending order of magnitude.
+     */
+    public enum Period {
+        MINUTE,
+        HOUR,
+        HALF_DAY,
+        DAY,
+        WEEK,
+        MONTH,
+        YEAR,
+        NEVER,
+    }
+}

Added: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/WriterHandler.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/WriterHandler.java	                        (rev 0)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/WriterHandler.java	2009-07-03 04:07:45 UTC (rev 3328)
@@ -0,0 +1,165 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.logmanager.handlers;
+
+import java.io.Writer;
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+
+import java.util.logging.ErrorManager;
+import java.util.logging.Formatter;
+
+import org.jboss.logmanager.ExtLogRecord;
+
+/**
+ * A handler which writes to any {@code Writer}.
+ */
+public class WriterHandler extends ExtHandler {
+
+    protected final Object outputLock = new Object();
+    private Writer writer;
+
+    /**
+     * Publish a log record.
+     *
+     * @param record the log record to publish
+     */
+    public void publish(final ExtLogRecord record) {
+        if (isLoggable(record)) {
+            final String formatted;
+            final Formatter formatter = getFormatter();
+            try {
+                formatted = formatter.format(record);
+            } catch (Exception ex) {
+                reportError("Formatting error", ex, ErrorManager.FORMAT_FAILURE);
+                return;
+            }
+            try {
+                synchronized (outputLock) {
+                    final Writer writer = this.writer;
+                    if (writer == null) {
+                        return;
+                    }
+                    preWrite(record);
+                    writer.write(formatted);
+                }
+            } catch (Exception ex) {
+                reportError("Error writing log message", ex, ErrorManager.WRITE_FAILURE);
+                return;
+            }
+        }
+    }
+
+    /**
+     * Execute any pre-write policy, such as file rotation.  The write lock is held during this method, so make
+     * it quick.  The default implementation does nothing.
+     *
+     * @param record the record about to be logged
+     */
+    protected void preWrite(final ExtLogRecord record) {
+        // do nothing by default
+    }
+
+    /**
+     * Set the writer.  The writer will then belong to this handler; when the handler is closed or a new writer is set,
+     * this writer will be closed.
+     *
+     * @param writer the new writer, or {@code null} to disable logging
+     */
+    public void setWriter(final Writer writer) {
+        checkAccess();
+        final Writer oldWriter;
+        synchronized (outputLock) {
+            oldWriter = this.writer;
+            writeTail(oldWriter);
+            safeFlush(oldWriter);
+            writeHead(writer);
+            this.writer = writer;
+        }
+        if (oldWriter != null) {
+            safeClose(oldWriter);
+        }
+    }
+
+    private void writeHead(final Writer writer) {
+        if (writer != null) {
+            try {
+                writer.write(getFormatter().getHead(this));
+            } catch (Exception e) {
+                reportError("Error writing section header", e, ErrorManager.WRITE_FAILURE);
+            }
+        }
+    }
+
+    private void writeTail(final Writer writer) {
+        if (writer != null) {
+            try {
+                writer.write(getFormatter().getTail(this));
+            } catch (Exception ex) {
+                reportError("Error writing section tail", ex, ErrorManager.WRITE_FAILURE);
+            }
+        }
+    }
+
+    /**
+     * Flush this logger.
+     */
+    public void flush() {
+        // todo - maybe this synch is not really needed... if there's a perf detriment, drop it
+        synchronized (outputLock) {
+            safeFlush(writer);
+        }
+    }
+
+    /**
+     * Close this logger.
+     *
+     * @throws SecurityException if the caller does not have sufficient permission
+     */
+    public void close() throws SecurityException {
+        checkAccess();
+        setWriter(null);
+    }
+
+    /**
+     * Safely close the resource, reporting an error if the close fails.
+     *
+     * @param c the resource
+     */
+    protected void safeClose(Closeable c) {
+        try {
+            if (c != null) c.close();
+        } catch (Exception e) {
+            reportError("Error closing resource", e, ErrorManager.CLOSE_FAILURE);
+        }
+    }
+
+    private void safeFlush(Flushable f) {
+        try {
+            if (f != null) f.flush();
+        } catch (IOException e) {
+            reportError("Error on flush", e, ErrorManager.FLUSH_FAILURE);
+        }
+    }
+}




More information about the jboss-svn-commits mailing list