df6b799016ae6ee8d1a24c3921a6663b52283bc5
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / project / wizards / importtrace / BatchImportTraceWizard.java
1 /*******************************************************************************
2 * Copyright (c) 2013 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 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.ui.project.wizards.importtrace;
14
15 import java.io.File;
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;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.TreeSet;
25 import java.util.concurrent.BlockingQueue;
26
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;
60
61 /**
62 * Batch Import trace wizard.
63 *
64 * @author Matthew Khouzam
65 * @since 2.0
66 */
67 public class BatchImportTraceWizard extends ImportTraceWizard {
68
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;
73 // -----------------
74 // Constants
75 // -----------------
76
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$
80
81 // ------------------
82 // Fields
83 // ------------------
84
85 private IWizardPage fSelectDirectoriesPage;
86 private IWizardPage fScanPage;
87 private IWizardPage fSelectTypePage;
88
89 private final List<String> fTraceTypesToScan = new ArrayList<String>();
90 private final Set<String> fParentFilesToScan = new HashSet<String>();
91
92 private ImportTraceContentProvider fScannedTraces = new ImportTraceContentProvider();
93
94 private final Map<TraceValidationHelper, Boolean> fResults = new HashMap<TraceValidationHelper, Boolean>();
95 private boolean fOverwrite = true;
96 private boolean fLinked = true;
97
98 private BlockingQueue<TraceValidationHelper> fTracesToScan;
99 private final Set<FileAndName> fTraces = new TreeSet<FileAndName>();
100
101 private Map<String, Set<String>> fParentFiles = new HashMap<String, Set<String>>();
102
103 // Target import directory ('Traces' folder)
104 private IFolder fTargetFolder;
105
106 /**
107 * Returns the ScannedTraces model
108 *
109 * @return the ScannedTraces model
110 */
111 public ImportTraceContentProvider getScannedTraces() {
112 return fScannedTraces;
113 }
114
115 /**
116 * Constructor
117 */
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);
123 }
124 setDialogSettings(section);
125 setNeedsProgressMonitor(true);
126 }
127
128 @Override
129 public void init(IWorkbench workbench, IStructuredSelection selection) {
130
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();
140 break;
141 }
142 }
143 fResults.clear();
144 }
145
146 @Override
147 public void addPages() {
148 addPage(fSelectTypePage);
149 addPage(fSelectDirectoriesPage);
150 addPage(fScanPage);
151 final WizardDialog container = (WizardDialog) getContainer();
152 if (container != null) {
153 container.setPageSize(WIN_WIDTH, WIN_HEIGHT);
154 container.updateSize();
155 }
156 }
157
158 /**
159 * Add a file to scan
160 *
161 * @param fileName
162 * the file to scan
163 */
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);
168
169 }
170
171 }
172
173 /**
174 * Remove files from selection
175 *
176 * @param fileName
177 * the name of the file to remove
178 */
179 public void removeFile(final String fileName) {
180 fParentFiles.remove(fileName);
181 fParentFilesToScan.remove(fileName);
182 startUpdateTask(Messages.BatchImportTraceWizardRemove + ' ' + fileName, null);
183 }
184
185 private void startUpdateTask(final String taskName, final String fileName) {
186 try {
187 this.getContainer().run(true, true, new IRunnableWithProgress() {
188
189 @Override
190 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
191 synchronized (BatchImportTraceWizard.this) { // this should
192 // only run one
193 // at a time
194 SubMonitor sm;
195 sm = SubMonitor.convert(monitor);
196 sm.setTaskName(taskName);
197 sm.setWorkRemaining(TOTALWORK);
198 updateFiles(sm, fileName);
199 sm.done();
200 }
201 }
202 });
203 } catch (InvocationTargetException e) {
204 } catch (InterruptedException e) {
205 }
206 }
207
208 /**
209 * The set of names of the selected files
210 *
211 * @return the set of names of the selected files
212 */
213 public Set<String> getFileNames() {
214 return fParentFilesToScan;
215 }
216
217 /**
218 * Reset the trace list to import
219 */
220 public void clearTraces() {
221 fTraces.clear();
222 }
223
224 @Override
225 public boolean performFinish() {
226 if (fTraces.isEmpty()) {
227 return false;
228 }
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();
232 return success;
233 }
234
235 private boolean importTraces() {
236 boolean success = false;
237 IOverwriteQuery overwriteQuery = new IOverwriteQuery() {
238 @Override
239 public String queryOverwrite(String file) {
240 return fOverwrite ? IOverwriteQuery.ALL : IOverwriteQuery.NO_ALL;
241 }
242 };
243 FileSystemStructureProvider fileSystemStructureProvider = FileSystemStructureProvider.INSTANCE;
244
245 for (FileAndName traceToImport : fTraces) {
246 try {
247 if (fLinked) {
248 createLink(fTargetFolder, Path.fromOSString(traceToImport.getFile().getAbsolutePath()), traceToImport.getName());
249 success = setTraceType(traceToImport).isOK();
250 }
251 else {
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,
258 subList);
259 operation.setContext(getShell());
260 if (executeImportOperation(operation)) {
261 setTraceType(traceToImport);
262 success = true;
263 }
264 }
265 } catch (Exception e) {
266 }
267 }
268 return success;
269 }
270
271 private static void createLink(IFolder parentFolder, IPath location, String targetName) {
272 File source = new File(location.toString());
273 IWorkspace workspace = ResourcesPlugin.getWorkspace();
274 try {
275
276 if (source.isDirectory()) {
277 IFolder folder = parentFolder.getFolder(targetName);
278 IStatus result = workspace.validateLinkLocation(folder, location);
279 if (result.isOK()) {
280 folder.createLink(location, IResource.REPLACE, null);
281 } else {
282 Activator.getDefault().logError(result.getMessage());
283 }
284 } else {
285 IFile file = parentFolder.getFile(targetName);
286 IStatus result = workspace.validateLinkLocation(file, location);
287 if (result.isOK()) {
288 file.createLink(location, IResource.REPLACE, null);
289 } else {
290 Activator.getDefault().logError(result.getMessage());
291 }
292 }
293 } catch (CoreException e) {
294
295 }
296 }
297
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) {
302 try {
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)) {
309 traceTypeOK = true;
310 traceBundle = ce.getContributor().getName();
311 traceTypeId = ce.getAttribute(TmfTraceType.ID_ATTR);
312 traceIcon = ce.getAttribute(TmfTraceType.ICON_ATTR);
313 }
314 final String traceType = traceTypeId;
315 if (!traceTypeOK &&
316 (traceType.startsWith(TmfTraceType.CUSTOM_TXT_CATEGORY) ||
317 traceType.startsWith(TmfTraceType.CUSTOM_XML_CATEGORY))) {
318 // do custom trace stuff here
319 traceTypeOK = true;
320 traceBundle =
321 Activator.getDefault().getBundle().getSymbolicName();
322
323 traceTypeId = CustomTxtTrace.class.getCanonicalName() + ":" + traceType; //$NON-NLS-1$
324 traceIcon = DEFAULT_TRACE_ICON_PATH;
325 }
326 if (traceTypeOK) {
327 resource.setPersistentProperty(TmfCommonConstants.TRACEBUNDLE,
328 traceBundle);
329 resource.setPersistentProperty(TmfCommonConstants.TRACETYPE,
330 traceTypeId);
331 resource.setPersistentProperty(TmfCommonConstants.TRACEICON,
332 traceIcon);
333 }
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();
340 break;
341 }
342 }
343 }
344 } catch (CoreException e) {
345 Activator.getDefault().logError(Messages.BatchImportTraceWizardErrorImportingTraceResource
346 + " " + resource.getName(), e); //$NON-NLS-1$
347 }
348 }
349 return Status.OK_STATUS;
350 }
351
352 @Override
353 public boolean canFinish() {
354 return super.canFinish() && hasTracesToImport() && !hasConflicts();
355 }
356
357 /**
358 * Returns if a trace to import is selected
359 *
360 * @return if there are traces to import
361 */
362 public boolean hasTracesToImport() {
363 return fTraces.size() > 0;
364 }
365
366 /**
367 * Reset the files to scan
368 */
369 public void clearFilesToScan() {
370 fTracesToScan.clear();
371 }
372
373 /**
374 * Set the trace types to scan
375 *
376 * @param tracesToScan
377 * a list of trace types to scan for
378 */
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)) {
385 added.add(traceLoc);
386 }
387 }
388 fTraceTypesToScan.clear();
389 fTraceTypesToScan.addAll(tracesToScan);
390 updateTracesToScan(added);
391 }
392
393 /**
394 * Get the trace types to scan
395 *
396 * @return a list of traces to Scan for
397 */
398 public List<String> getTraceTypesToScan() {
399 return fTraceTypesToScan;
400 }
401
402 /**
403 * Add files to Import
404 *
405 * @param element
406 * add the file and tracetype to import
407 */
408 public void addFileToImport(FileAndName element) {
409 fTraces.add(element);
410 updateConflicts();
411 }
412
413 /**
414 * Remove the file to scan
415 *
416 * @param element
417 * the element to remove
418 */
419 public void removeFileToImport(FileAndName element) {
420 fTraces.remove(element);
421 element.setConflictingName(false);
422 updateConflicts();
423 }
424
425 /**
426 * Updates the trace to see if there are conflicts.
427 */
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);
432 }
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);
438 }
439 }
440 }
441 getContainer().updateButtons();
442 }
443
444 /**
445 * Is there a name conflict
446 */
447 boolean hasConflicts() {
448 boolean conflict = false;
449 for (FileAndName child : fTraces) {
450 conflict |= child.isConflictingName();
451 }
452 return conflict;
453 }
454
455 private boolean executeImportOperation(ImportOperation op) {
456 initializeOperation(op);
457
458 try {
459 getContainer().run(true, true, op);
460 } catch (InterruptedException e) {
461 return false;
462 } catch (InvocationTargetException e) {
463 System.out.println(e.getTargetException());
464 return false;
465 }
466
467 IStatus status = op.getStatus();
468 if (!status.isOK()) {
469 ErrorDialog.openError(getContainer().getShell(), Messages.ImportTraceWizardImportProblem, null, status);
470 return false;
471 }
472
473 return true;
474 }
475
476 private static void initializeOperation(ImportOperation op) {
477 op.setCreateContainerStructure(false);
478 op.setOverwriteResources(false);
479 op.setCreateLinks(true);
480 op.setVirtualFolders(false);
481 }
482
483 /**
484 * Override existing resources
485 *
486 * @param selection
487 * true or false
488 */
489 public void setOverwrite(boolean selection) {
490 fOverwrite = selection;
491 }
492
493 /**
494 * Is the trace linked?
495 *
496 * @param isLink
497 * true or false
498 */
499 public void setLinked(boolean isLink) {
500 fLinked = isLink;
501 }
502
503 /**
504 * @param tracesToScan
505 * sets the common traces to scan
506 */
507 public void setTracesToScan(BlockingQueue<TraceValidationHelper> tracesToScan) {
508 fTracesToScan = tracesToScan;
509 }
510
511 /**
512 * @param traceToScan
513 * The trace to scan
514 * @return if the trace has been scanned yet or not
515 */
516 public boolean hasScanned(TraceValidationHelper traceToScan) {
517 return fResults.containsKey(traceToScan);
518 }
519
520 /**
521 * Add a result to a cache
522 *
523 * @param traceToScan
524 * The trace that has been scanned
525 * @param validate
526 * if the trace is valid
527 */
528 public void addResult(TraceValidationHelper traceToScan, boolean validate) {
529 fResults.put(traceToScan, validate);
530 }
531
532 /**
533 * Gets if the trace has been scanned or not
534 *
535 * @param traceToScan
536 * the scanned trace
537 * @return whether it passes or not
538 */
539 public Boolean getResult(TraceValidationHelper traceToScan) {
540 return fResults.get(traceToScan);
541 }
542
543 /**
544 * Returns the amount of files scanned
545 *
546 * @return the amount of files scanned
547 */
548 public int getNumberOfResults() {
549 return fResults.size();
550 }
551
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));
558 }
559 IProgressMonitor pm = new NullProgressMonitor();
560 try {
561 updateScanQueue(pm, filesToScan, added);
562 } catch (InterruptedException e) {
563 }
564 }
565
566 /*
567 * I am a job. Make me work
568 */
569 private synchronized IStatus updateFiles(IProgressMonitor monitor, String traceToScan) {
570 final Set<String> filesToScan = new TreeSet<String>();
571
572 int workToDo = 1;
573 for (String name : fParentFiles.keySet()) {
574
575 final File file = new File(name);
576 final File[] listFiles = file.listFiles();
577 if (listFiles != null) {
578 workToDo += listFiles.length;
579 }
580 }
581 int step = TOTALWORK / workToDo;
582 try {
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;
591 }
592 }
593 filesToScan.clear();
594 for (String name : fParentFiles.keySet()) {
595 filesToScan.addAll(fParentFiles.get(name));
596 fParentFilesToScan.add(name);
597 }
598 IStatus cancelled = updateScanQueue(monitor, filesToScan, fTraceTypesToScan);
599 if (cancelled.matches(IStatus.CANCEL)) {
600 fParentFilesToScan.remove(traceToScan);
601 fParentFiles.remove(traceToScan);
602 }
603 } catch (InterruptedException e) {
604 monitor.done();
605 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e);
606 }
607
608 monitor.done();
609 return Status.OK_STATUS;
610 }
611
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;
623 }
624 }
625 }
626 }
627 }
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 }
682
683 }
This page took 0.046895 seconds and 4 git commands to generate.