@Override public int read(byte[] bytes, int off, int len) throws IOException { int nbRead; // Wait until at least 1 byte is available if a limit is set and try to read as many bytes are available // without exceeding the throughput limit or the number specified if(bpsLimit>=0) nbRead = in.read(bytes, off, Math.min(getNbAllowedBytes(),len)); else nbRead = in.read(bytes, off, len); // Increase read counter by the number of bytes that have actually been read by the underlying stream if(nbRead>0) addToLimitCounter(nbRead); return nbRead; }
/** * Closes the currently registered source InputStream. */ protected synchronized void closeCurrentInputStream() { if(tlin !=null) { try { tlin.close(); } catch(IOException e) {} } }
/** * Increases the number of bytes read this second to the given number. * * @param nbRead number of bytes that have been read or skipped from the underlying stream. */ private void addToLimitCounter(long nbRead) { updateLimitCounter(); this.nbBytesReadThisSecond += nbRead; }
@Override public int read() throws IOException { // Wait until at least 1 byte is available if a limit is set if(bpsLimit>=0) getNbAllowedBytes(); // Read the byte from the underlying stream int i = in.read(); // Increase read counter by 1 if(i>0) addToLimitCounter(1); return i; }
/** * Registers the given InputStream as currently in use, in order to: * <ul> * <li>count the number of bytes that have been read from it (see {@link #getCurrentFileByteCounter()}) * <li>block read methods calls when the job is paused * <li>limit the throughput if a limit has been specified (see {@link #setThroughputLimit(long)}) * <li>close the InputStream when the job is stopped * </ul> * * <p>This method should be called by subclasses when creating a new InputStream, before the InputStream is used. * * @param in the InputStream to be used * @return the 'augmented' InputStream using the given stream as the underlying InputStream */ protected synchronized InputStream setCurrentInputStream(InputStream in) { if(tlin==null) { tlin = new ThroughputLimitInputStream(new CounterInputStream(in, currentFileByteCounter), throughputLimit); } else { tlin.setUnderlyingInputStream(new CounterInputStream(in, currentFileByteCounter)); } return tlin; }
/** * Overrides {@link FileJob#jobPaused()} to pause any file processing * by having the source InputStream's read methods lock. */ @Override protected void jobPaused() { super.jobPaused(); synchronized(this) { if(tlin !=null) tlin.setThroughputLimit(0); } }
@Override public long skip(long l) throws IOException { long nbSkipped = in.skip(bpsLimit>=0?Math.min(getNbAllowedBytes(),l):l); // Increase read counter by the number of bytes that have actually been skipped by the underlying stream if(nbSkipped>0) addToLimitCounter(nbSkipped); return nbSkipped; }
/** * Overrides {@link FileJob#jobResumed()} to resume any file processing by releasing * the lock on the source InputStream's read methods. */ @Override protected void jobResumed() { super.jobResumed(); synchronized(this) { // Restore previous throughput limit (if any, -1 by default) if(tlin !=null) tlin.setThroughputLimit(throughputLimit); } }
/** * Sets a transfer throughput limit in bytes per seconds, replacing any previous limit. * This limit corresponds to the number of bytes that can be read from a registered InputStream. * * <p>Specifying 0 or -1 disables any throughput limit, the transfer will be carried out at full speed. * * <p>If this job is paused, the new limit will be effective after the job has been resumed. * If not, it will be effective immediately. * * @param bytesPerSecond new throughput limit in bytes per second, 0 or -1 to disable the limit */ public void setThroughputLimit(long bytesPerSecond) { // Note: ThroughputInputStream interprets 0 as a complete pause (blocks reads) which is different // from what a user would expect when specifying 0 as a limit this.throughputLimit = bytesPerSecond<=0?-1:bytesPerSecond; synchronized(this) { if(getState() != FileJobState.PAUSED && tlin !=null) tlin.setThroughputLimit(throughputLimit); } }
long msUntilNextSecond = updateLimitCounter(); msUntilNextSecond = updateLimitCounter();