Package com.mucommander.job

Source Code of com.mucommander.job.SplitFileJob

/*
* This file is part of muCommander, http://www.mucommander.com
* Copyright (C) 2002-2012 Maxence Bernard
*
* muCommander 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 3 of the License, or
* (at your option) any later version.
*
* muCommander 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, see <http://www.gnu.org/licenses/>.
*/

package com.mucommander.job;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mucommander.commons.file.AbstractFile;
import com.mucommander.commons.file.DummyFile;
import com.mucommander.commons.file.FileOperation;
import com.mucommander.commons.file.FilePermissions;
import com.mucommander.commons.file.FileURL;
import com.mucommander.commons.file.util.FileSet;
import com.mucommander.commons.io.BufferPool;
import com.mucommander.commons.io.ChecksumInputStream;
import com.mucommander.commons.io.FileTransferException;
import com.mucommander.commons.io.StreamUtils;
import com.mucommander.text.Translator;
import com.mucommander.ui.action.ActionProperties;
import com.mucommander.ui.action.impl.SplitFileAction;
import com.mucommander.ui.dialog.file.FileCollisionDialog;
import com.mucommander.ui.dialog.file.ProgressDialog;
import com.mucommander.ui.main.MainFrame;

/**
* This job split the file into parts with given size.
* @author Mariusz Jakubowski
*/
public class SplitFileJob extends AbstractCopyJob {
  private static final Logger LOGGER = LoggerFactory.getLogger(SplitFileJob.class);
 
    private long partSize;
  private AbstractFile sourceFile;
  private InputStream origFileStream;
  private AbstractFile destFolder;
  private long sizeLeft;
  private boolean recalculateCRC = false;


  /**
   * A class for holding file name and size of one part.
   * @author Mariusz Jakubowski
   *
   */
  private static class DummyDestFile extends DummyFile {
    private long size;
   
    public DummyDestFile(FileURL url, long size) {
      super(url);
      this.size = size;
    }
   
    @Override
        public long getSize() {
      return size;
    }
  }

 
  public SplitFileJob(ProgressDialog progressDialog, MainFrame mainFrame,
      AbstractFile file, AbstractFile destFolder, long partSize, int parts) {
        super(progressDialog, mainFrame, new FileSet(), destFolder, null, FileCollisionDialog.ASK_ACTION);
        this.partSize = partSize;
        this.setNbFiles(parts);
        this.sourceFile = file;
        this.destFolder = destFolder;
        this.errorDialogTitle = Translator.get("split_file_dialog.error_title");
        createInputStream();
        sizeLeft = sourceFile.getSize();
        for (int i=1; i<=parts; i++) {
          addDummyFile(i, Math.min(partSize, sizeLeft));
          sizeLeft -= partSize;
        }
        sizeLeft = sourceFile.getSize();
    }

  /**
   * Adds a dummy output file (used in progress monitoring).
   * @param i index of a file
   * @param size size of a file
   */
  private void addDummyFile(int i, long size) {
      String num;
      if (i<10) {
        num = "00" + Integer.toString(i);
      } else if (i<100) {
        num = "0" + Integer.toString(i);
      } else {
        num = Integer.toString(i);
      }
        FileURL childURL = (FileURL)destFolder.getURL().clone();
        childURL.setPath(destFolder.addTrailingSeparator(childURL.getPath()) + sourceFile.getName() + "." + num);
      DummyDestFile fileHolder = new DummyDestFile(childURL, size);
      files.add(fileHolder);
  }
 
 
  @Override
    protected void jobStarted() {
    super.jobStarted();
    createInputStream();
  }

  /**
   * Creates an input stream from the file.
   */
  private void createInputStream() {
        try {
          origFileStream = sourceFile.getInputStream();
    }
        catch (IOException e) {
            LOGGER.debug("Caught exception", e);
            showErrorDialog(errorDialogTitle,
                    Translator.get("error_while_transferring", sourceFile.getName()),
                    new String[]{CANCEL_TEXT},
                    new int[]{CANCEL_ACTION}
                    );
            setState(INTERRUPTED);
            return;
    }
        origFileStream = setCurrentInputStream(origFileStream);
        // init checksum calculation
        if (isIntegrityCheckEnabled()) {
      try {
        origFileStream = new ChecksumInputStream(origFileStream, MessageDigest.getInstance("CRC32"));
      } catch (NoSuchAlgorithmException e) {
        setIntegrityCheckEnabled(false);
                LOGGER.debug("Caught exception", e);
      }
        }
  }
 

