001: /*
002: * Copyright (C) The Apache Software Foundation. All rights reserved.
003: *
004: * This software is published under the terms of the Apache Software License
005: * version 1.1, a copy of which has been included with this distribution in
006: * the LICENSE file.
007: */
008: package org.jivesoftware.util.log.output;
009:
010: import org.jivesoftware.util.log.ErrorAware;
011: import org.jivesoftware.util.log.ErrorHandler;
012: import org.jivesoftware.util.log.LogEvent;
013: import org.jivesoftware.util.log.LogTarget;
014: import java.util.LinkedList;
015:
016: /**
017: * An asynchronous LogTarget that sends entries on in another thread.
018: * It is the responsibility of the user of this class to start
019: * the thread etc.
020: * <p/>
021: * <pre>
022: * LogTarget mySlowTarget = ...;
023: * AsyncLogTarget asyncTarget = new AsyncLogTarget( mySlowTarget );
024: * Thread thread = new Thread( asyncTarget );
025: * thread.setPriority( Thread.MIN_PRIORITY );
026: * thread.start();
027: * <p/>
028: * logger.setLogTargets( new LogTarget[] { asyncTarget } );
029: * </pre>
030: *
031: * @author <a href="mailto:peter@apache.org">Peter Donald</a>
032: */
033: public class AsyncLogTarget extends AbstractTarget implements Runnable {
034:
035: private final LinkedList m_list;
036: private final int m_queueSize;
037: private final LogTarget m_logTarget;
038:
039: public AsyncLogTarget(final LogTarget logTarget) {
040: this (logTarget, 15);
041: }
042:
043: public AsyncLogTarget(final LogTarget logTarget, final int queueSize) {
044: m_logTarget = logTarget;
045: m_list = new LinkedList();
046: m_queueSize = queueSize;
047: open();
048: }
049:
050: /**
051: * Provide component with ErrorHandler.
052: *
053: * @param errorHandler the errorHandler
054: */
055: public synchronized void setErrorHandler(
056: final ErrorHandler errorHandler) {
057: super .setErrorHandler(errorHandler);
058:
059: if (m_logTarget instanceof ErrorAware) {
060: ((ErrorAware) m_logTarget).setErrorHandler(errorHandler);
061: }
062: }
063:
064: /**
065: * Process a log event by adding it to queue.
066: *
067: * @param event the log event
068: */
069: public void doProcessEvent(final LogEvent event) {
070: synchronized (m_list) {
071: final int size = m_list.size();
072: while (m_queueSize <= size) {
073: try {
074: m_list.wait();
075: } catch (final InterruptedException ie) {
076: //This really should not occur ...
077: //Maybe we should log it though for
078: //now lets ignore it
079: }
080: }
081:
082: m_list.addFirst(event);
083:
084: if (size == 0) {
085: //tell the "server" thread to wake up
086: //if it is waiting for a queue to contain some items
087: m_list.notify();
088: }
089: }
090: }
091:
092: public void run() {
093: //set this variable when thread is interupted
094: //so we know we can shutdown thread soon.
095: boolean interupted = false;
096:
097: while (true) {
098: LogEvent event = null;
099:
100: synchronized (m_list) {
101: while (null == event) {
102: final int size = m_list.size();
103:
104: if (size > 0) {
105: event = (LogEvent) m_list.removeLast();
106:
107: if (size == m_queueSize) {
108: //tell the "client" thread to wake up
109: //if it is waiting for a queue position to open up
110: m_list.notify();
111: }
112:
113: } else if (interupted || Thread.interrupted()) {
114: //ie there is nothing in queue and thread is interrupted
115: //thus we stop thread
116: return;
117: } else {
118: try {
119: m_list.wait();
120: } catch (final InterruptedException ie) {
121: //Ignore this and let it be dealt in next loop
122: //Need to set variable as the exception throw cleared status
123: interupted = true;
124: }
125: }
126: }
127: }
128:
129: try {
130: //actually process an event
131: m_logTarget.processEvent(event);
132: } catch (final Throwable throwable) {
133: getErrorHandler().error("Unknown error writing event.",
134: throwable, event);
135: }
136: }
137: }
138: }
|