eu.geclipse.ui.internal.transfer.GridElementTransferOperation.java Source code

Java tutorial

Introduction

Here is the source code for eu.geclipse.ui.internal.transfer.GridElementTransferOperation.java

Source

/*****************************************************************************
 * Copyright (c) 2006-2008 g-Eclipse Consortium 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Initial development of the original code was made for the
 * g-Eclipse project founded by European Union
 * project number: FP6-IST-034327  http://www.geclipse.eu/
 *
 * Contributors:
 *    Mathias Stuempert - initial API and implementation
 *****************************************************************************/

package eu.geclipse.ui.internal.transfer;

import java.net.URI;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

import eu.geclipse.core.filesystem.GEclipseURI;
import eu.geclipse.core.filesystem.TransferInformation;
import eu.geclipse.core.filesystem.TransferManager;
import eu.geclipse.core.model.IGridConnection;
import eu.geclipse.core.model.IGridConnectionElement;
import eu.geclipse.core.model.IGridContainer;
import eu.geclipse.core.model.IGridElement;
import eu.geclipse.core.reporting.IProblem;
import eu.geclipse.core.reporting.ProblemException;
import eu.geclipse.ui.dialogs.ProblemDialog;
import eu.geclipse.ui.internal.Activator;

/**
 * Job for transferring elements from local to local, local to remote,
 * remote to local and remote to remote. Elements may either by copied
 * or moved. A move operation is an ordinary copy operation followed
 * by a delete operation. Both files and directories are supported.  
 */
public class GridElementTransferOperation extends Job {

    private enum OverwriteMode {
        /**
         * 
         */
        ASK,
        /**
         * 
         */
        OVERWRITE_ALL,
        /**
         * 
         */
        IGNORE_ALL
    }

    /**
     * The target of the transfer operation.
     */
    private IGridContainer globalTarget;

    /**
     * The elements to be transfered.
     */
    private IGridElement[] elements;

    /**
     * TransferOperation
     */
    private TransferInformation transferOperation;

    /**
     * Determines if this is a copy or a move operation. 
     */
    private boolean move;

    private OverwriteMode overwriteMode = OverwriteMode.ASK;

    /**
     * Create a new transfer operation. This may either be a copy or a
     * move operation.
     * 
     * @param elements The elements that should be transfered.
     * @param target The destination of the transfer.
     * @param move If true this operation will move the elements to the
     * target and will afterward delete the original files, otherwise
     * the original files will not be deleted.
     */
    public GridElementTransferOperation(final IGridElement[] elements, final IGridContainer target,
            final boolean move) {
        super(Messages.getString("GridElementTransferOperation.transfer_name")); //$NON-NLS-1$
        this.globalTarget = target;
        this.elements = elements;
        this.move = move;
    }

    /**
     * Create a new grid element transfer operation for file stores.
     * 
     * @param transferOperation transfer operation with information about transfer
     */
    public GridElementTransferOperation(final TransferInformation transferOperation) {
        super(Messages.getString("GridElementTransferOperation.transfer_name")); //$NON-NLS-1$
        this.transferOperation = transferOperation;
    }

