1 /*******************************************************************************
2 * Copyright (c) 2010, 2015 Ericsson, École Polytechnique de Montréal
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 * Francois Chouinard - Initial API and implementation
11 * Geneviève Bastien - Copied code to add/remove traces in this class
12 * Patrick Tasse - Close editors to release resources
13 * Geneviève Bastien - Experiment instantiated with trace type
14 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
;
18 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Arrays
;
22 import java
.util
.Collections
;
23 import java
.util
.Comparator
;
24 import java
.util
.HashMap
;
25 import java
.util
.List
;
28 import org
.eclipse
.core
.resources
.IContainer
;
29 import org
.eclipse
.core
.resources
.IFile
;
30 import org
.eclipse
.core
.resources
.IFolder
;
31 import org
.eclipse
.core
.resources
.IResource
;
32 import org
.eclipse
.core
.resources
.IResourceProxy
;
33 import org
.eclipse
.core
.resources
.IResourceProxyVisitor
;
34 import org
.eclipse
.core
.resources
.IWorkspace
;
35 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
36 import org
.eclipse
.core
.runtime
.CoreException
;
37 import org
.eclipse
.core
.runtime
.IConfigurationElement
;
38 import org
.eclipse
.core
.runtime
.IPath
;
39 import org
.eclipse
.core
.runtime
.IStatus
;
40 import org
.eclipse
.core
.runtime
.InvalidRegistryObjectException
;
41 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
42 import org
.eclipse
.core
.runtime
.Platform
;
43 import org
.eclipse
.jdt
.annotation
.NonNull
;
44 import org
.eclipse
.osgi
.util
.NLS
;
45 import org
.eclipse
.swt
.graphics
.Image
;
46 import org
.eclipse
.swt
.widgets
.Display
;
47 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
48 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.editors
.ITmfEventsEditorConstants
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.IAnalysisModuleHelper
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.TmfAnalysisManager
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceType
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TraceTypeHelper
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.experiment
.TmfExperiment
;
56 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.TmfEventsEditor
;
57 import org
.eclipse
.tracecompass
.tmf
.ui
.properties
.ReadOnlyTextPropertyDescriptor
;
58 import org
.eclipse
.ui
.views
.properties
.IPropertyDescriptor
;
59 import org
.eclipse
.ui
.views
.properties
.IPropertySource2
;
62 * Implementation of TMF Experiment Model Element.
66 * @author Francois Chouinard
69 public class TmfExperimentElement
extends TmfCommonProjectElement
implements IPropertySource2
{
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
75 // Property View stuff
76 private static final String INFO_CATEGORY
= "Info"; //$NON-NLS-1$
77 private static final String NAME
= "name"; //$NON-NLS-1$
78 private static final String PATH
= "path"; //$NON-NLS-1$
79 private static final String LOCATION
= "location"; //$NON-NLS-1$
80 private static final String FOLDER_SUFFIX
= "_exp"; //$NON-NLS-1$
81 private static final String EXPERIMENT_TYPE
= "type"; //$NON-NLS-1$
82 private static final String EXPERIMENT_TYPE_ID
= "type ID"; //$NON-NLS-1$
84 private static final ReadOnlyTextPropertyDescriptor NAME_DESCRIPTOR
= new ReadOnlyTextPropertyDescriptor(NAME
, NAME
);
85 private static final ReadOnlyTextPropertyDescriptor PATH_DESCRIPTOR
= new ReadOnlyTextPropertyDescriptor(PATH
, PATH
);
86 private static final ReadOnlyTextPropertyDescriptor LOCATION_DESCRIPTOR
= new ReadOnlyTextPropertyDescriptor(LOCATION
,
88 private static final ReadOnlyTextPropertyDescriptor TYPE_DESCRIPTOR
= new ReadOnlyTextPropertyDescriptor(EXPERIMENT_TYPE
, EXPERIMENT_TYPE
);
89 private static final ReadOnlyTextPropertyDescriptor TYPE_ID_DESCRIPTOR
= new ReadOnlyTextPropertyDescriptor(EXPERIMENT_TYPE_ID
, EXPERIMENT_TYPE_ID
);
91 private static final IPropertyDescriptor
[] DESCRIPTORS
= { NAME_DESCRIPTOR
, PATH_DESCRIPTOR
,
92 LOCATION_DESCRIPTOR
, TYPE_DESCRIPTOR
, TYPE_ID_DESCRIPTOR
};
95 NAME_DESCRIPTOR
.setCategory(INFO_CATEGORY
);
96 PATH_DESCRIPTOR
.setCategory(INFO_CATEGORY
);
97 LOCATION_DESCRIPTOR
.setCategory(INFO_CATEGORY
);
98 TYPE_DESCRIPTOR
.setCategory(INFO_CATEGORY
);
99 TYPE_ID_DESCRIPTOR
.setCategory(INFO_CATEGORY
);
102 // The mapping of available trace type IDs to their corresponding
103 // configuration element
104 private static final Map
<String
, IConfigurationElement
> TRACE_TYPE_ATTRIBUTES
= new HashMap
<>();
105 private static final Map
<String
, IConfigurationElement
> TRACE_TYPE_UI_ATTRIBUTES
= new HashMap
<>();
106 private static final Map
<String
, IConfigurationElement
> TRACE_CATEGORIES
= new HashMap
<>();
108 // ------------------------------------------------------------------------
109 // Static initialization
110 // ------------------------------------------------------------------------
113 * Initialize statically at startup by getting extensions from the platform
114 * extension registry.
116 public static void init() {
117 IConfigurationElement
[] config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType
.TMF_TRACE_TYPE_ID
);
118 for (IConfigurationElement ce
: config
) {
119 String elementName
= ce
.getName();
120 if (elementName
.equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
121 String traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
122 TRACE_TYPE_ATTRIBUTES
.put(traceTypeId
, ce
);
123 } else if (elementName
.equals(TmfTraceType
.CATEGORY_ELEM
)) {
124 String categoryId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
125 TRACE_CATEGORIES
.put(categoryId
, ce
);
130 * Read the corresponding tmf.ui "tracetypeui" extension point for this
131 * trace type, if it exists.
133 config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceTypeUIUtils
.TMF_TRACE_TYPE_UI_ID
);
134 for (IConfigurationElement ce
: config
) {
135 String elemName
= ce
.getName();
136 if (TmfTraceTypeUIUtils
.EXPERIMENT_ELEM
.equals(elemName
)) {
137 String traceType
= ce
.getAttribute(TmfTraceTypeUIUtils
.TRACETYPE_ATTR
);
138 TRACE_TYPE_UI_ATTRIBUTES
.put(traceType
, ce
);
143 // ------------------------------------------------------------------------
145 // ------------------------------------------------------------------------
150 * The name of the experiment
152 * The folder reference
154 * The experiment folder reference.
156 public TmfExperimentElement(String name
, IFolder folder
, TmfExperimentFolder parent
) {
157 super(name
, folder
, parent
);
160 // ------------------------------------------------------------------------
161 // TmfProjectModelElement
162 // ------------------------------------------------------------------------
165 public IFolder
getResource() {
166 return (IFolder
) super.getResource();
173 protected void refreshChildren() {
174 IFolder folder
= getResource();
176 /* Update the trace children of this experiment */
177 // Get the children from the model
178 Map
<String
, ITmfProjectModelElement
> childrenMap
= new HashMap
<>();
179 for (TmfTraceElement trace
: getTraces()) {
180 childrenMap
.put(trace
.getElementPath(), trace
);
183 List
<IResource
> members
= getTraceResources();
184 for (IResource resource
: members
) {
185 String name
= resource
.getName();
186 String elementPath
= resource
.getFullPath().makeRelativeTo(folder
.getFullPath()).toString();
187 ITmfProjectModelElement element
= childrenMap
.get(elementPath
);
188 if (element
instanceof TmfTraceElement
) {
189 childrenMap
.remove(elementPath
);
191 element
= new TmfTraceElement(name
, resource
, this);
196 // Cleanup dangling children from the model
197 for (ITmfProjectModelElement danglingChild
: childrenMap
.values()) {
198 removeChild(danglingChild
);
201 /* Update the analysis under this experiment */
202 super.refreshChildren();
205 * If the experiment is opened, add any analysis that was not added by
206 * the parent if it is available with the experiment
208 ITmfTrace experiment
= getTrace();
209 if (experiment
== null) {
213 /* super.refreshChildren() above should have set this */
214 TmfViewsElement viewsElement
= checkNotNull(getChildElementViews());
216 Map
<String
, TmfAnalysisElement
> analysisMap
= new HashMap
<>();
217 for (TmfAnalysisElement analysis
: getAvailableAnalysis()) {
218 analysisMap
.put(analysis
.getAnalysisId(), analysis
);
220 for (IAnalysisModuleHelper module
: TmfAnalysisManager
.getAnalysisModules().values()) {
221 if (!analysisMap
.containsKey(module
.getId()) && module
.appliesToExperiment() && (experiment
.getAnalysisModule(module
.getId()) != null)) {
222 IFolder newresource
= ResourcesPlugin
.getWorkspace().getRoot().getFolder(getResource().getFullPath().append(module
.getId()));
223 TmfAnalysisElement analysis
= new TmfAnalysisElement(module
.getName(), newresource
, viewsElement
, module
);
224 viewsElement
.addChild(analysis
);
225 analysis
.refreshChildren();
226 analysisMap
.put(module
.getId(), analysis
);
231 private List
<IResource
> getTraceResources() {
232 IFolder folder
= getResource();
233 final List
<IResource
> list
= new ArrayList
<>();
235 folder
.accept(new IResourceProxyVisitor() {
237 public boolean visit(IResourceProxy resource
) throws CoreException
{
238 if (resource
.isLinked()) {
239 list
.add(resource
.requestResource());
244 } catch (CoreException e
) {
246 Comparator
<IResource
> comparator
= new Comparator
<IResource
>() {
248 public int compare(IResource o1
, IResource o2
) {
249 return o1
.getFullPath().toString().compareTo(o2
.getFullPath().toString());
252 Collections
.sort(list
, comparator
);
260 public @NonNull Image
getIcon() {
261 Image icon
= super.getIcon();
262 return (icon
== null ? TmfProjectModelIcons
.DEFAULT_EXPERIMENT_ICON
: icon
);
269 public String
getLabelText() {
270 return getName() + " [" + getTraces().size() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
273 // ------------------------------------------------------------------------
275 // ------------------------------------------------------------------------
278 * Refreshes the trace type filed by reading the trace type persistent
279 * property of the resource reference.
281 * If trace type is null after refresh, set it to the generic trace type
282 * (for seamless upgrade)
285 public void refreshTraceType() {
286 super.refreshTraceType();
287 if (getTraceType() == null) {
288 IConfigurationElement ce
= TmfTraceType
.getTraceAttributes(TmfTraceType
.DEFAULT_EXPERIMENT_TYPE
);
291 IFolder experimentFolder
= getResource();
292 experimentFolder
.setPersistentProperty(TmfCommonConstants
.TRACETYPE
, ce
.getAttribute(TmfTraceType
.ID_ATTR
));
293 super.refreshTraceType();
294 } catch (InvalidRegistryObjectException
| CoreException e
) {
301 * Returns a list of TmfTraceElements contained in this experiment.
303 * @return a list of TmfTraceElements
306 public List
<TmfTraceElement
> getTraces() {
307 List
<ITmfProjectModelElement
> children
= getChildren();
308 List
<TmfTraceElement
> traces
= new ArrayList
<>();
309 for (ITmfProjectModelElement child
: children
) {
310 if (child
instanceof TmfTraceElement
) {
311 traces
.add((TmfTraceElement
) child
);
318 * Adds a trace to the experiment
321 * The trace element to add
323 public void addTrace(TmfTraceElement trace
) {
324 addTrace(trace
, true);
328 * Adds a trace to the experiment
331 * The trace element to add
333 * Flag for refreshing the project
335 public void addTrace(TmfTraceElement trace
, boolean refresh
) {
337 * Create a link to the actual trace and set the trace type
339 IFolder experiment
= getResource();
340 IResource resource
= trace
.getResource();
341 IPath location
= resource
.getLocation();
342 IWorkspace workspace
= ResourcesPlugin
.getWorkspace();
344 String traceTypeId
= TmfTraceType
.getTraceTypeId(trace
.getResource());
345 TraceTypeHelper traceType
= TmfTraceType
.getTraceType(traceTypeId
);
347 if (resource
instanceof IFolder
) {
348 IFolder folder
= experiment
.getFolder(trace
.getElementPath());
349 TraceUtils
.createFolder((IFolder
) folder
.getParent(), new NullProgressMonitor());
350 IStatus result
= workspace
.validateLinkLocation(folder
, location
);
351 if (result
.isOK() || result
.matches(IStatus
.INFO
| IStatus
.WARNING
)) {
352 folder
.createLink(location
, IResource
.REPLACE
, null);
353 if (traceType
!= null) {
354 TmfTraceTypeUIUtils
.setTraceType(folder
, traceType
, refresh
);
358 Activator
.getDefault().logError("Error creating link. Invalid trace location " + location
); //$NON-NLS-1$
361 IFile file
= experiment
.getFile(trace
.getElementPath());
362 TraceUtils
.createFolder((IFolder
) file
.getParent(), new NullProgressMonitor());
363 IStatus result
= workspace
.validateLinkLocation(file
, location
);
364 if (result
.isOK() || result
.matches(IStatus
.INFO
| IStatus
.WARNING
)) {
365 file
.createLink(location
, IResource
.REPLACE
, null);
366 if (traceType
!= null) {
367 TmfTraceTypeUIUtils
.setTraceType(file
, traceType
, refresh
);
370 Activator
.getDefault().logError("Error creating link. Invalid trace location " + location
); //$NON-NLS-1$
373 } catch (CoreException e
) {
374 Activator
.getDefault().logError("Error creating link to location " + location
, e
); //$NON-NLS-1$
380 * Removes a trace from an experiment
383 * The trace to remove
384 * @throws CoreException
387 public void removeTrace(TmfTraceElement trace
) throws CoreException
{
389 // Close editors in UI Thread
390 Display
.getDefault().syncExec(new Runnable() {
397 /* Finally, remove the trace from experiment */
399 deleteTraceResource(trace
.getResource());
400 deleteSupplementaryResources();
403 private void deleteTraceResource(IResource resource
) throws CoreException
{
404 resource
.delete(true, null);
405 IContainer parent
= resource
.getParent();
406 // delete empty folders up to the parent experiment folder
407 if (!parent
.equals(getResource()) && parent
.members().length
== 0) {
408 deleteTraceResource(parent
);
413 public IFile
createBookmarksFile() throws CoreException
{
414 return createBookmarksFile(getProject().getExperimentsFolder().getResource(), ITmfEventsEditorConstants
.EXPERIMENT_EDITOR_INPUT_TYPE
);
418 public String
getEditorId() {
419 /* See if a default editor was set for this experiment type */
420 if (getTraceType() != null) {
421 IConfigurationElement ce
= TRACE_TYPE_UI_ATTRIBUTES
.get(getTraceType());
423 IConfigurationElement
[] defaultEditorCE
= ce
.getChildren(TmfTraceTypeUIUtils
.DEFAULT_EDITOR_ELEM
);
424 if (defaultEditorCE
.length
== 1) {
425 return defaultEditorCE
[0].getAttribute(TmfTraceType
.ID_ATTR
);
430 /* No default editor, try to find a common editor for all traces */
431 final List
<TmfTraceElement
> traceEntries
= getTraces();
432 String commonEditorId
= null;
434 for (TmfTraceElement element
: traceEntries
) {
435 // If all traces use the same editorId, use it, otherwise use the
437 final String editorId
= element
.getEditorId();
438 if (commonEditorId
== null) {
439 commonEditorId
= (editorId
!= null) ? editorId
: TmfEventsEditor
.ID
;
440 } else if (!commonEditorId
.equals(editorId
)) {
441 commonEditorId
= TmfEventsEditor
.ID
;
448 * Instantiate a {@link TmfExperiment} object based on the experiment type
449 * and the corresponding extension.
451 * @return the {@link TmfExperiment} or <code>null</code> for an error
454 public TmfExperiment
instantiateTrace() {
457 // make sure that supplementary folder exists
458 refreshSupplementaryFolder();
460 if (getTraceType() != null) {
462 IConfigurationElement ce
= TRACE_TYPE_ATTRIBUTES
.get(getTraceType());
466 TmfExperiment experiment
= (TmfExperiment
) ce
.createExecutableExtension(TmfTraceType
.EXPERIMENT_TYPE_ATTR
);
469 } catch (CoreException e
) {
470 Activator
.getDefault().logError(NLS
.bind(Messages
.TmfExperimentElement_ErrorInstantiatingTrace
, getName()), e
);
476 public String
getTypeName() {
477 return Messages
.TmfExperimentElement_TypeName
;
480 // ------------------------------------------------------------------------
482 // ------------------------------------------------------------------------
485 public Object
getEditableValue() {
490 public IPropertyDescriptor
[] getPropertyDescriptors() {
491 return Arrays
.copyOf(DESCRIPTORS
, DESCRIPTORS
.length
);
495 public Object
getPropertyValue(Object id
) {
497 if (NAME
.equals(id
)) {
501 if (PATH
.equals(id
)) {
502 return getPath().toString();
505 if (LOCATION
.equals(id
)) {
506 return getLocation().toString();
509 if (EXPERIMENT_TYPE
.equals(id
)) {
510 if (getTraceType() != null) {
511 IConfigurationElement ce
= TRACE_TYPE_ATTRIBUTES
.get(getTraceType());
513 return ""; //$NON-NLS-1$
515 String categoryId
= ce
.getAttribute(TmfTraceType
.CATEGORY_ATTR
);
516 if (categoryId
!= null) {
517 IConfigurationElement category
= TRACE_CATEGORIES
.get(categoryId
);
518 if (category
!= null) {
519 return category
.getAttribute(TmfTraceType
.NAME_ATTR
) + ':' + ce
.getAttribute(TmfTraceType
.NAME_ATTR
);
522 return ce
.getAttribute(TmfTraceType
.NAME_ATTR
);
525 if (EXPERIMENT_TYPE_ID
.equals(id
)) {
526 if (getTraceType() != null) {
527 IConfigurationElement ce
= TRACE_TYPE_ATTRIBUTES
.get(getTraceType());
529 return ""; //$NON-NLS-1$
531 return ce
.getAttribute(TmfTraceType
.ID_ATTR
);
539 public void resetPropertyValue(Object id
) {
543 public void setPropertyValue(Object id
, Object value
) {
547 public boolean isPropertyResettable(Object id
) {
552 public boolean isPropertySet(Object id
) {
557 * Return the suffix for resource names
559 * @return The folder suffix
562 public String
getSuffix() {
563 return FOLDER_SUFFIX
;