DownloadManager.java :  » Net » frost-14 » frost » fileTransfer » download » Java Open Source

Java Open Source » Net » frost 14 
frost 14 » frost » fileTransfer » download » DownloadManager.java
/*
  DownloadManager.java / Frost

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License as
  published by the Free Software Foundation; either version 2 of
  the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package frost.fileTransfer.download;

import java.io.*;
import java.util.*;
import java.util.logging.*;

import frost.*;
import frost.fcp.*;
import frost.fileTransfer.*;
import frost.storage.*;
import frost.storage.perst.filelist.*;
import frost.util.*;
import frost.util.model.*;

public class DownloadManager implements ExitSavable {

    private static final Logger logger = Logger.getLogger(DownloadManager.class.getName());

  private DownloadModel model;
  private DownloadPanel panel;
  private DownloadTicker ticker;

  public DownloadManager() {
    super();
  }

  public void initialize() throws StorageException {
        getPanel();
    getModel().initialize();

        // on 0.5, load progress of all files
        if( FcpHandler.isFreenet05() ) {
            for(int x=0; x < getModel().getItemCount(); x++) {
                final FrostDownloadItem item = (FrostDownloadItem) getModel().getItemAt(x);
                frost.fcp.fcp05.FcpRequest.updateProgress(item);
            }
        }
  }

  /**
   * Start download now (manually).
   */
  public boolean startDownload(final FrostDownloadItem dlItem) {
      if( FileTransferManager.inst().getPersistenceManager() != null ) {
          return FileTransferManager.inst().getPersistenceManager().startDownload(dlItem);
      } else {
          return ticker.startDownload(dlItem);
      }
  }

  public void startTicker() {
        if (Core.isFreenetOnline()) {
            getTicker().start();
        }
    }

    public void exitSave() throws StorageException {
        getPanel().getTableFormat().saveTableLayout();
        getModel().exitSave();
    }

    public void addPanelToMainFrame(final MainFrame mainFrame) {
        mainFrame.addPanel("MainFrame.tabbedPane.downloads", getPanel());
    }

    /**
     * Count running items in model.
     */
    public void updateFileTransferInformation(final FileTransferInformation infos) {
        int waitingItems = 0;
        int runningItems = 0;
        for (int x = 0; x < model.getItemCount(); x++) {
            final FrostDownloadItem dlItem = (FrostDownloadItem) model.getItemAt(x);
            if( dlItem == null ) {
                continue;
            }
            if (dlItem.getState() != FrostDownloadItem.STATE_DONE
                    && dlItem.getState() != FrostDownloadItem.STATE_FAILED)
            {
                waitingItems++;
            }
            if (dlItem.getState() == FrostDownloadItem.STATE_PROGRESS) {
                runningItems++;
            }
        }
        infos.setDownloadsRunning(runningItems);
        infos.setDownloadsWaiting(waitingItems);
    }

    /**
     * Checks if a file with this name is already in model, and returns
     * a new name if needed.
     */
    public String ensureUniqueFilename(final String filename) {

        String newFilename = filename;
        int count = 2;

        while(true) {
            boolean loopAgain = false;
            for(int x=0; x < getModel().getItemCount(); x++) {
                final FrostDownloadItem dlItem = (FrostDownloadItem) getModel().getItemAt(x);
                if( dlItem.getFilename().equalsIgnoreCase(newFilename) ) {
                    loopAgain = true;
                    // we have a duplicate filename
                    // build new filename like "filename_2.ext"
                    final int pos = filename.lastIndexOf('.');
                    if( pos > 0 ) {
                        final String beforeDot = filename.substring(0, pos);
                        final String afterDot = filename.substring(pos);
                        newFilename = beforeDot + "_" + (count++) + afterDot;
                    } else {
                        // no '.' in filename
                        newFilename = filename + "_" + (count++);
                    }
                }
            }
            if( !loopAgain ) {
                break;
            }
        }
        return newFilename;
    }

  public DownloadPanel getPanel() {
    if (panel == null) {
      panel = new DownloadPanel();
      panel.setModel(getModel());
      panel.initialize();
    }
    return panel;
  }

  public DownloadModel getModel() {
    if (model == null) {
      model = new DownloadModel(new DownloadTableFormat());
    }
    return model;
  }

  private DownloadTicker getTicker() {
    if (ticker == null) {
      ticker = new DownloadTicker(getPanel());
    }
    return ticker;
  }

  /**
   * Add a new download item to the download table model.
   * @param key        complete key of download item
   * @param fileName   file name
   */
  public void addNewDownload(final String key, final String fileName) {
      // TODO: enhancement: search for key in shared files, maybe add as shared file
        final FrostDownloadItem dlItem = new FrostDownloadItem(fileName, key);
        model.addDownloadItem(dlItem); // false if file is already in table
  }

    /**
     * @return  true if request should be retried
     */
    public boolean notifyDownloadFinished(final FrostDownloadItem downloadItem, final FcpResultGet result, final File targetFile) {

        final String filename = downloadItem.getFilename();
        final String key = downloadItem.getKey();

        boolean retryImmediately = false;

        if (result == null || result.isSuccess() == false) {
            // download failed

            if( result != null ) {
                downloadItem.setErrorCodeDescription(result.getCodeDescription());
            }

            if( result != null
                    && FcpHandler.isFreenet07()
                    && result.getReturnCode() == 5
                    && key.startsWith("CHK@")
                    && key.indexOf("/") > 0 )
            {
                // 5 - Archive failure
                // node tries to access the file as a .zip file, try download again without any path
                final String newKey = key.substring(0, key.indexOf("/"));
                downloadItem.setKey(newKey);
                downloadItem.setState(FrostDownloadItem.STATE_WAITING);
                downloadItem.setLastDownloadStopTime(0);
                downloadItem.setInternalRemoveExpected(true);
                retryImmediately = true;

                logger.warning("Removed all path levels from key: "+key+" ; "+newKey);

            } else if( result != null
                    && FcpHandler.isFreenet07()
                    && result.getReturnCode() == 11
                    && key.startsWith("CHK@")
                    && key.indexOf("/") > 0 )
            {
                // 11 - The URI has more metastrings and I can't deal with them
                // remove one path level from CHK
                final String newKey = key.substring(0, key.lastIndexOf("/"));
                downloadItem.setKey(newKey);
                downloadItem.setState(FrostDownloadItem.STATE_WAITING);
                downloadItem.setLastDownloadStopTime(0);
                downloadItem.setInternalRemoveExpected(true);
                retryImmediately = true;

                logger.warning("Removed one path level from key: "+key+" ; "+newKey);

            } else if( result != null
                        && FcpHandler.isFreenet07()
                        && result.getReturnCode() == 27
                        && result.getRedirectURI() != null)
            {
                // permanent redirect, use new uri
                downloadItem.setKey(result.getRedirectURI());
                downloadItem.setState(FrostDownloadItem.STATE_WAITING);
                downloadItem.setInternalRemoveExpected(true);
                retryImmediately = true;

                logger.warning("Redirected to URI: "+result.getRedirectURI());

            } else if( result != null && result.isFatal() ) {
                // fatal, don't retry
//                downloadItem.setEnabled(Boolean.FALSE);  // keep enabled to allow sending of requests for shared files
                downloadItem.setState(FrostDownloadItem.STATE_FAILED);
                logger.warning("FILEDN: Download of " + filename + " failed FATALLY.");
            } else {
                downloadItem.setRetries(downloadItem.getRetries() + 1);

                logger.warning("FILEDN: Download of " + filename + " failed.");
                // set new state -> failed or waiting for another try
                if (downloadItem.getRetries() > Core.frostSettings.getIntValue(SettingsClass.DOWNLOAD_MAX_RETRIES)) {
//                    downloadItem.setEnabled(Boolean.valueOf(false)); // keep enabled to allow sending of requests for shared files
                    downloadItem.setState(FrostDownloadItem.STATE_FAILED);
                } else {
                    downloadItem.setState(FrostDownloadItem.STATE_WAITING);
                }
            }
        } else {

            logger.info("FILEDN: Download of " + filename + " was successful.");

            // download successful
            downloadItem.setFileSize(new Long(targetFile.length()));
            downloadItem.setState(FrostDownloadItem.STATE_DONE);
            downloadItem.setEnabled(Boolean.valueOf(false));

            downloadItem.setDownloadFinishedTime(System.currentTimeMillis());

            // update lastDownloaded time in filelist
            if( downloadItem.isSharedFile() ) {
                FileListStorage.inst().updateFrostFileListFileObjectAfterDownload(
                        downloadItem.getFileListFileObject().getSha(),
                        System.currentTimeMillis() );
            }

            // maybe log successful download to file localdata/downloads.txt
            if( Core.frostSettings.getBoolValue(SettingsClass.LOG_DOWNLOADS_ENABLED) && !downloadItem.isLoggedToFile() ) {
                final String line = downloadItem.getKey() + "/" + downloadItem.getFilename();
                final String fileName = Core.frostSettings.getValue(SettingsClass.DIR_LOCALDATA) + "Frost-Downloads.log";
                final File targetLogFile = new File(fileName);
                FileAccess.appendLineToTextfile(targetLogFile, line);
                downloadItem.setLoggedToFile(true);
            }

            // maybe remove finished download immediately
            if( Core.frostSettings.getBoolValue(SettingsClass.DOWNLOAD_REMOVE_FINISHED) ) {
                FileTransferManager.inst().getDownloadManager().getModel().removeFinishedDownloads();
            }
        }

        if( retryImmediately ) {
            downloadItem.setLastDownloadStopTime(-1);
        } else {
            downloadItem.setLastDownloadStopTime(System.currentTimeMillis());
        }

        return retryImmediately;
    }

    @SuppressWarnings("unchecked")
    public List<FrostDownloadItem> getDownloadItemList() {
        return getModel().getItems();
    }

    /**
     * Chooses next download item to start from download table.
     * @return the next download item to start downloading or null if a suitable
     *          one was not found.
     */
    public FrostDownloadItem selectNextDownloadItem() {

        // get the item with state "Waiting"
        final ArrayList<FrostDownloadItem> waitingItems = new ArrayList<FrostDownloadItem>();
        for (int i = 0; i < model.getItemCount(); i++) {
            final FrostDownloadItem dlItem = (FrostDownloadItem) model.getItemAt(i);
            final boolean itemIsEnabled = (dlItem.isEnabled()==null?true:dlItem.isEnabled().booleanValue());
            if( !itemIsEnabled ) {
                continue;
            }
            if( dlItem.isExternal() ) {
                continue;
            }
            if( dlItem.getKey() == null ) {
                // still no key, wait
                continue;
            }

            if( dlItem.getState() != FrostDownloadItem.STATE_WAITING ) {
                continue;
            }

            // check if waittime is expired
            final long waittimeMillis = Core.frostSettings.getIntValue(SettingsClass.DOWNLOAD_WAITTIME) * 60L * 1000L;
            // min->millisec
            if (dlItem.getLastDownloadStopTime() == 0 // never started
                || (System.currentTimeMillis() - dlItem.getLastDownloadStopTime()) > waittimeMillis)
            {
                waitingItems.add(dlItem);
            }
        }

        if (waitingItems.size() == 0) {
            return null;
        }

        if (waitingItems.size() > 1) { // performance issues
            Collections.sort(waitingItems, nextItemCmp);
        }
        return waitingItems.get(0);
    }

    public void notifyDownloadItemEnabledStateChanged(final FrostDownloadItem dlItem) {
        // for persistent items, set priority to 6 (pause) when disabled; and to configured default if enabled
        if( FileTransferManager.inst().getPersistenceManager() == null ) {
            return;
        }
        if( dlItem.isExternal() ) {
            return;
        }
        if( dlItem.getState() != FrostDownloadItem.STATE_PROGRESS ) {
            // not running, not in queue
            return;
        }
        final boolean itemIsEnabled = (dlItem.isEnabled()==null?true:dlItem.isEnabled().booleanValue());
        if( itemIsEnabled ) {
            // item is now enabled
            final int prio = Core.frostSettings.getIntValue(SettingsClass.FCP2_DEFAULT_PRIO_FILE_DOWNLOAD);
            FileTransferManager.inst().getPersistenceManager().changeItemPriorites(new ModelItem[] {dlItem}, prio);
        } else {
            // item is now disabled
            FileTransferManager.inst().getPersistenceManager().changeItemPriorites(new ModelItem[] {dlItem}, 6);
        }
    }

    /**
     * Used to sort FrostDownloadItems by lastUpdateStartTimeMillis ascending.
     */
    private static final Comparator<FrostDownloadItem> nextItemCmp = new Comparator<FrostDownloadItem>() {
        public int compare(final FrostDownloadItem value1, final FrostDownloadItem value2) {

            // choose item that with lowest addedTime
            final int cmp1 = Mixed.compareLong(value1.getDownloadAddedMillis(), value2.getDownloadAddedMillis());
            if( cmp1 != 0 ) {
                return cmp1;
            }

            // equal addedTimes, choose by blocksRemaining
            int blocksTodo1;
            int blocksTodo2;

            // compute remaining blocks
            if( value1.getRequiredBlocks() > 0 && value1.getDoneBlocks() > 0 ) {
                blocksTodo1 = value1.getRequiredBlocks() - value1.getDoneBlocks();
            } else {
                blocksTodo1 = Integer.MAX_VALUE; // never started
            }
            if( value2.getRequiredBlocks() > 0 && value2.getDoneBlocks() > 0 ) {
                blocksTodo2 = value2.getRequiredBlocks() - value2.getDoneBlocks();
            } else {
                blocksTodo2 = Integer.MAX_VALUE; // never started
            }

            final int cmp2 = Mixed.compareInt(blocksTodo1, blocksTodo2);
            if( cmp2 != 0 ) {
                return cmp2;
            }

            // equal remainingBlocks, choose smaller file (filesize can be -1)
            return Mixed.compareLong(value1.getFileSize(), value2.getFileSize());
        }
    };
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.