Remove all existing @since annotations
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / internal / tmf / ui / project / wizards / importtrace / BatchImportTraceWizard.java
1 /*******************************************************************************
2 * Copyright (c) 2013, 2014 Ericsson
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 * Matthew Khouzam - Initial API and implementation
11 * Marc-Andre Laperle - Log some exceptions
12 * Patrick Tasse - Add support for source location
13 *******************************************************************************/
14
15 package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
16
17 import java.io.File;
18 import java.io.FileInputStream;
19 import java.lang.reflect.InvocationTargetException;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.TreeSet;
30 import java.util.concurrent.BlockingQueue;
31
32 import org.eclipse.core.resources.IFile;
33 import org.eclipse.core.resources.IFolder;
34 import org.eclipse.core.resources.IResource;
35 import org.eclipse.core.resources.ResourcesPlugin;
36 import org.eclipse.core.runtime.CoreException;
37 import org.eclipse.core.runtime.IPath;
38 import org.eclipse.core.runtime.IProgressMonitor;
39 import org.eclipse.core.runtime.IStatus;
40 import org.eclipse.core.runtime.NullProgressMonitor;
41 import org.eclipse.core.runtime.Path;
42 import org.eclipse.core.runtime.Status;
43 import org.eclipse.core.runtime.SubMonitor;
44 import org.eclipse.core.runtime.URIUtil;
45 import org.eclipse.jface.dialogs.ErrorDialog;
46 import org.eclipse.jface.dialogs.IDialogSettings;
47 import org.eclipse.jface.operation.IRunnableWithProgress;
48 import org.eclipse.jface.viewers.IStructuredSelection;
49 import org.eclipse.jface.wizard.IWizardPage;
50 import org.eclipse.jface.wizard.WizardDialog;
51 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
52 import org.eclipse.tracecompass.internal.tmf.ui.project.model.TmfImportHelper;
53 import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
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.project.model.TraceValidationHelper;
57 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
58 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils;
59 import org.eclipse.ui.IWorkbench;
60 import org.eclipse.ui.dialogs.IOverwriteQuery;
61 import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider;
62 import org.eclipse.ui.wizards.datatransfer.ImportOperation;
63
64 /**
65 * Batch Import trace wizard.
66 *
67 * @author Matthew Khouzam
68 */
69 public class BatchImportTraceWizard extends ImportTraceWizard {
70
71 private static final int WIN_HEIGHT = 400;
72 private static final int WIN_WIDTH = 800;
73 private static final Status CANCEL_STATUS = new Status(IStatus.CANCEL, Activator.PLUGIN_ID, ""); //$NON-NLS-1$
74 private static final int TOTALWORK = 65536;
75 // -----------------
76 // Constants
77 // -----------------
78
79 private static final int MAX_FILES = TOTALWORK - 1;
80 private static final String BATCH_IMPORT_WIZARD = "BatchImportTraceWizard"; //$NON-NLS-1$
81
82 // ------------------
83 // Fields
84 // ------------------
85
86 private IWizardPage fSelectDirectoriesPage;
87 private ImportTraceWizardScanPage fScanPage;
88 private IWizardPage fSelectTypePage;
89 private IWizardPage fOptions;
90
91 private final List<String> fTraceTypesToScan = new ArrayList<>();
92 private final Set<String> fParentFilesToScan = new HashSet<>();
93
94 private ImportTraceContentProvider fScannedTraces = new ImportTraceContentProvider(fTraceTypesToScan, fParentFilesToScan);
95
96 private final Map<TraceValidationHelper, Boolean> fResults = new HashMap<>();
97 private boolean fOverwrite = true;
98 private boolean fLinked = true;
99
100 private BlockingQueue<TraceValidationHelper> fTracesToScan;
101 private final Set<FileAndName> fTraces = new TreeSet<>();
102
103 private Map<String, Set<String>> fParentFiles = new HashMap<>();
104
105 // Target import directory (trace folder)
106 private IFolder fTargetFolder;
107
108 /**
109 * Returns the ScannedTraces model
110 *
111 * @return the ScannedTraces model
112 */
113 public ImportTraceContentProvider getScannedTraces() {
114 return fScannedTraces;
115 }
116
117 /**
118 * Constructor
119 */
120 public BatchImportTraceWizard() {
121 IDialogSettings workbenchSettings = Activator.getDefault().getDialogSettings();
122 IDialogSettings section = workbenchSettings.getSection(BATCH_IMPORT_WIZARD);
123 if (section == null) {
124 section = workbenchSettings.addNewSection(BATCH_IMPORT_WIZARD);
125 }
126 setDialogSettings(section);
127 setNeedsProgressMonitor(true);
128 }
129
130 @Override
131 public void init(IWorkbench workbench, IStructuredSelection selection) {
132
133 fSelectDirectoriesPage = new ImportTraceWizardSelectDirectoriesPage(workbench, selection);
134 fScanPage = new ImportTraceWizardScanPage(workbench, selection);
135 fSelectTypePage = new ImportTraceWizardSelectTraceTypePage(workbench, selection);
136 fOptions = new ImportTraceWizardPageOptions(workbench, selection);
137 // keep in case it's called later
138 Iterator<?> iter = selection.iterator();
139 while (iter.hasNext()) {
140 Object selected = iter.next();
141 if (selected instanceof TmfTraceFolder) {
142 fTargetFolder = ((TmfTraceFolder) selected).getResource();
143 break;
144 }
145 }
146 fResults.clear();
147 }
148
149 @Override
150 public void addPages() {
151 addPage(fSelectTypePage);
152 addPage(fSelectDirectoriesPage);
153 addPage(fScanPage);
154 addPage(fOptions);
155 final WizardDialog container = (WizardDialog) getContainer();
156 if (container != null) {
157 container.setPageSize(WIN_WIDTH, WIN_HEIGHT);
158 }
159 }
160
161 /**
162 * Add a file to scan
163 *
164 * @param fileName
165 * the file to scan
166 */
167 public void addFileToScan(final String fileName) {
168 String absolutePath = new File(fileName).getAbsolutePath();
169 if (!fParentFiles.containsKey(absolutePath)) {
170 fParentFiles.put(absolutePath, new HashSet<String>());
171 startUpdateTask(Messages.BatchImportTraceWizardAdd + ' ' + absolutePath, absolutePath);
172
173 }
174
175 }
176
177 /**
178 * Remove files from selection
179 *
180 * @param fileName
181 * the name of the file to remove
182 */
183 public void removeFile(final String fileName) {
184 fParentFiles.remove(fileName);
185 fParentFilesToScan.remove(fileName);
186 startUpdateTask(Messages.BatchImportTraceWizardRemove + ' ' + fileName, null);
187 }
188
189 private void startUpdateTask(final String taskName, final String fileAbsolutePath) {
190 try {
191 this.getContainer().run(true, true, new IRunnableWithProgress() {
192
193 @Override
194 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
195 synchronized (BatchImportTraceWizard.this) { // this should
196 // only run one
197 // at a time
198 SubMonitor sm;
199 sm = SubMonitor.convert(monitor);
200 sm.setTaskName(taskName);
201 sm.setWorkRemaining(TOTALWORK);
202 updateFiles(sm, fileAbsolutePath);
203 sm.done();
204 }
205 }
206 });
207 } catch (InvocationTargetException e) {
208 Activator.getDefault().logError(Messages.ImportTraceWizardImportProblem, e);
209 } catch (InterruptedException e) {
210 }
211 }
212
213 /**
214 * The set of names of the selected files
215 *
216 * @return the set of names of the selected files
217 */
218 public Set<String> getFileNames() {
219 return fParentFilesToScan;
220 }
221
222 /**
223 * Reset the trace list to import
224 */
225 public void clearTraces() {
226 fTraces.clear();
227 }
228
229 @Override
230 public boolean performFinish() {
231 if (fTraces.isEmpty()) {
232 return false;
233 }
234 // if this turns out to be too slow, put in a progress monitor. Does not
235 // appear to be slow for the moment.
236 boolean success = importTraces();
237 return success;
238 }
239
240 private boolean importTraces() {
241 boolean success = false;
242 IOverwriteQuery overwriteQuery = new IOverwriteQuery() {
243 @Override
244 public String queryOverwrite(String file) {
245 return fOverwrite ? IOverwriteQuery.ALL : IOverwriteQuery.NO_ALL;
246 }
247 };
248 FileSystemStructureProvider fileSystemStructureProvider = FileSystemStructureProvider.INSTANCE;
249
250 for (FileAndName traceToImport : fTraces) {
251 try {
252 if (fLinked) {
253 if (TmfImportHelper.createLink(fTargetFolder, Path.fromOSString(traceToImport.getFile().getAbsolutePath()), traceToImport.getName()) == null) {
254 success = false;
255 }
256 else {
257 success = setTraceTypeAndSourceLocation(traceToImport).isOK();
258 }
259 }
260 else {
261 List<File> subList = new ArrayList<>();
262 IPath path = fTargetFolder.getFullPath();
263 File parentFile = traceToImport.getFile();
264 final boolean isFile = parentFile.isFile();
265 if (isFile) {
266 IFile resource = ResourcesPlugin.getWorkspace().getRoot().getFile(path.append(traceToImport.getName()));
267 if (fOverwrite || !resource.exists()) {
268 subList.add(parentFile);
269 parentFile = parentFile.getParentFile();
270 try (final FileInputStream source = new FileInputStream(traceToImport.getFile());) {
271 if (resource.exists()) {
272 resource.delete(IResource.FORCE, new NullProgressMonitor());
273 }
274 resource.create(source, true, new NullProgressMonitor());
275 }
276 setTraceTypeAndSourceLocation(traceToImport);
277 success = true;
278 }
279 } else {
280 path = path.addTrailingSeparator().append(traceToImport.getName());
281 // Add all files in trace directory
282 File[] fileList = traceToImport.getFile().listFiles();
283 for (File child : fileList) {
284 subList.add(child);
285 }
286
287 Collections.sort(subList, new Comparator<File>() {
288 @Override
289 public int compare(File o1, File o2) {
290 return o1.getAbsolutePath().compareTo(o2.getAbsolutePath());
291 }
292 });
293 ImportOperation operation = new ImportOperation(
294 path,
295 parentFile,
296 fileSystemStructureProvider,
297 overwriteQuery,
298 subList);
299 operation.setContext(getShell());
300 operation.setCreateContainerStructure(false);
301 if (executeImportOperation(operation)) {
302 setTraceTypeAndSourceLocation(traceToImport);
303 success = true;
304 }
305 }
306
307 }
308 } catch (Exception e) {
309 }
310 }
311 return success;
312 }
313
314 private IStatus setTraceTypeAndSourceLocation(FileAndName traceToImport) {
315 IStatus status = Status.OK_STATUS;
316 IResource resource = fTargetFolder.findMember(traceToImport.getName());
317 if (resource != null) {
318 try {
319 // Set the trace type for this resource
320 String traceTypeId = traceToImport.getTraceTypeId();
321 TraceTypeHelper traceType = TmfTraceType.getTraceType(traceTypeId);
322 if (traceType != null) {
323 status = TmfTraceTypeUIUtils.setTraceType(resource, traceType);
324 }
325
326 // Set the source location for this resource
327 File file = traceToImport.getFile();
328 String sourceLocation = null;
329 IResource sourceResource;
330 if (file.isDirectory()) {
331 sourceResource = ResourcesPlugin.getWorkspace().getRoot().getContainerForLocation(Path.fromOSString(file.getAbsolutePath()));
332 } else {
333 sourceResource = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(Path.fromOSString(file.getAbsolutePath()));
334 }
335 if (sourceResource != null && sourceResource.exists()) {
336 sourceLocation = sourceResource.getPersistentProperty(TmfCommonConstants.SOURCE_LOCATION);
337 }
338 if (sourceLocation == null) {
339 sourceLocation = URIUtil.toUnencodedString(file.toURI());
340 }
341 resource.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation);
342 } catch (CoreException e) {
343 Activator.getDefault().logError(Messages.BatchImportTraceWizardErrorImportingTraceResource
344 + ' ' + resource.getName(), e);
345 }
346 }
347 return status;
348 }
349
350 @Override
351 public boolean canFinish() {
352 return super.canFinish() && hasTracesToImport() && !hasConflicts() && (fTargetFolder != null);
353 }
354
355 /**
356 * Returns if a trace to import is selected
357 *
358 * @return if there are traces to import
359 */
360 public boolean hasTracesToImport() {
361 return fTraces.size() > 0;
362 }
363
364 /**
365 * Reset the files to scan
366 */
367 public void clearFilesToScan() {
368 fTracesToScan.clear();
369 }
370
371 /**
372 * Set the trace types to scan
373 *
374 * @param tracesToScan
375 * a list of trace types to scan for
376 */
377 public void setTraceTypesToScan(List<String> tracesToScan) {
378 // intersection to know if there's a diff.
379 // if there's a diff, we need to re-enque everything
380 List<String> added = new ArrayList<>();
381 for (String traceLoc : tracesToScan) {
382 if (!fTraceTypesToScan.contains(traceLoc)) {
383 added.add(traceLoc);
384 }
385 }
386 fTraceTypesToScan.clear();
387 fTraceTypesToScan.addAll(tracesToScan);
388 updateTracesToScan(added);
389 }
390
391 /**
392 * Get the trace types to scan
393 *
394 * @return a list of traces to Scan for
395 */
396 public List<String> getTraceTypesToScan() {
397 return fTraceTypesToScan;
398 }
399
400 /**
401 * Add files to Import
402 *
403 * @param element
404 * add the file and tracetype to import
405 */
406 public void addFileToImport(FileAndName element) {
407 fTraces.add(element);
408 updateConflicts();
409 }
410
411 /**
412 * Remove the file to scan
413 *
414 * @param element
415 * the element to remove
416 */
417 public void removeFileToImport(FileAndName element) {
418 fTraces.remove(element);
419 element.setConflictingName(false);
420 updateConflicts();
421 }
422
423 /**
424 * Updates the trace to see if there are conflicts.
425 */
426 public void updateConflicts() {
427 final FileAndName[] fChildren = fTraces.toArray(new FileAndName[0]);
428 for (int i = 0; i < fChildren.length; i++) {
429 fChildren[i].setConflictingName(false);
430 }
431 for (int i = 1; i < fChildren.length; i++) {
432 for (int j = 0; j < i; j++) {
433 if (fChildren[i].getName().equals(fChildren[j].getName())) {
434 fChildren[i].setConflictingName(true);
435 fChildren[j].setConflictingName(true);
436 }
437 }
438 }
439 getContainer().updateButtons();
440 }
441
442 /**
443 * Is there a name conflict
444 */
445 boolean hasConflicts() {
446 boolean conflict = false;
447 for (FileAndName child : fTraces) {
448 conflict |= child.isConflictingName();
449 }
450 return conflict;
451 }
452
453 private boolean executeImportOperation(ImportOperation op) {
454 initializeOperation(op);
455
456 try {
457 getContainer().run(true, true, op);
458 } catch (InterruptedException e) {
459 return false;
460 } catch (InvocationTargetException e) {
461 Activator.getDefault().logError(Messages.ImportTraceWizardImportProblem, e);
462 return false;
463 }
464
465 IStatus status = op.getStatus();
466 if (!status.isOK()) {
467 ErrorDialog.openError(getContainer().getShell(), Messages.ImportTraceWizardImportProblem, null, status);
468 return false;
469 }
470
471 return true;
472 }
473
474 private static void initializeOperation(ImportOperation op) {
475 op.setCreateContainerStructure(false);
476 op.setOverwriteResources(false);
477 op.setVirtualFolders(false);
478 }
479
480 /**
481 * Override existing resources
482 *
483 * @param selection
484 * true or false
485 */
486 public void setOverwrite(boolean selection) {
487 fOverwrite = selection;
488 }
489
490 /**
491 * Is the trace linked?
492 *
493 * @param isLink
494 * true or false
495 */
496 public void setLinked(boolean isLink) {
497 fLinked = isLink;
498 }
499
500 /**
501 * @param tracesToScan
502 * sets the common traces to scan
503 */
504 public void setTracesToScan(BlockingQueue<TraceValidationHelper> tracesToScan) {
505 fTracesToScan = tracesToScan;
506 }
507
508 /**
509 * @param traceToScan
510 * The trace to scan
511 * @return if the trace has been scanned yet or not
512 */
513 public boolean hasScanned(TraceValidationHelper traceToScan) {
514 return fResults.containsKey(traceToScan);
515 }
516
517 /**
518 * Add a result to a cache
519 *
520 * @param traceToScan
521 * The trace that has been scanned
522 * @param validate
523 * if the trace is valid
524 */
525 public void addResult(TraceValidationHelper traceToScan, boolean validate) {
526 fResults.put(traceToScan, validate);
527 }
528
529 /**
530 * Gets if the trace has been scanned or not
531 *
532 * @param traceToScan
533 * the scanned trace
534 * @return whether it passes or not
535 */
536 public boolean getResult(TraceValidationHelper traceToScan) {
537 return fResults.get(traceToScan);
538 }
539
540 /**
541 * Returns the amount of files scanned
542 *
543 * @return the amount of files scanned
544 */
545 public int getNumberOfResults() {
546 return fResults.size();
547 }
548
549 private void updateTracesToScan(final List<String> added) {
550 // Treeset is used instead of a hashset since the traces should be read
551 // in the order they were added.
552 final Set<String> filesToScan = new TreeSet<>();
553 for (String name : fParentFiles.keySet()) {
554 filesToScan.addAll(fParentFiles.get(name));
555 }
556 IProgressMonitor pm = new NullProgressMonitor();
557 try {
558 updateScanQueue(pm, filesToScan, added);
559 } catch (InterruptedException e) {
560 }
561
562 }
563
564 /*
565 * I am a job. Make me work
566 */
567 private synchronized IStatus updateFiles(IProgressMonitor monitor, String traceToScanAbsPath) {
568 final Set<String> filesToScan = new TreeSet<>();
569
570 int workToDo = 1;
571 for (String name : fParentFiles.keySet()) {
572
573 final File file = new File(name);
574 final File[] listFiles = file.listFiles();
575 if (listFiles != null) {
576 workToDo += listFiles.length;
577 }
578 }
579 int step = TOTALWORK / workToDo;
580 try {
581 for (String name : fParentFiles.keySet()) {
582 final File fileToAdd = new File(name);
583 final Set<String> parentFilesToScan = fParentFiles.get(fileToAdd.getAbsolutePath());
584 recurse(parentFilesToScan, fileToAdd, monitor, step);
585 if (monitor.isCanceled()) {
586 fParentFilesToScan.remove(traceToScanAbsPath);
587 fParentFiles.remove(traceToScanAbsPath);
588 return CANCEL_STATUS;
589 }
590 }
591 filesToScan.clear();
592 for (String name : fParentFiles.keySet()) {
593 filesToScan.addAll(fParentFiles.get(name));
594 fParentFilesToScan.add(name);
595 }
596 IStatus cancelled = updateScanQueue(monitor, filesToScan, fTraceTypesToScan);
597 if (cancelled.matches(IStatus.CANCEL)) {
598 fParentFilesToScan.remove(traceToScanAbsPath);
599 fParentFiles.remove(traceToScanAbsPath);
600 }
601 } catch (InterruptedException e) {
602 monitor.done();
603 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e);
604 }
605
606 monitor.done();
607 return Status.OK_STATUS;
608 }
609
610 private IStatus updateScanQueue(IProgressMonitor monitor, final Set<String> filesToScan, final List<String> traceTypes) throws InterruptedException {
611 for (String fileToScan : filesToScan) {
612 for (String traceCat : traceTypes) {
613 TraceValidationHelper tv = new TraceValidationHelper(fileToScan, traceCat);
614 // for thread safety, keep checks in this order.
615 if (!fResults.containsKey(tv)) {
616 if (!fTracesToScan.contains(tv)) {
617 fTracesToScan.put(tv);
618 monitor.subTask(tv.getTraceToScan());
619 if (monitor.isCanceled()) {
620 fScanPage.refresh();
621 return CANCEL_STATUS;
622 }
623 }
624 }
625 }
626 }
627 fScanPage.refresh();
628 return Status.OK_STATUS;
629 }
630
631 private IStatus recurse(Set<String> filesToScan, File fileToAdd, IProgressMonitor monitor, int step) {
632 final String absolutePath = fileToAdd.getAbsolutePath();
633 if (!filesToScan.contains(absolutePath) && (filesToScan.size() < MAX_FILES)) {
634 filesToScan.add(absolutePath);
635 final File[] listFiles = fileToAdd.listFiles();
636 if (null != listFiles) {
637 for (File child : listFiles) {
638 monitor.subTask(child.getName());
639 if (monitor.isCanceled()) {
640 return CANCEL_STATUS;
641 }
642 IStatus retVal = recurse(filesToScan, child, monitor);
643 if (retVal.matches(IStatus.CANCEL)) {
644 return retVal;
645 }
646 monitor.worked(step);
647 }
648 }
649 }
650 return Status.OK_STATUS;
651 }
652
653 private IStatus recurse(Set<String> filesToScan, File fileToAdd, IProgressMonitor monitor) {
654 final String absolutePath = fileToAdd.getAbsolutePath();
655 if (!filesToScan.contains(absolutePath) && (filesToScan.size() < MAX_FILES)) {
656 filesToScan.add(absolutePath);
657 final File[] listFiles = fileToAdd.listFiles();
658 if (null != listFiles) {
659 for (File child : listFiles) {
660 if (monitor.isCanceled()) {
661 return CANCEL_STATUS;
662 }
663 IStatus retVal = recurse(filesToScan, child, monitor);
664 if (retVal.matches(IStatus.CANCEL)) {
665 return retVal;
666 }
667 }
668 }
669 }
670 return Status.OK_STATUS;
671 }
672
673 /**
674 * Gets the folder in the resource (project)
675 *
676 * @param targetFolder
677 * the folder to import to
678 */
679 public void setTraceFolder(IFolder targetFolder) {
680 fTargetFolder = targetFolder;
681 if (this.getContainer() != null && this.getContainer().getCurrentPage() != null) {
682 this.getContainer().updateButtons();
683 }
684 }
685
686 /**
687 * Gets the target folder
688 *
689 * @return the target folder
690 */
691 public IFolder getTargetFolder() {
692 return fTargetFolder;
693 }
694
695 }
This page took 0.113058 seconds and 5 git commands to generate.