1 /*******************************************************************************
2 * Copyright (c) 2013, 2014 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
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.importexport
;
17 import java
.io
.IOException
;
18 import java
.io
.InputStream
;
19 import java
.lang
.reflect
.InvocationTargetException
;
21 import java
.text
.MessageFormat
;
22 import java
.util
.ArrayList
;
23 import java
.util
.Enumeration
;
24 import java
.util
.List
;
27 import org
.eclipse
.core
.resources
.IFile
;
28 import org
.eclipse
.core
.resources
.IFolder
;
29 import org
.eclipse
.core
.resources
.IMarker
;
30 import org
.eclipse
.core
.resources
.IResource
;
31 import org
.eclipse
.core
.runtime
.CoreException
;
32 import org
.eclipse
.core
.runtime
.IPath
;
33 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
34 import org
.eclipse
.core
.runtime
.IStatus
;
35 import org
.eclipse
.core
.runtime
.Path
;
36 import org
.eclipse
.core
.runtime
.Status
;
37 import org
.eclipse
.core
.runtime
.SubProgressMonitor
;
38 import org
.eclipse
.core
.runtime
.URIUtil
;
39 import org
.eclipse
.jface
.operation
.ModalContext
;
40 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
41 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.AbstractTracePackageOperation
;
42 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageBookmarkElement
;
43 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageElement
;
44 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageFilesElement
;
45 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageSupplFileElement
;
46 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageSupplFilesElement
;
47 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageTraceElement
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceImportException
;
50 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceType
;
51 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TraceTypeHelper
;
52 import org
.eclipse
.linuxtools
.tmf
.core
.util
.Pair
;
53 import org
.eclipse
.linuxtools
.tmf
.ui
.editors
.TmfEventsEditor
;
54 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceElement
;
55 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceFolder
;
56 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceTypeUIUtils
;
57 import org
.eclipse
.ui
.dialogs
.IOverwriteQuery
;
58 import org
.eclipse
.ui
.ide
.IDE
;
59 import org
.eclipse
.ui
.internal
.wizards
.datatransfer
.TarException
;
60 import org
.eclipse
.ui
.wizards
.datatransfer
.IImportStructureProvider
;
61 import org
.eclipse
.ui
.wizards
.datatransfer
.ImportOperation
;
64 * An operation that imports a trace package from an archive
66 * @author Marc-Andre Laperle
68 @SuppressWarnings("restriction")
69 public class TracePackageImportOperation
extends AbstractTracePackageOperation
implements IOverwriteQuery
{
71 private final TracePackageElement
[] fImportTraceElements
;
72 private final TmfTraceFolder fTmfTraceFolder
;
75 * Constructs a new import operation
77 * @param importTraceElements
78 * the trace element to be imported
80 * the output file name
81 * @param tmfTraceFolder
82 * the destination folder
84 public TracePackageImportOperation(String fileName
, TracePackageElement
[] importTraceElements
, TmfTraceFolder tmfTraceFolder
) {
86 fImportTraceElements
= importTraceElements
;
87 fTmfTraceFolder
= tmfTraceFolder
;
90 private class ImportProvider
implements IImportStructureProvider
{
92 private Exception fException
;
95 public List
getChildren(Object element
) {
100 public InputStream
getContents(Object element
) {
101 InputStream inputStream
= null;
104 inputStream
= ((ArchiveProviderElement
) element
).getContents();
105 } catch (IOException e
) {
107 } catch (TarException e
) {
114 public String
getFullPath(Object element
) {
115 return ((ArchiveProviderElement
) element
).getFullPath();
119 public String
getLabel(Object element
) {
120 return ((ArchiveProviderElement
) element
).getLabel();
124 public boolean isFolder(Object element
) {
125 return ((ArchiveProviderElement
) element
).isFolder();
128 public Exception
getException() {
133 private class ArchiveProviderElement
{
135 private final String fPath
;
136 private final String fLabel
;
138 private ArchiveFile fArchiveFile
;
139 private ArchiveEntry fEntry
;
141 public ArchiveProviderElement(String destinationPath
, String label
, ArchiveFile archiveFile
, ArchiveEntry entry
) {
142 fPath
= destinationPath
;
144 this.fArchiveFile
= archiveFile
;
148 public InputStream
getContents() throws TarException
, IOException
{
149 return fArchiveFile
.getInputStream(fEntry
);
152 public String
getFullPath() {
156 public String
getLabel() {
160 public boolean isFolder() {
166 * Run the operation. The status (result) of the operation can be obtained
167 * with {@link #getStatus}
169 * @param progressMonitor
170 * the progress monitor to use to display progress and receive
171 * requests for cancellation
174 public void run(IProgressMonitor progressMonitor
) {
175 int totalWork
= getNbCheckedElements(fImportTraceElements
) * 2;
176 progressMonitor
.beginTask(Messages
.TracePackageImportOperation_ImportingPackage
, totalWork
);
177 doRun(progressMonitor
);
178 progressMonitor
.done();
181 private void doRun(IProgressMonitor progressMonitor
) {
183 setStatus(deleteExistingTraces(progressMonitor
));
184 if (getStatus().getSeverity() != IStatus
.OK
) {
188 TracePackageFilesElement traceFilesElement
= null;
189 for (TracePackageElement packageElement
: fImportTraceElements
) {
190 TracePackageTraceElement traceElement
= (TracePackageTraceElement
) packageElement
;
191 if (!isFilesChecked(packageElement
)) {
195 TracePackageElement
[] children
= traceElement
.getChildren();
196 for (TracePackageElement element
: children
) {
197 ModalContext
.checkCanceled(progressMonitor
);
199 if (element
instanceof TracePackageFilesElement
) {
200 traceFilesElement
= (TracePackageFilesElement
) element
;
201 setStatus(importTraceFiles(traceFilesElement
, traceElement
, progressMonitor
));
203 } else if (element
instanceof TracePackageSupplFilesElement
) {
204 TracePackageSupplFilesElement suppFilesElement
= (TracePackageSupplFilesElement
) element
;
205 setStatus(importSupplFiles(suppFilesElement
, traceElement
, progressMonitor
));
208 if (getStatus().getSeverity() != IStatus
.OK
) {
214 } catch (InterruptedException e
) {
215 setStatus(Status
.CANCEL_STATUS
);
220 * Returns whether or not the Files element is checked under the given trace
223 * @param tracePackageElement
224 * the trace package element
225 * @return whether or not the Files element is checked under the given trace
228 public static boolean isFilesChecked(TracePackageElement tracePackageElement
) {
229 for (TracePackageElement element
: tracePackageElement
.getChildren()) {
230 if (element
instanceof TracePackageFilesElement
) {
231 return element
.isChecked();
239 * Return the matching TmfTraceElement for a given trace element.
241 private TmfTraceElement
getMatchingTraceElement(TracePackageTraceElement tracePackageElement
) {
242 IPath tracePath
= fTmfTraceFolder
.getPath().append(tracePackageElement
.getDestinationElementPath());
243 List
<TmfTraceElement
> traces
= fTmfTraceFolder
.getTraces();
244 for (TmfTraceElement t
: traces
) {
245 if (t
.getPath().equals(tracePath
)) {
253 private IStatus
deleteExistingTraces(IProgressMonitor progressMonitor
) {
254 for (TracePackageElement packageElement
: fImportTraceElements
) {
255 TracePackageTraceElement traceElement
= (TracePackageTraceElement
) packageElement
;
256 if (!isFilesChecked(traceElement
)) {
260 TmfTraceElement existingTrace
= getMatchingTraceElement(traceElement
);
261 if (existingTrace
!= null) {
263 existingTrace
.delete(new SubProgressMonitor(progressMonitor
, 1, SubProgressMonitor
.PREPEND_MAIN_LABEL_TO_SUBTASK
));
264 } catch (CoreException e
) {
265 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
);
270 return Status
.OK_STATUS
;
273 private void importBookmarks(IResource traceRes
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
274 for (TracePackageElement o
: traceElement
.getChildren()) {
275 if (o
instanceof TracePackageBookmarkElement
&& o
.isChecked()) {
278 IFile bookmarksFile
= null;
279 TmfTraceElement tmfTraceElement
= getMatchingTraceElement(traceElement
);
280 if (tmfTraceElement
!= null) {
282 bookmarksFile
= tmfTraceElement
.createBookmarksFile();
284 // Make sure that if a bookmark is double-clicked first
285 // before opening the trace, it opens the right editor
287 // Get the editor id from the extension point
288 String traceEditorId
= tmfTraceElement
.getEditorId();
289 final String editorId
= (traceEditorId
!= null) ? traceEditorId
: TmfEventsEditor
.ID
;
290 IDE
.setDefaultEditor(bookmarksFile
, editorId
);
292 } catch (CoreException e
) {
293 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmarkFile
, traceRes
.getName()), e
);
297 if (bookmarksFile
== null) {
301 TracePackageBookmarkElement bookmarkElement
= (TracePackageBookmarkElement
) o
;
303 List
<Map
<String
, String
>> bookmarks
= bookmarkElement
.getBookmarks();
304 for (Map
<String
, String
> attrs
: bookmarks
) {
305 IMarker createMarker
= null;
307 createMarker
= bookmarksFile
.createMarker(IMarker
.BOOKMARK
);
308 } catch (CoreException e
) {
309 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmark
, traceRes
.getName()), e
);
311 if (createMarker
!= null && createMarker
.exists()) {
313 for (String key
: attrs
.keySet()) {
314 String value
= attrs
.get(key
);
315 if (key
.equals(IMarker
.LOCATION
)) {
316 createMarker
.setAttribute(IMarker
.LOCATION
, Integer
.valueOf(value
).intValue());
318 createMarker
.setAttribute(key
, value
);
321 } catch (CoreException e
) {
322 Activator
.getDefault().logError(MessageFormat
.format(Messages
.TracePackageImportOperation_ErrorCreatingBookmark
, traceRes
.getName()), e
);
332 private IStatus
importTraceFiles(TracePackageFilesElement traceFilesElement
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
333 List
<Pair
<String
, String
>> fileNameAndLabelPairs
= new ArrayList
<>();
335 String sourceName
= traceFilesElement
.getFileName();
336 String destinationName
= traceElement
.getImportName();
338 fileNameAndLabelPairs
.add(new Pair
<>(sourceName
, destinationName
));
340 IPath containerPath
= fTmfTraceFolder
.getPath();
341 IStatus status
= importFiles(getSpecifiedArchiveFile(), fileNameAndLabelPairs
, containerPath
, Path
.EMPTY
, monitor
);
342 if (getStatus().getSeverity() != IStatus
.OK
) {
346 // We need to set the trace type before importing the supplementary files so we do it here
347 IResource traceRes
= fTmfTraceFolder
.getResource().findMember(traceElement
.getDestinationElementPath());
348 if (traceRes
== null || !traceRes
.exists()) {
349 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorFindingImportedTrace
, destinationName
));
352 TraceTypeHelper traceType
= null;
353 String traceTypeStr
= traceElement
.getTraceType();
354 if (traceTypeStr
!= null) {
355 traceType
= TmfTraceType
.getTraceType(traceTypeStr
);
356 if (traceType
== null) {
357 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorSettingTraceType
, traceElement
.getTraceType(), destinationName
));
361 monitor
.subTask(MessageFormat
.format(Messages
.TracePackageImportOperation_DetectingTraceType
, destinationName
));
362 traceType
= TmfTraceTypeUIUtils
.selectTraceType(traceRes
.getLocation().toOSString(), null, null);
363 } catch (TmfTraceImportException e
) {
364 // Could not figure out the type
368 if (traceType
!= null) {
370 TmfTraceTypeUIUtils
.setTraceType(traceRes
, traceType
);
371 } catch (CoreException e
) {
372 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, MessageFormat
.format(Messages
.ImportTracePackageWizardPage_ErrorSettingTraceType
, traceElement
.getTraceType(), destinationName
), e
);
376 importBookmarks(traceRes
, traceElement
, monitor
);
379 URI uri
= new File(getFileName()).toURI();
380 IPath entryPath
= new Path(traceFilesElement
.getFileName());
381 if (traceRes
instanceof IFolder
) {
382 entryPath
= entryPath
.addTrailingSeparator();
384 String sourceLocation
= URIUtil
.toUnencodedString(URIUtil
.toJarURI(uri
, entryPath
));
385 traceRes
.setPersistentProperty(TmfCommonConstants
.SOURCE_LOCATION
, sourceLocation
);
386 } catch (CoreException e
) {
392 private IStatus
importSupplFiles(TracePackageSupplFilesElement suppFilesElement
, TracePackageTraceElement traceElement
, IProgressMonitor monitor
) {
393 List
<Pair
<String
, String
>> fileNameAndLabelPairs
= new ArrayList
<>();
394 for (TracePackageElement child
: suppFilesElement
.getChildren()) {
395 TracePackageSupplFileElement supplFile
= (TracePackageSupplFileElement
) child
;
396 fileNameAndLabelPairs
.add(new Pair
<>(supplFile
.getText(), new Path(supplFile
.getText()).lastSegment()));
399 if (!fileNameAndLabelPairs
.isEmpty()) {
400 TmfTraceElement existingTrace
= getMatchingTraceElement(traceElement
);
401 if (existingTrace
!= null) {
402 ArchiveFile archiveFile
= getSpecifiedArchiveFile();
403 existingTrace
.refreshSupplementaryFolder();
404 // Project/Traces/A/B -> A/B
405 IPath traceFolderRelativePath
= fTmfTraceFolder
.getPath().makeRelativeTo(fTmfTraceFolder
.getProject().getTracesFolder().getPath());
406 // Project/.tracing/A/B/
407 IFolder traceSupplementaryFolder
= fTmfTraceFolder
.getTraceSupplementaryFolder(traceFolderRelativePath
.toString());
408 IPath destinationContainerPath
= traceSupplementaryFolder
.getFullPath();
409 // Remove the .tracing segment at the beginnin so that a file in folder .tracing/A/B/ imports destinationContainerPath/A/B/
410 Path baseSourcePath
= new Path(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER_NAME
);
411 return importFiles(archiveFile
, fileNameAndLabelPairs
, destinationContainerPath
, baseSourcePath
, monitor
);
415 return Status
.OK_STATUS
;
418 private IStatus
importFiles(ArchiveFile archiveFile
, List
<Pair
<String
, String
>> fileNameAndLabelPairs
, IPath destinationContainerPath
, IPath baseSourcePath
, IProgressMonitor monitor
) {
419 List
<ArchiveProviderElement
> objects
= new ArrayList
<>();
420 Enumeration
<?
> entries
= archiveFile
.entries();
421 while (entries
.hasMoreElements()) {
422 ArchiveEntry entry
= (ArchiveEntry
) entries
.nextElement();
423 String entryName
= entry
.getName();
424 IPath fullArchivePath
= new Path(entryName
);
425 if (fullArchivePath
.hasTrailingSeparator()) {
426 // We only care about file entries as the folders will get created by the ImportOperation
430 for (Pair
<String
, String
> fileNameAndLabel
: fileNameAndLabelPairs
) {
432 // Examples: Traces/aaa/kernel/ .tracing/aaa/testtexttrace.txt/statistics.ht
433 IPath searchedArchivePath
= new Path(fileNameAndLabel
.getFirst());
435 // Check if this archive entry matches the searched file name at this archive location
436 boolean fileMatch
= entryName
.equalsIgnoreCase(searchedArchivePath
.toString());
437 // For example Traces/aaa/kernel/metadata matches Traces/aaa/kernel/
438 boolean folderMatch
= entryName
.startsWith(searchedArchivePath
+ "/"); //$NON-NLS-1$
440 if (fileMatch
|| folderMatch
) {
441 // .tracing/aaa/testtexttrace.txt/statistics.ht -> aaa/testtexttrace.txt/statistics.ht
442 IPath destinationPath
= fullArchivePath
.makeRelativeTo(baseSourcePath
);
444 // metadata statistics.ht
445 // We don't use the label when the entry is a folder match because the labels for individual files
446 // under the folder are not specified in the manifest so just use the last segment.
447 String resourceLabel
= folderMatch ? fullArchivePath
.lastSegment() : fileNameAndLabel
.getSecond();
449 ArchiveProviderElement pe
= new ArchiveProviderElement(destinationPath
.toString(), resourceLabel
, archiveFile
, entry
);
456 ImportProvider provider
= new ImportProvider();
458 ImportOperation operation
= new ImportOperation(destinationContainerPath
,
459 null, provider
, this,
461 operation
.setCreateContainerStructure(true);
462 operation
.setOverwriteResources(true);
465 operation
.run(new SubProgressMonitor(monitor
, fileNameAndLabelPairs
.size(), SubProgressMonitor
.PREPEND_MAIN_LABEL_TO_SUBTASK
));
467 } catch (InvocationTargetException e
) {
468 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
);
469 } catch (InterruptedException e
) {
470 return Status
.CANCEL_STATUS
;
471 } catch (IOException e
) {
472 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
);
475 if (provider
.getException() != null) {
476 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, provider
.getException());
479 return operation
.getStatus();
483 public String
queryOverwrite(String pathString
) {
484 // We always overwrite once we reach this point