Java tutorial
package byps.http; /* USE THIS FILE ACCORDING TO THE COPYRIGHT RULES IN LICENSE.TXT WHICH IS PART OF THE SOURCE CODE PACKAGE */ import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.util.HashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import byps.BContentStream; import byps.BException; import byps.BExceptionC; import byps.BTargetId; public class HIncomingSplittedStreamAsync extends BContentStream { private static Log log = LogFactory.getLog(HIncomingSplittedStreamAsync.class); protected final File tempDir; protected long readPos; protected long currentPartId; protected long maxPartId = Long.MAX_VALUE; protected HIncomingStreamAsync currentStreamPart; private HashMap<Long, HIncomingStreamAsync> streamParts = new HashMap<Long, HIncomingStreamAsync>(); HIncomingSplittedStreamAsync(BTargetId targetId, String contentType, long totalLength, String contentDisposition, long lifetimeMillis, File tempDir) throws IOException { super(contentType, totalLength, lifetimeMillis); this.setTargetId(targetId); this.tempDir = tempDir; setContentDisposition(contentDisposition); } public synchronized void addStream(long partId, long contentLength, boolean isLastPart, HRequestContext rctxt) throws IOException { if (log.isDebugEnabled()) log.debug("addStream(" + targetId + ", partId=" + partId + ", contentLength=" + contentLength + ", isLastPart=" + isLastPart); HIncomingStreamAsync streamPart = new HIncomingStreamAsync(targetId, contentType, contentLength, "", lifetimeMillis, tempDir, rctxt); streamParts.put(partId, streamPart); if (isLastPart) maxPartId = partId + 1; notifyAll(); // notify thread that might wait in read() if (log.isDebugEnabled()) log.debug(")addStream"); } @Override public void close() throws IOException { if (log.isDebugEnabled()) log.debug("close("); for (HIncomingStreamAsync strm : streamParts.values()) { try { strm.close(); } catch (IOException ignored) { } } streamParts.clear(); // Causes isExpired() to return true super.close(); if (log.isDebugEnabled()) log.debug(")close"); } private HIncomingStreamAsync getCurrentStreamPart(boolean nextPart) throws IOException { if (nextPart || currentStreamPart == null) { long t1 = System.currentTimeMillis(); long timeout = lifetimeMillis; synchronized (this) { if (nextPart) currentPartId++; if (currentPartId < maxPartId) { currentStreamPart = streamParts.get(currentPartId); while (currentStreamPart == null) { try { wait(timeout); long t2 = System.currentTimeMillis(); if (t2 - t1 > timeout) { throw new BException(BExceptionC.TIMEOUT, "Timeout while reading stream part"); } } catch (InterruptedException e) { throw new InterruptedIOException(); } currentStreamPart = streamParts.get(currentPartId); } } else { currentStreamPart = null; } } } return currentStreamPart; } private int internalRead(byte[] b, int off, int len) throws IOException { int ret = -1; final long totalLength = super.contentLength; if (totalLength == -1 || readPos < totalLength) { HIncomingStreamAsync streamPart = getCurrentStreamPart(false); if (streamPart != null) { ret = b != null ? streamPart.read(b, off, len) : streamPart.read(); while (ret == -1) { streamPart.close(); streamPart = getCurrentStreamPart(true); if (streamPart == null) break; ret = b != null ? streamPart.read(b, off, len) : streamPart.read(); } } } if (ret != -1) { readPos += ret; } return ret; } @Override public int read(byte[] b, int off, int len) throws IOException { return internalRead(b, off, len); } @Override public int read() throws IOException { return internalRead(null, 0, 0); } @Override public synchronized BContentStream materialize() throws BException { if (readPos != 0) throw new BException(BExceptionC.INTERNAL, "InputStream cannot be copied after bytes alread have been read."); HIncomingStreamSync istrm = null; try { istrm = new HIncomingStreamSync(this, lifetimeMillis, tempDir); istrm.assignStream(this); // Reset stream IDs. // Otherwise the stream would not be sent, see BOutput.createStreamRequest. istrm.setTargetId(BTargetId.ZERO); // materialize closes "this" this.close(); } catch (IOException e) { throw new BException(BExceptionC.IOERROR, "Failed to clone stream", e); } return istrm; } }