View Javadoc

1   /* SinkHandler
2    * Copyright (C) 2005 Internet Archive.
3    *
4    * Created on Jul 7, 2003
5    *
6    * This file is part of the Heritrix web crawler (crawler.archive.org).
7    *
8    * Heritrix is free software; you can redistribute it and/or modify
9    * it under the terms of the GNU Lesser Public License as published by
10   * the Free Software Foundation; either version 2.1 of the License, or
11   * any later version.
12   *
13   * Heritrix is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU Lesser Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser Public License
19   * along with Heritrix; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21   */
22  package org.archive.io;
23  
24  import java.util.Iterator;
25  import java.util.Vector;
26  import java.util.logging.Handler;
27  import java.util.logging.Level;
28  import java.util.logging.LogManager;
29  import java.util.logging.LogRecord;
30  import java.util.logging.Logger;
31  
32  
33  
34  /***
35   * A handler that keeps an in-memory vector of all events deemed loggable by
36   * configuration.
37   * Use it to iterate over logged events long after their occurance. One such
38   * use is as a sink for WARNING+SEVERE loggable events. Has support for
39   * whether a log record has been already-read.
40   * TODO: Add being able to get LogRecords by log level: i.e. return all
41   * Level.SEVERE, etc.
42   * TODO: Back the vector with a bdbje collection.
43   * @author stack
44   * @version $Date: 2006-09-22 17:23:04 +0000 (Fri, 22 Sep 2006) $ $Revision: 4646 $
45   */
46  public class SinkHandler extends Handler {
47      /***
48       * Alerts that have occured.
49       */
50      private Vector<SinkHandlerLogRecord> sink
51       = new Vector<SinkHandlerLogRecord>();
52      
53      public SinkHandler() {
54          LogManager manager = LogManager.getLogManager();
55          String className = getClass().getName();
56          String tmp = manager.getProperty(className + ".level");
57          if (tmp != null) {
58              setLevel(Level.parse(tmp));
59          }
60      }
61      
62      public void publish(LogRecord record) {
63          if (!isLoggable(record)) {
64              return;
65          }
66          this.sink.add(new SinkHandlerLogRecord(record));
67      }
68  
69      public void flush() {
70          // Nothing to do.
71      }
72  
73      public void close() throws SecurityException {
74          flush();
75      }
76      
77      /***
78       * @return SinkHandler instance if one registered or null.
79       */
80      public static SinkHandler getInstance() {
81          SinkHandler h = null;
82          Handler[] handlers = Logger.getLogger("").getHandlers();
83          for (int i = 0; i < handlers.length; i++) {
84              if (handlers[i] instanceof SinkHandler) {
85                  h = (SinkHandler) handlers[i];
86                  break;
87              }
88          }
89          if (h == null) {
90              // None setup automatically (Not found in heritrix.properties --
91              // can happen when deployed in a containter such as tomcat).
92              // Create one manually here.
93              h = new SinkHandler();
94              h.setLevel(Level.WARNING);
95              Logger.getLogger("").addHandler(h);
96          }
97          return h;
98      }
99      
100     /***
101      * @return all SinkHandlerLogRecords.
102      */
103     public Vector getAll() {
104         return this.sink;
105     }
106     
107     /***
108      * @return Return all unread SinkHandlerLogRecords or null if none unread
109      */
110     public Vector<SinkHandlerLogRecord> getAllUnread() {
111         if (this.sink == null) {
112             return null;
113         }
114         Vector<SinkHandlerLogRecord> newLogRecords;
115         newLogRecords = new Vector<SinkHandlerLogRecord>();
116         for (final Iterator i = this.sink.iterator(); i.hasNext();) {
117             SinkHandlerLogRecord lr = (SinkHandlerLogRecord) i.next();
118             if (!lr.isRead()) {
119                 newLogRecords.add(lr);
120             }
121         }
122         return (newLogRecords.size() == 0) ? null : newLogRecords;
123     }
124     
125     /***
126      * @return Count of all records.
127      */
128     public int getCount() {
129         return this.sink != null? this.sink.size(): 0;
130     }
131     
132     /***
133      * @return The count of unread log records.
134      */
135     public int getUnreadCount() {
136         if (this.sink == null) {
137             return 0;
138         }
139         int n = 0;
140         for (final Iterator i = this.sink.iterator(); i.hasNext();) {
141             SinkHandlerLogRecord lr = (SinkHandlerLogRecord)i.next();
142             if (!lr.isRead()) {
143                 n++;
144             }
145         }
146         return n;
147     }
148 
149     /***
150      * @param id The <code>sequenceNumber</code> ID of the log record to find.
151      * @return A SinkHandlerLogRecord of the given ID or null if not found.
152      */
153     public SinkHandlerLogRecord get(long id) {
154         if (this.sink == null) {
155             return null;
156         }
157         for (final Iterator i = this.sink.iterator(); i.hasNext();) {
158             SinkHandlerLogRecord lr = (SinkHandlerLogRecord)i.next();
159             if (lr.getSequenceNumber() == id) {
160                 return lr;
161             }
162         }
163         return null;
164     }
165 
166     /***
167      * @param id The <code>sequenceNumber</code> ID of the log record to find.
168      * @return The removed SinkHandlerLogRecord or null if none removed.
169      */
170     public SinkHandlerLogRecord remove(final long id) {
171         SinkHandlerLogRecord shlr = null;
172         if (this.sink == null) {
173             return  shlr;
174         }
175         for (final Iterator i = this.sink.iterator(); i.hasNext();) {
176             SinkHandlerLogRecord lr = (SinkHandlerLogRecord)i.next();
177             if (lr.getSequenceNumber() == id) {
178                 i.remove();
179                 shlr = lr;
180                 break;
181             }
182         }
183         return shlr;
184     }
185 
186     /***
187      * @param id The <code>sequenceNumber</code> ID of the log record to find
188      * and mark as read.
189      */
190     public void read(final long id) {
191         for (final Iterator i = this.sink.iterator(); i.hasNext();) {
192             SinkHandlerLogRecord lr = (SinkHandlerLogRecord)i.next();
193             if (lr.getSequenceNumber() == id) {
194                 lr.setRead();
195                 break;
196             }
197         }
198     }
199 }