001: package dalma.impl;
002:
003: import java.io.BufferedOutputStream;
004: import java.io.File;
005: import java.io.FileOutputStream;
006: import java.io.IOException;
007: import java.io.ObjectOutputStream;
008: import java.io.ObjectInputStream;
009: import java.io.BufferedInputStream;
010: import java.io.FileInputStream;
011: import java.io.Serializable;
012: import java.util.logging.Handler;
013: import java.util.logging.Level;
014: import java.util.logging.LogRecord;
015: import java.util.logging.Logger;
016: import java.util.List;
017: import java.util.AbstractList;
018:
019: /**
020: * Records log data to file system, in such a way that
021: * it can be retrieved later.
022: *
023: * <p>
024: * More precisely, this class stores one log entry per one file,
025: * into a directory.
026: *
027: * @author Kohsuke Kawaguchi
028: */
029: final class LogRecorder extends Handler implements Serializable {
030: private final File dir;
031: private int id = 0;
032:
033: private static final Logger logger = Logger
034: .getLogger(LogRecorder.class.getName());
035:
036: /**
037: * View of all the current log entries as a {@link List}.
038: */
039: private transient/*final*/ListView allLogs = new ListView();
040:
041: private final class ListView extends AbstractList<LogRecord> {
042: public LogRecord get(int index) {
043: try {
044: ObjectInputStream ois = new ObjectInputStream(
045: new BufferedInputStream(new FileInputStream(
046: getFile(index))));
047: try {
048: return (LogRecord) ois.readObject();
049: } finally {
050: ois.close();
051: }
052: } catch (IOException e) {
053: logger.log(Level.WARNING, "Failed to read log record",
054: e);
055: return null;
056: } catch (ClassNotFoundException e) {
057: logger.log(Level.WARNING, "Failed to read log record",
058: e);
059: return null;
060: }
061: }
062:
063: public int size() {
064: return id;
065: }
066: }
067:
068: public LogRecorder(File dir) {
069: this .dir = dir;
070: if (!dir.isDirectory())
071: throw new IllegalArgumentException(dir
072: + " is not a directory");
073: // TODO: implement faster binary search like search
074: while (getFile(id).exists())
075: id++;
076: }
077:
078: /**
079: * Gets a virtual {@link List} that contains all log records written thus far.
080: */
081: public List<LogRecord> getLogs() {
082: return allLogs;
083: }
084:
085: public synchronized void publish(LogRecord record) {
086: File data;
087:
088: do {
089: data = getFile(id);
090: id++;
091: } while (data.exists());
092:
093: try {
094: ObjectOutputStream os = new ObjectOutputStream(
095: new BufferedOutputStream(new FileOutputStream(data)));
096: try {
097: os.writeObject(record);
098: } finally {
099: os.close();
100: }
101: } catch (IOException e) {
102: logger.log(Level.WARNING, "Failed to write log record", e);
103: // just throw away this log record
104: }
105: }
106:
107: public void flush() {
108: // noop
109: }
110:
111: public void close() throws SecurityException {
112: // noop
113: }
114:
115: private File getFile(int n) {
116: return new File(dir, String.format("%06d", n));
117: }
118:
119: private void readObject(ObjectInputStream in) throws IOException,
120: ClassNotFoundException {
121: in.defaultReadObject();
122: allLogs = new ListView();
123: }
124: }
|