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
.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
.tracepkg
.AbstractTracePackageOperation
;
46 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageBookmarkElement
;
47 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageElement
;
48 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageFilesElement
;
49 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageSupplFileElement
;
50 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageSupplFilesElement
;
51 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageTraceElement
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceImportException
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceType
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TraceTypeHelper
;
56 import org
.eclipse
.tracecompass
.tmf
.core
.util
.Pair
;
57 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.TmfEventsEditor
;
58 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceElement
;
59 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceFolder
;
60 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceTypeUIUtils
;
61 import org
.eclipse
.ui
.dialogs
.IOverwriteQuery
;
62 import org
.eclipse
.ui
.ide
.IDE
;
63 import org
.eclipse
.ui
.internal
.wizards
.datatransfer
.TarException
;
64 import org
.eclipse
.ui
.wizards
.datatransfer
.IImportStructureProvider
;
65 import org
.eclipse
.ui
.wizards
.datatransfer
.ImportOperation
;
68 * An operation that imports a trace package from an archive
70 * @author Marc-Andre Laperle
72 @SuppressWarnings("restriction")
73 public class TracePackageImportOperation
extends AbstractTracePackageOperation
implements IOverwriteQuery
{
75 private final TracePackageElement
[] fImportTraceElements
;
76 private final TmfTraceFolder fTmfTraceFolder
;
79 * Constructs a new import operation
81 * @param importTraceElements
82 * the trace element to be imported
84 * the output file name
85 * @param tmfTraceFolder
86 * the destination folder
88 public TracePackageImportOperation(String fileName
, TracePackageElement
[] importTraceElements
, TmfTraceFolder tmfTraceFolder
) {
90 fImportTraceElements
= importTraceElements
;
91 fTmfTraceFolder
= tmfTraceFolder
;
94 private class ImportProvider
implements IImportStructureProvider
{
96 private Exception fException
;
99 public List
getChildren(Object element
) {
104 public InputStream
getContents(Object element
) {
105 InputStream inputStream
= null;
108 inputStream
= ((ArchiveProviderElement
) element
).getContents();
109 } catch (IOException e
) {
111 } catch (TarException e
) {
118 public String
getFullPath(Object element
) {
119 return ((ArchiveProviderElement
) element
).getFullPath();
123 public String
getLabel(Object element
) {
124 return ((ArchiveProviderElement
) element
).getLabel();
128 public boolean isFolder(Object element
) {
129 return ((ArchiveProviderElement
) element
).isFolder();
132 public Exception
getException() {
137 private class ArchiveProviderElement
{
139 private final String fPath
;
140 private final String fLabel
;
142 private ArchiveFile fArchiveFile
;
143 private ArchiveEntry fEntry
;
145 public ArchiveProviderElement(String destinationPath
, String label
, ArchiveFile archiveFile
, ArchiveEntry entry
) {
146 fPath
= destinationPath
;
148 this.fArchiveFile
= archiveFile
;
152 public InputStream
getContents() throws TarException
, IOException
{
153 return fArchiveFile
.getInputStream(fEntry
);
156 public String
getFullPath() {
160 public String
getLabel() {
164 public boolean isFolder() {
170 * Run the operation. The status (result) of the operation can be obtained
171 * with {@link #getStatus}
173 * @param progressMonitor
174 * the progress monitor to use to display progress and receive
175 * requests for cancellation
178 public void run(IProgressMonitor progressMonitor
) {
179 int totalWork
= getNbCheckedElements(fImportTraceElements
) * 2;
180 progressMonitor
.beginTask(Messages
.TracePackageImportOperation_ImportingPackage
, totalWork
);
181 doRun(progressMonitor
);
182 progressMonitor
.done();
185 private void doRun(IProgressMonitor progressMonitor
) {
187 setStatus(deleteExistingTraces(progressMonitor
));
188 if (getStatus().getSeverity() != IStatus
.OK
) {
192 TracePackageFilesElement traceFilesElement
= null;
193 for (TracePackageElement packageElement
: fImportTraceElements
) {
194 TracePackageTraceElement traceElement
= (TracePackageTraceElement
) packageElement
;
195 if (!isFilesChecked(packageElement
)) {
199 TracePackageElement
[] children
= traceElement
.getChildren();
200 for (TracePackageElement element
: children
) {
201 ModalContext
.checkCanceled(progressMonitor
);
203 if (element
instanceof TracePackageFilesElement
) {
204 traceFilesElement
= (TracePackageFilesElement
) element
;
205 setStatus(importTraceFiles(traceFilesElement
, traceElement
, progressMonitor
));
207 } else if (element
instanceof TracePackageSupplFilesElement
) {
208 TracePackageSupplFilesElement suppFilesElement
= (TracePackageSupplFilesElement
) element
;
209 setStatus(importSupplFiles(suppFilesElement
, traceElement
, progressMonitor
));
212 if (getStatus().getSeverity() != IStatus
.OK
) {
218 } catch (InterruptedException e
) {
219 setStatus(Status
.CANCEL_STATUS
);
224 * Returns whether or not the Files element is checked under the given trace
227 * @param tracePackageElement
228 * the trace package element
229 * @return whether or not the Files element is checked under the given trace
232 public static boolean isFilesChecked(TracePackageElement tracePackageElement
) {
233 for (TracePackageElement element
: tracePackageElement
.getChildren()) {
234 if (element
instanceof TracePackageFilesElement
) {
235 return element
.isChecked();
243 * Return the matching TmfTraceElement for a given trace element.
245 private TmfTraceElement
getMatchingTraceElement(TracePackageTraceElement tracePackageElement
) {
246 IPath tracePath
= fTmfTraceFolder
.getPath().append(tracePackageElement
.getDestinationElementPath());
247 List
<TmfTraceElement
> traces
= fTmfTraceFolder
.getTraces();
248 for (TmfTraceElement t
: traces
) {
249 if (t
.getPath().equals(tracePath
)) {
257 private IStatus
deleteExistingTraces(IProgressMonitor progressMonitor
) {
258 for (TracePackageElement packageElement
: fImportTraceElements
) {
259 TracePackageTraceElement traceElement
= (TracePackageTraceElement
) packageElement
;
260 if (!isFilesChecked(traceElement
)) {
264 TmfTraceElement existingTrace
= getMatchingTraceElement(traceElement
);
265 if (existingTrace
!= null) {
267 existingTrace
.delete(SubMonitor
.convert(progressMonitor
));
268 } catch (CoreException e
) {
269 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
);
274 return Status
.OK_STATUS
;
277 private void importBookmarks(IResource traceRes
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
278 for (TracePackageElement o
: traceElement
.getChildren()) {
279 if (o
instanceof TracePackageBookmarkElement
&& o
.isChecked()) {
282 IFile bookmarksFile
= null;
283 TmfTraceElement tmfTraceElement
= getMatchingTraceElement(traceElement
);
284 if (tmfTraceElement
!= null) {
286 bookmarksFile
= tmfTraceElement
.createBookmarksFile();
288 // Make sure that if a bookmark is double-clicked first
289 // before opening the trace, it opens the right editor
291 // Get the editor id from the extension point
292 String traceEditorId
= tmfTraceElement
.getEditorId();
293 final String editorId
= (traceEditorId
!= null) ? traceEditorId
: TmfEventsEditor
.ID
;
294 IDE
.setDefaultEditor(bookmarksFile
, editorId
);
296 } catch (CoreException e
) {
297 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmarkFile
, traceRes
.getName()), e
);
301 if (bookmarksFile
== null) {
305 TracePackageBookmarkElement bookmarkElement
= (TracePackageBookmarkElement
) o
;
307 List
<Map
<String
, String
>> bookmarks
= bookmarkElement
.getBookmarks();
308 for (Map
<String
, String
> attrs
: bookmarks
) {
309 IMarker createMarker
= null;
311 createMarker
= bookmarksFile
.createMarker(IMarker
.BOOKMARK
);
312 } catch (CoreException e
) {
313 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmark
, traceRes
.getName()), e
);
315 if (createMarker
!= null && createMarker
.exists()) {
317 for (Entry
<String
, String
> entry
: attrs
.entrySet()) {
318 String key
= entry
.getKey();
319 String value
= entry
.getValue();
320 if (key
.equals(IMarker
.LOCATION
)) {
322 /* try location as an integer for backward compatibility */
323 createMarker
.setAttribute(IMarker
.LOCATION
, Integer
.parseInt(value
));
324 } catch (NumberFormatException e
) {
325 createMarker
.setAttribute(IMarker
.LOCATION
, value
);
328 createMarker
.setAttribute(key
, value
);
331 } catch (CoreException e
) {
332 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmark
, traceRes
.getName()), e
);
342 private IStatus
importTraceFiles(TracePackageFilesElement traceFilesElement
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
343 List
<Pair
<String
, String
>> fileNameAndLabelPairs
= new ArrayList
<>();
345 String sourceName
= checkNotNull(traceFilesElement
.getFileName());
346 String destinationName
= checkNotNull(traceElement
.getImportName());
348 fileNameAndLabelPairs
.add(new Pair
<>(sourceName
, destinationName
));
350 IPath containerPath
= fTmfTraceFolder
.getPath();
351 IStatus status
= importFiles(getSpecifiedArchiveFile(), fileNameAndLabelPairs
, containerPath
, Path
.EMPTY
, monitor
);
352 if (getStatus().getSeverity() != IStatus
.OK
) {
356 // We need to set the trace type before importing the supplementary files so we do it here
357 IResource traceRes
= fTmfTraceFolder
.getResource().findMember(traceElement
.getDestinationElementPath());
358 if (traceRes
== null || !traceRes
.exists()) {
359 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorFindingImportedTrace
, destinationName
));
362 TraceTypeHelper traceType
= null;
363 String traceTypeStr
= traceElement
.getTraceType();
364 if (traceTypeStr
!= null) {
365 traceType
= TmfTraceType
.getTraceType(traceTypeStr
);
366 if (traceType
== null) {
367 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorSettingTraceType
, traceElement
.getTraceType(), destinationName
));
371 monitor
.subTask(MessageFormat
.format(Messages
.TracePackageImportOperation_DetectingTraceType
, destinationName
));
372 traceType
= TmfTraceTypeUIUtils
.selectTraceType(traceRes
.getLocation().toOSString(), null, null);
373 } catch (TmfTraceImportException e
) {
374 // Could not figure out the type
378 if (traceType
!= null) {
380 TmfTraceTypeUIUtils
.setTraceType(traceRes
, traceType
);
381 } catch (CoreException e
) {
382 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorSettingTraceType
, traceElement
.getTraceType(), destinationName
), e
);
386 importBookmarks(traceRes
, traceElement
, monitor
);
389 URI uri
= new File(getFileName()).toURI();
390 IPath entryPath
= new Path(traceFilesElement
.getFileName());
391 if (traceRes
instanceof IFolder
) {
392 entryPath
= entryPath
.addTrailingSeparator();
394 String sourceLocation
= URIUtil
.toUnencodedString(URIUtil
.toJarURI(uri
, entryPath
));
395 traceRes
.setPersistentProperty(TmfCommonConstants
.SOURCE_LOCATION
, sourceLocation
);
396 } catch (CoreException e
) {
402 private IStatus
importSupplFiles(TracePackageSupplFilesElement suppFilesElement
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
403 List
<Pair
<String
, String
>> fileNameAndLabelPairs
= new ArrayList
<>();
404 for (TracePackageElement child
: suppFilesElement
.getChildren()) {
405 if (child
.isChecked()) {
406 TracePackageSupplFileElement supplFile
= (TracePackageSupplFileElement
) child
;
407 fileNameAndLabelPairs
.add(new Pair
<>(checkNotNull(supplFile
.getText()), checkNotNull(new Path(supplFile
.getText()).lastSegment())));
411 if (!fileNameAndLabelPairs
.isEmpty()) {
412 TmfTraceElement existingTrace
= getMatchingTraceElement(traceElement
);
413 if (existingTrace
!= null) {
414 ArchiveFile archiveFile
= getSpecifiedArchiveFile();
415 existingTrace
.refreshSupplementaryFolder();
416 // Project/Traces/A/B -> A/B
417 IPath traceFolderRelativePath
= fTmfTraceFolder
.getPath().makeRelativeTo(fTmfTraceFolder
.getProject().getTracesFolder().getPath());
418 // Project/.tracing/A/B/
419 IFolder traceSupplementaryFolder
= fTmfTraceFolder
.getTraceSupplementaryFolder(traceFolderRelativePath
.toString());
420 IPath destinationContainerPath
= traceSupplementaryFolder
.getFullPath();
421 // Remove the .tracing segment at the beginnin so that a file in folder .tracing/A/B/ imports destinationContainerPath/A/B/
422 Path baseSourcePath
= new Path(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER_NAME
);
423 return importFiles(archiveFile
, fileNameAndLabelPairs
, destinationContainerPath
, baseSourcePath
, monitor
);
427 return Status
.OK_STATUS
;
430 private IStatus
importFiles(ArchiveFile archiveFile
, List
<Pair
<String
, String
>> fileNameAndLabelPairs
, IPath destinationContainerPath
, IPath baseSourcePath
, IProgressMonitor monitor
) {
431 List
<ArchiveProviderElement
> objects
= new ArrayList
<>();
432 Enumeration
<@NonNull ?
> entries
= archiveFile
.entries();
433 while (entries
.hasMoreElements()) {
434 ArchiveEntry entry
= (ArchiveEntry
) entries
.nextElement();
435 String entryName
= entry
.getName();
436 IPath fullArchivePath
= new Path(entryName
);
437 if (fullArchivePath
.hasTrailingSeparator()) {
438 // We only care about file entries as the folders will get created by the ImportOperation
442 for (Pair
<String
, String
> fileNameAndLabel
: fileNameAndLabelPairs
) {
444 // Examples: Traces/aaa/kernel/ .tracing/aaa/testtexttrace.txt/statistics.ht
445 IPath searchedArchivePath
= new Path(fileNameAndLabel
.getFirst());
447 // Check if this archive entry matches the searched file name at this archive location
448 boolean fileMatch
= entryName
.equalsIgnoreCase(searchedArchivePath
.toString());
449 // For example Traces/aaa/kernel/metadata matches Traces/aaa/kernel/
450 boolean folderMatch
= entryName
.startsWith(searchedArchivePath
+ "/"); //$NON-NLS-1$
452 if (fileMatch
|| folderMatch
) {
453 // .tracing/aaa/testtexttrace.txt/statistics.ht -> aaa/testtexttrace.txt/statistics.ht
454 IPath destinationPath
= fullArchivePath
.makeRelativeTo(baseSourcePath
);
456 // metadata statistics.ht
457 // We don't use the label when the entry is a folder match because the labels for individual files
458 // under the folder are not specified in the manifest so just use the last segment.
459 String resourceLabel
= folderMatch ? fullArchivePath
.lastSegment() : fileNameAndLabel
.getSecond();
461 ArchiveProviderElement pe
= new ArchiveProviderElement(destinationPath
.toString(), resourceLabel
, archiveFile
, entry
);
468 ImportProvider provider
= new ImportProvider();
470 ImportOperation operation
= new ImportOperation(destinationContainerPath
,
471 null, provider
, this,
473 operation
.setCreateContainerStructure(true);
474 operation
.setOverwriteResources(true);
477 operation
.run(SubMonitor
.convert(monitor
));
479 } catch (InvocationTargetException e
) {
480 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
);
481 } catch (InterruptedException e
) {
482 return Status
.CANCEL_STATUS
;
483 } catch (IOException e
) {
484 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
);
487 if (provider
.getException() != null) {
488 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, provider
.getException());
491 return operation
.getStatus();
495 public String
queryOverwrite(String pathString
) {
496 // We always overwrite once we reach this point