    @Override
    protected boolean processFile(AbstractFile file, Object recurseParams) {
        if(getState()==INTERRUPTED)
            return false;
       
        // Create destination AbstractFile instance
        AbstractFile destFile = createDestinationFile(baseDestFolder, file.getName());
        if (destFile == null)
            return false;

        destFile = checkForCollision(sourceFile, baseDestFolder, destFile, false);
        if (destFile == null)
            return false;
       
        OutputStream out = null;
        try {
      out = destFile.getOutputStream();
     
      try {
        long written = StreamUtils.copyStream(origFileStream, out, BufferPool.getDefaultBufferSize(), partSize);
        sizeLeft -= written;
      } catch (FileTransferException e) {
        if (e.getReason() == FileTransferException.WRITING_DESTINATION) {
          // out of disk space - ask a user for a new disk
          recalculateCRC = true;    // recalculate CRC (DigestInputStream doesn't support mark() and reset())
          out.close();
          out = null;
          sizeLeft -= e.getBytesWritten();
          showErrorDialog(ActionProperties.getActionLabel(SplitFileAction.Descriptor.ACTION_ID),
              Translator.get("split_file_dialog.insert_new_media"),
              new String[]{OK_TEXT, CANCEL_TEXT},
              new int[]{OK_ACTION, CANCEL_ACTION});
          if (getState()==INTERRUPTED) {
            return false;
          }
          // create new output file if necessary
          if ((sizeLeft>0) && (getCurrentFileIndex() == getNbFiles()-1)) {
            setNbFiles(getNbFiles() + 1);
            addDummyFile(getNbFiles(), sizeLeft);
          }
        } else {
          throw e;
        }
      }
     
          // Preserve source file's date
            if(destFile.isFileOperationSupported(FileOperation.CHANGE_DATE)) {
                try {
                    destFile.changeDate(sourceFile.getDate());
                }
                catch (IOException e) {
                    LOGGER.debug("failed to change date of "+destFile, e);
                    // Fail silently
                }
            }

          // Preserve source file's permissions: preserve only the permissions bits that are supported by the source
            // file and use default permissions for the rest of them.
            if(destFile.isFileOperationSupported(FileOperation.CHANGE_PERMISSION)) {
                try {
                    // use #importPermissions(AbstractFile, int) to avoid isDirectory test
                    destFile.importPermissions(sourceFile, FilePermissions.DEFAULT_FILE_PERMISSIONS);
                }
                catch (IOException e) {
                    LOGGER.debug("failed to import "+sourceFile+" permissions into "+destFile, e);
                    // Fail silently
                }
            }
    }
        catch (IOException e) {
            LOGGER.debug("Caught exception", e);

            showErrorDialog(errorDialogTitle,
                    Translator.get("error_while_transferring", destFile.getName()),
                    new String[]{CANCEL_TEXT},
                    new int[]{CANCEL_ACTION}
                    );
      return false;
     
    } finally {
            try {
              if (out!=null)
                out.close();
            }
            catch(IOException e2) {
            }
    }
   
      return true;
    }


    // This job modifies baseDestFolder and its subfolders
    @Override
    protected boolean hasFolderChanged(AbstractFile folder) {
        return baseDestFolder.isParentOf(folder);
    }
   
    @Override
    protected void jobCompleted() {
      // create checksum file
      if (isIntegrityCheckEnabled()) {
            if(origFileStream!=null && (origFileStream instanceof ChecksumInputStream)) {
              String crcFileName = sourceFile.getName() + ".sfv";
                try {
                String sourceChecksum;
                if (recalculateCRC ) {
                  origFileStream = sourceFile.getInputStream();
            sourceChecksum = AbstractFile.calculateChecksum(origFileStream, MessageDigest.getInstance("CRC32"));
            origFileStream.close();
                } else {
                    sourceChecksum = ((ChecksumInputStream)origFileStream).getChecksumString();
                }
          AbstractFile crcFile = baseDestFolder.getDirectChild(crcFileName);
          OutputStream crcStream = crcFile.getOutputStream();
          String line = sourceFile.getName() + " " + sourceChecksum;
          crcStream.write(line.getBytes("utf-8"));
          crcStream.close();
        } catch (Exception e) {
                    LOGGER.debug("Caught exception", e);
         
                showErrorDialog(errorDialogTitle,
                        Translator.get("error_while_transferring", crcFileName),
                        new String[]{CANCEL_TEXT},
                        new int[]{CANCEL_ACTION}
                        );
        }
            }
      }
      super.jobCompleted();
    }


}
TOP

Related Classes of com.mucommander.job.SplitFileJob

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.