tmf: Bug 495067: Canceling remote import shows Internal error dialog
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.remote.ui / src / org / eclipse / tracecompass / internal / tmf / remote / ui / wizards / fetch / model / RemoteImportTracesOperation.java
index 77ac3dffc0326cf412fd5456e2f785a303d009ed..7cfe7ede9ab2b0321cf2ac6060f57973beb6c297 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015 Ericsson
+ * Copyright (c) 2015, 2016 Ericsson
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
 
 package org.eclipse.tracecompass.internal.tmf.remote.ui.wizards.fetch.model;
 
+import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.reflect.InvocationTargetException;
 import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.filesystem.EFS;
 import org.eclipse.core.filesystem.IFileInfo;
 import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
@@ -31,6 +38,7 @@ import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 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.SubMonitor;
@@ -41,8 +49,14 @@ import org.eclipse.swt.widgets.Shell;
 import org.eclipse.tracecompass.internal.tmf.remote.ui.Activator;
 import org.eclipse.tracecompass.internal.tmf.remote.ui.messages.RemoteMessages;
 import org.eclipse.tracecompass.internal.tmf.ui.project.operations.TmfWorkspaceModifyOperation;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ArchiveUtil;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.FileSystemObjectImportStructureProvider;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.IFileSystemObject;
 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportConfirmation;
 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportConflictHandler;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportTraceWizardPage;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TraceFileSystemElement;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TraceValidateAndImportOperation;
 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement;
 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement;
 import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
@@ -54,14 +68,17 @@ import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder;
 import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils;
+import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider;
 
 /**
- * Operation to import a set of traces from a remote node into a tracing project.
+ * Operation to import a set of traces from a remote node into a tracing
+ * project.
  *
  * @author Bernd Hufmann
  */
 public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
 
+    private static final String TRACE_IMPORT = ".traceRemoteImport"; //$NON-NLS-1$
     // ------------------------------------------------------------------------
     // Constants
     // ------------------------------------------------------------------------
@@ -76,20 +93,23 @@ public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
     private final TmfTraceFolder fDestination;
     private final Object[] fTraceElements;
     private final ImportConflictHandler fConflictHandler;
+    private final List<IResource> fImportedResources = new ArrayList<>();
 
     // ------------------------------------------------------------------------
     // Constructor(s)
     // ------------------------------------------------------------------------
     /**
-     * Operation to import a set of traces from a remote node into a tracing project.
+     * Operation to import a set of traces from a remote node into a tracing
+     * project.
+     *
      * @param shell
-     *                shell to display confirmation dialog
+     *            shell to display confirmation dialog
      * @param destination
-     *                The destination traces folder
+     *            The destination traces folder
      * @param elements
-     *                The trace model elements describing the traces to import
+     *            The trace model elements describing the traces to import
      * @param overwriteAll
-     *                 Flag to indicate to overwrite all existing traces
+     *            Flag to indicate to overwrite all existing traces
      */
     public RemoteImportTracesOperation(Shell shell, TmfTraceFolder destination, Object[] elements, boolean overwriteAll) {
         super();
@@ -113,7 +133,7 @@ public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
         try {
             doRun(monitor);
             setStatus(Status.OK_STATUS);
-        } catch (InterruptedException e) {
+        } catch (InterruptedException | OperationCanceledException e) {
             setStatus(Status.CANCEL_STATUS);
             throw e;
         } catch (Exception e) {
@@ -173,7 +193,7 @@ public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
                     IFileStore remoteFile = traceFilesElement.getRemoteFile();
 
                     // Preserve folder structure
-                    IPath sessionParentPath = TmfTraceCoreUtils.newSafePath(rootPath);
+                    IPath sessionParentPath = TmfTraceCoreUtils.newSafePath(rootPath).removeLastSegments(1);
                     IPath traceParentPath = TmfTraceCoreUtils.newSafePath(remoteFile.getParent().toURI().getPath());
                     IPath relativeTracePath = Path.EMPTY;
                     if (sessionParentPath.isPrefixOf(traceParentPath)) {
@@ -225,12 +245,13 @@ public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
                             childMonitor.done();
                             traceTypeHelper = TmfTraceTypeUIUtils.selectTraceType(traceRes.getLocation().toOSString(), null, null);
                         } catch (TmfTraceImportException e) {
-                            //Could not figure out the type
+                            // Could not figure out the type
                         }
                     }
 
                     if (traceTypeHelper != null) {
                         TmfTraceTypeUIUtils.setTraceType(traceRes, traceTypeHelper);
+                        fImportedResources.add(traceRes);
                     }
 
                     // Set source location
@@ -275,10 +296,9 @@ public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
                 // TODO allow for downloading index directory and files
                 if (!info.isDirectory()) {
                     SubMonitor childMonitor = subMonitor.newChild(1);
-                    childMonitor.setTaskName(RemoteMessages.RemoteImportTracesOperation_DownloadTask + ' '  + trace.getName()+ '/' + source.getName());
-
+                    childMonitor.setTaskName(RemoteMessages.RemoteImportTracesOperation_DownloadTask + ' ' + trace.getName() + '/' + source.getName());
                     try (InputStream in = source.openInputStream(EFS.NONE, new NullProgressMonitor())) {
-                        copy(in, destination, childMonitor, info.getLength());
+                        copy(in, folder, destination, childMonitor, info.getLength());
                     }
                 }
             }
@@ -309,24 +329,87 @@ public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
 
         IPath destination = folder.getLocation().addTrailingSeparator().append(traceName);
         IFileInfo info = trace.fetchInfo();
