1 /*******************************************************************************
2 * Copyright (c) 2013 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 * Matthew Khouzam - Initial API and implementation
11 * Marc-Andre Laperle - Log some exceptions
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.ui
.project
.wizards
.importtrace
;
17 import java
.io
.FileInputStream
;
18 import java
.lang
.reflect
.InvocationTargetException
;
19 import java
.util
.ArrayList
;
20 import java
.util
.Collections
;
21 import java
.util
.Comparator
;
22 import java
.util
.HashMap
;
23 import java
.util
.HashSet
;
24 import java
.util
.Iterator
;
25 import java
.util
.List
;
28 import java
.util
.TreeSet
;
29 import java
.util
.concurrent
.BlockingQueue
;
31 import org
.eclipse
.core
.resources
.IFile
;
32 import org
.eclipse
.core
.resources
.IFolder
;
33 import org
.eclipse
.core
.resources
.IResource
;
34 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
35 import org
.eclipse
.core
.runtime
.CoreException
;
36 import org
.eclipse
.core
.runtime
.IPath
;
37 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
38 import org
.eclipse
.core
.runtime
.IStatus
;
39 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
40 import org
.eclipse
.core
.runtime
.Path
;
41 import org
.eclipse
.core
.runtime
.Status
;
42 import org
.eclipse
.core
.runtime
.SubMonitor
;
43 import org
.eclipse
.jface
.dialogs
.ErrorDialog
;
44 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
45 import org
.eclipse
.jface
.operation
.IRunnableWithProgress
;
46 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
47 import org
.eclipse
.jface
.wizard
.IWizardPage
;
48 import org
.eclipse
.jface
.wizard
.Wizard
;
49 import org
.eclipse
.jface
.wizard
.WizardDialog
;
50 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
51 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.model
.TmfImportHelper
;
52 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceType
;
53 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TraceTypeHelper
;
54 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TraceValidationHelper
;
55 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
56 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfProjectElement
;
57 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfProjectRegistry
;
58 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceElement
;
59 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceFolder
;
60 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceTypeUIUtils
;
61 import org
.eclipse
.ui
.IImportWizard
;
62 import org
.eclipse
.ui
.IWorkbench
;
63 import org
.eclipse
.ui
.dialogs
.IOverwriteQuery
;
64 import org
.eclipse
.ui
.wizards
.datatransfer
.FileSystemStructureProvider
;
65 import org
.eclipse
.ui
.wizards
.datatransfer
.ImportOperation
;
68 * Batch Import trace wizard.
70 * @author Matthew Khouzam
73 public class BatchImportTraceWizard
extends Wizard
implements IImportWizard
{
75 private static final int WIN_HEIGHT
= 400;
76 private static final int WIN_WIDTH
= 800;
77 private static final Status CANCEL_STATUS
= new Status(IStatus
.CANCEL
, Activator
.PLUGIN_ID
, ""); //$NON-NLS-1$
78 private static final int TOTALWORK
= 65536;
83 private static final int MAX_FILES
= TOTALWORK
- 1;
84 private static final String BATCH_IMPORT_WIZARD
= "BatchImportTraceWizard"; //$NON-NLS-1$
90 private IWizardPage fSelectDirectoriesPage
;
91 private ImportTraceWizardScanPage fScanPage
;
92 private IWizardPage fSelectTypePage
;
93 private IWizardPage fOptions
;
95 private final List
<String
> fTraceTypesToScan
= new ArrayList
<>();
96 private final Set
<String
> fParentFilesToScan
= new HashSet
<>();
98 private ImportTraceContentProvider fScannedTraces
= new ImportTraceContentProvider(fTraceTypesToScan
, fParentFilesToScan
);
100 private final Map
<TraceValidationHelper
, Boolean
> fResults
= new HashMap
<>();
101 private boolean fOverwrite
= true;
102 private boolean fLinked
= true;
104 private BlockingQueue
<TraceValidationHelper
> fTracesToScan
;
105 private final Set
<FileAndName
> fTraces
= new TreeSet
<>();
107 private Map
<String
, Set
<String
>> fParentFiles
= new HashMap
<>();
109 // Target import directory ('Traces' folder)
110 private IFolder fTargetFolder
;
113 * Returns the ScannedTraces model
115 * @return the ScannedTraces model
117 public ImportTraceContentProvider
getScannedTraces() {
118 return fScannedTraces
;
124 public BatchImportTraceWizard() {
125 IDialogSettings workbenchSettings
= Activator
.getDefault().getDialogSettings();
126 IDialogSettings section
= workbenchSettings
.getSection(BATCH_IMPORT_WIZARD
);
127 if (section
== null) {
128 section
= workbenchSettings
.addNewSection(BATCH_IMPORT_WIZARD
);
130 setDialogSettings(section
);
131 setNeedsProgressMonitor(true);
135 public void init(IWorkbench workbench
, IStructuredSelection selection
) {
137 fSelectDirectoriesPage
= new ImportTraceWizardSelectDirectoriesPage(workbench
, selection
);
138 fScanPage
= new ImportTraceWizardScanPage(workbench
, selection
);
139 fSelectTypePage
= new ImportTraceWizardSelectTraceTypePage(workbench
, selection
);
140 fOptions
= new ImportTraceWizardPageOptions(workbench
, selection
);
141 // keep in case it's called later
142 Iterator
<?
> iter
= selection
.iterator();
143 while (iter
.hasNext()) {
144 Object selected
= iter
.next();
145 if (selected
instanceof TmfTraceFolder
) {
146 fTargetFolder
= ((TmfTraceFolder
) selected
).getResource();
154 public void addPages() {
155 addPage(fSelectTypePage
);
156 addPage(fSelectDirectoriesPage
);
159 final WizardDialog container
= (WizardDialog
) getContainer();
160 if (container
!= null) {
161 container
.setPageSize(WIN_WIDTH
, WIN_HEIGHT
);
171 public void addFileToScan(final String fileName
) {
172 String absolutePath
= new File(fileName
).getAbsolutePath();
173 if (!fParentFiles
.containsKey(absolutePath
)) {
174 fParentFiles
.put(absolutePath
, new HashSet
<String
>());
175 startUpdateTask(Messages
.BatchImportTraceWizardAdd
+ ' ' + absolutePath
, absolutePath
);
182 * Remove files from selection
185 * the name of the file to remove
187 public void removeFile(final String fileName
) {
188 fParentFiles
.remove(fileName
);
189 fParentFilesToScan
.remove(fileName
);
190 startUpdateTask(Messages
.BatchImportTraceWizardRemove
+ ' ' + fileName
, null);
193 private void startUpdateTask(final String taskName
, final String fileAbsolutePath
) {
195 this.getContainer().run(true, true, new IRunnableWithProgress() {
198 public void run(IProgressMonitor monitor
) throws InvocationTargetException
, InterruptedException
{
199 synchronized (BatchImportTraceWizard
.this) { // this should
203 sm
= SubMonitor
.convert(monitor
);
204 sm
.setTaskName(taskName
);
205 sm
.setWorkRemaining(TOTALWORK
);
206 updateFiles(sm
, fileAbsolutePath
);
211 } catch (InvocationTargetException e
) {
212 Activator
.getDefault().logError(Messages
.ImportTraceWizardImportProblem
, e
);
213 } catch (InterruptedException e
) {
218 * The set of names of the selected files
220 * @return the set of names of the selected files
222 public Set
<String
> getFileNames() {
223 return fParentFilesToScan
;
227 * Reset the trace list to import
229 public void clearTraces() {
234 public boolean performFinish() {
235 if (fTraces
.isEmpty()) {
238 // if this turns out to be too slow, put in a progress monitor. Does not
239 // appear to be slow for the moment.
240 boolean success
= importTraces();
244 private boolean importTraces() {
245 boolean success
= false;
246 IOverwriteQuery overwriteQuery
= new IOverwriteQuery() {
248 public String
queryOverwrite(String file
) {
249 return fOverwrite ? IOverwriteQuery
.ALL
: IOverwriteQuery
.NO_ALL
;
252 FileSystemStructureProvider fileSystemStructureProvider
= FileSystemStructureProvider
.INSTANCE
;
254 for (FileAndName traceToImport
: fTraces
) {
257 if (TmfImportHelper
.createLink(fTargetFolder
, Path
.fromOSString(traceToImport
.getFile().getAbsolutePath()), traceToImport
.getName()) == null) {
261 success
= setTraceType(traceToImport
).isOK();
265 List
<File
> subList
= new ArrayList
<>();
266 IPath path
= fTargetFolder
.getFullPath();
267 File parentFile
= traceToImport
.getFile();
268 final boolean isFile
= parentFile
.isFile();
270 IFile resource
= ResourcesPlugin
.getWorkspace().getRoot().getFile(path
.append(traceToImport
.getName()));
271 if (fOverwrite
|| !resource
.exists()) {
272 subList
.add(parentFile
);
273 parentFile
= parentFile
.getParentFile();
274 try (final FileInputStream source
= new FileInputStream(traceToImport
.getFile());) {
275 if (resource
.exists()) {
276 resource
.delete(IResource
.FORCE
, new NullProgressMonitor());
278 resource
.create(source
, true, new NullProgressMonitor());
280 setTraceType(traceToImport
);
284 // Add trace directory
285 subList
.add(traceToImport
.getFile());
286 // Add all files in trace directory
287 File
[] fileList
= traceToImport
.getFile().listFiles();
288 for (File child
: fileList
) {
292 Collections
.sort(subList
, new Comparator
<File
>() {
294 public int compare(File o1
, File o2
) {
295 return o1
.getAbsolutePath().compareTo(o2
.getAbsolutePath());
298 ImportOperation operation
= new ImportOperation(
300 parentFile
.getParentFile(),
301 fileSystemStructureProvider
,
304 operation
.setContext(getShell());
305 operation
.setCreateContainerStructure(false);
306 if (executeImportOperation(operation
)) {
307 setTraceType(traceToImport
);
313 } catch (Exception e
) {
319 private IStatus
setTraceType(FileAndName traceToImport
) {
320 IStatus validate
= Status
.OK_STATUS
;
321 IPath path
= fTargetFolder
.getFullPath().append(traceToImport
.getName());
322 IResource resource
= ResourcesPlugin
.getWorkspace().getRoot().findMember(path
);
323 if (resource
!= null) {
325 // Set the trace type for this resource
326 String traceTypeId
= traceToImport
.getTraceTypeId();
327 TraceTypeHelper traceType
= TmfTraceType
.getInstance().getTraceType(traceTypeId
);
328 if (traceType
!= null) {
329 TmfTraceTypeUIUtils
.setTraceType(path
, traceType
);
332 TmfProjectElement tmfProject
=
333 TmfProjectRegistry
.getProject(resource
.getProject());
334 if (tmfProject
!= null) {
335 final TmfTraceFolder tracesFolder
= tmfProject
.getTracesFolder();
337 List
<TmfTraceElement
> traces
= tracesFolder
.getTraces();
338 boolean found
= false;
339 for (TmfTraceElement traceElement
: traces
) {
340 if (traceElement
.getName().equals(resource
.getName())) {
341 traceElement
.refreshTraceType();
347 TmfTraceElement te
= new TmfTraceElement(traceToImport
.getName(), resource
, tracesFolder
);
348 te
.refreshTraceType();
349 traces
= tracesFolder
.getTraces();
350 for (TmfTraceElement traceElement
: traces
) {
351 if (traceElement
.getName().equals(resource
.getName())) {
352 traceElement
.refreshTraceType();
353 ITmfTrace tmfTrace
= null;
355 tmfTrace
= traceElement
.instantiateTrace();
356 if (tmfTrace
!= null) {
357 validate
= tmfTrace
.validate(tmfProject
.getResource(), traceElement
.getLocation().getPath());
359 return new Status(IStatus
.ERROR
, traceElement
.getName(), "File does not exist : " + traceElement
.getLocation().getPath()); //$NON-NLS-1$
362 if (tmfTrace
!= null) {
373 } catch (CoreException e
) {
374 Activator
.getDefault().logError(Messages
.BatchImportTraceWizardErrorImportingTraceResource
375 + ' ' + resource
.getName(), e
);
382 public boolean canFinish() {
383 return super.canFinish() && hasTracesToImport() && !hasConflicts() && (fTargetFolder
!= null);
387 * Returns if a trace to import is selected
389 * @return if there are traces to import
391 public boolean hasTracesToImport() {
392 return fTraces
.size() > 0;
396 * Reset the files to scan
398 public void clearFilesToScan() {
399 fTracesToScan
.clear();
403 * Set the trace types to scan
405 * @param tracesToScan
406 * a list of trace types to scan for
408 public void setTraceTypesToScan(List
<String
> tracesToScan
) {
409 // intersection to know if there's a diff.
410 // if there's a diff, we need to re-enque everything
411 List
<String
> added
= new ArrayList
<>();
412 for (String traceLoc
: tracesToScan
) {
413 if (!fTraceTypesToScan
.contains(traceLoc
)) {
417 fTraceTypesToScan
.clear();
418 fTraceTypesToScan
.addAll(tracesToScan
);
419 updateTracesToScan(added
);
423 * Get the trace types to scan
425 * @return a list of traces to Scan for
427 public List
<String
> getTraceTypesToScan() {
428 return fTraceTypesToScan
;
432 * Add files to Import
435 * add the file and tracetype to import
437 public void addFileToImport(FileAndName element
) {
438 fTraces
.add(element
);
443 * Remove the file to scan
446 * the element to remove
448 public void removeFileToImport(FileAndName element
) {
449 fTraces
.remove(element
);
450 element
.setConflictingName(false);
455 * Updates the trace to see if there are conflicts.
457 public void updateConflicts() {
458 final FileAndName
[] fChildren
= fTraces
.toArray(new FileAndName
[0]);
459 for (int i
= 0; i
< fChildren
.length
; i
++) {
460 fChildren
[i
].setConflictingName(false);
462 for (int i
= 1; i
< fChildren
.length
; i
++) {
463 for (int j
= 0; j
< i
; j
++) {
464 if (fChildren
[i
].getName().equals(fChildren
[j
].getName())) {
465 fChildren
[i
].setConflictingName(true);
466 fChildren
[j
].setConflictingName(true);
470 getContainer().updateButtons();
474 * Is there a name conflict
476 boolean hasConflicts() {
477 boolean conflict
= false;
478 for (FileAndName child
: fTraces
) {
479 conflict
|= child
.isConflictingName();
484 private boolean executeImportOperation(ImportOperation op
) {
485 initializeOperation(op
);
488 getContainer().run(true, true, op
);
489 } catch (InterruptedException e
) {
491 } catch (InvocationTargetException e
) {
492 Activator
.getDefault().logError(Messages
.ImportTraceWizardImportProblem
, e
);
496 IStatus status
= op
.getStatus();
497 if (!status
.isOK()) {
498 ErrorDialog
.openError(getContainer().getShell(), Messages
.ImportTraceWizardImportProblem
, null, status
);
505 private static void initializeOperation(ImportOperation op
) {
506 op
.setCreateContainerStructure(false);
507 op
.setOverwriteResources(false);
508 op
.setVirtualFolders(false);
512 * Override existing resources
517 public void setOverwrite(boolean selection
) {
518 fOverwrite
= selection
;
522 * Is the trace linked?
527 public void setLinked(boolean isLink
) {
532 * @param tracesToScan
533 * sets the common traces to scan
535 public void setTracesToScan(BlockingQueue
<TraceValidationHelper
> tracesToScan
) {
536 fTracesToScan
= tracesToScan
;
542 * @return if the trace has been scanned yet or not
545 public boolean hasScanned(TraceValidationHelper traceToScan
) {
546 return fResults
.containsKey(traceToScan
);
550 * Add a result to a cache
553 * The trace that has been scanned
555 * if the trace is valid
558 public void addResult(TraceValidationHelper traceToScan
, boolean validate
) {
559 fResults
.put(traceToScan
, validate
);
563 * Gets if the trace has been scanned or not
567 * @return whether it passes or not
570 public Boolean
getResult(TraceValidationHelper traceToScan
) {
571 return fResults
.get(traceToScan
);
575 * Returns the amount of files scanned
577 * @return the amount of files scanned
579 public int getNumberOfResults() {
580 return fResults
.size();
583 private void updateTracesToScan(final List
<String
> added
) {
584 // Treeset is used instead of a hashset since the traces should be read
585 // in the order they were added.
586 final Set
<String
> filesToScan
= new TreeSet
<>();
587 for (String name
: fParentFiles
.keySet()) {
588 filesToScan
.addAll(fParentFiles
.get(name
));
590 IProgressMonitor pm
= new NullProgressMonitor();
592 updateScanQueue(pm
, filesToScan
, added
);
593 } catch (InterruptedException e
) {
599 * I am a job. Make me work
601 private synchronized IStatus
updateFiles(IProgressMonitor monitor
, String traceToScanAbsPath
) {
602 final Set
<String
> filesToScan
= new TreeSet
<>();
605 for (String name
: fParentFiles
.keySet()) {
607 final File file
= new File(name
);
608 final File
[] listFiles
= file
.listFiles();
609 if (listFiles
!= null) {
610 workToDo
+= listFiles
.length
;
613 int step
= TOTALWORK
/ workToDo
;
615 for (String name
: fParentFiles
.keySet()) {
616 final File fileToAdd
= new File(name
);
617 final Set
<String
> parentFilesToScan
= fParentFiles
.get(fileToAdd
.getAbsolutePath());
618 recurse(parentFilesToScan
, fileToAdd
, monitor
, step
);
619 if (monitor
.isCanceled()) {
620 fParentFilesToScan
.remove(traceToScanAbsPath
);
621 fParentFiles
.remove(traceToScanAbsPath
);
622 return CANCEL_STATUS
;
626 for (String name
: fParentFiles
.keySet()) {
627 filesToScan
.addAll(fParentFiles
.get(name
));
628 fParentFilesToScan
.add(name
);
630 IStatus cancelled
= updateScanQueue(monitor
, filesToScan
, fTraceTypesToScan
);
631 if (cancelled
.matches(IStatus
.CANCEL
)) {
632 fParentFilesToScan
.remove(traceToScanAbsPath
);
633 fParentFiles
.remove(traceToScanAbsPath
);
635 } catch (InterruptedException e
) {
637 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, e
.getMessage(), e
);
641 return Status
.OK_STATUS
;
644 private IStatus
updateScanQueue(IProgressMonitor monitor
, final Set
<String
> filesToScan
, final List
<String
> traceTypes
) throws InterruptedException
{
645 for (String fileToScan
: filesToScan
) {
646 for (String traceCat
: traceTypes
) {
647 TraceValidationHelper tv
= new TraceValidationHelper(fileToScan
, traceCat
);
648 // for thread safety, keep checks in this order.
649 if (!fResults
.containsKey(tv
)) {
650 if (!fTracesToScan
.contains(tv
)) {
651 fTracesToScan
.put(tv
);
652 monitor
.subTask(tv
.getTraceToScan());
653 if (monitor
.isCanceled()) {
655 return CANCEL_STATUS
;
662 return Status
.OK_STATUS
;
665 private IStatus
recurse(Set
<String
> filesToScan
, File fileToAdd
, IProgressMonitor monitor
, int step
) {
666 final String absolutePath
= fileToAdd
.getAbsolutePath();
667 if (!filesToScan
.contains(absolutePath
) && (filesToScan
.size() < MAX_FILES
)) {
668 filesToScan
.add(absolutePath
);
669 final File
[] listFiles
= fileToAdd
.listFiles();
670 if (null != listFiles
) {
671 for (File child
: listFiles
) {
672 monitor
.subTask(child
.getName());
673 if (monitor
.isCanceled()) {
674 return CANCEL_STATUS
;
676 IStatus retVal
= recurse(filesToScan
, child
, monitor
);
677 if (retVal
.matches(IStatus
.CANCEL
)) {
680 monitor
.worked(step
);
684 return Status
.OK_STATUS
;
687 private IStatus
recurse(Set
<String
> filesToScan
, File fileToAdd
, IProgressMonitor monitor
) {
688 final String absolutePath
= fileToAdd
.getAbsolutePath();
689 if (!filesToScan
.contains(absolutePath
) && (filesToScan
.size() < MAX_FILES
)) {
690 filesToScan
.add(absolutePath
);
691 final File
[] listFiles
= fileToAdd
.listFiles();
692 if (null != listFiles
) {
693 for (File child
: listFiles
) {
694 if (monitor
.isCanceled()) {
695 return CANCEL_STATUS
;
697 IStatus retVal
= recurse(filesToScan
, child
, monitor
);
698 if (retVal
.matches(IStatus
.CANCEL
)) {
704 return Status
.OK_STATUS
;
708 * Gets the folder in the resource (project)
710 * @param targetFolder
711 * the folder to import to
713 public void setTraceFolder(IFolder targetFolder
) {
714 fTargetFolder
= targetFolder
;
715 if (this.getContainer() != null && this.getContainer().getCurrentPage() != null) {
716 this.getContainer().updateButtons();
721 * Gets the target folder
723 * @return the target folder
725 public IFolder
getTargetFolder() {
726 return fTargetFolder
;