1 /*******************************************************************************
2 * Copyright (c) 2014 É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 * Mathieu Rail - Initial API and implementation
11 * Guilliano Molaire - Initial API and implementation
12 *******************************************************************************/
14 package org
.eclipse
.tracecompass
.tmf
.core
.analysis
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
19 import java
.util
.Map
.Entry
;
22 import org
.eclipse
.jdt
.annotation
.NonNull
;
23 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
24 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTraceWithPreDefinedEvents
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfEventTypeCollectionHelper
;
28 * Class that contains all the values associated with a type needed by an
29 * analysis in order to execute. Each value is peered with a level that
30 * determines the importance of that specific value for the requirement.
32 * The type gives an indication about the kind of value the requirement
33 * contains. The value should depend on the type. For instance, a requirement
34 * type could be "event" and all the values that would be added in the
35 * requirement object could indicate the possible events handled by the
38 * For these values, a level will be assigned indicating how important the value
39 * is based on two possibilities: Mandatory or optional.
41 * Moreover, useful information that can not be leveled with a priority but are
42 * important for the proper execution of an analysis can be added.
44 * @author Guilliano Molaire
45 * @author Mathieu Rail
47 public class TmfAnalysisRequirement
{
50 * String for requirement type 'event', that can be used by analysis
52 public static final String TYPE_EVENT
= "event"; //$NON-NLS-1$
54 private final String fType
;
55 private final Map
<String
, ValuePriorityLevel
> fValues
= new HashMap
<>();
56 private final Set
<String
> fInformation
= new HashSet
<>();
59 * The possible level for each value. They must be listed in ascending order
62 public enum ValuePriorityLevel
{
63 /** The value could be absent and the analysis would still work */
65 /** The value must be present at runtime (for the analysis) */
73 * The type of the requirement
75 public TmfAnalysisRequirement(String type
) {
80 * Constructor. Instantiate a requirement object with a list of values of
84 * The type of the requirement
86 * All the values associated with that type
88 * A level associated with all the values
90 public TmfAnalysisRequirement(String type
, Iterable
<String
> values
, ValuePriorityLevel level
) {
92 addValues(values
, level
);
96 * Merges the values of the specified requirement with those of this
97 * requirement. All new values will retain their priority value level. If a
98 * value was already inside the current requirement, the current priority
99 * level will be overridden if the new priority level is higher.
101 * @param subRequirement
102 * The requirement to be merged into the current one
103 * @param maxSubRequirementValueLevel
104 * The level associated with all the new values or currently
105 * lower priority ones
106 * @return True if the merge was successful
108 public Boolean
merge(TmfAnalysisRequirement subRequirement
, ValuePriorityLevel maxSubRequirementValueLevel
) {
109 /* Two requirements can't be merged if their types are different */
110 if (!isSameType(subRequirement
)) {
114 Set
<String
> values
= subRequirement
.getValues();
115 for (String value
: values
) {
117 * Sub-requirement value levels are limited to
118 * maxSubRequirementValueLevel, so the level associated with the
119 * values in the merge is the minimum value between
120 * maxSubRequirementValueLevel and its true level.
122 int minLevel
= Math
.min(subRequirement
.getValueLevel(value
).ordinal(), maxSubRequirementValueLevel
.ordinal());
123 ValuePriorityLevel subRequirementValueLevel
= ValuePriorityLevel
.values()[minLevel
];
125 if (fValues
.containsKey(value
)) {
127 * If a value is already in a requirement, we update the level
128 * by the highest value between the current level in the
129 * requirement and the level of the value in the
132 ValuePriorityLevel requirementValueLevel
= getValueLevel(value
);
134 int newValueLevel
= Math
.max(requirementValueLevel
.ordinal(), subRequirementValueLevel
.ordinal());
135 ValuePriorityLevel highestLevel
= ValuePriorityLevel
.values()[newValueLevel
];
136 addValue(value
, highestLevel
);
139 addValue(value
, subRequirementValueLevel
);
143 /* Merge the information */
144 fInformation
.addAll(subRequirement
.getInformation());
150 * Adds a list of value inside the requirement with the same level.
155 * The level associated with all the values
157 public void addValues(Iterable
<String
> values
, ValuePriorityLevel level
) {
158 for (String value
: values
) {
159 addValue(value
, level
);
164 * Adds a value with his associated level into the requirement. If the value
165 * is already contained in the requirement the method modifies its existing
173 public void addValue(String value
, ValuePriorityLevel level
) {
174 synchronized (fValues
) {
175 fValues
.put(value
, level
);
180 * Adds an information about the requirement.
183 * The information to be added
185 public void addInformation(String information
) {
186 fInformation
.add(information
);
190 * Determines if the analysis requirement has the same type of another
194 * Requirement whose type is to be compared to this requirement's
196 * @return True if the two requirements have the same type; otherwise false
198 public Boolean
isSameType(TmfAnalysisRequirement requirement
) {
199 return fType
.equals(requirement
.getType());
203 * Gets the requirement type. The type is read only.
205 * @return The type of this requirement
207 public String
getType() {
212 * Gets all the values associated with the requirement.
214 * @return Set containing the values
216 public Set
<String
> getValues() {
217 synchronized (fValues
) {
218 return fValues
.keySet();
223 * Gets all the values associated with the requirement with a given priority
228 * @return Set containing the values with the given priority level
230 public Set
<String
> getValues(ValuePriorityLevel level
) {
231 synchronized (fValues
) {
232 Set
<String
> values
= new HashSet
<>();
233 for (Entry
<String
, ValuePriorityLevel
> entry
: fValues
.entrySet()) {
234 if (entry
.getValue() == level
) {
235 values
.add(entry
.getKey());
243 * Gets information about the requirement.
245 * @return The set of all the information
247 public Set
<String
> getInformation() {
252 * Gets the level associated with a particular type
256 * @return The level or null if the value does not exist
258 public ValuePriorityLevel
getValueLevel(String value
) {
259 synchronized (fValues
) {
260 return fValues
.get(value
);
265 * Verifies whether a trace fulfills this requirement
268 * The trace on which to check for this requirement
269 * @return True if the trace has all mandatory values of this requirement
271 public boolean isFulfilled(@NonNull ITmfTrace trace
) {
274 if (trace
instanceof ITmfTraceWithPreDefinedEvents
) {
275 Set
<String
> traceEvents
= TmfEventTypeCollectionHelper
.getEventNames(((ITmfTraceWithPreDefinedEvents
) trace
).getContainedEventTypes());
276 Set
<String
> mandatoryValues
= getValues(ValuePriorityLevel
.MANDATORY
);
277 return traceEvents
.containsAll(mandatoryValues
);
287 public String
toString() {
288 return fType
+ ": " + fValues
; //$NON-NLS-1$