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