8f5cad157606e026bc01bfa075f055ffe438cc3e
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / internal / tmf / ui / project / wizards / tracepkg / importexport / TracePackageImportOperation.java
1 /*******************************************************************************
2 * Copyright (c) 2013, 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 * Marc-Andre Laperle - Initial API and implementation
11 * Patrick Tasse - Add support for source location
12 *******************************************************************************/
13
14 package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport;
15
16 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.lang.reflect.InvocationTargetException;
22 import java.net.URI;
23 import java.text.MessageFormat;
24 import java.util.ArrayList;
25 import java.util.Enumeration;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29
30 import org.eclipse.core.resources.IFile;
31 import org.eclipse.core.resources.IFolder;
32 import org.eclipse.core.resources.IMarker;
33 import org.eclipse.core.resources.IResource;
34 import org.eclipse.core.runtime.CoreException;
35 import org.eclipse.core.runtime.IPath;
36 import org.eclipse.core.runtime.IProgressMonitor;
37 import org.eclipse.core.runtime.IStatus;
38 import org.eclipse.core.runtime.Path;
39 import org.eclipse.core.runtime.Status;
40 import org.eclipse.core.runtime.SubMonitor;
41 import org.eclipse.core.runtime.URIUtil;
42 import org.eclipse.jdt.annotation.NonNull;
43 import org.eclipse.jface.operation.ModalContext;
44 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
45 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TarException;
46 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.AbstractTracePackageOperation;
47 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageBookmarkElement;
48 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement;
49 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageFilesElement;
50 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFileElement;
51 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFilesElement;
52 import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement;
53 import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
54 import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceImportException;
55 import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
56 import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper;
57 import org.eclipse.tracecompass.tmf.core.util.Pair;
58 import org.eclipse.tracecompass.tmf.ui.editors.TmfEventsEditor;
59 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement;
60 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
61 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils;
62 import org.eclipse.ui.dialogs.IOverwriteQuery;
63 import org.eclipse.ui.ide.IDE;
64 import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider;
65 import org.eclipse.ui.wizards.datatransfer.ImportOperation;
66
67 /**
68 * An operation that imports a trace package from an archive
69 *
70 * @author Marc-Andre Laperle
71 */
72 public class TracePackageImportOperation extends AbstractTracePackageOperation implements IOverwriteQuery {
73
74 private final TracePackageElement[] fImportTraceElements;
75 private final TmfTraceFolder fTmfTraceFolder;
76
77 /**
78 * Constructs a new import operation
79 *
80 * @param importTraceElements
81 * the trace element to be imported
82 * @param fileName
83 * the output file name
84 * @param tmfTraceFolder
85 * the destination folder
86 */
87 public TracePackageImportOperation(String fileName, TracePackageElement[] importTraceElements, TmfTraceFolder tmfTraceFolder) {
88 super(fileName);
89 fImportTraceElements = importTraceElements;
90 fTmfTraceFolder = tmfTraceFolder;
91 }
92
93 private class ImportProvider implements IImportStructureProvider {
94
95 private Exception fException;
96
97 @Override
98 public List getChildren(Object element) {
99 return null;
100 }
101
102 @Override
103 public InputStream getContents(Object element) {
104 InputStream inputStream = null;
105 // We can add throws
106 try {
107 inputStream = ((ArchiveProviderElement) element).getContents();
108 } catch (IOException e) {
109 fException = e;
110 } catch (TarException e) {
111 fException = e;
112 }
113 return inputStream;
114 }
115
116 @Override
117 public String getFullPath(Object element) {
118 return ((ArchiveProviderElement) element).getFullPath();
119 }
120
121 @Override
122 public String getLabel(Object element) {
123 return ((ArchiveProviderElement) element).getLabel();
124 }
125
126 @Override
127 public boolean isFolder(Object element) {
128 return ((ArchiveProviderElement) element).isFolder();
129 }
130
131 public Exception getException() {
132 return fException;
133 }
134 }
135
136 private class ArchiveProviderElement {
137
138 private final String fPath;
139 private final String fLabel;
140
141 private ArchiveFile fArchiveFile;
142 private ArchiveEntry fEntry;
143
144 public ArchiveProviderElement(String destinationPath, String label, ArchiveFile archiveFile, ArchiveEntry entry) {
145 fPath = destinationPath;
146 fLabel = label;
147 this.fArchiveFile = archiveFile;
148 this.fEntry = entry;
149 }
150
151 public InputStream getContents() throws TarException, IOException {
152 return fArchiveFile.getInputStream(fEntry);
153 }
154
155 public String getFullPath() {
156 return fPath;
157 }
158
159 public String getLabel() {
160 return fLabel;
161 }
162
163 public boolean isFolder() {
164 return false;
165 }
166 }
167
168 /**
169 * Run the operation. The status (result) of the operation can be obtained
170 * with {@link #getStatus}
171 *
172 * @param progressMonitor
173 * the progress monitor to use to display progress and receive
174 * requests for cancellation
175 */
176 @Override
177 public void run(IProgressMonitor progressMonitor) {
178 int totalWork = getNbCheckedElements(fImportTraceElements) * 2;
179 progressMonitor.beginTask(Messages.TracePackageImportOperation_ImportingPackage, totalWork);
180 doRun(progressMonitor);
181 progressMonitor.done();
182 }
183
184 private void doRun(IProgressMonitor progressMonitor) {
185 try {
186 setStatus(deleteExistingTraces(progressMonitor));
187 if (getStatus().getSeverity() != IStatus.OK) {
188 return;
189 }
190
191 TracePackageFilesElement traceFilesElement = null;
192 for (TracePackageElement packageElement : fImportTraceElements) {
193 TracePackageTraceElement traceElement = (TracePackageTraceElement) packageElement;
194 if (!isFilesChecked(packageElement)) {
195 continue;
196 }
197
198 TracePackageElement[] children = traceElement.getChildren();
199 for (TracePackageElement element : children) {
200 ModalContext.checkCanceled(progressMonitor);
201
202 if (element instanceof TracePackageFilesElement) {
203 traceFilesElement = (TracePackageFilesElement) element;
204 setStatus(importTraceFiles(traceFilesElement, traceElement, progressMonitor));
205
206 } else if (element instanceof TracePackageSupplFilesElement) {
207 TracePackageSupplFilesElement suppFilesElement = (TracePackageSupplFilesElement) element;
208 setStatus(importSupplFiles(suppFilesElement, traceElement, progressMonitor));
209 }
210
211 if (getStatus().getSeverity() != IStatus.OK) {
212 return;
213 }
214 }
215 }
216
217 } catch (InterruptedException e) {
218 setStatus(Status.CANCEL_STATUS);
219 }
220 }
221
222 /**
223 * Returns whether or not the Files element is checked under the given trace
224 * package element
225 *
226 * @param tracePackageElement
227 * the trace package element
228 * @return whether or not the Files element is checked under the given trace
229 * package element
230 */
231 public static boolean isFilesChecked(TracePackageElement tracePackageElement) {
232 for (TracePackageElement element : tracePackageElement.getChildren()) {
233 if (element instanceof TracePackageFilesElement) {
234 return element.isChecked();
235 }
236 }
237
238 return false;
239 }
240
241 /**
242 * Return the matching TmfTraceElement for a given trace element.
243 */
244 private TmfTraceElement getMatchingTraceElement(TracePackageTraceElement tracePackageElement) {
245 IPath tracePath = fTmfTraceFolder.getPath().append(tracePackageElement.getDestinationElementPath());
246 List<TmfTraceElement> traces = fTmfTraceFolder.getTraces();
247 for (TmfTraceElement t : traces) {
248 if (t.getPath().equals(tracePath)) {
249 return t;
250 }
251 }
252
253 return null;
254 }
255
256 private IStatus deleteExistingTraces(IProgressMonitor progressMonitor) {
257 for (TracePackageElement packageElement : fImportTraceElements) {
258 TracePackageTraceElement traceElement = (TracePackageTraceElement) packageElement;
259 if (!isFilesChecked(traceElement)) {
260 continue;
261 }
262
263 TmfTraceElement existingTrace = getMatchingTraceElement(traceElement);
264 if (existingTrace != null) {
265 try {
266 existingTrace.delete(SubMonitor.convert(progressMonitor));
267 } catch (CoreException e) {
268 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, e);
269 }
270 }
271 }
272
273 return Status.OK_STATUS;
274 }
275
276 private void importBookmarks(IResource traceRes, TracePackageTraceElement traceElement, IProgressMonitor monitor) {
277 for (TracePackageElement o : traceElement.getChildren()) {
278 if (o instanceof TracePackageBookmarkElement && o.isChecked()) {
279
280 // Get element
281 IFile bookmarksFile = null;
282 TmfTraceElement tmfTraceElement = getMatchingTraceElement(traceElement);
283 if (tmfTraceElement != null) {
284 try {
285 bookmarksFile = tmfTraceElement.createBookmarksFile();
286
287 // Make sure that if a bookmark is double-clicked first
288 // before opening the trace, it opens the right editor
289
290 // Get the editor id from the extension point
291 String traceEditorId = tmfTraceElement.getEditorId();
292 final String editorId = (traceEditorId != null) ? traceEditorId : TmfEventsEditor.ID;
293 IDE.setDefaultEditor(bookmarksFile, editorId);
294
295 } catch (CoreException e) {
296 Activator.getDefault().logError(MessageFormat.format(Messages.TracePackageImportOperation_ErrorCreatingBookmarkFile, traceRes.getName()), e);
297 }
298 }
299
300 if (bookmarksFile == null) {
301 break;
302 }
303
304 TracePackageBookmarkElement bookmarkElement = (TracePackageBookmarkElement) o;
305
306 List<Map<String, String>> bookmarks = bookmarkElement.getBookmarks();
307 for (Map<String, String> attrs : bookmarks) {
308 IMarker createMarker = null;
309 try {
310 createMarker = bookmarksFile.createMarker(IMarker.BOOKMARK);
311 } catch (CoreException e) {
312 Activator.getDefault().logError(MessageFormat.format(Messages.TracePackageImportOperation_ErrorCreatingBookmark, traceRes.getName()), e);
313 }
314 if (createMarker != null && createMarker.exists()) {
315 try {
316 for (Entry<String, String> entry : attrs.entrySet()) {
317 String key = entry.getKey();
318 String value = entry.getValue();
319 if (key.equals(IMarker.LOCATION)) {
320 try {
321 /* try location as an integer for backward compatibility */
322 createMarker.setAttribute(IMarker.LOCATION, Integer.parseInt(value));
323 } catch (NumberFormatException e) {
324 createMarker.setAttribute(IMarker.LOCATION, value);
325 }
326 } else {
327 createMarker.setAttribute(key, value);
328 }
329 }
330 } catch (CoreException e) {
331 Activator.getDefault().logError(MessageFormat.format(Messages.TracePackageImportOperation_ErrorCreatingBookmark, traceRes.getName()), e);
332 }
333 }
334 }
335 }
336 }
337
338 monitor.worked(1);
339 }
340
341 private IStatus importTraceFiles(TracePackageFilesElement traceFilesElement, TracePackageTraceElement traceElement, IProgressMonitor monitor) {
342 List<Pair<String, String>> fileNameAndLabelPairs = new ArrayList<>();
343
344 String sourceName = checkNotNull(traceFilesElement.getFileName());
345 String destinationName = checkNotNull(traceElement.getImportName());
346
347 fileNameAndLabelPairs.add(new Pair<>(sourceName, destinationName));
348
349 IPath containerPath = fTmfTraceFolder.getPath();
350 IStatus status = importFiles(getSpecifiedArchiveFile(), fileNameAndLabelPairs, containerPath, Path.EMPTY, monitor);
351 if (getStatus().getSeverity() != IStatus.OK) {
352 return status;
353 }
354
355 // We need to set the trace type before importing the supplementary files so we do it here
356 IResource traceRes = fTmfTraceFolder.getResource().findMember(traceElement.getDestinationElementPath());
357 if (traceRes == null || !traceRes.exists()) {
358 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format(Messages.ImportTracePackageWizardPage_ErrorFindingImportedTrace, destinationName));
359 }
360
361 TraceTypeHelper traceType = null;
362 String traceTypeStr = traceElement.getTraceType();
363 if (traceTypeStr != null) {
364 traceType = TmfTraceType.getTraceType(traceTypeStr);
365 if (traceType == null) {
366 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format(Messages.ImportTracePackageWizardPage_ErrorSettingTraceType, traceElement.getTraceType(), destinationName));
367 }
368 } else {
369 try {
370 monitor.subTask(MessageFormat.format(Messages.TracePackageImportOperation_DetectingTraceType, destinationName));
371 traceType = TmfTraceTypeUIUtils.selectTraceType(traceRes.getLocation().toOSString(), null, null);
372 } catch (TmfTraceImportException e) {
373 // Could not figure out the type
374 }
375 }
376
377 if (traceType != null) {
378 try {
379 TmfTraceTypeUIUtils.setTraceType(traceRes, traceType);
380 } catch (CoreException e) {
381 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format(Messages.ImportTracePackageWizardPage_ErrorSettingTraceType, traceElement.getTraceType(), destinationName), e);
382 }
383 }
384
385 importBookmarks(traceRes, traceElement, monitor);
386
387 try {
388 URI uri = new File(getFileName()).toURI();
389 IPath entryPath = new Path(traceFilesElement.getFileName());
390 if (traceRes instanceof IFolder) {
391 entryPath = entryPath.addTrailingSeparator();
392 }
393 String sourceLocation = URIUtil.toUnencodedString(URIUtil.toJarURI(uri, entryPath));
394 traceRes.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation);
395 } catch (CoreException e) {
396 }
397
398 return status;
399 }
400
401 private IStatus importSupplFiles(TracePackageSupplFilesElement suppFilesElement, TracePackageTraceElement traceElement, IProgressMonitor monitor) {
402 List<Pair<String, String>> fileNameAndLabelPairs = new ArrayList<>();
403 for (TracePackageElement child : suppFilesElement.getChildren()) {
404 if (child.isChecked()) {
405 TracePackageSupplFileElement supplFile = (TracePackageSupplFileElement) child;
406 fileNameAndLabelPairs.add(new Pair<>(checkNotNull(supplFile.getText()), checkNotNull(new Path(supplFile.getText()).lastSegment())));
407 }
408 }
409
410 if (!fileNameAndLabelPairs.isEmpty()) {
411 TmfTraceElement existingTrace = getMatchingTraceElement(traceElement);
412 if (existingTrace != null) {
413 ArchiveFile archiveFile = getSpecifiedArchiveFile();
414 existingTrace.refreshSupplementaryFolder();
415 // Project/Traces/A/B -> A/B
416 IPath traceFolderRelativePath = fTmfTraceFolder.getPath().makeRelativeTo(fTmfTraceFolder.getProject().getTracesFolder().getPath());
417 // Project/.tracing/A/B/
418 IFolder traceSupplementaryFolder = fTmfTraceFolder.getTraceSupplementaryFolder(traceFolderRelativePath.toString());
419 IPath destinationContainerPath = traceSupplementaryFolder.getFullPath();
420 // Remove the .tracing segment at the beginnin so that a file in folder .tracing/A/B/ imports destinationContainerPath/A/B/
421 Path baseSourcePath = new Path(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME);
422 return importFiles(archiveFile, fileNameAndLabelPairs, destinationContainerPath, baseSourcePath, monitor);
423 }
424 }
425
426 return Status.OK_STATUS;
427 }
428
429 private IStatus importFiles(ArchiveFile archiveFile, List<Pair<String, String>> fileNameAndLabelPairs, IPath destinationContainerPath, IPath baseSourcePath, IProgressMonitor monitor) {
430 List<ArchiveProviderElement> objects = new ArrayList<>();
431 Enumeration<@NonNull ?> entries = archiveFile.entries();
432 while (entries.hasMoreElements()) {
433 ArchiveEntry entry = (ArchiveEntry) entries.nextElement();
434 String entryName = entry.getName();
435 IPath fullArchivePath = new Path(entryName);
436 if (fullArchivePath.hasTrailingSeparator()) {
437 // We only care about file entries as the folders will get created by the ImportOperation
438 continue;
439 }
440
441 for (Pair<String, String> fileNameAndLabel : fileNameAndLabelPairs) {
442
443 // Examples: Traces/aaa/kernel/ .tracing/aaa/testtexttrace.txt/statistics.ht
444 IPath searchedArchivePath = new Path(fileNameAndLabel.getFirst());
445
446 // Check if this archive entry matches the searched file name at this archive location
447 boolean fileMatch = entryName.equalsIgnoreCase(searchedArchivePath.toString());
448 // For example Traces/aaa/kernel/metadata matches Traces/aaa/kernel/
449 boolean folderMatch = entryName.startsWith(searchedArchivePath + "/"); //$NON-NLS-1$
450
451 if (fileMatch || folderMatch) {
452 // .tracing/aaa/testtexttrace.txt/statistics.ht -> aaa/testtexttrace.txt/statistics.ht
453 IPath destinationPath = fullArchivePath.makeRelativeTo(baseSourcePath);
454
455 // metadata statistics.ht
456 // We don't use the label when the entry is a folder match because the labels for individual files
457 // under the folder are not specified in the manifest so just use the last segment.
458 String resourceLabel = folderMatch ? fullArchivePath.lastSegment() : fileNameAndLabel.getSecond();
459
460 ArchiveProviderElement pe = new ArchiveProviderElement(destinationPath.toString(), resourceLabel, archiveFile, entry);
461 objects.add(pe);
462 break;
463 }
464 }
465 }
466
467 ImportProvider provider = new ImportProvider();
468
469 ImportOperation operation = new ImportOperation(destinationContainerPath,
470 null, provider, this,
471 objects);
472 operation.setCreateContainerStructure(true);
473 operation.setOverwriteResources(true);
474
475 try {
476 operation.run(SubMonitor.convert(monitor));
477 archiveFile.close();
478 } catch (InvocationTargetException e) {
479 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, e);
480 } catch (InterruptedException e) {
481 return Status.CANCEL_STATUS;
482 } catch (IOException e) {
483 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, e);
484 }
485
486 if (provider.getException() != null) {
487 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, provider.getException());
488 }
489
490 return operation.getStatus();
491 }
492
493 @Override
494 public String queryOverwrite(String pathString) {
495 // We always overwrite once we reach this point
496 return null;
497 }
498 }
This page took 0.041565 seconds and 4 git commands to generate.