1 6 package org.prevayler.foundation; 7 8 import java.io.*; 9 10 11 public class DurableOutputStream { 12 private static final int NOT_CLOSED = 0; 13 private static final int CLOSE_CALLED = 1; 14 private static final int REALLY_CLOSED = 2; 15 16 private final File _file; 17 private final ObjectOutputStream _objectOutputStream; 18 private final FileOutputStream _fileOutputStream; 19 private final FileDescriptor _fileDescriptor; 20 21 private IOException _exceptionWhileSynching; 22 private IOException _exceptionWhileClosing; 23 24 private int _objectsWritten = 0; 25 private int _objectsSynced = 0; 26 private int _fileSyncCount = 0; 27 28 private int _closingState = NOT_CLOSED; 29 30 public DurableOutputStream(File file) throws IOException { 31 _file = file; 32 _fileOutputStream = new FileOutputStream(file); 33 _fileDescriptor = _fileOutputStream.getFD(); 34 _objectOutputStream = new ObjectOutputStream(new BufferedOutputStream(_fileOutputStream, 16 * 512)); 36 startSyncher(); 37 } 38 39 private void startSyncher() { 40 Thread syncher = new Thread () { 41 public void run() { 42 syncher(); 43 } 44 }; 45 syncher.setDaemon(true); 46 syncher.start(); 47 } 48 49 50 public void sync(Object object, Turn myTurn) throws IOException { 51 int thisWrite; 52 53 try { 54 myTurn.start(); 55 thisWrite = writeObject(object); 56 } finally { 57 myTurn.end(); 58 } 59 60 waitUntilSynced(thisWrite); 61 } 62 63 private synchronized int writeObject(Object object) throws IOException { 64 if (_closingState != NOT_CLOSED) { 65 throw new IOException("stream is closing"); 66 } 67 68 _objectOutputStream.writeObject(object); 69 _objectOutputStream.reset(); 70 _objectsWritten++; 71 notifyAll(); 72 return _objectsWritten; 73 } 74 75 private synchronized void waitUntilSynced(int thisWrite) throws IOException { 76 while (_objectsSynced < thisWrite && _exceptionWhileSynching == null) { 77 Cool.wait(this); 78 } 79 if (_objectsSynced < thisWrite) { 80 throw _exceptionWhileSynching; 81 } 82 } 83 84 public synchronized void close() throws IOException { 85 if (_closingState == NOT_CLOSED) { 86 _closingState = CLOSE_CALLED; 87 notifyAll(); 88 } 89 90 while (_closingState != REALLY_CLOSED) { 91 Cool.wait(this); 92 } 93 94 if (_exceptionWhileClosing != null) { 95 throw _exceptionWhileClosing; 96 } 97 } 98 99 private synchronized void syncher() { 100 try { 101 while (true) { 102 while (_objectsSynced == _objectsWritten && _closingState == NOT_CLOSED) { 103 Cool.wait(this); 104 } 105 106 if (_objectsSynced == _objectsWritten) { 107 break; 108 } 109 110 _objectOutputStream.flush(); 111 112 _fileOutputStream.flush(); 119 120 _fileDescriptor.sync(); 121 122 _objectsSynced = _objectsWritten; 123 _fileSyncCount++; 124 125 notifyAll(); 126 } 127 } catch (IOException duringSync) { 128 _exceptionWhileSynching = duringSync; 129 } finally { 130 try { 131 _objectOutputStream.close(); 132 } catch (IOException duringClose) { 133 _exceptionWhileClosing = duringClose; 134 } 135 _closingState = REALLY_CLOSED; 136 notifyAll(); 137 } 138 } 139 140 141 public File file() { 142 return _file; 143 } 144 145 public synchronized int fileSyncCount() { 146 return _fileSyncCount; 147 } 148 149 public synchronized boolean reallyClosed() { 150 return _closingState == REALLY_CLOSED; 151 } 152 153 } 154 | Popular Tags |