/** * Update the progress bar of the currently downloaded file in main window. Only update if progess * has at least increased by one percent of the total file size of the downloaded file. * * @param downloadedBytes The current amount of downloaded bytes * @param lastProgBarUpdate The byte count at the last progress bar update * @param file The download file * @return The byte count at the last progress bar update */ private int updateProgressBar(int downloadedBytes, int lastProgBarUpdate, DownloadFile file) { int totalSize = (int) file.getTotalFileSize(); // only update progess bar if progess has at least increased by one percent int diff = downloadedBytes - lastProgBarUpdate; int onePercent = (int) totalSize / 100; if (diff >= onePercent) { final String filename = file.getFilename(); final int db = downloadedBytes; SwingUtilities.invokeLater( new Runnable() { public void run() { mainApp.updateDownloadQueue(filename, db); } }); return downloadedBytes; // prog bar updated, so return the new byte count } return lastProgBarUpdate; // no update, so return the previous byte count }
/** This method starts the thread and begins to download the file. */ public void run() { int maxThreads = Integer.parseInt(mainApp.getPrefValue("ServerSettingsThreadCount")); int runningThreads = 0; HashMap<String, Integer> downloadedBytes = new HashMap<String, Integer>(); HashMap<String, Integer> lastProgBarUpdate = new HashMap<String, Integer>(); // loop at all segments of the download file while (!shutdown && (segQueue.hasMoreSegments() || runningThreads > 0)) { // more segments to go? while (segQueue.hasMoreSegments() && runningThreads < maxThreads && !pause && nioClient.hasFreeSlot()) { // get next download segment of the download file DownloadFileSegment seg = segQueue.nextSegment(); if (seg == null) break; String filename = seg.getDlFile().getFilename(); logger.msg("Downloading next segment of file: " + filename, MyLogger.SEV_DEBUG); // create new response handler RspHandler newHandler = new RspHandler(seg); activeRspHandlers.add(newHandler); // map the new response handler to the download file Vector<RspHandler> tmpVector = dlFileRspHandlerMap.get(seg.getDlFile()); if (tmpVector == null) tmpVector = new Vector<RspHandler>(); tmpVector.add(newHandler); dlFileRspHandlerMap.put(seg.getDlFile(), tmpVector); // start data download nioClient.fetchArticleData(seg.getGroups().firstElement(), seg.getArticleId(), newHandler); // increase thread counter runningThreads++; } // check if the next element of the result set is already finished Vector<RspHandler> toRemoveVector = new Vector<RspHandler>(); for (int i = 0; i < activeRspHandlers.size(); i++) { RspHandler handler = activeRspHandlers.get(i); // handle error response from NNTP server if (handler.getError() == RspHandler.ERR_NONE) { // no error, do nothing } else if (handler.getError() == RspHandler.ERR_AUTH) { // do nothing for this error (?) } else if (handler.getError() == RspHandler.ERR_FETCH) { // TODO: handle "430 no such article" error (?) String msg = "no such article found: <" + handler.dlFileSeg().getArticleId() + "> (" + handler.getErrorMsg() + ")"; logger.msg(msg, MyLogger.SEV_WARNING); } else { // all other errors shutdown = true; } // update downloaded byte counter ... DownloadFile dlFile = handler.dlFileSeg().getDlFile(); String filename = dlFile.getFilename(); int bytes = 0; Integer bytesInt = downloadedBytes.get(filename); if (bytesInt != null) bytes = bytesInt; bytes += handler.newByteCount(); downloadedBytes.put(filename, bytes); // ... and progres bar in main window int last = 0; Integer lastInt = lastProgBarUpdate.get(filename); if (lastInt != null) last = lastInt; last = updateProgressBar(bytes, last, dlFile); lastProgBarUpdate.put(filename, last); // all data downloaded? if (handler.isFinished()) { toRemoveVector.add(handler); runningThreads--; decrSegCount(filename); // decrease main window segment // counter // segment done, so check if whole download file is finished // now dlFile.removeSegment(handler.dlFileSeg().getIndex()); if (!dlFile.hasMoreSegments()) { try { handleFinishedDlFile(dlFile); } catch (Exception e) { logger.printStackTrace(e); } } } } activeRspHandlers.removeAll(toRemoveVector); toRemoveVector.removeAllElements(); // all tasks done? if (!segQueue.hasMoreSegments() && runningThreads == 0) { break; } try { // let the thread sleep a bit Thread.sleep(10); } catch (InterruptedException e) { // shutdown if interrupted shutdown = true; } } // end of main loop logger.msg("FileDownloader has finished downloading all files", MyLogger.SEV_DEBUG); }
/** * This method is called when a whole download file has been finished downloading. It updates main * application window and starts the decoding thread. * * @param dlFile The DownloadFile object that is finished */ private void handleFinishedDlFile(final DownloadFile dlFile) { final String filename = dlFile.getFilename(); logger.msg("File downloading finished: " + filename, MyLogger.SEV_INFO); // notify application that download has finished SwingUtilities.invokeLater( new Runnable() { public void run() { mainApp.fileDownloadFinished(filename); mainApp.setProgBarToDecoding(filename, dlFile.getSegCount()); } }); // create result vector Vector<byte[]> articleData = new Vector<byte[]>(); Vector<RspHandler> rspHandlers = dlFileRspHandlerMap.get(dlFile); for (int i = 0; i < rspHandlers.size(); i++) { byte[] tmpArray = removeFirstLine(rspHandlers.get(i).getData(true)); articleData.add(tmpArray); rspHandlers.set(i, null); // free some memory } // call garbage collector rspHandlers = null; dlFileRspHandlerMap.remove(dlFile); Runtime.getRuntime().gc(); logger.msg( "First line(s) dump:\n" + HelloNzbToolkit.firstLineFromByteData(articleData.get(0), 2), MyLogger.SEV_DEBUG); // determine data encoding (yenc or UU) String encoding = null; boolean bHasData = false; for (int i = 0; i < articleData.size(); i++) { byte[] abyteHelp = articleData.get(i); if (abyteHelp.length > 0) { bHasData = true; if (bytesEqualsString(abyteHelp, "=ybegin")) { encoding = "yenc"; break; } else if (bytesEqualsString(abyteHelp, "begin ")) { encoding = "uu"; break; } } } if (encoding == null) { if (bHasData) { encoding = "yenc"; logger.msg( "No suitable decoder (no data) found for downloaded file: " + dlFile.getFilename() + " -- Assuming yenc.", MyLogger.SEV_WARNING); } else { // too bad, no decoder found for this file :( logger.msg( "No suitable decoder found for downloaded file (no data): " + dlFile.getFilename(), MyLogger.SEV_ERROR); // update main application window SwingUtilities.invokeLater( new Runnable() { public void run() { mainApp.fileDecodingFinished(dlFile.getFilename()); } }); return; } } /* * // determine data encoding String encoding = null; * if(bytesEqualsString(articleData.get(0), "=ybegin")) encoding = * "yenc"; else if(bytesEqualsString(articleData.get(0), "begin ")) * encoding = "uu"; else { // too bad, no decoder found for this file :( * logger.msg("No suitable decoder found for downloaded file: " + * dlFile.getFilename(), MyLogger.SEV_ERROR); * * // update main application window SwingUtilities.invokeLater(new * Runnable() { public void run() { * mainApp.fileDecodingFinished(dlFile.getFilename()); } } ); * * return; } */ // start data decoding background thread FileDecoder fileDecoder = new FileDecoder(mainApp, dlDir, dlFile, articleData, encoding); Thread t = new Thread(fileDecoder); t.start(); }