com.amazonaws.eclipse.explorer.s3.dnd.DownloadDropAssistant.java Source code

Java tutorial

Introduction

Here is the source code for com.amazonaws.eclipse.explorer.s3.dnd.DownloadDropAssistant.java

Source

/*
 * Copyright 2011 Amazon Technologies, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *    http://aws.amazon.com/apache2.0
 *
 * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
 * OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and
 * limitations under the License.
 */
package com.amazonaws.eclipse.explorer.s3.dnd;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.ui.navigator.CommonDropAdapter;
import org.eclipse.ui.navigator.CommonDropAdapterAssistant;

import com.amazonaws.eclipse.core.AwsToolkitCore;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;

/**
 * Handles dropping an S3 key onto a supported resource in the project explorer.
 */
public class DownloadDropAssistant extends CommonDropAdapterAssistant {

    public DownloadDropAssistant() {
    }

    /**
     * All validation is left to the configuration in plugin.xml. Any match
     * between possibleChildren and possibleDropTargets will be considered
     * valid.
     */
    @Override
    public IStatus validateDrop(Object target, int operation, TransferData transferType) {
        return validatePluginTransferDrop(
                (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection(), target);
    }

    @Override
    public IStatus validatePluginTransferDrop(IStructuredSelection aDragSelection, Object aDropTarget) {
        if (aDropTarget instanceof IResource)
            return Status.OK_STATUS;
        else
            return Status.CANCEL_STATUS;
    }

    @Override
    public IStatus handlePluginTransferDrop(IStructuredSelection aDragSelection, Object aDropTarget) {
        return doDrop(aDropTarget, aDragSelection);
    }

    @Override
    public IStatus handleDrop(CommonDropAdapter aDropAdapter, final DropTargetEvent aDropTargetEvent,
            Object aTarget) {

        if (aDropTargetEvent.data instanceof StructuredSelection) {
            IStructuredSelection s3ObjectSelection = (StructuredSelection) aDropTargetEvent.data;
            return doDrop(aTarget, s3ObjectSelection);
        }

        return Status.OK_STATUS;
    }

    protected IStatus doDrop(Object aTarget, IStructuredSelection s3ObjectSelection) {
        if (!(aTarget instanceof IResource)) {
            return Status.CANCEL_STATUS;
        }

        // Drop targets can be folders, projects, or files. In the case of
        // files, we just want to identify the parent directory.
        IResource resource = (IResource) aTarget;
        if (resource instanceof IFile) {
            resource = resource.getParent();
        }

        final IResource dropFolder = resource;

        final S3ObjectSummary s3object = (S3ObjectSummary) s3ObjectSelection.getFirstElement();

        final File f = dropFolder.getLocation().toFile();
        if (!f.exists())
            return Status.CANCEL_STATUS;

        String fileName = getOutputFileName(s3object, f);

        if (fileName == null || fileName.length() == 0) {
            return Status.CANCEL_STATUS;
        }

        final File outputFile = new File(fileName);

        new DownloadObjectJob("Downloading " + s3object.getKey(), s3object, dropFolder, outputFile).schedule();

        return Status.OK_STATUS;
    }

    /**
     * Opens a save-file dialog to prompt the user for a file name.
     */
    private String getOutputFileName(final S3ObjectSummary s3object, final File f) {
        FileDialog dialog = new FileDialog(Display.getDefault().getActiveShell(), SWT.SAVE);
        dialog.setFilterPath(f.getAbsolutePath());
        dialog.setFileName(s3object.getKey());
        dialog.setOverwrite(true);
        String fileName = dialog.open();
        return fileName;
    }

    /**
     * Async job to download an object from S3
     */
    private final class DownloadObjectJob extends Job {

        private final S3ObjectSummary s3object;
        private final IResource dropFolder;
        private final File outputFile;

        private DownloadObjectJob(String name, S3ObjectSummary s3object, IResource dropFolder, File outputFile) {
            super(name);
            this.s3object = s3object;
            this.dropFolder = dropFolder;
            this.outputFile = outputFile;
        }

        @Override
        protected IStatus run(final IProgressMonitor monitor) {
            FileOutputStream fos = null;
            try {
                AmazonS3 client = AwsToolkitCore.getClientFactory().getS3Client();
                S3Object object = client.getObject(s3object.getBucketName(), s3object.getKey());

                // This number is used for reporting only; the download
                // will appear to complete early if the file is bigger
                // than 2GB.
                long totalNumBytes = object.getObjectMetadata().getContentLength();
                if (totalNumBytes > Integer.MAX_VALUE)
                    totalNumBytes = Integer.MAX_VALUE;
                monitor.beginTask("Downloading", (int) totalNumBytes);

                // For a new file this is a no-op, but it truncates an
                // existing file for overwrite.
                RandomAccessFile raf = new RandomAccessFile(outputFile, "rw");
                raf.setLength(0);
                raf.close();

                fos = new FileOutputStream(outputFile);
                InputStream is = object.getObjectContent();
                byte[] buffer = new byte[4096];
                int bytesRead = 0;
                while ((bytesRead = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, bytesRead);
                    monitor.worked(bytesRead);
                }
            } catch (Exception e) {
                return new Status(Status.ERROR, AwsToolkitCore.PLUGIN_ID, "Error downloading file from S3", e);
            } finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (Exception e) {
                        AwsToolkitCore.getDefault().logException("Couldn't close file output stream", e);
                    }
                }
                monitor.done();
            }

            // Refresh the drop folder
            // TODO: this won't work if they chose another folder in the
            // file selection dialog.
            Display.getDefault().asyncExec(new Runnable() {

                public void run() {
                    try {
                        dropFolder.refreshLocal(1, monitor);
                    } catch (CoreException e) {
                        AwsToolkitCore.getDefault().logException("Couldn't refresh local files", e);
                    }
                }
            });

            return Status.OK_STATUS;
        }
    }
}