code: public static long copy(InputStream input, OutputStream output, boolean autoclose) throws IOException {
  		// check input parameters
  		if(input == null) {
  			logger.error("input stream must not be null");
  			throw new InvalidParameterException("input stream must not be null");
  		}		
  		if(output == null) {
  			logger.error("output stream must not be null");
  			throw new InvalidParameterException("output stream must not be null");
  		}
  		
  		// read a "bufferful" at a time and copy into the output stream 
  		try {
  			long total = 0;
  			byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
  			int read = 0;
  			while((read = input.read(buffer)) > 0) {
  //				logger.trace("read {} bytes from input stream", read);
  				total += read;
  				output.write(buffer, 0, read);
  			}
  //			logger.trace("total of {} bytes copied", total);
  			return total;
  		} finally {
  			if(autoclose) {
  				try {
  					input.close();
  				} catch(IOException e) {
  					logger.warn("error closing input stream", e);
  				}
  				try {
  					output.close();
  				} catch(IOException e) {
  					logger.warn("error closing output stream", e);
  				}
  			}
  		}
  	}
docs: Copies all the bytes it can read from the input stream into the output
  stream; input and output streams management (opening, flushing, closing)
  are all up to the caller.
  
  @param input
  an open and ready-to-be-read input stream.
  @param output
  an open output stream.
  @param autoclose
  whether input and output stream should be closed once this method has
  finished using them.
  @return
  the total number of bytes copied.
  @throws IOException