[jboss-svn-commits] JBoss Common SVN: r3303 - in jboss-logmanager/trunk/src/main/java/org/jboss/logmanager: handlers and 1 other directory.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Wed Jun 24 17:22:54 EDT 2009


Author: david.lloyd at jboss.com
Date: 2009-06-24 17:22:53 -0400 (Wed, 24 Jun 2009)
New Revision: 3303

Added:
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ArrayQueue.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/AsyncHandler.java
Modified:
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/ExtLogRecord.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ExtHandler.java
Log:
Add async handler, because apparently people want it

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/ExtLogRecord.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/ExtLogRecord.java	2009-06-22 23:35:46 UTC (rev 3302)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/ExtLogRecord.java	2009-06-24 21:22:53 UTC (rev 3303)
@@ -115,6 +115,16 @@
     }
 
     /**
+     * Disable caller calculation for this record.  If the caller has already been calculated, leave it; otherwise
+     * set the caller to {@code "unknown"}.
+     */
+    public void disableCallerCalculation() {
+        if (calculateCaller) {
+            setUnknownCaller();
+        }
+    }
+
+    /**
      * Copy all fields and prepare this object to be passed to another thread or to be serialized.  Calling this method
      * more than once has no additional effect and will not incur extra copies.
      */

Added: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ArrayQueue.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ArrayQueue.java	                        (rev 0)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ArrayQueue.java	2009-06-24 21:22:53 UTC (rev 3303)
@@ -0,0 +1,76 @@
+/*
+ * 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.util.Queue;
+import java.util.Iterator;
+import java.util.AbstractQueue;
+
+final class ArrayQueue<T> extends AbstractQueue<T> implements Queue<T> {
+    private final T[] elements;
+    private int head, cnt;
+
+    @SuppressWarnings({ "unchecked" })
+    public ArrayQueue(int size) {
+        elements = (T[]) new Object[size];
+    }
+
+    public Iterator<T> iterator() {
+        throw new UnsupportedOperationException();
+    }
+
+    public int size() {
+        return cnt;
+    }
+
+    public boolean offer(final T o) {
+        final T[] elements = this.elements;
+        final int length = elements.length;
+        final int cnt = this.cnt;
+        if (cnt == length) {
+            return false;
+        }
+        elements[(head + cnt) % length] = o;
+        this.cnt = cnt + 1;
+        return true;
+    }
+
+    public T poll() {
+        final T[] elements = this.elements;
+        final int length = elements.length;
+        final int head = this.head;
+        final int cnt = this.cnt;
+        if (cnt == 0) {
+            return null;
+        } else try {
+            return elements[head];
+        } finally {
+            this.head = head + 1 % length;
+            this.cnt = cnt - 1;
+        }
+    }
+
+    public T peek() {
+        return cnt == 0 ? null : elements[head];
+    }
+}

Added: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/AsyncHandler.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/AsyncHandler.java	                        (rev 0)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/AsyncHandler.java	2009-06-24 21:22:53 UTC (rev 3303)
@@ -0,0 +1,185 @@
+/*
+ * 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.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.Executors;
+import java.util.Queue;
+
+import java.util.logging.Handler;
+import java.util.logging.ErrorManager;
+
+public final class AsyncHandler extends ExtHandler {
+
+    private final CopyOnWriteArrayList<Handler> handlers = new CopyOnWriteArrayList<Handler>();
+    private final ThreadFactory threadFactory;
+    private final Queue<ExtLogRecord> recordQueue;
+    private final AsyncThread asyncThread = new AsyncThread();
+
+    private boolean closed;
+    private boolean taskRunning;
+
+    private static final int DEFAULT_QUEUE_LENGTH = 512;
+
+    public AsyncHandler(final int queueLength, final ThreadFactory threadFactory) {
+        recordQueue = new ArrayQueue<ExtLogRecord>(queueLength);
+        this.threadFactory = threadFactory;
+    }
+
+    public AsyncHandler(final ThreadFactory threadFactory) {
+        this(DEFAULT_QUEUE_LENGTH, threadFactory);
+    }
+
+    public AsyncHandler(final int queueLength) {
+        this(queueLength, Executors.defaultThreadFactory());
+    }
+
+    public AsyncHandler() {
+        this(DEFAULT_QUEUE_LENGTH);
+    }
+
+    public void addHandler(final Handler handler) {
+        checkAccess();
+        synchronized (recordQueue) {
+            if (closed) {
+                throw new IllegalStateException("Handler is closed");
+            }
+            handlers.add(handler);
+        }
+    }
+
+    public void removeHandler(final Handler handler) {
+        checkAccess();
+        synchronized (recordQueue) {
+            if (! closed) {
+                handlers.remove(handler);
+            }
+        }
+    }
+
+    public void publish(final ExtLogRecord record) {
+        final Queue<ExtLogRecord> recordQueue = this.recordQueue;
+        boolean intr = Thread.interrupted();
+        // prepare record to move to another thread
+        record.copyAll();
+        try {
+            synchronized (recordQueue) {
+                if (closed) {
+                    return;
+                }
+                startTaskIfNotRunning();
+                while (! recordQueue.offer(record)) {
+                    try {
+                        recordQueue.wait();
+                    } catch (InterruptedException e) {
+                        intr = true;
+                    }
+                    if (closed) {
+                        return;
+                    }
+                    startTaskIfNotRunning();
+                }
+                recordQueue.notify();
+            }
+        } finally {
+            if (intr) Thread.currentThread().interrupt();
+        }
+    }
+
+    private void startTaskIfNotRunning() {
+        if (! taskRunning) {
+            taskRunning = true;
+            threadFactory.newThread(asyncThread).start();
+        }
+    }
+
+    public void flush() {
+        for (Handler handler : handlers) {
+            handler.flush();
+        }
+    }
+
+    public void close() throws SecurityException {
+        checkAccess();
+        closed = true;
+        asyncThread.interrupt();
+        handlers.clear();
+    }
+
+    private final class AsyncThread implements Runnable {
+        private volatile Thread thread;
+
+        void interrupt() {
+            final Thread thread = this.thread;
+            if (thread != null) {
+                thread.interrupt();
+            }
+        }
+
+        public void run() {
+            thread = Thread.currentThread();
+            final Queue<ExtLogRecord> recordQueue = AsyncHandler.this.recordQueue;
+            final CopyOnWriteArrayList<Handler> handlers = AsyncHandler.this.handlers;
+
+            boolean intr = false;
+            try {
+                for (;;) {
+                    ExtLogRecord rec;
+                    synchronized (recordQueue) {
+                        while ((rec = recordQueue.poll()) == null) {
+                            if (closed) {
+                                return;
+                            }
+                            try {
+                                recordQueue.wait();
+                            } catch (InterruptedException e) {
+                                intr = true;
+                            }
+                        }
+                        recordQueue.notify();
+                    }
+                    for (Handler handler : handlers) try {
+                        handler.publish(rec);
+                    } catch (Exception e) {
+                        getErrorManager().error("Publication error", e, ErrorManager.WRITE_FAILURE);
+                    } catch (VirtualMachineError e) {
+                        throw e;
+                    } catch (Throwable t) {
+                        // ignore :-/
+                    }
+                }
+            } finally {
+                synchronized (recordQueue) {
+                    taskRunning = false;
+                    recordQueue.notify();
+                }
+                thread = null;
+                if (intr) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }
+    }
+}

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-06-22 23:35:46 UTC (rev 3302)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/handlers/ExtHandler.java	2009-06-24 21:22:53 UTC (rev 3303)
@@ -26,8 +26,10 @@
 
 import java.util.logging.Handler;
 import java.util.logging.LogRecord;
+import java.util.logging.LoggingPermission;
 
 import java.io.Flushable;
+import java.security.Permission;
 
 /**
  * An extended logger handler.  Use this class as a base class for log handlers which require {@code ExtLogRecord}
@@ -36,6 +38,7 @@
 public abstract class ExtHandler extends Handler implements Flushable {
 
     private static final String LOGGER_CLASS_NAME = org.jboss.logmanager.Logger.class.getName();
+    private static final Permission CONTROL_PERMISSION = new LoggingPermission("control", null);
 
     /** {@inheritDoc} */
     public final void publish(final LogRecord record) {
@@ -53,4 +56,16 @@
      * @param record the log record to publish
      */
     public abstract void publish(final ExtLogRecord record);
+
+    /**
+     * Check access.
+     *
+     * @throws SecurityException if a security manager is installed and the caller does not have the {@code "control" LoggingPermission}
+     */
+    protected void checkAccess() throws SecurityException {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(CONTROL_PERMISSION);
+        }
+    }
 }




More information about the jboss-svn-commits mailing list