    /**
     * Get the destination of this transfer.
     * 
     * @return This transfer's target.
     */
    public IGridContainer getTarget() {
        return this.globalTarget;
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public IStatus run(final IProgressMonitor monitor) {

        IProgressMonitor localMonitor = monitor == null ? new NullProgressMonitor() : monitor;

        MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK,
                Messages.getString("GridElementTransferOperation.op_status"), //$NON-NLS-1$
                null);

        if (this.transferOperation != null) {
            //Resume file stores
            localMonitor.beginTask(Messages.getString("GridElementTransferOperation.transfering_element_progress"), //$NON-NLS-1$
                    1);
            String sourceName = new Path(this.transferOperation.getSource().toURI().getPath()).lastSegment();
            TransferParams data = new TransferParams(this.transferOperation.getSource(), null,
                    this.transferOperation.getDestination(),
                    this.transferOperation.getDestination().getChild(sourceName), localMonitor);
            try {
                checkExistingTarget(data);
            } catch (ProblemException exc) {
                String msg = String.format(Messages.getString("GridElementTransferOperation.errCannotCopyFile"), //$NON-NLS-1$
                        sourceName);
                data.status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, msg, exc);
                status.merge(data.status);
            }
            if (localMonitor.isCanceled()) {
                throw new OperationCanceledException();
            }
            if (data.status.isOK()) {
                IStatus resStatus = TransferManager.getManager().resumeTransfer(this.transferOperation,
                        localMonitor);
                status.merge(resStatus);
            }
        } else {
            //Transfer grid elements
            localMonitor.beginTask(Messages.getString("GridElementTransferOperation.transfering_element_progress"), //$NON-NLS-1$
                    this.elements.length + 1);
            for (int i = 0; i < this.elements.length; i++) {

                localMonitor.subTask(this.elements[i].getName());

                IProgressMonitor subMonitor = new SubProgressMonitor(localMonitor, 1);
                IStatus tempStatus = transferElement(this.elements[i], this.globalTarget, subMonitor);

                if (!tempStatus.isOK()) {
                    status.merge(tempStatus);
                }

                if (localMonitor.isCanceled()) {
                    throw new OperationCanceledException();
                }

                if (this.move) {
                    IGridContainer parent = this.elements[i].getParent();
                    boolean refresh = true;
                    for (int j = i + 1; j < this.elements.length; j++) {
                        if (this.elements[j].getParent().equals(parent)) {
                            refresh = false;
                            break;
                        }
                    }
                    if (refresh) {
                        try {
                            // TODO mathias progress monitoring
                            parent.refresh(null);
                        } catch (ProblemException pExc) {
                            status.merge(pExc.getStatus());
                        }
                    }
                }

            }

            try {
                if (status.isOK()) {
                    if (this.globalTarget.getResource() instanceof IContainer) {
                        //Refresh only if target is a container
                        this.globalTarget.refresh(new SubProgressMonitor(localMonitor, 1));
                    } else {
                        this.globalTarget.getParent().refresh(new SubProgressMonitor(localMonitor, 1));
                        for (IGridElement elem : this.globalTarget.getParent()
                                .getChildren(new SubProgressMonitor(localMonitor, 1))) {
                            if (elem.getResource() instanceof IContainer && elem instanceof IGridContainer) {
                                ((IGridContainer) elem).refresh(new SubProgressMonitor(localMonitor, 1));
                            }
                        }
                    }
                }
            } catch (ProblemException pExc) {
                status.merge(pExc.getStatus());
            }
        }

