001: /* SinkHandler
002: * Copyright (C) 2005 Internet Archive.
003: *
004: * Created on Jul 7, 2003
005: *
006: * This file is part of the Heritrix web crawler (crawler.archive.org).
007: *
008: * Heritrix is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU Lesser Public License as published by
010: * the Free Software Foundation; either version 2.1 of the License, or
011: * any later version.
012: *
013: * Heritrix is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU Lesser Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser Public License
019: * along with Heritrix; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021: */
022: package org.archive.io;
023:
024: import java.util.Iterator;
025: import java.util.Vector;
026: import java.util.logging.Handler;
027: import java.util.logging.Level;
028: import java.util.logging.LogManager;
029: import java.util.logging.LogRecord;
030: import java.util.logging.Logger;
031:
032: /**
033: * A handler that keeps an in-memory vector of all events deemed loggable by
034: * configuration.
035: * Use it to iterate over logged events long after their occurance. One such
036: * use is as a sink for WARNING+SEVERE loggable events. Has support for
037: * whether a log record has been already-read.
038: * TODO: Add being able to get LogRecords by log level: i.e. return all
039: * Level.SEVERE, etc.
040: * TODO: Back the vector with a bdbje collection.
041: * @author stack
042: * @version $Date: 2006-09-22 17:23:04 +0000 (Fri, 22 Sep 2006) $ $Revision: 4646 $
043: */
044: public class SinkHandler extends Handler {
045: /**
046: * Alerts that have occured.
047: */
048: private Vector<SinkHandlerLogRecord> sink = new Vector<SinkHandlerLogRecord>();
049:
050: public SinkHandler() {
051: LogManager manager = LogManager.getLogManager();
052: String className = getClass().getName();
053: String tmp = manager.getProperty(className + ".level");
054: if (tmp != null) {
055: setLevel(Level.parse(tmp));
056: }
057: }
058:
059: public void publish(LogRecord record) {
060: if (!isLoggable(record)) {
061: return;
062: }
063: this .sink.add(new SinkHandlerLogRecord(record));
064: }
065:
066: public void flush() {
067: // Nothing to do.
068: }
069:
070: public void close() throws SecurityException {
071: flush();
072: }
073:
074: /**
075: * @return SinkHandler instance if one registered or null.
076: */
077: public static SinkHandler getInstance() {
078: SinkHandler h = null;
079: Handler[] handlers = Logger.getLogger("").getHandlers();
080: for (int i = 0; i < handlers.length; i++) {
081: if (handlers[i] instanceof SinkHandler) {
082: h = (SinkHandler) handlers[i];
083: break;
084: }
085: }
086: if (h == null) {
087: // None setup automatically (Not found in heritrix.properties --
088: // can happen when deployed in a containter such as tomcat).
089: // Create one manually here.
090: h = new SinkHandler();
091: h.setLevel(Level.WARNING);
092: Logger.getLogger("").addHandler(h);
093: }
094: return h;
095: }
096:
097: /**
098: * @return all SinkHandlerLogRecords.
099: */
100: public Vector getAll() {
101: return this .sink;
102: }
103:
104: /**
105: * @return Return all unread SinkHandlerLogRecords or null if none unread
106: */
107: public Vector<SinkHandlerLogRecord> getAllUnread() {
108: if (this .sink == null) {
109: return null;
110: }
111: Vector<SinkHandlerLogRecord> newLogRecords;
112: newLogRecords = new Vector<SinkHandlerLogRecord>();
113: for (final Iterator i = this .sink.iterator(); i.hasNext();) {
114: SinkHandlerLogRecord lr = (SinkHandlerLogRecord) i.next();
115: if (!lr.isRead()) {
116: newLogRecords.add(lr);
117: }
118: }
119: return (newLogRecords.size() == 0) ? null : newLogRecords;
120: }
121:
122: /**
123: * @return Count of all records.
124: */
125: public int getCount() {
126: return this .sink != null ? this .sink.size() : 0;
127: }
128:
129: /**
130: * @return The count of unread log records.
131: */
132: public int getUnreadCount() {
133: if (this .sink == null) {
134: return 0;
135: }
136: int n = 0;
137: for (final Iterator i = this .sink.iterator(); i.hasNext();) {
138: SinkHandlerLogRecord lr = (SinkHandlerLogRecord) i.next();
139: if (!lr.isRead()) {
140: n++;
141: }
142: }
143: return n;
144: }
145:
146: /**
147: * @param id The <code>sequenceNumber</code> ID of the log record to find.
148: * @return A SinkHandlerLogRecord of the given ID or null if not found.
149: */
150: public SinkHandlerLogRecord get(long id) {
151: if (this .sink == null) {
152: return null;
153: }
154: for (final Iterator i = this .sink.iterator(); i.hasNext();) {
155: SinkHandlerLogRecord lr = (SinkHandlerLogRecord) i.next();
156: if (lr.getSequenceNumber() == id) {
157: return lr;
158: }
159: }
160: return null;
161: }
162:
163: /**
164: * @param id The <code>sequenceNumber</code> ID of the log record to find.
165: * @return The removed SinkHandlerLogRecord or null if none removed.
166: */
167: public SinkHandlerLogRecord remove(final long id) {
168: SinkHandlerLogRecord shlr = null;
169: if (this .sink == null) {
170: return shlr;
171: }
172: for (final Iterator i = this .sink.iterator(); i.hasNext();) {
173: SinkHandlerLogRecord lr = (SinkHandlerLogRecord) i.next();
174: if (lr.getSequenceNumber() == id) {
175: i.remove();
176: shlr = lr;
177: break;
178: }
179: }
180: return shlr;
181: }
182:
183: /**
184: * @param id The <code>sequenceNumber</code> ID of the log record to find
185: * and mark as read.
186: */
187: public void read(final long id) {
188: for (final Iterator i = this .sink.iterator(); i.hasNext();) {
189: SinkHandlerLogRecord lr = (SinkHandlerLogRecord) i.next();
190: if (lr.getSequenceNumber() == id) {
191: lr.setRead();
192: break;
193: }
194: }
195: }
196: }
|