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 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.ui
.project
.wizards
.importtrace
;
16 import java
.lang
.reflect
.InvocationTargetException
;
17 import java
.util
.ArrayList
;
18 import java
.util
.HashMap
;
19 import java
.util
.HashSet
;
20 import java
.util
.Iterator
;
21 import java
.util
.List
;
24 import java
.util
.TreeSet
;
25 import java
.util
.concurrent
.BlockingQueue
;
27 import org
.eclipse
.core
.resources
.IFile
;
28 import org
.eclipse
.core
.resources
.IFolder
;
29 import org
.eclipse
.core
.resources
.IResource
;
30 import org
.eclipse
.core
.resources
.IWorkspace
;
31 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
32 import org
.eclipse
.core
.runtime
.CoreException
;
33 import org
.eclipse
.core
.runtime
.IConfigurationElement
;
34 import org
.eclipse
.core
.runtime
.IPath
;
35 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
36 import org
.eclipse
.core
.runtime
.IStatus
;
37 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
38 import org
.eclipse
.core
.runtime
.Path
;
39 import org
.eclipse
.core
.runtime
.Status
;
40 import org
.eclipse
.core
.runtime
.SubMonitor
;
41 import org
.eclipse
.jface
.dialogs
.ErrorDialog
;
42 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
43 import org
.eclipse
.jface
.operation
.IRunnableWithProgress
;
44 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
45 import org
.eclipse
.jface
.wizard
.IWizardPage
;
46 import org
.eclipse
.jface
.wizard
.WizardDialog
;
47 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
48 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.parsers
.custom
.CustomTxtTrace
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
50 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfProjectElement
;
51 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfProjectRegistry
;
52 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceElement
;
53 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceFolder
;
54 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceType
;
55 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TraceValidationHelper
;
56 import org
.eclipse
.ui
.IWorkbench
;
57 import org
.eclipse
.ui
.dialogs
.IOverwriteQuery
;
58 import org
.eclipse
.ui
.wizards
.datatransfer
.FileSystemStructureProvider
;
59 import org
.eclipse
.ui
.wizards
.datatransfer
.ImportOperation
;
62 * Batch Import trace wizard.
64 * @author Matthew Khouzam
67 public class BatchImportTraceWizard
extends ImportTraceWizard
{
69 private static final int WIN_HEIGHT
= 400;
70 private static final int WIN_WIDTH
= 800;
71 private static final Status CANCEL_STATUS
= new Status(IStatus
.CANCEL
, Activator
.PLUGIN_ID
, ""); //$NON-NLS-1$
72 private static final int TOTALWORK
= 65536;
77 private static final int MAX_FILES
= TOTALWORK
- 1;
78 private static final String DEFAULT_TRACE_ICON_PATH
= "icons/elcl16/trace.gif"; //$NON-NLS-1$
79 private static final String BATCH_IMPORT_WIZARD
= "BatchImportTraceWizard"; //$NON-NLS-1$
85 private IWizardPage fSelectDirectoriesPage
;
86 private IWizardPage fScanPage
;
87 private IWizardPage fSelectTypePage
;
89 private final List
<String
> fTraceTypesToScan
= new ArrayList
<String
>();
90 private final Set
<String
> fParentFilesToScan
= new HashSet
<String
>();
92 private ImportTraceContentProvider fScannedTraces
= new ImportTraceContentProvider();
94 private final Map
<TraceValidationHelper
, Boolean
> fResults
= new HashMap
<TraceValidationHelper
, Boolean
>();
95 private boolean fOverwrite
= true;
96 private boolean fLinked
= true;
98 private BlockingQueue
<TraceValidationHelper
> fTracesToScan
;
99 private final Set
<FileAndName
> fTraces
= new TreeSet
<FileAndName
>();
101 private Map
<String
, Set
<String
>> fParentFiles
= new HashMap
<String
, Set
<String
>>();
103 // Target import directory ('Traces' folder)
104 private IFolder fTargetFolder
;
107 * Returns the ScannedTraces model
109 * @return the ScannedTraces model
111 public ImportTraceContentProvider
getScannedTraces() {
112 return fScannedTraces
;
118 public BatchImportTraceWizard() {
119 IDialogSettings workbenchSettings
= Activator
.getDefault().getDialogSettings();
120 IDialogSettings section
= workbenchSettings
.getSection(BATCH_IMPORT_WIZARD
);
121 if (section
== null) {
122 section
= workbenchSettings
.addNewSection(BATCH_IMPORT_WIZARD
);
124 setDialogSettings(section
);
125 setNeedsProgressMonitor(true);
129 public void init(IWorkbench workbench
, IStructuredSelection selection
) {
131 fSelectDirectoriesPage
= new ImportTraceWizardSelectDirectoriesPage(workbench
, selection
);
132 fScanPage
= new ImportTraceWizardScanPage(workbench
, selection
);
133 fSelectTypePage
= new ImportTraceWizardSelectTraceTypePage(workbench
, selection
);
134 // keep in case it's called later
135 Iterator
<?
> iter
= selection
.iterator();
136 while (iter
.hasNext()) {
137 Object selected
= iter
.next();
138 if (selected
instanceof TmfTraceFolder
) {
139 fTargetFolder
= ((TmfTraceFolder
) selected
).getResource();
147 public void addPages() {
148 addPage(fSelectTypePage
);
149 addPage(fSelectDirectoriesPage
);
151 final WizardDialog container
= (WizardDialog
) getContainer();
152 if (container
!= null) {
153 container
.setPageSize(WIN_WIDTH
, WIN_HEIGHT
);
154 container
.updateSize();
164 public void addFileToScan(final String fileName
) {
165 if (!fParentFiles
.containsKey(fileName
)) {
166 fParentFiles
.put(fileName
, new HashSet
<String
>());
167 startUpdateTask(Messages
.BatchImportTraceWizardAdd
+ ' ' + fileName
, fileName
);
174 * Remove files from selection
177 * the name of the file to remove
179 public void removeFile(final String fileName
) {
180 fParentFiles
.remove(fileName
);
181 fParentFilesToScan
.remove(fileName
);
182 startUpdateTask(Messages
.BatchImportTraceWizardRemove
+ ' ' + fileName
, null);
185 private void startUpdateTask(final String taskName
, final String fileName
) {
187 this.getContainer().run(true, true, new IRunnableWithProgress() {
190 public void run(IProgressMonitor monitor
) throws InvocationTargetException
, InterruptedException
{
191 synchronized (BatchImportTraceWizard
.this) { // this should
195 sm
= SubMonitor
.convert(monitor
);
196 sm
.setTaskName(taskName
);
197 sm
.setWorkRemaining(TOTALWORK
);
198 updateFiles(sm
, fileName
);
203 } catch (InvocationTargetException e
) {
204 } catch (InterruptedException e
) {
209 * The set of names of the selected files
211 * @return the set of names of the selected files
213 public Set
<String
> getFileNames() {
214 return fParentFilesToScan
;
218 * Reset the trace list to import
220 public void clearTraces() {
225 public boolean performFinish() {
226 if (fTraces
.isEmpty()) {
229 // if this turns out to be too slow, put in a progress monitor. Does not
230 // appear to be slow for the moment.
231 boolean success
= importTraces();
235 private boolean importTraces() {
236 boolean success
= false;
237 IOverwriteQuery overwriteQuery
= new IOverwriteQuery() {
239 public String
queryOverwrite(String file
) {
240 return fOverwrite ? IOverwriteQuery
.ALL
: IOverwriteQuery
.NO_ALL
;
243 FileSystemStructureProvider fileSystemStructureProvider
= FileSystemStructureProvider
.INSTANCE
;
245 for (FileAndName traceToImport
: fTraces
) {
248 createLink(fTargetFolder
, Path
.fromOSString(traceToImport
.getFile().getAbsolutePath()), traceToImport
.getName());
249 success
= setTraceType(traceToImport
).isOK();
252 List
<File
> subList
= new ArrayList
<File
>();
253 subList
.add(traceToImport
.getFile());
254 IPath path
= fTargetFolder
.getFullPath().append(traceToImport
.getName());
255 final File parentFile
= traceToImport
.getFile().getParentFile();
256 ImportOperation operation
= new ImportOperation(path
,
257 parentFile
, fileSystemStructureProvider
, overwriteQuery
,
259 operation
.setContext(getShell());
260 if (executeImportOperation(operation
)) {
261 setTraceType(traceToImport
);
265 } catch (Exception e
) {
271 private static void createLink(IFolder parentFolder
, IPath location
, String targetName
) {
272 File source
= new File(location
.toString());
273 IWorkspace workspace
= ResourcesPlugin
.getWorkspace();
276 if (source
.isDirectory()) {
277 IFolder folder
= parentFolder
.getFolder(targetName
);
278 IStatus result
= workspace
.validateLinkLocation(folder
, location
);
280 folder
.createLink(location
, IResource
.REPLACE
, null);
282 Activator
.getDefault().logError(result
.getMessage());
285 IFile file
= parentFolder
.getFile(targetName
);
286 IStatus result
= workspace
.validateLinkLocation(file
, location
);
288 file
.createLink(location
, IResource
.REPLACE
, null);
290 Activator
.getDefault().logError(result
.getMessage());
293 } catch (CoreException e
) {
298 private IStatus
setTraceType(FileAndName traceToImport
) {
299 IPath path
= fTargetFolder
.getFullPath().append(traceToImport
.getName());
300 IResource resource
= ResourcesPlugin
.getWorkspace().getRoot().findMember(path
);
301 if (resource
!= null) {
303 // Set the trace properties for this resource
304 boolean traceTypeOK
= false;
305 String traceBundle
= null, traceTypeId
= null, traceIcon
= null;
306 traceTypeId
= traceToImport
.getTraceTypeId();
307 IConfigurationElement ce
= TmfTraceType
.getInstance().getTraceAttributes(traceTypeId
);
308 if ((ce
!= null) && (ce
.getContributor() != null)) {
310 traceBundle
= ce
.getContributor().getName();
311 traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
312 traceIcon
= ce
.getAttribute(TmfTraceType
.ICON_ATTR
);
314 final String traceType
= traceTypeId
;
316 (traceType
.startsWith(TmfTraceType
.CUSTOM_TXT_CATEGORY
) ||
317 traceType
.startsWith(TmfTraceType
.CUSTOM_XML_CATEGORY
))) {
318 // do custom trace stuff here
321 Activator
.getDefault().getBundle().getSymbolicName();
323 traceTypeId
= CustomTxtTrace
.class.getCanonicalName() + ":" + traceType
; //$NON-NLS-1$
324 traceIcon
= DEFAULT_TRACE_ICON_PATH
;
327 resource
.setPersistentProperty(TmfCommonConstants
.TRACEBUNDLE
,
329 resource
.setPersistentProperty(TmfCommonConstants
.TRACETYPE
,
331 resource
.setPersistentProperty(TmfCommonConstants
.TRACEICON
,
334 TmfProjectElement tmfProject
=
335 TmfProjectRegistry
.getProject(resource
.getProject());
336 if (tmfProject
!= null) {
337 for (TmfTraceElement traceElement
: tmfProject
.getTracesFolder().getTraces()) {
338 if (traceElement
.getName().equals(resource
.getName())) {
339 traceElement
.refreshTraceType();
344 } catch (CoreException e
) {
345 Activator
.getDefault().logError(Messages
.BatchImportTraceWizardErrorImportingTraceResource
346 + " " + resource
.getName(), e
); //$NON-NLS-1$
349 return Status
.OK_STATUS
;
353 public boolean canFinish() {
354 return super.canFinish() && hasTracesToImport() && !hasConflicts();
358 * Returns if a trace to import is selected
360 * @return if there are traces to import
362 public boolean hasTracesToImport() {
363 return fTraces
.size() > 0;
367 * Reset the files to scan
369 public void clearFilesToScan() {
370 fTracesToScan
.clear();
374 * Set the trace types to scan
376 * @param tracesToScan
377 * a list of trace types to scan for
379 public void setTraceTypesToScan(List
<String
> tracesToScan
) {
380 // intersection to know if there's a diff.
381 // if there's a diff, we need to re-enque everything
382 List
<String
> added
= new ArrayList
<String
>();
383 for (String traceLoc
: tracesToScan
) {
384 if (!fTraceTypesToScan
.contains(traceLoc
)) {
388 fTraceTypesToScan
.clear();
389 fTraceTypesToScan
.addAll(tracesToScan
);
390 updateTracesToScan(added
);
394 * Get the trace types to scan
396 * @return a list of traces to Scan for
398 public List
<String
> getTraceTypesToScan() {
399 return fTraceTypesToScan
;
403 * Add files to Import
406 * add the file and tracetype to import
408 public void addFileToImport(FileAndName element
) {
409 fTraces
.add(element
);
414 * Remove the file to scan
417 * the element to remove
419 public void removeFileToImport(FileAndName element
) {
420 fTraces
.remove(element
);
421 element
.setConflictingName(false);
426 * Updates the trace to see if there are conflicts.
428 public void updateConflicts() {
429 final FileAndName
[] fChildren
= fTraces
.toArray(new FileAndName
[0]);
430 for (int i
= 0; i
< fChildren
.length
; i
++) {
431 fChildren
[i
].setConflictingName(false);
433 for (int i
= 1; i
< fChildren
.length
; i
++) {
434 for (int j
= 0; j
< i
; j
++) {
435 if (fChildren
[i
].getName().equals(fChildren
[j
].getName())) {
436 fChildren
[i
].setConflictingName(true);
437 fChildren
[j
].setConflictingName(true);
441 getContainer().updateButtons();
445 * Is there a name conflict
447 boolean hasConflicts() {
448 boolean conflict
= false;
449 for (FileAndName child
: fTraces
) {
450 conflict
|= child
.isConflictingName();
455 private boolean executeImportOperation(ImportOperation op
) {
456 initializeOperation(op
);
459 getContainer().run(true, true, op
);
460 } catch (InterruptedException e
) {
462 } catch (InvocationTargetException e
) {
463 System
.out
.println(e
.getTargetException());
467 IStatus status
= op
.getStatus();
468 if (!status
.isOK()) {
469 ErrorDialog
.openError(getContainer().getShell(), Messages
.ImportTraceWizardImportProblem
, null, status
);
476 private static void initializeOperation(ImportOperation op
) {
477 op
.setCreateContainerStructure(false);
478 op
.setOverwriteResources(false);
479 op
.setCreateLinks(true);
480 op
.setVirtualFolders(false);
484 * Override existing resources
489 public void setOverwrite(boolean selection
) {
490 fOverwrite
= selection
;
494 * Is the trace linked?
499 public void setLinked(boolean isLink
) {
504 * @param tracesToScan
505 * sets the common traces to scan
507 public void setTracesToScan(BlockingQueue
<TraceValidationHelper
> tracesToScan
) {
508 fTracesToScan
= tracesToScan
;
514 * @return if the trace has been scanned yet or not
516 public boolean hasScanned(TraceValidationHelper traceToScan
) {
517 return fResults
.containsKey(traceToScan
);
521 * Add a result to a cache
524 * The trace that has been scanned
526 * if the trace is valid
528 public void addResult(TraceValidationHelper traceToScan
, boolean validate
) {
529 fResults
.put(traceToScan
, validate
);
533 * Gets if the trace has been scanned or not
537 * @return whether it passes or not
539 public Boolean
getResult(TraceValidationHelper traceToScan
) {
540 return fResults
.get(traceToScan
);
544 * Returns the amount of files scanned
546 * @return the amount of files scanned
548 public int getNumberOfResults() {
549 return fResults
.size();
552 private void updateTracesToScan(final List
<String
> added
) {
553 // Treeset is used instead of a hashset since the traces should be read
554 // in the order they were added.
555 final Set
<String
> filesToScan
= new TreeSet
<String
>();
556 for (String name
: fParentFiles
.keySet()) {
557 filesToScan
.addAll(fParentFiles
.get(name
));
559 IProgressMonitor pm
= new NullProgressMonitor();
561 updateScanQueue(pm
, filesToScan
, added
);
562 } catch (InterruptedException e
) {
567 * I am a job. Make me work
569 private synchronized IStatus
updateFiles(IProgressMonitor monitor
, String traceToScan
) {
570 final Set
<String
> filesToScan
= new TreeSet
<String
>();
573 for (String name
: fParentFiles
.keySet()) {
575 final File file
= new File(name
);
576 final File
[] listFiles
= file
.listFiles();
577 if (listFiles
!= null) {
578 workToDo
+= listFiles
.length
;
581 int step
= TOTALWORK
/ workToDo
;
583 for (String name
: fParentFiles
.keySet()) {
584 final File fileToAdd
= new File(name
);
585 final Set
<String
> parentFilesToScan
= fParentFiles
.get(fileToAdd
.getAbsolutePath());
586 recurse(parentFilesToScan
, fileToAdd
, monitor
, step
);
587 if (monitor
.isCanceled()) {
588 fParentFilesToScan
.remove(traceToScan
);
589 fParentFiles
.remove(traceToScan
);
590 return CANCEL_STATUS
;
594 for (String name
: fParentFiles
.keySet()) {
595 filesToScan
.addAll(fParentFiles
.get(name
));
596 fParentFilesToScan
.add(name
);
598 IStatus cancelled
= updateScanQueue(monitor
, filesToScan
, fTraceTypesToScan
);
599 if (cancelled
.matches(IStatus
.CANCEL
)) {
600 fParentFilesToScan
.remove(traceToScan
);
601 fParentFiles
.remove(traceToScan
);
603 } catch (InterruptedException e
) {
605 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, e
.getMessage(), e
);
609 return Status
.OK_STATUS
;
612 private IStatus
updateScanQueue(IProgressMonitor monitor
, final Set
<String
> filesToScan
, final List
<String
> traceTypes
) throws InterruptedException
{
613 for (String fileToScan
: filesToScan
) {
614 for (String traceCat
: traceTypes
) {
615 TraceValidationHelper tv
= new TraceValidationHelper(fileToScan
, traceCat
);
616 // for thread safety, keep checks in this order.
617 if (!fResults
.containsKey(tv
)) {
618 if (!fTracesToScan
.contains(tv
)) {
619 fTracesToScan
.put(tv
);
620 monitor
.subTask(tv
.getTraceToScan());
621 if (monitor
.isCanceled()) {
622 return CANCEL_STATUS
;
628 return Status
.OK_STATUS
;
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
;
642 IStatus retVal
= recurse(filesToScan
, child
, monitor
);
643 if (retVal
.matches(IStatus
.CANCEL
)) {
646 monitor
.worked(step
);
650 return Status
.OK_STATUS
;
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
;
663 IStatus retVal
= recurse(filesToScan
, child
, monitor
);
664 if (retVal
.matches(IStatus
.CANCEL
)) {
670 return Status
.OK_STATUS
;
674 * Gets the folder in the resource (project)
676 * @param targetFolder
677 * the folder to import to
679 public void setTraceFolder(IFolder targetFolder
) {
680 fTargetFolder
= targetFolder
;