        if (status.getSeverity() == IStatus.ERROR) {
            showProblemDialog(status);
        }
        return Status.OK_STATUS; // always return OK, because we displays our own ProblemDialog 
    }

    private void showProblemDialog(final MultiStatus status) {
        IWorkbench workbench = PlatformUI.getWorkbench();
        IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
        if (window == null) {
            IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
            if (windows.length > 0) {
                window = windows[0];
            }
        }
        if (window != null) {
            final Shell shell = window.getShell();
            shell.getDisplay().syncExec(new Runnable() {

                public void run() {
                    ProblemDialog.openProblem(shell,
                            Messages.getString("GridElementTransferOperation.problemDialogTitle"), //$NON-NLS-1$
                            status.getChildren().length == 1
                                    ? Messages.getString("GridElementTransferOperation.msgElementCannotBeCopied") //$NON-NLS-1$
                                    : Messages.getString("GridElementTransferOperation.msgElementsCannotBeCopied"), //$NON-NLS-1$
                            createProblemException(status));
                }
            });
        }
    }

    ProblemException createProblemException(final MultiStatus multiStatus) {
        ProblemException problemException = null;
        List<IStatus> failedStatuses = new ArrayList<IStatus>();
        for (IStatus childStatus : multiStatus.getChildren()) {
            if (childStatus.getSeverity() != IStatus.OK) {
                failedStatuses.add(childStatus);
            }
        }
        Throwable firstException = failedStatuses.size() > 0 ? failedStatuses.get(0).getException() : null;
        problemException = new ProblemException("eu.geclipse.ui.problem.tranfserOperationFailed", //$NON-NLS-1$
                firstException, Activator.PLUGIN_ID);
        IProblem problem = problemException.getProblem();
        for (IStatus status : failedStatuses) {
            String msg = status.getMessage();
            if (status.getException() != null && !msg.equals(status.getException().getMessage())) {
                msg = msg + "\n" + status.getException().getMessage(); //$NON-NLS-1$
            }
            problem.addReason(msg);
        }
        return problemException;
    }

    /**
     * Copy the specified file store to the destination file store.
     * The source may be a file or a directory. Directories will be copied
     * recursively.
     * 
     * @param from The source of the transfer.
     * @param to The target of the transfer.
     * @param monitor A progress monitor used to track the transfer.
     * @return A status object tracking errors of the transfer. 
     */
    private IStatus copy(final IFileStore from, final IFileStore to, final IProgressMonitor monitor) {

        TransferParams data = new TransferParams(from, null, to, to.getChild(from.getName()), monitor);
        try {
            checkExistingTarget(data);
        } catch (ProblemException exc) {
            String msg = String.format(Messages.getString("GridElementTransferOperation.errCannotCopyFile"), //$NON-NLS-1$
                    from.getName());
            data.status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, msg, exc);
        }
        if (monitor.isCanceled()) {
            throw new OperationCanceledException();
        }
        if (data.status.isOK()) {
            data.status = TransferManager.getManager().startTransfer(from, to, this.move, monitor);
        }
        return data.status;

    }

    /**
     * Private class holding parameters passed to methods during transferring file.
     * Some parameters can be changed within method, and those changes should be visibled outside method,
     * so its cannot be passed as normal parameters.
     */
    private static class TransferParams {
        IFileStore sourceFile;
        IFileStore targetDirectory;
        IFileStore targetFile;
        IFileInfo sourceFileInfo;
        IStatus status = Status.OK_STATUS;
        IProgressMonitor monitor;

        TransferParams(final IFileStore sourceFile, final IFileInfo sourceFileInfo, final IFileStore toDirectory,
                final IFileStore to, final IProgressMonitor monitor) {
            super();
            this.sourceFile = sourceFile;
            this.targetDirectory = toDirectory;
            this.targetFile = to;
            this.sourceFileInfo = sourceFileInfo;
            this.monitor = monitor;
        }
    }

    private IStatus transferElement(final IGridElement element, final IGridContainer target,
            final IProgressMonitor monitor) {

        IStatus status = Status.OK_STATUS;
        monitor.beginTask(
                Messages.getString("GridElementTransferOperation.transfering_progress") + element.getName(), 10); //$NON-NLS-1$

        if (!(element instanceof IGridConnectionElement) && !(target instanceof IGridConnectionElement)) {

            IResource sResource = element.getResource();
            IResource tResource = target.getResource();
            IPath destination = tResource.getFullPath().append(sResource.getName());

            try {
                if (this.move) {
                    sResource.move(destination, IResource.NONE, monitor);
                } else {
                    sResource.copy(destination, IResource.NONE, monitor);
                }
            } catch (CoreException cExc) {
                status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.OK,
                        Messages.getString("GridElementTransferOperation.copy_resources_failed"), //$NON-NLS-1$
                        cExc);
            }

        }

        else if ((element instanceof IGridConnection) && !(target instanceof IGridConnectionElement)) {

            try {

                IGridConnection connection = (IGridConnection) element;
                URI uri = ((IGridConnection) element).getConnectionFileStore().toURI();
                IResource sResource = element.getResource();
                IContainer tFolder = (IContainer) target.getResource();

                if (connection.isFolder()) {
                    IFolder folder = tFolder.getFolder(new Path(sResource.getName()));
                    folder.createLink(uri, IResource.NONE, new SubProgressMonitor(monitor, 5));
                } else {
                    IFile file = tFolder.getFile(new Path(sResource.getName()));
                    file.createLink(uri, IResource.NONE, new SubProgressMonitor(monitor, 5));
                }

                if (this.move) {
                    sResource.delete(IResource.NONE, new SubProgressMonitor(monitor, 5));
                }

            } catch (CoreException cExc) {
                status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.OK,
                        Messages.getString("GridElementTransferOperation.copy_linked_resource_failed"), //$NON-NLS-1$
                        cExc);
            }

        }

        else {

            // Prepare variables
            IFileStore inStore = null;
            IFileStore outStore = null;

            // Get input file store
            try {
                inStore = getFileStore(element);
            } catch (CoreException cExc) {
                status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.OK,
                        String.format(Messages.getString("GridElementTransferOperation.unable_get_filestore"), //$NON-NLS-1$
                                element.getName()), cExc);
            }

            if (status.isOK()) {
                try {
                    outStore = getFileStore(target);
                } catch (CoreException cExc) {
                    status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.OK,
                            String.format(Messages.getString("GridElementTransferOperation.unable_get_filestore"), //$NON-NLS-1$
                                    target.getName()), cExc);
                }
            }

            if (status.isOK()) {

                // Put in try-finally-clause to ensure that monitor.done() is called
                try {

                    // Copy operation
                    IProgressMonitor subMonitor = new SubProgressMonitor(monitor, this.move ? 9 : 10);
                    if (monitor.isCanceled()) {
                        throw new OperationCanceledException();
                    }
                    status = copy(inStore, outStore, subMonitor);

                    /*
                    if ( status.isOK() ) {
                      startRefresh( target );
                          
                      if ( monitor.isCanceled() ) {
                        throw new OperationCanceledException();
                      }
                          
                      if ( this.move ) {
                        status = delete( inStore, new SubProgressMonitor( monitor, 3 ) );
                        if ( status.isOK() ) {
                          startRefresh( element.getParent() );
                        }
                      }
                    }
                    */
                } finally {
                    monitor.done();
                }
            }
        }

        return status;
    }

    /**
     * Get the file store from the specified element.
     *  
     * @param element The element to get the file store from.
     * @return The element's file store.
     * @throws CoreException If an error occurs while retrieving the file store.
     */
    private IFileStore getFileStore(final IGridElement element) throws CoreException {

        IFileStore result = null;

        if (element instanceof IGridConnectionElement) {
            result = ((IGridConnectionElement) element).getConnectionFileStore();
        } else {
            result = element.getFileStore();
        }

        return result;
    }

    private void checkExistingTarget(final TransferParams data) throws ProblemException {
        IFileInfo targetInfo = null;
        GEclipseURI geclURI = new GEclipseURI(data.targetFile.toURI());
        try {
            targetInfo = EFS.getStore(geclURI.toSlaveURI()).fetchInfo(EFS.NONE, new NullProgressMonitor());
        } catch (ProblemException problemExc) {
            throw new ProblemException("eu.geclipse.core.filesystem.serverCouldNotBeContacted",
                    String.format("Could not contact server to fetch file info for %s",
                            data.targetFile.toURI().toString()),
                    problemExc, Activator.PLUGIN_ID);
        } catch (CoreException exc) {
            throw new ProblemException("eu.geclipse.core.problem.net.malformedURL",
                    String.format("URL %s is malformed or EFS using scheme %s doesn't exist",
                            data.targetFile.toURI().toString(), geclURI.getSlaveScheme()),
                    exc, Activator.PLUGIN_ID);
        }

        if (targetInfo != null && targetInfo.exists()) {

            if (data.sourceFile.toURI().equals(data.targetFile.toURI())) {
                String msg = String.format(
                        Messages.getString("GridElementTransferOperation.errSourceAndTargetAreTheSame"), //$NON-NLS-1$
                        data.sourceFile.getName());
                throw new ProblemException("eu.geclipse.ui.problem.fileCannotOverwriteItself", msg, //$NON-NLS-1$
                        Activator.PLUGIN_ID);
            }

            switch (this.overwriteMode) {
            case ASK:
                askOverwrite(data, targetInfo);
                break;
            case OVERWRITE_ALL:
                deleteTarget(data);
                break;
            case IGNORE_ALL:
                ignoreTransfer(data);
                break;
            }
        }
    }

    private void askOverwrite(final TransferParams data, final IFileInfo targetInfo) {

        class Runner implements Runnable {
            int exitCode;
            private final Display display;

            Runner(final Display display) {
                this.display = display;
            }

            public void run() {
                Shell shell = null;
                String[] labels = { Messages.getString("GridElementTransferOperation.buttonYes"), //$NON-NLS-1$
                        Messages.getString("GridElementTransferOperation.buttonYesAll"), //$NON-NLS-1$
                        Messages.getString("GridElementTransferOperation.buttonNo"), //$NON-NLS-1$
                        Messages.getString("GridElementTransferOperation.buttonNoAll"), //$NON-NLS-1$
                        Messages.getString("GridElementTransferOperation.buttonCancel") }; //$NON-NLS-1$

                if (this.display != null) {
                    shell = this.display.getActiveShell();
                }

                String message = String.format(Messages.getString("GridElementTransferOperation.overwriteMsg"), //$NON-NLS-1$
                        data.targetFile.getName(), formatURI(data.targetFile.toURI()),
                        formatDate(targetInfo.getLastModified()), formatURI(data.sourceFile.toURI()), "" //$NON-NLS-1$
                );

                MessageDialog dialog = new MessageDialog(shell,
                        Messages.getString("GridElementTransferOperation.overwriteTitle"), //$NON-NLS-1$
                        null, message, MessageDialog.QUESTION, labels, 0);
                this.exitCode = dialog.open();
            }
        }

        Display display = PlatformUI.getWorkbench().getDisplay();
        Runner runner = new Runner(display);
        display.syncExec(runner);

        switch (runner.exitCode) {
        case 0:
            deleteTarget(data);
            break;

        case 1:
            this.overwriteMode = OverwriteMode.OVERWRITE_ALL;
            deleteTarget(data);
            break;

        case 2:
            ignoreTransfer(data);
            break;

        case 3:
            this.overwriteMode = OverwriteMode.IGNORE_ALL;
            ignoreTransfer(data);
            break;

        case 4:
            data.status = Status.CANCEL_STATUS;
            data.monitor.setCanceled(true);
            break;
        }
    }

    String formatURI(final URI uri) {
        String uriString = ""; //$NON-NLS-1$
        GEclipseURI gUri = new GEclipseURI(uri);
        URI slaveURI = gUri.toSlaveURI();

        if (slaveURI == null) {
            uriString = uri.toString();
        } else {
            uriString = slaveURI.toString();
        }
        return uriString;
    }

    String formatDate(final long lastModified) {
        String dateString = ""; //$NON-NLS-1$

        if (lastModified != EFS.NONE) {
            dateString = DateFormat.getDateTimeInstance().format(new Date(lastModified));
        }

        return dateString;
    }

    private void deleteTarget(final TransferParams data) {
        String filename = data.targetFile.getName();

        try {
            data.monitor.subTask(
                    String.format(Messages.getString("GridElementTransferOperation.deletingTarget"), filename)); //$NON-NLS-1$
            data.targetFile.delete(EFS.NONE, data.monitor);

            if (!data.monitor.isCanceled()) {
                data.targetFile = data.targetDirectory.getChild(filename);
            }
        } catch (CoreException exception) {
            data.status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,
                    String.format(Messages.getString("GridElementTransferOperation.errCannotDeleteTarget"), //$NON-NLS-1$
                            data.targetFile.getName()),
                    exception);
        }
    }

    private void ignoreTransfer(final TransferParams data) {
        data.status = new Status(IStatus.INFO, Activator.PLUGIN_ID,
                Messages.getString("GridElementTransferOperation.targetExists")); //$NON-NLS-1$
    }
    /*
    private void startRefresh( final IGridContainer container ) {
          
      Job refreshJob = new Job( "Refresh @ " + container.getName() ) {
        @Override
        protected IStatus run( final IProgressMonitor monitor ) {
    try {
      container.refresh( new SubProgressMonitor( monitor, 1 ) );
    } catch ( ProblemException pExc ) {
      Activator.logException( pExc );
    }
    return Status.OK_STATUS;
        }
      };
      refreshJob.setSystem( true );
      refreshJob.schedule();
          
    }
    */
}