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
.requirements
;
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
.jdt
.annotation
.Nullable
;
24 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTraceWithPreDefinedEvents
;
26 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfEventTypeCollectionHelper
;
29 * Class that contains all the values associated with a type needed by an
30 * analysis in order to execute. Each value is peered with a level that
31 * determines the importance of that specific value for the requirement.
33 * The type gives an indication about the kind of value the requirement
34 * contains. The value should depend on the type. For instance, a requirement
35 * type could be "event" and all the values that would be added in the
36 * requirement object could indicate the possible events handled by the
39 * For these values, a level will be assigned indicating how important the value
40 * is based on two possibilities: Mandatory or optional.
42 * Moreover, useful information that can not be leveled with a priority but are
43 * important for the proper execution of an analysis can be added.
45 * @author Guilliano Molaire
46 * @author Mathieu Rail
49 public class TmfAnalysisRequirement
{
52 * String for requirement type 'event', that can be used by analysis
54 public static final String TYPE_EVENT
= "event"; //$NON-NLS-1$
56 private final String fType
;
57 private final Map
<String
, @NonNull ValuePriorityLevel
> fValues
= new HashMap
<>();
58 private final Set
<@NonNull String
> fInformation
= new HashSet
<>();
61 * The possible level for each value. They must be listed in ascending order
64 public enum ValuePriorityLevel
{
65 /** The value could be absent and the analysis would still work */
67 /** The value must be present at runtime (for the analysis) */
75 * The type of the requirement
77 public TmfAnalysisRequirement(String type
) {
82 * Constructor. Instantiate a requirement object with a list of values of
86 * The type of the requirement
88 * All the values associated with that type
90 * A level associated with all the values
92 public TmfAnalysisRequirement(String type
, Iterable
<String
> values
, ValuePriorityLevel level
) {
94 addValues(values
, level
);
98 * Merges the values of the specified requirement with those of this
99 * requirement. All new values will retain their priority value level. If a
100 * value was already inside the current requirement, the current priority
101 * level will be overridden if the new priority level is higher.
103 * @param subRequirement
104 * The requirement to be merged into the current one
105 * @param maxSubRequirementValueLevel
106 * The level associated with all the new values or currently
107 * lower priority ones
108 * @return True if the merge was successful
110 public Boolean
merge(TmfAnalysisRequirement subRequirement
, ValuePriorityLevel maxSubRequirementValueLevel
) {
111 /* Two requirements can't be merged if their types are different */
112 if (!isSameType(subRequirement
)) {
116 Set
<String
> values
= subRequirement
.getValues();
117 for (String value
: values
) {
119 * Sub-requirement value levels are limited to
120 * maxSubRequirementValueLevel, so the level associated with the
121 * values in the merge is the minimum value between
122 * maxSubRequirementValueLevel and its true level.
124 ValuePriorityLevel valueLevel
= subRequirement
.getValueLevel(value
);
125 if (valueLevel
== null) {
126 throw new NullPointerException();
128 int minLevel
= Math
.min(valueLevel
.ordinal(), maxSubRequirementValueLevel
.ordinal());
129 ValuePriorityLevel subRequirementValueLevel
= ValuePriorityLevel
.values()[minLevel
];
131 if (fValues
.containsKey(value
)) {
133 * If a value is already in a requirement, we update the level
134 * by the highest value between the current level in the
135 * requirement and the level of the value in the
138 ValuePriorityLevel requirementValueLevel
= getValueLevel(value
);
139 if (requirementValueLevel
== null) {
140 throw new NullPointerException();
143 int newValueLevel
= Math
.max(requirementValueLevel
.ordinal(), subRequirementValueLevel
.ordinal());
144 ValuePriorityLevel highestLevel
= ValuePriorityLevel
.values()[newValueLevel
];
145 addValue(value
, highestLevel
);
148 addValue(value
, subRequirementValueLevel
);
152 /* Merge the information */
153 fInformation
.addAll(subRequirement
.getInformation());
159 * Adds a list of value inside the requirement with the same level.
164 * The level associated with all the values
166 public void addValues(Iterable
<String
> values
, ValuePriorityLevel level
) {
167 for (String value
: values
) {
168 addValue(value
, level
);
173 * Adds a value with his associated level into the requirement. If the value
174 * is already contained in the requirement the method modifies its existing
182 public void addValue(String value
, ValuePriorityLevel level
) {
183 synchronized (fValues
) {
184 fValues
.put(value
, level
);
189 * Adds an information about the requirement.
192 * The information to be added
194 public void addInformation(String information
) {
195 fInformation
.add(information
);
199 * Determines if the analysis requirement has the same type of another
203 * Requirement whose type is to be compared to this requirement's
205 * @return True if the two requirements have the same type; otherwise false
207 public Boolean
isSameType(TmfAnalysisRequirement requirement
) {
208 return fType
.equals(requirement
.getType());
212 * Gets the requirement type. The type is read only.
214 * @return The type of this requirement
216 public String
getType() {
221 * Gets all the values associated with the requirement.
223 * @return Set containing the values
225 public Set
<String
> getValues() {
226 synchronized (fValues
) {
227 return fValues
.keySet();
232 * Gets all the values associated with the requirement with a given priority
237 * @return Set containing the values with the given priority level
239 public Set
<String
> getValues(ValuePriorityLevel level
) {
240 synchronized (fValues
) {
241 Set
<String
> values
= new HashSet
<>();
242 for (Entry
<String
, ValuePriorityLevel
> entry
: fValues
.entrySet()) {
243 if (entry
.getValue() == level
) {
244 values
.add(entry
.getKey());
252 * Gets information about the requirement.
254 * @return The set of all the information
256 public Set
<@NonNull String
> getInformation() {
261 * Gets the level associated with a particular type
265 * @return The level or null if the value does not exist
267 public @Nullable ValuePriorityLevel
getValueLevel(String value
) {
268 synchronized (fValues
) {
269 return fValues
.get(value
);
274 * Verifies whether a trace fulfills this requirement
277 * The trace on which to check for this requirement
278 * @return True if the trace has all mandatory values of this requirement
280 public boolean isFulfilled(ITmfTrace trace
) {
283 if (trace
instanceof ITmfTraceWithPreDefinedEvents
) {
284 Set
<String
> traceEvents
= TmfEventTypeCollectionHelper
.getEventNames(((ITmfTraceWithPreDefinedEvents
) trace
).getContainedEventTypes());
285 Set
<String
> mandatoryValues
= getValues(ValuePriorityLevel
.MANDATORY
);
286 return traceEvents
.containsAll(mandatoryValues
);
296 public String
toString() {
297 return fType
+ ": " + fValues
; //$NON-NLS-1$