@Override public long download(boolean resume, DownloadCompleteCallback callback) { switch (status) { case ABORTED: case UNRECOVERABLE_ERROR: case DOWNLOAD_FINISHED: return 0; default: } int bytes = 0; File file = new File(toFile); try { long localFileSize = 0; if (file.exists() && resume) { localFileSize = file.length(); s_logger.info("Resuming download to file (current size)=" + localFileSize); } Date start = new Date(); int responseCode = 0; if (localFileSize > 0) { // require partial content support for resume request.addRequestHeader("Range", "bytes=" + localFileSize + "-"); if (client.executeMethod(request) != HttpStatus.SC_PARTIAL_CONTENT) { errorString = "HTTP Server does not support partial get"; status = TemplateDownloader.Status.UNRECOVERABLE_ERROR; return 0; } } else if ((responseCode = client.executeMethod(request)) != HttpStatus.SC_OK) { status = TemplateDownloader.Status.UNRECOVERABLE_ERROR; errorString = " HTTP Server returned " + responseCode + " (expected 200 OK) "; return 0; // FIXME: retry? } Header contentLengthHeader = request.getResponseHeader("Content-Length"); boolean chunked = false; long remoteSize2 = 0; if (contentLengthHeader == null) { Header chunkedHeader = request.getResponseHeader("Transfer-Encoding"); if (chunkedHeader == null || !"chunked".equalsIgnoreCase(chunkedHeader.getValue())) { status = TemplateDownloader.Status.UNRECOVERABLE_ERROR; errorString = " Failed to receive length of download "; return 0; // FIXME: what status do we put here? Do we retry? } else if ("chunked".equalsIgnoreCase(chunkedHeader.getValue())) { chunked = true; } } else { remoteSize2 = Long.parseLong(contentLengthHeader.getValue()); } if (remoteSize == 0) { remoteSize = remoteSize2; } if (remoteSize > MAX_TEMPLATE_SIZE_IN_BYTES) { s_logger.info( "Remote size is too large: " + remoteSize + " , max=" + MAX_TEMPLATE_SIZE_IN_BYTES); status = Status.UNRECOVERABLE_ERROR; errorString = "Download file size is too large"; return 0; } if (remoteSize == 0) { remoteSize = MAX_TEMPLATE_SIZE_IN_BYTES; } InputStream in = !chunked ? new BufferedInputStream(request.getResponseBodyAsStream()) : new ChunkedInputStream(request.getResponseBodyAsStream()); RandomAccessFile out = new RandomAccessFile(file, "rwd"); out.seek(localFileSize); s_logger.info( "Starting download from " + getDownloadUrl() + " to " + toFile + " remoteSize=" + remoteSize + " , max size=" + MAX_TEMPLATE_SIZE_IN_BYTES); byte[] block = new byte[CHUNK_SIZE]; long offset = 0; boolean done = false; status = TemplateDownloader.Status.IN_PROGRESS; while (!done && status != Status.ABORTED && offset <= remoteSize) { if ((bytes = in.read(block, 0, CHUNK_SIZE)) > -1) { out.write(block, 0, bytes); offset += bytes; out.seek(offset); totalBytes += bytes; } else { done = true; } } Date finish = new Date(); String downloaded = "(incomplete download)"; if (totalBytes >= remoteSize) { status = TemplateDownloader.Status.DOWNLOAD_FINISHED; downloaded = "(download complete remote=" + remoteSize + "bytes)"; } errorString = "Downloaded " + totalBytes + " bytes " + downloaded; downloadTime += finish.getTime() - start.getTime(); out.close(); return totalBytes; } catch (HttpException hte) { status = TemplateDownloader.Status.UNRECOVERABLE_ERROR; errorString = hte.getMessage(); } catch (IOException ioe) { status = TemplateDownloader.Status.UNRECOVERABLE_ERROR; // probably a file write error? errorString = ioe.getMessage(); } finally { if (status == Status.UNRECOVERABLE_ERROR && file.exists() && !file.isDirectory()) { file.delete(); } request.releaseConnection(); if (callback != null) { callback.downloadComplete(status); } } return 0; }
@Override public long download(boolean resume, DownloadCompleteCallback callback) { if (_status == Status.ABORTED || _status == Status.UNRECOVERABLE_ERROR || _status == Status.DOWNLOAD_FINISHED) { return 0; } _start = System.currentTimeMillis(); _resume = resume; File src; try { src = new File(new URI(_downloadUrl)); } catch (URISyntaxException e1) { s_logger.warn("Invalid URI " + _downloadUrl); _status = Status.UNRECOVERABLE_ERROR; return 0; } File dst = new File(_toFile); FileChannel fic = null; FileChannel foc = null; FileInputStream fis = null; FileOutputStream fos = null; try { if (_storage != null) { dst.createNewFile(); _storage.setWorldReadableAndWriteable(dst); } ByteBuffer buffer = ByteBuffer.allocate(1024 * 512); try { fis = new FileInputStream(src); } catch (FileNotFoundException e) { s_logger.warn("Unable to find " + _downloadUrl); _errorString = "Unable to find " + _downloadUrl; return -1; } fic = fis.getChannel(); try { fos = new FileOutputStream(dst); } catch (FileNotFoundException e) { s_logger.warn("Unable to find " + _toFile); return -1; } foc = fos.getChannel(); _remoteSize = src.length(); _totalBytes = 0; _status = TemplateDownloader.Status.IN_PROGRESS; try { while (_status != Status.ABORTED && fic.read(buffer) != -1) { buffer.flip(); int count = foc.write(buffer); _totalBytes += count; buffer.clear(); } } catch (IOException e) { s_logger.warn("Unable to download", e); } String downloaded = "(incomplete download)"; if (_totalBytes == _remoteSize) { _status = TemplateDownloader.Status.DOWNLOAD_FINISHED; downloaded = "(download complete)"; } _errorString = "Downloaded " + _remoteSize + " bytes " + downloaded; _downloadTime += System.currentTimeMillis() - _start; return _totalBytes; } catch (Exception e) { _status = TemplateDownloader.Status.UNRECOVERABLE_ERROR; _errorString = e.getMessage(); return 0; } finally { if (fic != null) { try { fic.close(); } catch (IOException e) { s_logger.info("[ignore] error while closing file input channel."); } } if (foc != null) { try { foc.close(); } catch (IOException e) { s_logger.info("[ignore] error while closing file output channel."); } } if (fis != null) { try { fis.close(); } catch (IOException e) { s_logger.info("[ignore] error while closing file input stream."); } } if (fos != null) { try { fos.close(); } catch (IOException e) { s_logger.info("[ignore] error while closing file output stream."); } } if (_status == Status.UNRECOVERABLE_ERROR && dst.exists()) { dst.delete(); } if (callback != null) { callback.downloadComplete(_status); } } }