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 InputArchiveMetaData { 49 50 private static final String CLASS_NAME 51 = "de/schlichtherle/io/InputArchiveMetaData".replace('/', '.'); private static final Logger logger = Logger.getLogger(CLASS_NAME, CLASS_NAME); 53 54 70 private final Archive archive; 71 72 private final InputArchive inArchive; 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 InputArchiveMetaData(final Archive archive, final InputArchive inArchive) { 103 assert inArchive != null; 104 105 this.archive = archive; 106 this.inArchive = inArchive; 107 108 inArchive.setMetaData(this); 109 } 110 111 synchronized InputStream getInputStream( 112 final ArchiveEntry entry, 113 final ArchiveEntry dstEntry) 114 throws IOException { 115 assert entry != null; 116 final InputStream in = inArchive.getInputStream(entry, dstEntry); 117 return in != null ? new EntryInputStream(in) : null; 118 } 119 120 133 synchronized int waitAllInputStreamsByOtherThreads(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 EntryInputStream in = (EntryInputStream) i.next(); 168 try { 169 in.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 EntryInputStream extends SynchronizedInputStream { 190 private boolean closed; 191 192 private EntryInputStream(final InputStream in) { 193 super(in, InputArchiveMetaData.this); 194 assert in != null; 195 streams.put(this, InputArchiveMetaData.this); tlStreams.increment(); 197 InputArchiveMetaData.this.notify(); } 199 200 private final void ensureNotStopped() throws IOException { 201 if (stopped) 202 throw new ArchiveEntryStreamClosedException(); 203 } 204 205 public int read() throws IOException { 206 ensureNotStopped(); 207 return super.read(); 208 } 209 210 public int read(byte[] b) throws IOException { 211 ensureNotStopped(); 212 return super.read(b); 213 } 214 215 public int read(byte[] b, int off, int len) throws IOException { 216 ensureNotStopped(); 217 return super.read(b, off, len); 218 } 219 220 public long skip(long n) throws IOException { 221 ensureNotStopped(); 222 return super.skip(n); 223 } 224 225 public int available() throws IOException { 226 ensureNotStopped(); 227 return super.available(); 228 } 229 230 238 public final void close() throws IOException { 239 if (closed) 240 return; 241 242 synchronized (lock) { 244 try { 245 doClose(); 246 } finally { 247 final Object removed = streams.remove(this); 248 assert removed == InputArchiveMetaData.this; 249 tlStreams.decrement(); 250 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!"; 251 InputArchiveMetaData.this.notify(); } 253 } 254 } 255 256 266 private void doClose() throws IOException { 267 assert !closed; 268 if (closed) 269 return; 270 271 closed = true; 272 in.close(); } 274 275 public void mark(int readlimit) { 276 if (!stopped) 277 super.mark(readlimit); 278 } 279 280 public void reset() throws IOException { 281 ensureNotStopped(); 282 super.reset(); 283 } 284 285 public boolean markSupported() { 286 return !stopped && super.markSupported(); 287 } 288 289 295 protected void finalize() { 296 if (closed) 297 return; 298 299 logger.finest("finalize.open"); 300 try { 301 doClose(); 302 } catch (IOException failure) { 303 logger.log(Level.FINE, "finalize.exception", failure); 304 } 305 } 306 } } 308 | Popular Tags |