1 /*******************************************************************************
2 * Copyright (c) 2013, 2015 Ericsson
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
10 * Marc-Andre Laperle - Initial API and implementation
11 * Patrick Tasse - Add support for source location
12 *******************************************************************************/
14 package org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.importexport
;
16 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
19 import java
.io
.IOException
;
20 import java
.io
.InputStream
;
21 import java
.lang
.reflect
.InvocationTargetException
;
23 import java
.text
.MessageFormat
;
24 import java
.util
.ArrayList
;
25 import java
.util
.Enumeration
;
26 import java
.util
.List
;
28 import java
.util
.Map
.Entry
;
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
.SubProgressMonitor
;
41 import org
.eclipse
.core
.runtime
.URIUtil
;
42 import org
.eclipse
.jface
.operation
.ModalContext
;
43 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
44 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.AbstractTracePackageOperation
;
45 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageBookmarkElement
;
46 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageElement
;
47 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageFilesElement
;
48 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageSupplFileElement
;
49 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageSupplFilesElement
;
50 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageTraceElement
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceImportException
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceType
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TraceTypeHelper
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.util
.Pair
;
56 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.TmfEventsEditor
;
57 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceElement
;
58 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceFolder
;
59 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceTypeUIUtils
;
60 import org
.eclipse
.ui
.dialogs
.IOverwriteQuery
;
61 import org
.eclipse
.ui
.ide
.IDE
;
62 import org
.eclipse
.ui
.internal
.wizards
.datatransfer
.TarException
;
63 import org
.eclipse
.ui
.wizards
.datatransfer
.IImportStructureProvider
;
64 import org
.eclipse
.ui
.wizards
.datatransfer
.ImportOperation
;
67 * An operation that imports a trace package from an archive
69 * @author Marc-Andre Laperle
71 @SuppressWarnings("restriction")
72 public class TracePackageImportOperation
extends AbstractTracePackageOperation
implements IOverwriteQuery
{
74 private final TracePackageElement
[] fImportTraceElements
;
75 private final TmfTraceFolder fTmfTraceFolder
;
78 * Constructs a new import operation
80 * @param importTraceElements
81 * the trace element to be imported
83 * the output file name
84 * @param tmfTraceFolder
85 * the destination folder
87 public TracePackageImportOperation(String fileName
, TracePackageElement
[] importTraceElements
, TmfTraceFolder tmfTraceFolder
) {
89 fImportTraceElements
= importTraceElements
;
90 fTmfTraceFolder
= tmfTraceFolder
;
93 private class ImportProvider
implements IImportStructureProvider
{
95 private Exception fException
;
98 public List
getChildren(Object element
) {
103 public InputStream
getContents(Object element
) {
104 InputStream inputStream
= null;
107 inputStream
= ((ArchiveProviderElement
) element
).getContents();
108 } catch (IOException e
) {
110 } catch (TarException e
) {
117 public String
getFullPath(Object element
) {
118 return ((ArchiveProviderElement
) element
).getFullPath();
122 public String
getLabel(Object element
) {
123 return ((ArchiveProviderElement
) element
).getLabel();
127 public boolean isFolder(Object element
) {
128 return ((ArchiveProviderElement
) element
).isFolder();
131 public Exception
getException() {
136 private class ArchiveProviderElement
{
138 private final String fPath
;
139 private final String fLabel
;
141 private ArchiveFile fArchiveFile
;
142 private ArchiveEntry fEntry
;
144 public ArchiveProviderElement(String destinationPath
, String label
, ArchiveFile archiveFile
, ArchiveEntry entry
) {
145 fPath
= destinationPath
;
147 this.fArchiveFile
= archiveFile
;
151 public InputStream
getContents() throws TarException
, IOException
{
152 return fArchiveFile
.getInputStream(fEntry
);
155 public String
getFullPath() {
159 public String
getLabel() {
163 public boolean isFolder() {
169 * Run the operation. The status (result) of the operation can be obtained
170 * with {@link #getStatus}
172 * @param progressMonitor
173 * the progress monitor to use to display progress and receive
174 * requests for cancellation
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();
184 private void doRun(IProgressMonitor progressMonitor
) {
186 setStatus(deleteExistingTraces(progressMonitor
));
187 if (getStatus().getSeverity() != IStatus
.OK
) {
191 TracePackageFilesElement traceFilesElement
= null;
192 for (TracePackageElement packageElement
: fImportTraceElements
) {
193 TracePackageTraceElement traceElement
= (TracePackageTraceElement
) packageElement
;
194 if (!isFilesChecked(packageElement
)) {
198 TracePackageElement
[] children
= traceElement
.getChildren();
199 for (TracePackageElement element
: children
) {
200 ModalContext
.checkCanceled(progressMonitor
);
202 if (element
instanceof TracePackageFilesElement
) {
203 traceFilesElement
= (TracePackageFilesElement
) element
;
204 setStatus(importTraceFiles(traceFilesElement
, traceElement
, progressMonitor
));
206 } else if (element
instanceof TracePackageSupplFilesElement
) {
207 TracePackageSupplFilesElement suppFilesElement
= (TracePackageSupplFilesElement
) element
;
208 setStatus(importSupplFiles(suppFilesElement
, traceElement
, progressMonitor
));
211 if (getStatus().getSeverity() != IStatus
.OK
) {
217 } catch (InterruptedException e
) {
218 setStatus(Status
.CANCEL_STATUS
);
223 * Returns whether or not the Files element is checked under the given trace
226 * @param tracePackageElement
227 * the trace package element
228 * @return whether or not the Files element is checked under the given trace
231 public static boolean isFilesChecked(TracePackageElement tracePackageElement
) {
232 for (TracePackageElement element
: tracePackageElement
.getChildren()) {
233 if (element
instanceof TracePackageFilesElement
) {
234 return element
.isChecked();
242 * Return the matching TmfTraceElement for a given trace element.
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
)) {
256 private IStatus
deleteExistingTraces(IProgressMonitor progressMonitor
) {
257 for (TracePackageElement packageElement
: fImportTraceElements
) {
258 TracePackageTraceElement traceElement
= (TracePackageTraceElement
) packageElement
;
259 if (!isFilesChecked(traceElement
)) {
263 TmfTraceElement existingTrace
= getMatchingTraceElement(traceElement
);
264 if (existingTrace
!= null) {
266 existingTrace
.delete(new SubProgressMonitor(progressMonitor
, 1, SubProgressMonitor
.PREPEND_MAIN_LABEL_TO_SUBTASK
));
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
);
273 return Status
.OK_STATUS
;
276 private void importBookmarks(IResource traceRes
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
277 for (TracePackageElement o
: traceElement
.getChildren()) {
278 if (o
instanceof TracePackageBookmarkElement
&& o
.isChecked()) {
281 IFile bookmarksFile
= null;
282 TmfTraceElement tmfTraceElement
= getMatchingTraceElement(traceElement
);
283 if (tmfTraceElement
!= null) {
285 bookmarksFile
= tmfTraceElement
.createBookmarksFile();
287 // Make sure that if a bookmark is double-clicked first
288 // before opening the trace, it opens the right editor
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
);
295 } catch (CoreException e
) {
296 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmarkFile
, traceRes
.getName()), e
);
300 if (bookmarksFile
== null) {
304 TracePackageBookmarkElement bookmarkElement
= (TracePackageBookmarkElement
) o
;
306 List
<Map
<String
, String
>> bookmarks
= bookmarkElement
.getBookmarks();
307 for (Map
<String
, String
> attrs
: bookmarks
) {
308 IMarker createMarker
= null;
310 createMarker
= bookmarksFile
.createMarker(IMarker
.BOOKMARK
);
311 } catch (CoreException e
) {
312 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmark
, traceRes
.getName()), e
);
314 if (createMarker
!= null && createMarker
.exists()) {
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 createMarker
.setAttribute(IMarker
.LOCATION
, Integer
.valueOf(value
).intValue());
322 createMarker
.setAttribute(key
, value
);
325 } catch (CoreException e
) {
326 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmark
, traceRes
.getName()), e
);
336 private IStatus
importTraceFiles(TracePackageFilesElement traceFilesElement
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
337 List
<Pair
<String
, String
>> fileNameAndLabelPairs
= new ArrayList
<>();
339 String sourceName
= checkNotNull(traceFilesElement
.getFileName());
340 String destinationName
= checkNotNull(traceElement
.getImportName());
342 fileNameAndLabelPairs
.add(new Pair
<>(sourceName
, destinationName
));
344 IPath containerPath
= fTmfTraceFolder
.getPath();
345 IStatus status
= importFiles(getSpecifiedArchiveFile(), fileNameAndLabelPairs
, containerPath
, Path
.EMPTY
, monitor
);
346 if (getStatus().getSeverity() != IStatus
.OK
) {
350 // We need to set the trace type before importing the supplementary files so we do it here
351 IResource traceRes
= fTmfTraceFolder
.getResource().findMember(traceElement
.getDestinationElementPath());
352 if (traceRes
== null || !traceRes
.exists()) {
353 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorFindingImportedTrace
, destinationName
));
356 TraceTypeHelper traceType
= null;
357 String traceTypeStr
= traceElement
.getTraceType();
358 if (traceTypeStr
!= null) {
359 traceType
= TmfTraceType
.getTraceType(traceTypeStr
);
360 if (traceType
== null) {
361 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorSettingTraceType
, traceElement
.getTraceType(), destinationName
));
365 monitor
.subTask(MessageFormat
.format(Messages
.TracePackageImportOperation_DetectingTraceType
, destinationName
));
366 traceType
= TmfTraceTypeUIUtils
.selectTraceType(traceRes
.getLocation().toOSString(), null, null);
367 } catch (TmfTraceImportException e
) {
368 // Could not figure out the type
372 if (traceType
!= null) {
374 TmfTraceTypeUIUtils
.setTraceType(traceRes
, traceType
);
375 } catch (CoreException e
) {
376 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorSettingTraceType
, traceElement
.getTraceType(), destinationName
), e
);
380 importBookmarks(traceRes
, traceElement
, monitor
);
383 URI uri
= new File(getFileName()).toURI();
384 IPath entryPath
= new Path(traceFilesElement
.getFileName());
385 if (traceRes
instanceof IFolder
) {
386 entryPath
= entryPath
.addTrailingSeparator();
388 String sourceLocation
= URIUtil
.toUnencodedString(URIUtil
.toJarURI(uri
, entryPath
));
389 traceRes
.setPersistentProperty(TmfCommonConstants
.SOURCE_LOCATION
, sourceLocation
);
390 } catch (CoreException e
) {
396 private IStatus
importSupplFiles(TracePackageSupplFilesElement suppFilesElement
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
397 List
<Pair
<String
, String
>> fileNameAndLabelPairs
= new ArrayList
<>();
398 for (TracePackageElement child
: suppFilesElement
.getChildren()) {
399 if (child
.isChecked()) {
400 TracePackageSupplFileElement supplFile
= (TracePackageSupplFileElement
) child
;
401 fileNameAndLabelPairs
.add(new Pair
<>(checkNotNull(supplFile
.getText()), checkNotNull(new Path(supplFile
.getText()).lastSegment())));
405 if (!fileNameAndLabelPairs
.isEmpty()) {
406 TmfTraceElement existingTrace
= getMatchingTraceElement(traceElement
);
407 if (existingTrace
!= null) {
408 ArchiveFile archiveFile
= getSpecifiedArchiveFile();
409 existingTrace
.refreshSupplementaryFolder();
410 // Project/Traces/A/B -> A/B
411 IPath traceFolderRelativePath
= fTmfTraceFolder
.getPath().makeRelativeTo(fTmfTraceFolder
.getProject().getTracesFolder().getPath());
412 // Project/.tracing/A/B/
413 IFolder traceSupplementaryFolder
= fTmfTraceFolder
.getTraceSupplementaryFolder(traceFolderRelativePath
.toString());
414 IPath destinationContainerPath
= traceSupplementaryFolder
.getFullPath();
415 // Remove the .tracing segment at the beginnin so that a file in folder .tracing/A/B/ imports destinationContainerPath/A/B/
416 Path baseSourcePath
= new Path(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER_NAME
);
417 return importFiles(archiveFile
, fileNameAndLabelPairs
, destinationContainerPath
, baseSourcePath
, monitor
);
421 return Status
.OK_STATUS
;
424 private IStatus
importFiles(ArchiveFile archiveFile
, List
<Pair
<String
, String
>> fileNameAndLabelPairs
, IPath destinationContainerPath
, IPath baseSourcePath
, IProgressMonitor monitor
) {
425 List
<ArchiveProviderElement
> objects
= new ArrayList
<>();
426 Enumeration
<?
> entries
= archiveFile
.entries();
427 while (entries
.hasMoreElements()) {
428 ArchiveEntry entry
= (ArchiveEntry
) entries
.nextElement();
429 String entryName
= entry
.getName();
430 IPath fullArchivePath
= new Path(entryName
);
431 if (fullArchivePath
.hasTrailingSeparator()) {
432 // We only care about file entries as the folders will get created by the ImportOperation
436 for (Pair
<String
, String
> fileNameAndLabel
: fileNameAndLabelPairs
) {
438 // Examples: Traces/aaa/kernel/ .tracing/aaa/testtexttrace.txt/statistics.ht
439 IPath searchedArchivePath
= new Path(fileNameAndLabel
.getFirst());
441 // Check if this archive entry matches the searched file name at this archive location
442 boolean fileMatch
= entryName
.equalsIgnoreCase(searchedArchivePath
.toString());
443 // For example Traces/aaa/kernel/metadata matches Traces/aaa/kernel/
444 boolean folderMatch
= entryName
.startsWith(searchedArchivePath
+ "/"); //$NON-NLS-1$
446 if (fileMatch
|| folderMatch
) {
447 // .tracing/aaa/testtexttrace.txt/statistics.ht -> aaa/testtexttrace.txt/statistics.ht
448 IPath destinationPath
= fullArchivePath
.makeRelativeTo(baseSourcePath
);
450 // metadata statistics.ht
451 // We don't use the label when the entry is a folder match because the labels for individual files
452 // under the folder are not specified in the manifest so just use the last segment.
453 String resourceLabel
= folderMatch ? fullArchivePath
.lastSegment() : fileNameAndLabel
.getSecond();
455 ArchiveProviderElement pe
= new ArchiveProviderElement(destinationPath
.toString(), resourceLabel
, archiveFile
, entry
);
462 ImportProvider provider
= new ImportProvider();
464 ImportOperation operation
= new ImportOperation(destinationContainerPath
,
465 null, provider
, this,
467 operation
.setCreateContainerStructure(true);
468 operation
.setOverwriteResources(true);
471 operation
.run(new SubProgressMonitor(monitor
, fileNameAndLabelPairs
.size(), SubProgressMonitor
.PREPEND_MAIN_LABEL_TO_SUBTASK
));
473 } catch (InvocationTargetException e
) {
474 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
);
475 } catch (InterruptedException e
) {
476 return Status
.CANCEL_STATUS
;
477 } catch (IOException e
) {
478 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
);
481 if (provider
.getException() != null) {
482 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, provider
.getException());
485 return operation
.getStatus();
489 public String
queryOverwrite(String pathString
) {
490 // We always overwrite once we reach this point