1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 Ecole Polytechnique de Montreal
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 * Florian Wininger - Initial API and implementation
11 ******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.model
;
15 import java
.util
.List
;
17 import org
.eclipse
.jdt
.annotation
.NonNull
;
18 import org
.eclipse
.jdt
.annotation
.Nullable
;
19 import org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.Activator
;
20 import org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.module
.IXmlStateSystemContainer
;
21 import org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.stateprovider
.TmfXmlStrings
;
22 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
23 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
24 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateValueTypeException
;
25 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
26 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
28 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
29 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventField
;
30 import org
.eclipse
.tracecompass
.tmf
.core
.event
.aspect
.TmfCpuAspect
;
31 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
32 import org
.w3c
.dom
.Element
;
35 * This Class implements a State Value in the XML-defined state system, along
36 * with the path to get to the value (either a list of state attributes or an
41 * <stateAttribute type="location" value="CurrentThread" />
42 * <stateAttribute type="constant" value="System_call" />
43 * <stateValue type="null" />
46 * @author Florian Wininger
48 public abstract class TmfXmlStateValue
implements ITmfXmlStateValue
{
50 private final TmfXmlStateValueBase fStateValue
;
52 /* Path in the State System */
53 private final List
<ITmfXmlStateAttribute
> fPath
;
54 /* Event field to match with this state value */
55 private final @Nullable String fEventField
;
57 /* Whether this state value is an increment of the previous value */
58 private final boolean fIncrement
;
59 /* Whether to update the current attribute or create a new state */
60 private final boolean fUpdate
;
62 private final ValueTypeStack fStackType
;
63 /* Forced value type */
64 private final ITmfStateValue
.Type fForcedType
;
66 private final IXmlStateSystemContainer fContainer
;
69 * Different behaviors of an attribute that is to be stacked
71 protected enum ValueTypeStack
{
74 /** Peek at the value at the top of the stack */
76 /** Take the value at the top of the stack */
78 /** Push the value on the stack */
82 * Get the type stack value corresponding to a string
85 * The string to match to a value
86 * @return The ValueTypeStack value
88 public static ValueTypeStack
getTypeFromString(String input
) {
90 case TmfXmlStrings
.STACK_PUSH
:
92 case TmfXmlStrings
.STACK_POP
:
94 case TmfXmlStrings
.STACK_PEEK
:
105 * @param modelFactory
106 * The factory used to create XML model elements
108 * The state value XML element
110 * The state system container this state value belongs to
112 * The event field where to get the value
114 * The attributes representing the path to this value
116 protected TmfXmlStateValue(ITmfXmlModelFactory modelFactory
, Element node
, IXmlStateSystemContainer container
, List
<ITmfXmlStateAttribute
> attributes
, @Nullable String eventField
) {
118 fContainer
= container
;
119 fEventField
= eventField
;
120 if (!node
.getNodeName().equals(TmfXmlStrings
.STATE_VALUE
)) {
121 throw new IllegalArgumentException("TmfXmlStateValue constructor: Element is not a stateValue"); //$NON-NLS-1$
124 /* Check if there is an increment for the value */
125 fIncrement
= Boolean
.parseBoolean(node
.getAttribute(TmfXmlStrings
.INCREMENT
));
127 /* Check if this value is an update of the ongoing state */
128 fUpdate
= Boolean
.parseBoolean(node
.getAttribute(TmfXmlStrings
.UPDATE
));
130 /* Process the XML Element state value */
131 fStateValue
= initializeStateValue(modelFactory
, node
);
134 * Forced type allows to convert the value to a certain type : For
135 * example, a process's TID in an event field may arrive with a LONG
136 * format but we want to store the data in an INT
138 switch (node
.getAttribute(TmfXmlStrings
.FORCED_TYPE
)) {
139 case TmfXmlStrings
.TYPE_STRING
:
140 fForcedType
= ITmfStateValue
.Type
.STRING
;
142 case TmfXmlStrings
.TYPE_INT
:
143 fForcedType
= ITmfStateValue
.Type
.INTEGER
;
145 case TmfXmlStrings
.TYPE_LONG
:
146 fForcedType
= ITmfStateValue
.Type
.LONG
;
148 case TmfXmlStrings
.TYPE_DOUBLE
:
149 fForcedType
= ITmfStateValue
.Type
.DOUBLE
;
152 fForcedType
= ITmfStateValue
.Type
.NULL
;
156 * Stack Actions : allow to define a stack with PUSH/POP/PEEK methods
158 String stack
= node
.getAttribute(TmfXmlStrings
.ATTRIBUTE_STACK
);
159 fStackType
= ValueTypeStack
.getTypeFromString(stack
);
163 * Initialize a {@link TmfXmlStateValueBase} object for the type and value
165 * @param modelFactory
166 * The factory used to create XML model elements
168 * The state value XML element
169 * @return The internal state value type corresponding to this state value
171 protected TmfXmlStateValueBase
initializeStateValue(ITmfXmlModelFactory modelFactory
, Element node
) {
172 return new TmfXmlStateValueNull();
176 * Return the state system container this class is attached to
178 * @return The state system container
180 protected IXmlStateSystemContainer
getSsContainer() {
185 * Get the state system associated with this value's container
187 * @return The state system associated with the state system container
189 protected @Nullable ITmfStateSystem
getStateSystem() {
190 return fContainer
.getStateSystem();
194 * Return whether this value is an increment of the previous value
196 * @return <code>true</code> if the value is an increment
198 protected boolean isIncrement() {
203 * Return whether this value should replace the current value of the
204 * attribute or if a new state should be created.
206 * @return <code>true</code> if the value is to replace the current one
208 protected boolean isUpdate() {
213 * Get the stack type of this attribute. If the attribute is to be pushed or
214 * popped to a stack. The behavior of the stack attribute will depend on the
215 * implementation of the model.
217 * @return The stack type of the attribute
219 protected ValueTypeStack
getStackType() {
224 * Get the forced type of the value. For example, if the value obtained from
225 * the attributes is not in this forced type, it will be converted to this.
227 * @return The desired type of the value
229 protected ITmfStateValue
.Type
getForcedType() {
234 public ITmfStateValue
getValue(@Nullable ITmfEvent event
, @Nullable TmfXmlScenarioInfo scenarioInfo
) throws AttributeNotFoundException
{
235 return fStateValue
.getValue(event
, scenarioInfo
);
239 * Get the value of the event field that is the path of this state value
243 * @return the value of the event field
246 public ITmfStateValue
getEventFieldValue(@NonNull ITmfEvent event
) {
247 String eventField
= fEventField
;
248 if (eventField
== null) {
249 throw new IllegalStateException();
251 return getEventFieldValue(event
, eventField
);
255 * Get the value of an event field
260 * The name of the field of which to get the value
261 * @return The value of the event field
263 protected ITmfStateValue
getEventFieldValue(ITmfEvent event
, String fieldName
) {
265 ITmfStateValue value
= TmfStateValue
.nullValue();
267 final ITmfEventField field
= event
.getContent().getField(fieldName
);
269 /* If the field does not exist, see if it's a special case */
272 if (fieldName
.equalsIgnoreCase(TmfXmlStrings
.CPU
)) {
273 /* A "CPU" field will return the CPU aspect if available */
274 Integer cpu
= TmfTraceUtils
.resolveIntEventAspectOfClassForEvent(event
.getTrace(), TmfCpuAspect
.class, event
);
276 return TmfStateValue
.newValueInt(cpu
.intValue());
278 } else if (fieldName
.equalsIgnoreCase(TmfXmlStrings
.TIMESTAMP
)) {
280 * Exception also for "TIMESTAMP", returns the timestamp of this
283 return TmfStateValue
.newValueLong(event
.getTimestamp().getValue());
288 Object fieldValue
= field
.getValue();
291 * Try to find the right type. The type can be forced by
292 * "forcedType" argument.
295 if (fieldValue
instanceof String
) {
296 String fieldString
= (String
) fieldValue
;
298 switch (fForcedType
) {
300 value
= TmfStateValue
.newValueInt(Integer
.parseInt(fieldString
));
303 value
= TmfStateValue
.newValueLong(Long
.parseLong(fieldString
));
306 value
= TmfStateValue
.newValueDouble(Double
.parseDouble(fieldString
));
309 throw new IllegalStateException("Custom type cannot be forced"); //$NON-NLS-1$
313 value
= TmfStateValue
.newValueString(fieldString
);
316 } else if (fieldValue
instanceof Long
) {
317 Long fieldLong
= (Long
) fieldValue
;
319 switch (fForcedType
) {
321 value
= TmfStateValue
.newValueInt(fieldLong
.intValue());
324 value
= TmfStateValue
.newValueString(fieldLong
.toString());
327 value
= TmfStateValue
.newValueDouble(fieldLong
.doubleValue());
330 throw new IllegalStateException("Custom type cannot be forced"); //$NON-NLS-1$
334 value
= TmfStateValue
.newValueLong(fieldLong
);
337 } else if (fieldValue
instanceof Integer
) {
338 Integer fieldInteger
= (Integer
) fieldValue
;
340 switch (fForcedType
) {
342 value
= TmfStateValue
.newValueLong(fieldInteger
.longValue());
345 value
= TmfStateValue
.newValueString(fieldInteger
.toString());
348 value
= TmfStateValue
.newValueDouble(fieldInteger
.doubleValue());
351 throw new IllegalStateException("Custom type cannot be forced"); //$NON-NLS-1$
355 value
= TmfStateValue
.newValueInt(fieldInteger
);
358 } else if (fieldValue
instanceof Double
) {
359 Double fieldDouble
= (Double
) fieldValue
;
361 switch (fForcedType
) {
363 value
= TmfStateValue
.newValueLong(fieldDouble
.longValue());
366 value
= TmfStateValue
.newValueString(fieldDouble
.toString());
369 value
= TmfStateValue
.newValueInt(fieldDouble
.intValue());
372 throw new IllegalStateException("Custom type cannot be forced"); //$NON-NLS-1$
376 value
= TmfStateValue
.newValueDouble(fieldDouble
);
384 * Get the list of state attributes, the path to the state value
386 * @return the list of Attribute to have the path in the State System
389 public List
<ITmfXmlStateAttribute
> getAttributes() {
394 public void handleEvent(@NonNull ITmfEvent event
, @Nullable TmfXmlScenarioInfo scenarioInfo
) throws AttributeNotFoundException
, StateValueTypeException
, TimeRangeException
{
395 int quark
= IXmlStateSystemContainer
.ROOT_QUARK
;
397 for (ITmfXmlStateAttribute attribute
: fPath
) {
398 quark
= attribute
.getAttributeQuark(event
, quark
, scenarioInfo
);
399 /* the query is not valid, we stop the state change */
400 if (quark
== IXmlStateSystemContainer
.ERROR_QUARK
) {
401 Activator
.logError("Not found XML attribute " + attribute
); //$NON-NLS-1$
406 long ts
= event
.getTimestamp().getValue();
407 fStateValue
.handleEvent(event
, quark
, ts
, scenarioInfo
);
411 public String
toString() {
412 StringBuilder builder
= new StringBuilder("TmfXmlStateValue: "); //$NON-NLS-1$
413 if (fEventField
!= null) {
414 builder
.append("Field=").append(fEventField
).append("; "); //$NON-NLS-1$ //$NON-NLS-2$
415 } else if (!fPath
.isEmpty()) {
416 builder
.append("Path=").append(fPath
).append("; "); //$NON-NLS-1$ //$NON-NLS-2$
418 builder
.append(fStateValue
);
419 return builder
.toString();
423 * Base class for all state values. Contain default methods to handle event,
424 * process or increment the value
426 protected abstract class TmfXmlStateValueBase
{
429 * Get the value associated with this state value.
432 * The event which can be used to retrieve the value if
433 * necessary. The event can be <code>null</code> if no event
435 * @param scenarioInfo
436 * The active scenario details. The value should be null if
438 * @return The state value corresponding to this XML state value
439 * @throws AttributeNotFoundException
440 * Pass through the exception it received
442 public abstract ITmfStateValue
getValue(@Nullable ITmfEvent event
, @Nullable TmfXmlScenarioInfo scenarioInfo
) throws AttributeNotFoundException
;
445 * Do something with the state value, possibly using an event
448 * The event being handled. If there is no event is
449 * available, use <code>null</code>.
451 * The quark for this value
453 * The timestamp of the event
454 * @param scenarioInfo
455 * The active scenario details. The value should be null if
457 * @throws StateValueTypeException
458 * Pass through the exception it received
459 * @throws TimeRangeException
460 * Pass through the exception it received
461 * @throws AttributeNotFoundException
462 * Pass through the exception it received
464 public void handleEvent(ITmfEvent event
, int quark
, long timestamp
, @Nullable TmfXmlScenarioInfo scenarioInfo
) throws StateValueTypeException
, TimeRangeException
, AttributeNotFoundException
{
466 incrementValue(event
, quark
, timestamp
, scenarioInfo
);
468 ITmfStateValue value
= getValue(event
, scenarioInfo
);
469 processValue(quark
, timestamp
, value
);
474 * Set the value of a quark at a given timestamp.
477 * The quark for this value
481 * The value of this state value
482 * @throws TimeRangeException
483 * Pass through the exception it received
484 * @throws StateValueTypeException
485 * Pass through the exception it received
486 * @throws AttributeNotFoundException
487 * Pass through the exception it received
489 @SuppressWarnings("unused")
490 protected void processValue(int quark
, long timestamp
, ITmfStateValue value
) throws TimeRangeException
, StateValueTypeException
, AttributeNotFoundException
{
494 * Increments the value of the parameter
497 * The event being handled
499 * The quark for this value
501 * The timestamp of the event
502 * @param scenarioInfo
503 * The active scenario details. The value should be null if
505 * @throws StateValueTypeException
506 * Pass through the exception it received
507 * @throws TimeRangeException
508 * Pass through the exception it received
509 * @throws AttributeNotFoundException
510 * Pass through the exception it received
512 @SuppressWarnings("unused")
513 protected void incrementValue(ITmfEvent event
, int quark
, long timestamp
, @Nullable TmfXmlScenarioInfo scenarioInfo
) throws StateValueTypeException
, TimeRangeException
, AttributeNotFoundException
{
517 /* This state value uses a constant value, defined in the XML */
518 private class TmfXmlStateValueNull
extends TmfXmlStateValueBase
{
521 public ITmfStateValue
getValue(@Nullable ITmfEvent event
, @Nullable TmfXmlScenarioInfo scenarioInfo
) throws AttributeNotFoundException
{
522 return TmfStateValue
.nullValue();
526 public String
toString() {
527 return "NULL"; //$NON-NLS-1$