c005442069dc5734ea76672fb81287ebe3a160ec
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / analysis / requirements / TmfAnalysisRequirement.java
1 /*******************************************************************************
2 * Copyright (c) 2014 École Polytechnique de Montréal
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 * Mathieu Rail - Initial API and implementation
11 * Guilliano Molaire - Initial API and implementation
12 *******************************************************************************/
13
14 package org.eclipse.tracecompass.tmf.core.analysis.requirements;
15
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Set;
21
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;
27
28 /**
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.
32 *
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
37 * analysis.
38 *
39 * For these values, a level will be assigned indicating how important the value
40 * is based on two possibilities: Mandatory or optional.
41 *
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.
44 *
45 * @author Guilliano Molaire
46 * @author Mathieu Rail
47 * @since 2.0
48 */
49 public class TmfAnalysisRequirement {
50
51 /**
52 * String for requirement type 'event', that can be used by analysis
53 */
54 public static final String TYPE_EVENT = "event"; //$NON-NLS-1$
55
56 private final String fType;
57 private final Map<String, @NonNull ValuePriorityLevel> fValues = new HashMap<>();
58 private final Set<@NonNull String> fInformation = new HashSet<>();
59
60 /**
61 * The possible level for each value. They must be listed in ascending order
62 * of priority.
63 */
64 public enum ValuePriorityLevel {
65 /** The value could be absent and the analysis would still work */
66 OPTIONAL,
67 /** The value must be present at runtime (for the analysis) */
68 MANDATORY
69 }
70
71 /**
72 * Constructor
73 *
74 * @param type
75 * The type of the requirement
76 */
77 public TmfAnalysisRequirement(String type) {
78 fType = type;
79 }
80
81 /**
82 * Constructor. Instantiate a requirement object with a list of values of
83 * the same level
84 *
85 * @param type
86 * The type of the requirement
87 * @param values
88 * All the values associated with that type
89 * @param level
90 * A level associated with all the values
91 */
92 public TmfAnalysisRequirement(String type, Iterable<String> values, ValuePriorityLevel level) {
93 fType = type;
94 addValues(values, level);
95 }
96
97 /**
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.
102 *
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
109 */
110 public Boolean merge(TmfAnalysisRequirement subRequirement, ValuePriorityLevel maxSubRequirementValueLevel) {
111 /* Two requirements can't be merged if their types are different */
112 if (!isSameType(subRequirement)) {
113 return false;
114 }
115
116 Set<String> values = subRequirement.getValues();
117 for (String value : values) {
118 /*
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.
123 */
124 ValuePriorityLevel valueLevel = subRequirement.getValueLevel(value);
125 if (valueLevel == null) {
126 throw new NullPointerException();
127 }
128 int minLevel = Math.min(valueLevel.ordinal(), maxSubRequirementValueLevel.ordinal());
129 ValuePriorityLevel subRequirementValueLevel = ValuePriorityLevel.values()[minLevel];
130
131 if (fValues.containsKey(value)) {
132 /*
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
136 * sub-requirement.
137 */
138 ValuePriorityLevel requirementValueLevel = getValueLevel(value);
139 if (requirementValueLevel == null) {
140 throw new NullPointerException();
141 }
142
143 int newValueLevel = Math.max(requirementValueLevel.ordinal(), subRequirementValueLevel.ordinal());
144 ValuePriorityLevel highestLevel = ValuePriorityLevel.values()[newValueLevel];
145 addValue(value, highestLevel);
146 }
147 else {
148 addValue(value, subRequirementValueLevel);
149 }
150 }
151
152 /* Merge the information */
153 fInformation.addAll(subRequirement.getInformation());
154
155 return true;
156 }
157
158 /**
159 * Adds a list of value inside the requirement with the same level.
160 *
161 * @param values
162 * A list of value
163 * @param level
164 * The level associated with all the values
165 */
166 public void addValues(Iterable<String> values, ValuePriorityLevel level) {
167 for (String value : values) {
168 addValue(value, level);
169 }
170 }
171
172 /**
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
175 * value level.
176 *
177 * @param value
178 * The value
179 * @param level
180 * The level
181 */
182 public void addValue(String value, ValuePriorityLevel level) {
183 synchronized (fValues) {
184 fValues.put(value, level);
185 }
186 }
187
188 /**
189 * Adds an information about the requirement.
190 *
191 * @param information
192 * The information to be added
193 */
194 public void addInformation(String information) {
195 fInformation.add(information);
196 }
197
198 /**
199 * Determines if the analysis requirement has the same type of another
200 * requirement.
201 *
202 * @param requirement
203 * Requirement whose type is to be compared to this requirement's
204 * type.
205 * @return True if the two requirements have the same type; otherwise false
206 */
207 public Boolean isSameType(TmfAnalysisRequirement requirement) {
208 return fType.equals(requirement.getType());
209 }
210
211 /**
212 * Gets the requirement type. The type is read only.
213 *
214 * @return The type of this requirement
215 */
216 public String getType() {
217 return fType;
218 }
219
220 /**
221 * Gets all the values associated with the requirement.
222 *
223 * @return Set containing the values
224 */
225 public Set<String> getValues() {
226 synchronized (fValues) {
227 return fValues.keySet();
228 }
229 }
230
231 /**
232 * Gets all the values associated with the requirement with a given priority
233 * level.
234 *
235 * @param level
236 * The desired level
237 * @return Set containing the values with the given priority level
238 */
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());
245 }
246 }
247 return values;
248 }
249 }
250
251 /**
252 * Gets information about the requirement.
253 *
254 * @return The set of all the information
255 */
256 public Set<@NonNull String> getInformation() {
257 return fInformation;
258 }
259
260 /**
261 * Gets the level associated with a particular type
262 *
263 * @param value
264 * The value
265 * @return The level or null if the value does not exist
266 */
267 public @Nullable ValuePriorityLevel getValueLevel(String value) {
268 synchronized (fValues) {
269 return fValues.get(value);
270 }
271 }
272
273 /**
274 * Verifies whether a trace fulfills this requirement
275 *
276 * @param trace
277 * The trace on which to check for this requirement
278 * @return True if the trace has all mandatory values of this requirement
279 */
280 public boolean isFulfilled(ITmfTrace trace) {
281 switch (fType) {
282 case TYPE_EVENT:
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);
287 }
288 break;
289 default:
290 return true;
291 }
292 return true;
293 }
294
295 @Override
296 public String toString() {
297 return fType + ": " + fValues; //$NON-NLS-1$
298 }
299 }
This page took 0.03703 seconds and 4 git commands to generate.