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
1 /*******************************************************************************
2 * Copyright (c) 2015, 2016 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Bernd Hufmann - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.internal.tmf.remote.ui.wizards.fetch.model;
14
15 import java.io.File;
16 import java.io.FileNotFoundException;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.OutputStream;
21 import java.lang.reflect.InvocationTargetException;
22 import java.net.URI;
23 import java.nio.file.Files;
24 import java.nio.file.StandardCopyOption;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28
29 import org.eclipse.core.commands.ExecutionException;
30 import org.eclipse.core.filesystem.EFS;
31 import org.eclipse.core.filesystem.IFileInfo;
32 import org.eclipse.core.filesystem.IFileStore;
33 import org.eclipse.core.resources.IFile;
34 import org.eclipse.core.resources.IFolder;
35 import org.eclipse.core.resources.IResource;
36 import org.eclipse.core.runtime.CoreException;
37 import org.eclipse.core.runtime.IPath;
38 import org.eclipse.core.runtime.IProgressMonitor;
39 import org.eclipse.core.runtime.IStatus;
40 import org.eclipse.core.runtime.NullProgressMonitor;
41 import org.eclipse.core.runtime.OperationCanceledException;
42 import org.eclipse.core.runtime.Path;
43 import org.eclipse.core.runtime.Status;
44 import org.eclipse.core.runtime.SubMonitor;
45 import org.eclipse.core.runtime.URIUtil;
46 import org.eclipse.jface.operation.ModalContext;
47 import org.eclipse.osgi.util.NLS;
48 import org.eclipse.swt.widgets.Shell;
49 import org.eclipse.tracecompass.internal.tmf.remote.ui.Activator;
50 import org.eclipse.tracecompass.internal.tmf.remote.ui.messages.RemoteMessages;
51 import org.eclipse.tracecompass.internal.tmf.ui.project.operations.TmfWorkspaceModifyOperation;
52 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ArchiveUtil;
53 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.FileSystemObjectImportStructureProvider;
54 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.IFileSystemObject;
55 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportConfirmation;
56 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportConflictHandler;
57 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportTraceWizardPage;
58 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TraceFileSystemElement;
59 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TraceValidateAndImportOperation;
60 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement;
61 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement;
62 import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
63 import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceCoreUtils;
64 import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceImportException;
65 import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
66 import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper;
67 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
68 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils;
69 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder;
70 import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils;
71 import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider;
72
73 /**
74 * Operation to import a set of traces from a remote node into a tracing
75 * project.
76 *
77 * @author Bernd Hufmann
78 */
79 public class RemoteImportTracesOperation extends TmfWorkspaceModifyOperation {
80
81 private static final String TRACE_IMPORT = ".traceRemoteImport"; //$NON-NLS-1$
82 // ------------------------------------------------------------------------
83 // Constants
84 // ------------------------------------------------------------------------
85 private static final int BUFFER_IN_KB = 16;
86 private static final int BYTES_PER_KB = 1024;
87
88 // ------------------------------------------------------------------------
89 // Attributes
90 // ------------------------------------------------------------------------
91 private IStatus fStatus;
92 private final Shell fShell;
93 private final TmfTraceFolder fDestination;
94 private final Object[] fTraceElements;
95 private final ImportConflictHandler fConflictHandler;
96 private final List<IResource> fImportedResources = new ArrayList<>();
97
98 // ------------------------------------------------------------------------
99 // Constructor(s)
100 // ------------------------------------------------------------------------
101 /**
102 * Operation to import a set of traces from a remote node into a tracing
103 * project.
104 *
105 * @param shell
106 * shell to display confirmation dialog
107 * @param destination
108 * The destination traces folder
109 * @param elements
110 * The trace model elements describing the traces to import
111 * @param overwriteAll
112 * Flag to indicate to overwrite all existing traces
113 */
114 public RemoteImportTracesOperation(Shell shell, TmfTraceFolder destination, Object[] elements, boolean overwriteAll) {
115 super();
116 fShell = shell;
117 fDestination = destination;
118 fTraceElements = Arrays.copyOf(elements, elements.length);
119 if (overwriteAll) {
120 fConflictHandler = new ImportConflictHandler(fShell, destination, ImportConfirmation.OVERWRITE_ALL);
121 } else {
122 fConflictHandler = new ImportConflictHandler(fShell, destination, ImportConfirmation.SKIP);
123 }
124 }
125
126 // ------------------------------------------------------------------------
127 // Operations
128 // ------------------------------------------------------------------------
129 @Override
130 protected void execute(IProgressMonitor monitor) throws CoreException,
131 InvocationTargetException, InterruptedException {
132
133 try {
134 doRun(monitor);
135 setStatus(Status.OK_STATUS);
136 } catch (InterruptedException | OperationCanceledException e) {
137 setStatus(Status.CANCEL_STATUS);
138 throw e;
139 } catch (Exception e) {
140 setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, RemoteMessages.RemoteImportTracesOperation_ImportFailure, e));
141 throw new InvocationTargetException(e);
142 }
143 }
144
145 // ------------------------------------------------------------------------
146 // Helper methods
147 // ------------------------------------------------------------------------
148 private void doRun(IProgressMonitor monitor) throws ExecutionException, CoreException, IOException, InterruptedException {
149
150 IFolder destinationFolder = fDestination.getResource();
151 if (!destinationFolder.exists()) {
152 throw new ExecutionException(RemoteMessages.RemoteImportTracesOperation_ImportDialogInvalidTracingProject + " (" + TmfTracesFolder.TRACES_FOLDER_NAME + ")"); //$NON-NLS-1$//$NON-NLS-2$
153 }
154
155 SubMonitor subMonitor = SubMonitor.convert(monitor, fTraceElements.length * 4);
156 subMonitor.beginTask(RemoteMessages.RemoteImportTracesOperation_DownloadTask, fTraceElements.length * 4);
157
158 for (Object packageElement : fTraceElements) {
159 if (!(packageElement instanceof TracePackageTraceElement)) {
160 continue;
161 }
162 TracePackageTraceElement traceElement = (TracePackageTraceElement) packageElement;
163 TracePackageElement parentElement = traceElement.getParent();
164 while (parentElement != null) {
165 if (parentElement instanceof RemoteImportTraceGroupElement) {
166 break;
167 }
168 parentElement = parentElement.getParent();
169 }
170
171 if (parentElement == null) {
172 continue;
173 }
174
175 RemoteImportTraceGroupElement traceGroup = (RemoteImportTraceGroupElement) parentElement;
176 String rootPath = traceGroup.getRootImportPath();
177
178 // Create folder with node name in destination folder
179 RemoteImportConnectionNodeElement nodeElement = (RemoteImportConnectionNodeElement) traceGroup.getParent();
180 String nodeName = nodeElement.getName();
181 IFolder nodeFolder = destinationFolder.getFolder(nodeName);
182
183 TracePackageElement[] children = traceElement.getChildren();
184 SubMonitor childMonitor = subMonitor.newChild(1);
185 TraceUtils.createFolder(nodeFolder, childMonitor);
186
187 for (TracePackageElement element : children) {
188 ModalContext.checkCanceled(monitor);
189
190 if (element instanceof RemoteImportTraceFilesElement) {
191 RemoteImportTraceFilesElement traceFilesElement = (RemoteImportTraceFilesElement) element;
192
193 IFileStore remoteFile = traceFilesElement.getRemoteFile();
194
195 // Preserve folder structure
196 IPath sessionParentPath = TmfTraceCoreUtils.newSafePath(rootPath).removeLastSegments(1);
197 IPath traceParentPath = TmfTraceCoreUtils.newSafePath(remoteFile.getParent().toURI().getPath());
198 IPath relativeTracePath = Path.EMPTY;
199 if (sessionParentPath.isPrefixOf(traceParentPath)) {
200 relativeTracePath = traceParentPath.makeRelativeTo(sessionParentPath);
201 }
202
203 String[] segments = relativeTracePath.segments();
204 for (int i = 0; i < segments.length; i++) {
205 String segment = TmfTraceCoreUtils.validateName(TmfTraceCoreUtils.safePathToString(segments[i]));
206 if (i == 0) {
207 relativeTracePath = new Path(segment);
208 } else {
209 relativeTracePath = relativeTracePath.append(segment);
210 }
211 }
212
213 IFolder traceFolder = nodeFolder.getFolder(new Path(relativeTracePath.toOSString()));
214 childMonitor = subMonitor.newChild(1);
215 TraceUtils.createFolder(traceFolder, childMonitor);
216 childMonitor.done();
217
218 // Import trace
219 IResource traceRes = null;
220 IFileInfo info = remoteFile.fetchInfo();
221 if (info.isDirectory()) {
222 traceRes = downloadDirectoryTrace(remoteFile, traceFolder, subMonitor.newChild(1));
223 } else {
224 traceRes = downloadFileTrace(remoteFile, traceFolder, subMonitor.newChild(1));
225 }
226
227 String traceName = traceElement.getText();
228 if (traceRes == null || !traceRes.exists()) {
229 continue;
230 }
231
232 // Select trace type
233 TraceTypeHelper traceTypeHelper = null;
234 String traceTypeStr = traceElement.getTraceType();
235 if (traceTypeStr != null) {
236 traceTypeHelper = TmfTraceType.getTraceType(traceTypeStr);
237 }
238
239 // no specific trace type found
240 if (traceTypeHelper == null) {
241 try {
242 // Try to auto-detect the trace typ
243 childMonitor = subMonitor.newChild(1);
244 childMonitor.setTaskName(NLS.bind(RemoteMessages.RemoteImportTracesOperation_DetectingTraceType, traceName));
245 childMonitor.done();
246 traceTypeHelper = TmfTraceTypeUIUtils.selectTraceType(traceRes.getLocation().toOSString(), null, null);
247 } catch (TmfTraceImportException e) {
248 // Could not figure out the type
249 }
250 }
251
252 if (traceTypeHelper != null) {
253 TmfTraceTypeUIUtils.setTraceType(traceRes, traceTypeHelper);
254 fImportedResources.add(traceRes);
255 }
256
257 // Set source location
258 URI uri = remoteFile.toURI();
259 String sourceLocation = URIUtil.toUnencodedString(uri);
260 traceRes.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation);
261 }
262 }
263 }
264 }
265
266 // Download a directory trace
267 private IResource downloadDirectoryTrace(IFileStore trace, IFolder traceFolder, IProgressMonitor monitor) throws CoreException, IOException, InterruptedException {
268
269 IFileStore[] sources = trace.childStores(EFS.NONE, monitor);
270
271 // Don't import just the metadata file
272 if (sources.length > 1) {
273 String traceName = trace.getName();
274
275 traceName = TmfTraceCoreUtils.validateName(traceName);
276
277 IFolder folder = traceFolder.getFolder(traceName);
278 String newName = fConflictHandler.checkAndHandleNameClash(folder.getFullPath(), monitor);
279 if (newName == null) {
280 return null;
281 }
282
283 folder = traceFolder.getFolder(newName);
284 folder.create(true, true, null);
285
286 SubMonitor subMonitor = SubMonitor.convert(monitor, sources.length);
287 subMonitor.beginTask(RemoteMessages.RemoteImportTracesOperation_DownloadTask, sources.length);
288
289 for (IFileStore source : sources) {
290 if (subMonitor.isCanceled()) {
291 throw new InterruptedException();
292 }
293
294 IPath destination = folder.getLocation().addTrailingSeparator().append(source.getName());
295 IFileInfo info = source.fetchInfo();
296 // TODO allow for downloading index directory and files
297 if (!info.isDirectory()) {
298 SubMonitor childMonitor = subMonitor.newChild(1);
299 childMonitor.setTaskName(RemoteMessages.RemoteImportTracesOperation_DownloadTask + ' ' + trace.getName() + '/' + source.getName());
300 try (InputStream in = source.openInputStream(EFS.NONE, new NullProgressMonitor())) {
301 copy(in, folder, destination, childMonitor, info.getLength());
302 }
303 }
304 }
305 folder.refreshLocal(IResource.DEPTH_INFINITE, null);
306 return folder;
307 }
308 return null;
309 }
310
311 // Download file trace
312 private IResource downloadFileTrace(IFileStore trace, IFolder traceFolder, IProgressMonitor monitor) throws CoreException, IOException, InterruptedException {
313
314 IFolder folder = traceFolder;
315 String traceName = trace.getName();
316
317 traceName = TmfTraceCoreUtils.validateName(traceName);
318
319 IResource resource = folder.findMember(traceName);
320 if ((resource != null) && resource.exists()) {
321 String newName = fConflictHandler.checkAndHandleNameClash(resource.getFullPath(), monitor);
322 if (newName == null) {
323 return null;
324 }
325 traceName = newName;
326 }
327 SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
328 subMonitor.beginTask(RemoteMessages.RemoteImportTracesOperation_DownloadTask, 1);
329
330 IPath destination = folder.getLocation().addTrailingSeparator().append(traceName);
331 IFileInfo info = trace.fetchInfo();
332 subMonitor.setTaskName(RemoteMessages.RemoteImportTracesOperation_DownloadTask + ' ' + trace.getName() + '/' + trace.getName());
333 try (InputStream in = trace.openInputStream(EFS.NONE, new NullProgressMonitor())) {
334 copy(in, folder, destination, subMonitor, info.getLength());
335 }
336 folder.refreshLocal(IResource.DEPTH_INFINITE, null);
337 return folder.findMember(traceName);
338 }
339
340 private void copy(InputStream in, IFolder destFolder, IPath destination, SubMonitor monitor, long length) throws IOException {
341 IFolder intermediateTempFolder = null;
342 IFile tempFile = null;
343 File intermediateFile = null;
344 try {
345 intermediateTempFolder = fDestination.getProject().getResource().getFolder(TRACE_IMPORT);
346 if (intermediateTempFolder.exists()) {
347 intermediateTempFolder.delete(true, SubMonitor.convert(monitor));
348 }
349 intermediateTempFolder.create(true, true, SubMonitor.convert(monitor));
350 tempFile = intermediateTempFolder.getFile(destination.lastSegment());
351 tempFile.create(null, true, SubMonitor.convert(monitor));
352 intermediateFile = tempFile.getLocation().toFile();
353 intermediateFile.createNewFile();
354 copy(in, intermediateFile, length, monitor);
355 if (ArchiveUtil.isArchiveFile(intermediateFile)) {
356 // Select all the elements in the archive
357 FileSystemObjectImportStructureProvider importProvider = new FileSystemObjectImportStructureProvider(FileSystemStructureProvider.INSTANCE, null);
358 IFileSystemObject fileSystemObject = importProvider.getIFileSystemObject(intermediateFile);
359 TraceFileSystemElement rootTraceFileElement = TraceFileSystemElement.createRootTraceFileElement(fileSystemObject, importProvider);
360
361 // Select all the elements in the archive
362 List<TraceFileSystemElement> list = new ArrayList<>();
363 rootTraceFileElement.getAllChildren(list);
364 if (!destFolder.exists()) {
365 destFolder.create(true, true, SubMonitor.convert(monitor));
366 }
367 final IFolder folder = destFolder.getFolder(destination.lastSegment());
368 if (!folder.exists()) {
369 folder.create(true, true, SubMonitor.convert(monitor));
370 }
371
372 final TraceValidateAndImportOperation operation = new TraceValidateAndImportOperation(
373 fShell, list, null, intermediateTempFolder.getLocation(), destFolder.getFullPath(), false,
374 ImportTraceWizardPage.OPTION_PRESERVE_FOLDER_STRUCTURE | ImportTraceWizardPage.OPTION_IMPORT_UNRECOGNIZED_TRACES,
375 fDestination);
376 operation.setConflictHandler(fConflictHandler);
377 operation.run(SubMonitor.convert(monitor));
378 monitor.done();
379 } else {
380 // should be lightning fast unless someone maps different files
381 // to different physical disks. In windows and linux, moves are
382 // super fast on the same drive
383 Files.move(intermediateFile.toPath(), destination.toFile().toPath(), StandardCopyOption.REPLACE_EXISTING);
384 }
385 } catch (CoreException | InvocationTargetException | InterruptedException e) {
386 Activator.getDefault().logError(e.getMessage(), e);
387 } finally {
388 if (intermediateFile != null && intermediateFile.exists()) {
389 intermediateFile.delete();
390 }
391 try {
392 if (tempFile != null && tempFile.exists()) {
393 tempFile.delete(true, SubMonitor.convert(monitor));
394 }
395 if (intermediateTempFolder != null && intermediateTempFolder.exists()) {
396 intermediateTempFolder.delete(true, SubMonitor.convert(monitor));
397 }
398 } catch (CoreException e) {
399 Activator.getDefault().logError(e.getMessage(), e);
400 }
401 }
402 }
403
404 private static void copy(InputStream in, File intermediateFile, long length, SubMonitor monitor) throws IOException, FileNotFoundException {
405 try (OutputStream out = new FileOutputStream(intermediateFile)) {
406 monitor.setWorkRemaining((int) (length / BYTES_PER_KB));
407 byte[] buf = new byte[BYTES_PER_KB * BUFFER_IN_KB];
408 int counter = 0;
409 for (;;) {
410 int n = in.read(buf);
411 if (n <= 0) {
412 break;
413 }
414 out.write(buf, 0, n);
415 counter = (counter % BYTES_PER_KB) + n;
416 monitor.worked(counter / BYTES_PER_KB);
417 }
418 }
419 }
420
421 /**
422 * Set the result status for this operation
423 *
424 * @param status
425 * the status
426 */
427 protected void setStatus(IStatus status) {
428 fStatus = status;
429 }
430
431 /**
432 * Gets the result of the operation.
433 *
434 * @return result status of operation
435 */
436 public IStatus getStatus() {
437 return fStatus;
438 }
439
440 /**
441 * Get the list of resources that were imported by this operation. An
442 * example use case would be to use this to open traces that were imported
443 * by this operation.
444 *
445 * Note this includes only valid traces and doesn'tinclude unrecognized
446 * files.
447 *
448 * @return the trace resources that were imported
449 */
450 public List<IResource> getImportedResources() {
451 return fImportedResources;
452 }
453 }
This page took 0.049843 seconds and 5 git commands to generate.