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