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 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.importexport
;
15 import java
.io
.ByteArrayInputStream
;
16 import java
.io
.StringWriter
;
17 import java
.lang
.reflect
.InvocationTargetException
;
18 import java
.lang
.reflect
.Method
;
19 import java
.util
.ArrayList
;
20 import java
.util
.HashSet
;
23 import javax
.xml
.parsers
.DocumentBuilderFactory
;
24 import javax
.xml
.transform
.OutputKeys
;
25 import javax
.xml
.transform
.Transformer
;
26 import javax
.xml
.transform
.TransformerFactory
;
27 import javax
.xml
.transform
.dom
.DOMSource
;
28 import javax
.xml
.transform
.stream
.StreamResult
;
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
.Status
;
39 import org
.eclipse
.core
.runtime
.SubMonitor
;
40 import org
.eclipse
.jface
.operation
.ModalContext
;
41 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
42 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.AbstractTracePackageOperation
;
43 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.ITracePackageConstants
;
44 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageBookmarkElement
;
45 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageElement
;
46 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageFilesElement
;
47 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageSupplFileElement
;
48 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageSupplFilesElement
;
49 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageTraceElement
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
51 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceElement
;
52 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TraceUtils
;
53 import org
.eclipse
.ui
.internal
.wizards
.datatransfer
.ArchiveFileExportOperation
;
54 import org
.w3c
.dom
.Document
;
55 import org
.w3c
.dom
.Element
;
56 import org
.w3c
.dom
.Node
;
59 * An operation that exports a trace package to an archive
61 * @author Marc-Andre Laperle
63 @SuppressWarnings("restriction")
64 public class TracePackageExportOperation
extends AbstractTracePackageOperation
{
66 private static final String TRACE_EXPORT_TEMP_FOLDER
= ".traceExport"; //$NON-NLS-1$
68 private final TracePackageTraceElement
[] fTraceExportElements
;
69 private final boolean fUseCompression
;
70 private final boolean fUseTar
;
71 private final Set
<IResource
> fResources
;
72 private IFolder fExportFolder
;
75 * Constructs a new export operation
77 * @param traceExportElements
78 * the trace elements to be exported
79 * @param useCompression
80 * whether or not to use compression
82 * use tar format or zip
84 * the output file name
86 public TracePackageExportOperation(TracePackageTraceElement
[] traceExportElements
, boolean useCompression
, boolean useTar
, String fileName
) {
88 fTraceExportElements
= traceExportElements
;
89 fUseCompression
= useCompression
;
91 fResources
= new HashSet
<>();
95 * Run the operation. The status (result) of the operation can be obtained
96 * with {@link #getStatus}
98 * @param progressMonitor
99 * the progress monitor to use to display progress and receive
100 * requests for cancellation
103 public void run(IProgressMonitor progressMonitor
) {
106 int totalWork
= getNbCheckedElements(fTraceExportElements
) * 2;
107 progressMonitor
.beginTask(Messages
.TracePackageExportOperation_GeneratingPackage
, totalWork
);
109 fExportFolder
= createExportFolder(progressMonitor
);
111 Document doc
= DocumentBuilderFactory
.newInstance().newDocumentBuilder().newDocument();
112 Element createElement
= doc
.createElement(ITracePackageConstants
.TMF_EXPORT_ELEMENT
);
113 Node tmfNode
= doc
.appendChild(createElement
);
115 for (TracePackageTraceElement tracePackageElement
: fTraceExportElements
) {
116 if (!isFilesChecked(tracePackageElement
)) {
120 exportTrace(progressMonitor
, tmfNode
, tracePackageElement
);
123 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
124 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
125 transformer
.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); //$NON-NLS-1$ //$NON-NLS-2$
126 DOMSource source
= new DOMSource(doc
);
127 StringWriter buffer
= new StringWriter();
128 StreamResult result
= new StreamResult(buffer
);
129 transformer
.transform(source
, result
);
130 String content
= buffer
.getBuffer().toString();
132 ModalContext
.checkCanceled(progressMonitor
);
134 exportManifest(content
);
136 setStatus(exportToArchive(progressMonitor
, totalWork
));
138 fExportFolder
.delete(true, SubMonitor
.convert(progressMonitor
));
140 progressMonitor
.done();
142 } catch (InterruptedException e
) {
143 setStatus(Status
.CANCEL_STATUS
);
144 } catch (Exception e
) {
145 setStatus(new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.Messages
.TracePackage_ErrorOperation
, e
));
149 private IFolder
createExportFolder(IProgressMonitor monitor
) throws CoreException
{
150 IFolder folder
= fTraceExportElements
[0].getTraceElement().getProject().getResource().getFolder(TRACE_EXPORT_TEMP_FOLDER
);
151 if (folder
.exists()) {
152 folder
.delete(true, null);
154 folder
.create(IResource
.FORCE
| IResource
.HIDDEN
, true, SubMonitor
.convert(monitor
));
158 private void exportTrace(IProgressMonitor monitor
, Node tmfNode
, TracePackageTraceElement tracePackageElement
) throws InterruptedException
, CoreException
{
159 TmfTraceElement traceElement
= tracePackageElement
.getTraceElement();
160 Element traceXmlElement
= tmfNode
.getOwnerDocument().createElement(ITracePackageConstants
.TRACE_ELEMENT
);
161 traceXmlElement
.setAttribute(ITracePackageConstants
.TRACE_NAME_ATTRIB
, traceElement
.getResource().getName());
162 traceXmlElement
.setAttribute(ITracePackageConstants
.TRACE_TYPE_ATTRIB
, traceElement
.getTraceType());
163 Node traceNode
= tmfNode
.appendChild(traceXmlElement
);
165 for (TracePackageElement element
: tracePackageElement
.getChildren()) {
166 ModalContext
.checkCanceled(monitor
);
167 if (!element
.isChecked()) {
171 if (element
instanceof TracePackageSupplFilesElement
) {
172 exportSupplementaryFiles(monitor
, traceNode
, traceElement
, (TracePackageSupplFilesElement
) element
);
173 } else if (element
instanceof TracePackageBookmarkElement
) {
174 exportBookmarks(monitor
, traceNode
, (TracePackageBookmarkElement
) element
);
175 } else if (element
instanceof TracePackageFilesElement
) {
176 exportTraceFiles(monitor
, traceNode
, (TracePackageFilesElement
) element
);
183 private void exportSupplementaryFiles(IProgressMonitor monitor
, Node traceNode
, TmfTraceElement traceElement
, TracePackageSupplFilesElement element
) throws InterruptedException
, CoreException
{
184 Document doc
= traceNode
.getOwnerDocument();
185 if (element
.getChildren().length
> 0) {
187 IPath projectPath
= traceElement
.getProject().getPath();
189 for (TracePackageElement child
: element
.getChildren()) {
190 TracePackageSupplFileElement supplFile
= (TracePackageSupplFileElement
) child
;
191 ModalContext
.checkCanceled(monitor
);
192 IResource res
= supplFile
.getResource();
193 // project/.tracing/A/B/statistics.ht -> .tracing/A/B/statistics.ht
194 IPath relativeToExportFolder
= res
.getFullPath().makeRelativeTo(projectPath
);
196 // project/.traceExport/.tracing/A/B
197 IFolder folder
= fExportFolder
.getFolder(relativeToExportFolder
.removeLastSegments(1));
198 TraceUtils
.createFolder(folder
, SubMonitor
.convert(monitor
));
200 res
.refreshLocal(0, SubMonitor
.convert(monitor
));
201 createExportResource(folder
, res
);
202 Element suppFileElement
= doc
.createElement(ITracePackageConstants
.SUPPLEMENTARY_FILE_ELEMENT
);
204 suppFileElement
.setAttribute(ITracePackageConstants
.SUPPLEMENTARY_FILE_NAME_ATTRIB
, relativeToExportFolder
.toString());
205 traceNode
.appendChild(suppFileElement
);
208 IFolder suppFilesFolder
= fExportFolder
.getFolder(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER_NAME
);
209 fResources
.add(suppFilesFolder
);
213 private void exportTraceFiles(IProgressMonitor monitor
, Node traceNode
, TracePackageFilesElement element
) throws CoreException
{
214 Document doc
= traceNode
.getOwnerDocument();
215 TmfTraceElement traceElement
= ((TracePackageTraceElement
) element
.getParent()).getTraceElement();
216 IResource resource
= traceElement
.getResource();
217 IPath traceFolderPath
= traceElement
.getProject().getTracesFolder().getPath();
219 // project/Traces/A/B/Kernel -> A/B/Kernel
220 IPath relativeToExportFolder
= resource
.getFullPath().makeRelativeTo(traceFolderPath
);
222 // project/.traceExport/A/B
223 IFolder folder
= fExportFolder
.getFolder(relativeToExportFolder
.removeLastSegments(1));
224 TraceUtils
.createFolder(folder
, SubMonitor
.convert(monitor
));
226 createExportResource(folder
, resource
);
227 Element fileElement
= doc
.createElement(ITracePackageConstants
.TRACE_FILE_ELEMENT
);
229 fileElement
.setAttribute(ITracePackageConstants
.TRACE_FILE_NAME_ATTRIB
, relativeToExportFolder
.toString());
230 traceNode
.appendChild(fileElement
);
232 // Always export the top-most folder containing the trace or the trace itself
233 IResource exportedResource
= fExportFolder
.findMember(relativeToExportFolder
.segment(0));
234 fResources
.add(exportedResource
);
238 * Creates a linked resource in the specified folder
240 * @param exportFolder the folder that will contain the linked resource
241 * @param res the resource to export
242 * @throws CoreException when createLink fails
243 * @return the created linked resource
245 private static IResource
createExportResource(IFolder exportFolder
, IResource res
) throws CoreException
{
246 IResource ret
= null;
247 // Note: The resources cannot be HIDDEN or else they are ignored by ArchiveFileExportOperation
248 if (res
instanceof IFolder
) {
249 IFolder folder
= exportFolder
.getFolder(res
.getName());
250 folder
.createLink(res
.getLocationURI(), IResource
.NONE
, null);
252 } else if (res
instanceof IFile
) {
253 IFile file
= exportFolder
.getFile(res
.getName());
254 file
.createLink(res
.getLocationURI(), IResource
.NONE
, null);
260 private static void exportBookmarks(IProgressMonitor monitor
, Node traceNode
, TracePackageBookmarkElement element
) throws CoreException
, InterruptedException
{
261 Document doc
= traceNode
.getOwnerDocument();
262 IFile bookmarksFile
= ((TracePackageTraceElement
) element
.getParent()).getTraceElement().getBookmarksFile();
263 if (bookmarksFile
!= null && bookmarksFile
.exists()) {
264 IMarker
[] findMarkers
= bookmarksFile
.findMarkers(IMarker
.BOOKMARK
, false, IResource
.DEPTH_ZERO
);
265 if (findMarkers
.length
> 0) {
266 Element bookmarksXmlElement
= doc
.createElement(ITracePackageConstants
.BOOKMARKS_ELEMENT
);
267 Node bookmarksNode
= traceNode
.appendChild(bookmarksXmlElement
);
269 for (IMarker marker
: findMarkers
) {
270 ModalContext
.checkCanceled(monitor
);
272 Element singleBookmarkXmlElement
= doc
.createElement(ITracePackageConstants
.BOOKMARK_ELEMENT
);
273 for (String key
: marker
.getAttributes().keySet()) {
274 singleBookmarkXmlElement
.setAttribute(key
, marker
.getAttribute(key
).toString());
277 bookmarksNode
.appendChild(singleBookmarkXmlElement
);
283 private void exportManifest(String content
) throws CoreException
{
284 IFile file
= fExportFolder
.getFile(ITracePackageConstants
.MANIFEST_FILENAME
);
285 ByteArrayInputStream inputStream
= new ByteArrayInputStream(content
.getBytes());
287 file
.setContents(inputStream
, IResource
.FORCE
, null);
289 file
.create(inputStream
, IResource
.FORCE
| IResource
.HIDDEN
, null);
291 fResources
.add(file
);
294 private IStatus
exportToArchive(IProgressMonitor monitor
, int totalWork
) throws InvocationTargetException
, InterruptedException
{
295 ArchiveFileExportOperation op
= new ArchiveFileExportOperation(new ArrayList
<>(fResources
), getFileName());
296 op
.setCreateLeadupStructure(false);
297 //FIXME: Remove use of reflection when support for Eclipse 4.5 is dropped
299 Method method
= op
.getClass().getMethod("setIncludeLinkedResources", boolean.class); //$NON-NLS-1$
300 method
.invoke(op
, true);
301 } catch (NoSuchMethodException
| SecurityException
| IllegalAccessException
| IllegalArgumentException e
) {
302 // Ignored, setIncludeLinkedResources doesn't exist in Eclipse < 4.6
304 op
.setUseCompression(fUseCompression
);
305 op
.setUseTarFormat(fUseTar
);
306 op
.run(SubMonitor
.convert(monitor
).newChild(totalWork
/ 2));
308 return op
.getStatus();