-        subMonitor.setTaskName(RemoteMessages.RemoteImportTracesOperation_DownloadTask + ' '  + trace.getName()+ '/' +trace.getName());
+        subMonitor.setTaskName(RemoteMessages.RemoteImportTracesOperation_DownloadTask + ' ' + trace.getName() + '/' + trace.getName());
         try (InputStream in = trace.openInputStream(EFS.NONE, new NullProgressMonitor())) {
-            copy(in, destination, subMonitor, info.getLength());
+            copy(in, folder, destination, subMonitor, info.getLength());
         }
         folder.refreshLocal(IResource.DEPTH_INFINITE, null);
         return folder.findMember(traceName);
     }
 
+    private void copy(InputStream in, IFolder destFolder, IPath destination, SubMonitor monitor, long length) throws IOException {
+        IFolder intermediateTempFolder = null;
+        IFile tempFile = null;
+        File intermediateFile = null;
+        try {
+            intermediateTempFolder = fDestination.getProject().getResource().getFolder(TRACE_IMPORT);
+            if (intermediateTempFolder.exists()) {
+                intermediateTempFolder.delete(true, SubMonitor.convert(monitor));
+            }
+            intermediateTempFolder.create(true, true, SubMonitor.convert(monitor));
+            tempFile = intermediateTempFolder.getFile(destination.lastSegment());
+            tempFile.create(null, true, SubMonitor.convert(monitor));
+            intermediateFile = tempFile.getLocation().toFile();
+            intermediateFile.createNewFile();
+            copy(in, intermediateFile, length, monitor);
+            if (ArchiveUtil.isArchiveFile(intermediateFile)) {
+                // Select all the elements in the archive
+                FileSystemObjectImportStructureProvider importProvider = new FileSystemObjectImportStructureProvider(FileSystemStructureProvider.INSTANCE, null);
+                IFileSystemObject fileSystemObject = importProvider.getIFileSystemObject(intermediateFile);
+                TraceFileSystemElement rootTraceFileElement = TraceFileSystemElement.createRootTraceFileElement(fileSystemObject, importProvider);
+
+                // Select all the elements in the archive
+                List<TraceFileSystemElement> list = new ArrayList<>();
+                rootTraceFileElement.getAllChildren(list);
+                if (!destFolder.exists()) {
+                    destFolder.create(true, true, SubMonitor.convert(monitor));
+                }
+                final IFolder folder = destFolder.getFolder(destination.lastSegment());
+                if (!folder.exists()) {
+                    folder.create(true, true, SubMonitor.convert(monitor));
+                }
 
-    private static void copy(InputStream in, IPath destination, SubMonitor monitor, long length) throws IOException {
-        try (OutputStream out = new FileOutputStream(destination.toFile())) {
+                final TraceValidateAndImportOperation operation = new TraceValidateAndImportOperation(
+                        fShell, list, null, intermediateTempFolder.getLocation(), destFolder.getFullPath(), false,
+                        ImportTraceWizardPage.OPTION_PRESERVE_FOLDER_STRUCTURE | ImportTraceWizardPage.OPTION_IMPORT_UNRECOGNIZED_TRACES,
+                        fDestination);
+                operation.setConflictHandler(fConflictHandler);
+                operation.run(SubMonitor.convert(monitor));
+                monitor.done();
+            } else {
+                // should be lightning fast unless someone maps different files
+                // to different physical disks. In windows and linux, moves are
+                // super fast on the same drive
+                Files.move(intermediateFile.toPath(), destination.toFile().toPath(), StandardCopyOption.REPLACE_EXISTING);
+            }
+        } catch (CoreException | InvocationTargetException | InterruptedException e) {
+            Activator.getDefault().logError(e.getMessage(), e);
+        } finally {
+            if (intermediateFile != null && intermediateFile.exists()) {
+                intermediateFile.delete();
+            }
+            try {
+                if (tempFile != null && tempFile.exists()) {
+                    tempFile.delete(true, SubMonitor.convert(monitor));
+                }
+                if (intermediateTempFolder != null && intermediateTempFolder.exists()) {
+                    intermediateTempFolder.delete(true, SubMonitor.convert(monitor));
+                }
+            } catch (CoreException e) {
+                Activator.getDefault().logError(e.getMessage(), e);
+            }
+        }
+    }
+
+    private static void copy(InputStream in, File intermediateFile, long length, SubMonitor monitor) throws IOException, FileNotFoundException {
+        try (OutputStream out = new FileOutputStream(intermediateFile)) {
             monitor.setWorkRemaining((int) (length / BYTES_PER_KB));
             byte[] buf = new byte[BYTES_PER_KB * BUFFER_IN_KB];
             int counter = 0;
             for (;;) {
                 int n = in.read(buf);
                 if (n <= 0) {
-                    return;
+                    break;
                 }
                 out.write(buf, 0, n);
                 counter = (counter % BYTES_PER_KB) + n;
@@ -353,4 +436,18 @@ public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
     public IStatus getStatus() {
         return fStatus;
     }
+
+    /**
+     * Get the list of resources that were imported by this operation. An
+     * example use case would be to use this to open traces that were imported
+     * by this operation.
+     *
+     * Note this includes only valid traces and doesn'tinclude unrecognized
+     * files.
+     *
+     * @return the trace resources that were imported
+     */
+    public List<IResource> getImportedResources() {
+        return fImportedResources;
+    }
 }
This page took 0.02696 seconds and 5 git commands to generate.