package org.limewire.http.entity; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.http.entity.AbstractHttpEntity; import org.apache.http.nio.ContentEncoder; import org.apache.http.nio.IOControl; import org.apache.http.nio.entity.ProducingNHttpEntity; import org.limewire.nio.NIODispatcher; import org.limewire.nio.observer.Shutdownable; import org.limewire.nio.timeout.StalledUploadWatchdog; /** * Abstract implementation of {@link ProducingNHttpEntity} that adds support for * timing out the transfer if it takes too long. */ public abstract class AbstractProducingNHttpEntity extends AbstractHttpEntity implements ProducingNHttpEntity { /** Cancels the transfer if inactivity for too long. */ private StalledUploadWatchdog watchdog; private long timeout = StalledUploadWatchdog.DELAY_TIME; private boolean initialized = false; /** shutdownable to shut off in case of a timeout */ private final Shutdownable timeoutable = new Shutdownable() { public void shutdown() { timeout(); } }; protected void activateTimeout() { if (this.watchdog == null) { this.watchdog = new StalledUploadWatchdog(timeout, NIODispatcher.instance() .getScheduledExecutorService()); } this.watchdog.activate(timeoutable); } protected void deactivateTimeout() { if (this.watchdog != null) { this.watchdog.deactivate(); } } /** * Throws <code>UnsupportedOperationException</code>. */ public InputStream getContent() throws IOException, IllegalStateException { throw new UnsupportedOperationException(); } public abstract long getContentLength(); /** * Throws <code>UnsupportedOperationException</code>. */ public boolean isRepeatable() { throw new UnsupportedOperationException(); } /** * Throws <code>UnsupportedOperationException</code>. */ public boolean isStreaming() { throw new UnsupportedOperationException(); } /** * Throws <code>UnsupportedOperationException</code>. */ public void writeTo(OutputStream outstream) throws IOException { throw new UnsupportedOperationException(); } public final void produceContent(ContentEncoder encoder, IOControl ioctrl) throws IOException { if (!initialized) { initialized = true; initialize(encoder, ioctrl); } if (!writeContent(encoder, ioctrl)) { encoder.complete(); } } /** * Sub-classes need to implement this and and write data to the * ContentEncoder. * * @throws IOException indicates an I/O error which will abort the * connection * @return true, if more data is expected; false, if the transfer is * complete */ public abstract boolean writeContent(ContentEncoder contentEncoder, IOControl ioctrl) throws IOException; /** * Invoked before the first call to * {@link #writeContent(ContentEncoder, IOControl)}. * * @throws IOException indicates an I/O error which will abort the * connection */ public abstract void initialize(ContentEncoder contentEncoder, IOControl ioctrl) throws IOException; /** * Invoked when the transfer times out. Needs to close the underlying * connection. */ public abstract void timeout(); }