X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=srcjar_unused%2Forg%2Fapache%2Flog4j%2FAsyncAppender.java;fp=srcjar_unused%2Forg%2Fapache%2Flog4j%2FAsyncAppender.java;h=214ffa7b9b12e08bfbb864b360a8314351c83875;hb=65740880573a48adc758bec3939ece9d9ae104dd;hp=0000000000000000000000000000000000000000;hpb=71aa78b8a7d54e5aeb6b278310dfd735efb77477;p=jalview.git
diff --git a/srcjar_unused/org/apache/log4j/AsyncAppender.java b/srcjar_unused/org/apache/log4j/AsyncAppender.java
new file mode 100644
index 0000000..214ffa7
--- /dev/null
+++ b/srcjar_unused/org/apache/log4j/AsyncAppender.java
@@ -0,0 +1,596 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Contibutors: Aaron Greenhouse
AsyncAppender
can only be script
+ * configured using the {@link org.apache.log4j.xml.DOMConfigurator}.
+ *
+ *
+ * @author Ceki Gülcü
+ * @author Curt Arnold
+ * @since 0.9.1
+ */
+public class AsyncAppender extends AppenderSkeleton
+ implements AppenderAttachable {
+ /**
+ * The default buffer size is set to 128 events.
+ */
+ public static final int DEFAULT_BUFFER_SIZE = 128;
+
+ /**
+ * Event buffer, also used as monitor to protect itself and
+ * discardMap from simulatenous modifications.
+ */
+ private final List buffer = new ArrayList();
+
+ /**
+ * Map of DiscardSummary objects keyed by logger name.
+ */
+ private final Map discardMap = new HashMap();
+
+ /**
+ * Buffer size.
+ */
+ private int bufferSize = DEFAULT_BUFFER_SIZE;
+
+ /** Nested appenders. */
+ AppenderAttachableImpl aai;
+
+ /**
+ * Nested appenders.
+ */
+ private final AppenderAttachableImpl appenders;
+
+ /**
+ * Dispatcher.
+ */
+ private final Thread dispatcher;
+
+ /**
+ * Should location info be included in dispatched messages.
+ */
+ private boolean locationInfo = false;
+
+ /**
+ * Does appender block when buffer is full.
+ */
+ private boolean blocking = true;
+
+ /**
+ * Create new instance.
+ */
+ public AsyncAppender() {
+ appenders = new AppenderAttachableImpl();
+
+ //
+ // only set for compatibility
+ aai = appenders;
+
+ dispatcher =
+ new Thread(new Dispatcher(this, buffer, discardMap, appenders));
+
+ // It is the user's responsibility to close appenders before
+ // exiting.
+ dispatcher.setDaemon(true);
+
+ // set the dispatcher priority to lowest possible value
+ // dispatcher.setPriority(Thread.MIN_PRIORITY);
+ dispatcher.setName("AsyncAppender-Dispatcher-" + dispatcher.getName());
+ dispatcher.start();
+ }
+
+ /**
+ * Add appender.
+ *
+ * @param newAppender appender to add, may not be null.
+ */
+ public void addAppender(final Appender newAppender) {
+ synchronized (appenders) {
+ appenders.addAppender(newAppender);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void append(final LoggingEvent event) {
+ //
+ // if dispatcher thread has died then
+ // append subsequent events synchronously
+ // See bug 23021
+ if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) {
+ synchronized (appenders) {
+ appenders.appendLoopOnAppenders(event);
+ }
+
+ return;
+ }
+
+ // Set the NDC and thread name for the calling thread as these
+ // LoggingEvent fields were not set at event creation time.
+ event.getNDC();
+ event.getThreadName();
+ // Get a copy of this thread's MDC.
+ event.getMDCCopy();
+ if (locationInfo) {
+ event.getLocationInformation();
+ }
+ event.getRenderedMessage();
+ event.getThrowableStrRep();
+
+ synchronized (buffer) {
+ while (true) {
+ int previousSize = buffer.size();
+
+ if (previousSize < bufferSize) {
+ buffer.add(event);
+
+ //
+ // if buffer had been empty
+ // signal all threads waiting on buffer
+ // to check their conditions.
+ //
+ if (previousSize == 0) {
+ buffer.notifyAll();
+ }
+
+ break;
+ }
+
+ //
+ // Following code is only reachable if buffer is full
+ //
+ //
+ // if blocking and thread is not already interrupted
+ // and not the dispatcher then
+ // wait for a buffer notification
+ boolean discard = true;
+ if (blocking
+ && !Thread.interrupted()
+ && Thread.currentThread() != dispatcher) {
+ try {
+ buffer.wait();
+ discard = false;
+ } catch (InterruptedException e) {
+ //
+ // reset interrupt status so
+ // calling code can see interrupt on
+ // their next wait or sleep.
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ //
+ // if blocking is false or thread has been interrupted
+ // add event to discard map.
+ //
+ if (discard) {
+ String loggerName = event.getLoggerName();
+ DiscardSummary summary = (DiscardSummary) discardMap.get(loggerName);
+
+ if (summary == null) {
+ summary = new DiscardSummary(event);
+ discardMap.put(loggerName, summary);
+ } else {
+ summary.add(event);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Close this AsyncAppender
by interrupting the dispatcher
+ * thread which will process all pending events before exiting.
+ */
+ public void close() {
+ /**
+ * Set closed flag and notify all threads to check their conditions.
+ * Should result in dispatcher terminating.
+ */
+ synchronized (buffer) {
+ closed = true;
+ buffer.notifyAll();
+ }
+
+ try {
+ dispatcher.join();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ org.apache.log4j.helpers.LogLog.error(
+ "Got an InterruptedException while waiting for the "
+ + "dispatcher to finish.", e);
+ }
+
+ //
+ // close all attached appenders.
+ //
+ synchronized (appenders) {
+ Enumeration iter = appenders.getAllAppenders();
+
+ if (iter != null) {
+ while (iter.hasMoreElements()) {
+ Object next = iter.nextElement();
+
+ if (next instanceof Appender) {
+ ((Appender) next).close();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get iterator over attached appenders.
+ * @return iterator or null if no attached appenders.
+ */
+ public Enumeration getAllAppenders() {
+ synchronized (appenders) {
+ return appenders.getAllAppenders();
+ }
+ }
+
+ /**
+ * Get appender by name.
+ *
+ * @param name name, may not be null.
+ * @return matching appender or null.
+ */
+ public Appender getAppender(final String name) {
+ synchronized (appenders) {
+ return appenders.getAppender(name);
+ }
+ }
+
+ /**
+ * Gets whether the location of the logging request call
+ * should be captured.
+ *
+ * @return the current value of the LocationInfo option.
+ */
+ public boolean getLocationInfo() {
+ return locationInfo;
+ }
+
+ /**
+ * Determines if specified appender is attached.
+ * @param appender appender.
+ * @return true if attached.
+ */
+ public boolean isAttached(final Appender appender) {
+ synchronized (appenders) {
+ return appenders.isAttached(appender);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean requiresLayout() {
+ return false;
+ }
+
+ /**
+ * Removes and closes all attached appenders.
+ */
+ public void removeAllAppenders() {
+ synchronized (appenders) {
+ appenders.removeAllAppenders();
+ }
+ }
+
+ /**
+ * Removes an appender.
+ * @param appender appender to remove.
+ */
+ public void removeAppender(final Appender appender) {
+ synchronized (appenders) {
+ appenders.removeAppender(appender);
+ }
+ }
+
+ /**
+ * Remove appender by name.
+ * @param name name.
+ */
+ public void removeAppender(final String name) {
+ synchronized (appenders) {
+ appenders.removeAppender(name);
+ }
+ }
+
+ /**
+ * The LocationInfo option takes a boolean value. By default, it is
+ * set to false which means there will be no effort to extract the location
+ * information related to the event. As a result, the event that will be
+ * ultimately logged will likely to contain the wrong location information
+ * (if present in the log format).
+ *
+ *
+ * Location information extraction is comparatively very slow and should be
+ * avoided unless performance is not a concern.
+ *
+ * @param flag true if location information should be extracted.
+ */
+ public void setLocationInfo(final boolean flag) {
+ locationInfo = flag;
+ }
+
+ /**
+ * Sets the number of messages allowed in the event buffer
+ * before the calling thread is blocked (if blocking is true)
+ * or until messages are summarized and discarded. Changing
+ * the size will not affect messages already in the buffer.
+ *
+ * @param size buffer size, must be positive.
+ */
+ public void setBufferSize(final int size) {
+ //
+ // log4j 1.2 would throw exception if size was negative
+ // and deadlock if size was zero.
+ //
+ if (size < 0) {
+ throw new java.lang.NegativeArraySizeException("size");
+ }
+
+ synchronized (buffer) {
+ //
+ // don't let size be zero.
+ //
+ bufferSize = (size < 1) ? 1 : size;
+ buffer.notifyAll();
+ }
+ }
+
+ /**
+ * Gets the current buffer size.
+ * @return the current value of the BufferSize option.
+ */
+ public int getBufferSize() {
+ return bufferSize;
+ }
+
+ /**
+ * Sets whether appender should wait if there is no
+ * space available in the event buffer or immediately return.
+ *
+ * @since 1.2.14
+ * @param value true if appender should wait until available space in buffer.
+ */
+ public void setBlocking(final boolean value) {
+ synchronized (buffer) {
+ blocking = value;
+ buffer.notifyAll();
+ }
+ }
+
+ /**
+ * Gets whether appender should block calling thread when buffer is full.
+ * If false, messages will be counted by logger and a summary
+ * message appended after the contents of the buffer have been appended.
+ *
+ * @since 1.2.14
+ * @return true if calling thread will be blocked when buffer is full.
+ */
+ public boolean getBlocking() {
+ return blocking;
+ }
+
+ /**
+ * Summary of discarded logging events for a logger.
+ */
+ private static final class DiscardSummary {
+ /**
+ * First event of the highest severity.
+ */
+ private LoggingEvent maxEvent;
+
+ /**
+ * Total count of messages discarded.
+ */
+ private int count;
+
+ /**
+ * Create new instance.
+ *
+ * @param event event, may not be null.
+ */
+ public DiscardSummary(final LoggingEvent event) {
+ maxEvent = event;
+ count = 1;
+ }
+
+ /**
+ * Add discarded event to summary.
+ *
+ * @param event event, may not be null.
+ */
+ public void add(final LoggingEvent event) {
+ if (event.getLevel().toInt() > maxEvent.getLevel().toInt()) {
+ maxEvent = event;
+ }
+
+ count++;
+ }
+
+ /**
+ * Create event with summary information.
+ *
+ * @return new event.
+ */
+ public LoggingEvent createEvent() {
+ String msg =
+ MessageFormat.format(
+ "Discarded {0} messages due to full event buffer including: {1}",
+ new Object[] { new Integer(count), maxEvent.getMessage() });
+
+ return new LoggingEvent(
+ "org.apache.log4j.AsyncAppender.DONT_REPORT_LOCATION",
+ Logger.getLogger(maxEvent.getLoggerName()),
+ maxEvent.getLevel(),
+ msg,
+ null);
+ }
+ }
+
+ /**
+ * Event dispatcher.
+ */
+ private static class Dispatcher implements Runnable {
+ /**
+ * Parent AsyncAppender.
+ */
+ private final AsyncAppender parent;
+
+ /**
+ * Event buffer.
+ */
+ private final List buffer;
+
+ /**
+ * Map of DiscardSummary keyed by logger name.
+ */
+ private final Map discardMap;
+
+ /**
+ * Wrapped appenders.
+ */
+ private final AppenderAttachableImpl appenders;
+
+ /**
+ * Create new instance of dispatcher.
+ *
+ * @param parent parent AsyncAppender, may not be null.
+ * @param buffer event buffer, may not be null.
+ * @param discardMap discard map, may not be null.
+ * @param appenders appenders, may not be null.
+ */
+ public Dispatcher(
+ final AsyncAppender parent, final List buffer, final Map discardMap,
+ final AppenderAttachableImpl appenders) {
+
+ this.parent = parent;
+ this.buffer = buffer;
+ this.appenders = appenders;
+ this.discardMap = discardMap;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ boolean isActive = true;
+
+ //
+ // if interrupted (unlikely), end thread
+ //
+ try {
+ //
+ // loop until the AsyncAppender is closed.
+ //
+ while (isActive) {
+ LoggingEvent[] events = null;
+
+ //
+ // extract pending events while synchronized
+ // on buffer
+ //
+ synchronized (buffer) {
+ int bufferSize = buffer.size();
+ isActive = !parent.closed;
+
+ while ((bufferSize == 0) && isActive) {
+ buffer.wait();
+ bufferSize = buffer.size();
+ isActive = !parent.closed;
+ }
+
+ if (bufferSize > 0) {
+ events = new LoggingEvent[bufferSize + discardMap.size()];
+ buffer.toArray(events);
+
+ //
+ // add events due to buffer overflow
+ //
+ int index = bufferSize;
+
+ for (
+ Iterator iter = discardMap.values().iterator();
+ iter.hasNext();) {
+ events[index++] = ((DiscardSummary) iter.next()).createEvent();
+ }
+
+ //
+ // clear buffer and discard map
+ //
+ buffer.clear();
+ discardMap.clear();
+
+ //
+ // allow blocked appends to continue
+ buffer.notifyAll();
+ }
+ }
+
+ //
+ // process events after lock on buffer is released.
+ //
+ if (events != null) {
+ for (int i = 0; i < events.length; i++) {
+ synchronized (appenders) {
+ appenders.appendLoopOnAppenders(events[i]);
+ }
+ }
+ }
+ }
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+}