package org.limewire.swarm.http.listener; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpResponse; import org.apache.http.nio.ContentDecoder; import org.apache.http.nio.IOControl; import org.limewire.collection.Range; import org.limewire.swarm.SwarmCoordinator; import org.limewire.swarm.SwarmFile; import org.limewire.swarm.SwarmWriteJob; import org.limewire.swarm.SwarmWriteJobControl; import org.limewire.swarm.http.SwarmHttpContentImpl; import org.limewire.swarm.http.SwarmHttpUtils; import org.limewire.util.Objects; public class SwarmHttpContentListener implements ResponseContentListener { private static final Log LOG = LogFactory.getLog(SwarmHttpContentListener.class); private final SwarmCoordinator swarmCoordinator; private boolean finished; private Range leaseRange; private SwarmWriteJob writeJob; private final SwarmFile swarmFile; public SwarmHttpContentListener(SwarmCoordinator fileCoordinator, SwarmFile swarmFile, Range leaseRange) { this.swarmCoordinator = Objects.nonNull(fileCoordinator, "fileCoordinator"); this.leaseRange = Objects.nonNull(leaseRange, "leaseRange"); this.swarmFile = swarmFile; } public void contentAvailable(ContentDecoder decoder, IOControl ioctrl) throws IOException { if (!swarmCoordinator.isComplete()) { LOG.trace("contentAvailable called"); if (finished) { String message = "Already finished."; LOG.warn(message); throw new IOException(message); } if (!decoder.isCompleted()) { if (writeJob == null) { writeJob = swarmCoordinator.createWriteJob(leaseRange, createControl(ioctrl)); } try { writeJob.write(new SwarmHttpContentImpl(decoder)); } catch (IOException e) { LOG.warn(e.getMessage(), e); throw e; } } } else { LOG.warn("contentAvailable called when swarmCoordinator already complete."); } } private SwarmWriteJobControl createControl(final IOControl finalIOControl) { SwarmWriteJobControl callBack = new SwarmWriteJobControl() { public void pause() { finalIOControl.suspendInput(); finalIOControl.suspendOutput(); } public void resume() { finalIOControl.requestOutput(); finalIOControl.requestInput(); } }; return callBack; } public void finished() { LOG.trace("finished"); if (!finished) { finished = true; if (leaseRange != null) { swarmCoordinator.unlease(leaseRange); leaseRange = null; } } } public void initialize(HttpResponse response) throws IOException { if (finished) { String message = "Already finished"; LOG.warn(message); throw new IOException(message); } Range actualRange = SwarmHttpUtils.parseContentRange(response); long startByte = swarmFile.getStartBytePosition(); actualRange = Range.createRange(startByte + actualRange.getLow(), startByte + actualRange.getHigh()); validateActualRangeAndShrinkExpectedRange(actualRange); } private void validateActualRangeAndShrinkExpectedRange(Range actualRange) throws IOException { if (actualRange.getLow() < leaseRange.getLow() || actualRange.getHigh() > leaseRange.getHigh()) { String message = "Invalid actual range. Expected: " + leaseRange + ", Actual: " + actualRange; LOG.warn(message); throw new IOException(message); } if (!actualRange.equals(leaseRange)) { leaseRange = swarmCoordinator.renewLease(leaseRange, actualRange); } } }