1 6 21 22 package de.schlichtherle.io; 23 24 import de.schlichtherle.io.*; 25 import de.schlichtherle.io.archive.Archive; 26 import de.schlichtherle.io.archive.spi.*; 27 import de.schlichtherle.io.util.*; 28 import de.schlichtherle.util.*; 29 30 import java.io.*; 31 import java.util.*; 32 import java.util.logging.*; 33 34 48 public final class OutputArchiveMetaData { 49 50 private static final String CLASS_NAME 51 = "de/schlichtherle/io/OutputArchiveMetaData".replace('/', '.'); private static final Logger logger = Logger.getLogger(CLASS_NAME, CLASS_NAME); 53 54 70 private final Archive archive; 71 72 private final OutputArchive outArchive; 73 74 86 private final Map streams = File.isLenient() 87 ? (Map) new WeakHashMap() 88 : new HashMap(); 89 90 94 private final ThreadLocalCounter tlStreams = new ThreadLocalCounter(); 95 96 private volatile boolean stopped; 97 98 102 OutputArchiveMetaData(final Archive archive, final OutputArchive outArchive) { 103 assert outArchive != null; 104 105 this.archive = archive; 106 this.outArchive = outArchive; 107 108 outArchive.setMetaData(this); 109 } 110 111 synchronized OutputStream getOutputStream( 112 final ArchiveEntry entry, 113 final ArchiveEntry srcEntry) 114 throws IOException { 115 assert entry != null; 116 final OutputStream out = outArchive.getOutputStream(entry, srcEntry); 117 return out != null ? new EntryOutputStream(out) : null; 118 } 119 120 133 synchronized int waitAllOutputStreamsByOtherThreads(final long timeout) { 134 final long start = System.currentTimeMillis(); 135 final int localStreams = tlStreams.getCounter(); 136 try { 138 while (streams.size() > localStreams) { 139 long toWait; 140 if (timeout > 0) { 141 toWait = timeout - (System.currentTimeMillis() - start); 142 if (toWait <= 0) 143 break; 144 } else { 145 toWait = 0; 146 } 147 System.gc(); System.runFinalization(); wait(toWait); 150 } 151 } catch (InterruptedException ignored) { 152 } 153 154 return streams.size(); 155 } 156 157 164 synchronized ArchiveException closeAllStreams( 165 ArchiveException exceptionChain) { 166 for (final Iterator i = streams.keySet().iterator(); i.hasNext(); ) { 167 final EntryOutputStream out = (EntryOutputStream) i.next(); 168 try { 169 out.doClose(); 170 } catch (IOException failure) { 171 exceptionChain = new ArchiveWarningException( 172 exceptionChain, failure); 173 } 174 } 175 176 stopped = true; 177 streams.clear(); 178 179 return exceptionChain; 180 } 181 182 189 private final class EntryOutputStream extends SynchronizedOutputStream { 190 private boolean closed; 191 192 private EntryOutputStream(final OutputStream out) { 193 super(out, OutputArchiveMetaData.this); 194 assert out != null; 195 streams.put(this, OutputArchiveMetaData.this); tlStreams.increment(); 197 OutputArchiveMetaData.this.notify(); } 199 200 private final void ensureNotStopped() throws IOException { 201 if (stopped) 202 throw new ArchiveEntryStreamClosedException(); 203 } 204 205 public void write(int b) throws IOException { 206 ensureNotStopped(); 207 super.write(b); 208 } 209 210 public void write(byte[] b) throws IOException { 211 ensureNotStopped(); 212 super.write(b); 213 } 214 215 public void write(byte[] b, int off, int len) throws IOException { 216 ensureNotStopped(); 217 super.write(b, off, len); 218 } 219 220 public void flush() throws IOException { 221 ensureNotStopped(); 222 super.flush(); 223 } 224 225 233 public final void close() throws IOException { 234 if (closed) 235 return; 236 237 synchronized (lock) { 239 try { 240 try { 241 super.flush(); 242 } finally { 243 doClose(); 244 } 245 } finally { 246 final Object removed = streams.remove(this); 247 assert removed == OutputArchiveMetaData.this; 248 tlStreams.decrement(); 249 assert tlStreams.getCounter() >= 0 : "This stream has been closed by a different thread than the thread which created it - this is considered an application bug!"; 250 OutputArchiveMetaData.this.notify(); } 252 } 253 } 254 255 265 private void doClose() throws IOException { 266 assert !closed; 267 if (closed) 268 return; 269 270 closed = true; 271 try { 272 } finally { 274 out.close(); } 276 } 277 278 284 protected void finalize() { 285 if (closed) 286 return; 287 288 logger.finer("finalize.open"); 289 try { 290 doClose(); 291 } catch (IOException failure) { 292 logger.log(Level.FINE, "finalize.exception", failure); 293 } 294 } 295 } } 297 | Popular Tags |