******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlLocation;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlPatternEventHandler;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlScenarioHistoryBuilder;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.readwrite.TmfXmlReadWriteModelFactory;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.XmlUtils;
import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
/**
* State provider for the pattern analysis
private final @NonNull String fStateId;
+ /** Map for defined values */
+ private final Map<String, String> fDefinedValues = new HashMap<>();
+
/** List of all Locations */
private final @NonNull Set<@NonNull TmfXmlLocation> fLocations;
+ /** Map for stored values */
+ private final @NonNull Map<@NonNull String, @NonNull String> fStoredFields = new HashMap<>();
+
+ private TmfXmlPatternEventHandler fHandler;
+
private final ISegmentListener fListener;
+ private final @NonNull TmfXmlScenarioHistoryBuilder fHistoryBuilder;
+
/**
* @param trace
* The active trace
fStateId = stateid;
fFilePath = file;
fListener = listener;
+ fHistoryBuilder = new TmfXmlScenarioHistoryBuilder();
final String pathString = fFilePath.makeAbsolute().toOSString();
Element doc = XmlUtils.getElementInFile(pathString, TmfXmlStrings.PATTERN, fStateId);
- fLocations = new HashSet<>();
if (doc == null) {
+ fLocations = new HashSet<>();
Activator.logError("Failed to find a pattern in " + pathString); //$NON-NLS-1$
return;
}
+
+ /* parser for defined Fields */
+ NodeList storedFieldNodes = doc.getElementsByTagName(TmfXmlStrings.STORED_FIELD);
+ for (int i = 0; i < storedFieldNodes.getLength(); i++) {
+ Element element = (Element) storedFieldNodes.item(i);
+ String key = element.getAttribute(TmfXmlStrings.ALIAS);
+ fStoredFields.put(element.getAttribute(TmfXmlStrings.ID), key.isEmpty() ? element.getAttribute(TmfXmlStrings.ID) : key);
+ }
+
+ /* parser for defined Values */
+ NodeList definedStateNodes = doc.getElementsByTagName(TmfXmlStrings.DEFINED_VALUE);
+ for (int i = 0; i < definedStateNodes.getLength(); i++) {
+ Element element = (Element) definedStateNodes.item(i);
+ fDefinedValues.put(element.getAttribute(TmfXmlStrings.NAME), element.getAttribute(TmfXmlStrings.VALUE));
+ }
+
+ ITmfXmlModelFactory modelFactory = TmfXmlReadWriteModelFactory.getInstance();
+ /* parser for the locations */
+ NodeList locationNodes = doc.getElementsByTagName(TmfXmlStrings.LOCATION);
+ final Set<@NonNull TmfXmlLocation> locations = new HashSet<>();
+ for (int i = 0; i < locationNodes.getLength(); i++) {
+ Element element = (Element) locationNodes.item(i);
+ if (element == null) {
+ continue;
+ }
+ TmfXmlLocation location = modelFactory.createLocation(element, this);
+ locations.add(location);
+ }
+ fLocations = Collections.unmodifiableSet(locations);
+
+ /* parser for the event handlers */
+ NodeList nodes = doc.getElementsByTagName(TmfXmlStrings.PATTERN_HANDLER);
+ fHandler = modelFactory.createPatternEventHandler(NonNullUtils.checkNotNull((Element) nodes.item(0)), this);
}
@Override
public String getAttributeValue(String name) {
- return null;
+ String attribute = name;
+ if (attribute.startsWith(TmfXmlStrings.VARIABLE_PREFIX)) {
+ /* search the attribute in the map without the fist character $ */
+ attribute = getDefinedValue(attribute.substring(1));
+ }
+ return attribute;
+ }
+
+ /**
+ * Get the defined value associated with a constant
+ *
+ * @param constant
+ * The constant defining this value
+ * @return The actual value corresponding to this constant
+ */
+ public String getDefinedValue(String constant) {
+ return fDefinedValues.get(constant);
+ }
+
+ /**
+ * Get the stored fiels map
+ *
+ * @return The map of stored fields
+ */
+ public @NonNull Map<@NonNull String, @NonNull String> getStoredFields() {
+ return fStoredFields;
}
@Override
@Override
protected void eventHandle(@NonNull ITmfEvent event) {
+ fHandler.handleEvent(event);
}
/**
@Override
public void dispose() {
+ waitForEmptyQueue();
fListener.onNewSegment(XmlPatternSegmentStoreModule.END_SEGMENT);
+ fHandler.dispose();
super.dispose();
}
-}
+
+ /**
+ * Get the history builder of this analysis
+ *
+ * @return The history builder
+ */
+ public @NonNull TmfXmlScenarioHistoryBuilder getHistoryBuilder() {
+ return fHistoryBuilder;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+
+/**
+ * Interface for an action behavior. An action is an output of the pattern.
+ * Basically something that the pattern needs to do if it reaches a given state.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public interface ITmfXmlAction {
+
+ /** The save stored fields action label */
+ String SAVE_STORED_FIELDS_STRING = "saveStoredFields"; //$NON-NLS-1$
+
+ /** The clear stored fields action label */
+ String CLEAR_STORED_FIELDS_STRING = "clearStoredFields"; //$NON-NLS-1$
+
+ /**
+ * Execute the action
+ *
+ * @param event
+ * The active event
+ * @param scenarioInfo
+ * The active scenario details. Or <code>null</code> if there is
+ * no scenario.
+ */
+ void execute(ITmfEvent event, TmfXmlScenarioInfo scenarioInfo);
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+
+/**
+ * Determines a true or false value for a given input. The input is an event and
+ * an optional scenarioInfo.
+ *
+ * @author Matthew Khouzam
+ * @since 2.0
+ */
+public interface ITmfXmlCondition {
+
+ /**
+ * Test the result of the condition for an event
+ *
+ * @param event
+ * The event on which to test the condition
+ * @param scenarioInfo
+ * The active scenario details. Or <code>null</code> if there is
+ * no scenario.
+ * @return Whether the condition is true or not
+ * @since 2.0
+ */
+ boolean test(ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo);
+
+}
\ No newline at end of file
import java.util.List;
+import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
import org.w3c.dom.Element;
*/
TmfXmlLocation createLocation(Element node, IXmlStateSystemContainer container);
+ /**
+ * Create a new XML pattern event handler
+ *
+ * @param node
+ * The XML pattern event handler element
+ * @param container
+ * The state system container this pattern event handler belongs to
+ * @return The new XML pattern event handler
+ * @since 2.0
+ */
+ TmfXmlPatternEventHandler createPatternEventHandler(Element node, IXmlStateSystemContainer container);
+
+ /**
+ * Create a new XML transition validator
+ *
+ * @param node
+ * The XML test element
+ * @param container
+ * The state system container this test belongs to
+ * @return The new {@link TmfXmlTransitionValidator}
+ * @since 2.0
+ */
+ TmfXmlTransitionValidator createTransitionValidator(Element node, IXmlStateSystemContainer container);
+
+ /**
+ * Create a new XML action
+ *
+ * @param node
+ * The XML action element
+ * @param container
+ * The state system container this action belongs to
+ * @return The new {@link TmfXmlAction}
+ * @since 2.0
+ */
+ TmfXmlAction createAction(Element node, IXmlStateSystemContainer container);
+
+ /**
+ * Create a new XML FSM
+ *
+ * @param node
+ * The XML FSM element
+ * @param container
+ * The state system container this FSM belongs to
+ * @return The new {@link TmfXmlFsm}
+ * @since 2.0
+ */
+ TmfXmlFsm createFsm(Element node, IXmlStateSystemContainer container);
+
+ /**
+ * Create a new XML state
+ *
+ * @param node
+ * The XML state element
+ * @param container
+ * The state system container this state belongs to
+ * @param parent
+ * The parent state
+ * @return The new {@link TmfXmlState}
+ * @since 2.0
+ */
+ TmfXmlState createState(Element node, IXmlStateSystemContainer container, @Nullable TmfXmlState parent);
+
+ /**
+ * Create a new XML state transition
+ *
+ * @param node
+ * The XML state transition element
+ * @param container
+ * The state system container this state transition belongs to
+ * @return The new XML {@link TmfXmlStateTransition}
+ * @since 2.0
+ */
+ TmfXmlStateTransition createStateTransition(Element node, IXmlStateSystemContainer container);
+
+ /**
+ * Create a new XML timestamp condition
+ *
+ * @param node
+ * The XML timestamp condition element
+ * @param container
+ * The state system container this timestamp condition belongs to
+ * @return The new {@link TmfXmlTimestampCondition}
+ * @since 2.0
+ */
+ TmfXmlTimestampCondition createTimestampsCondition(Element node, IXmlStateSystemContainer container);
+
+ /**
+ * Create a new pattern segment builder
+ *
+ * @param node
+ * The XML pattern segment builder
+ * @param container
+ * The state system container this pattern segment builder belongs to
+ * @return The new {@link TmfXmlPatternSegmentBuilder}
+ * @since 2.0
+ */
+ TmfXmlPatternSegmentBuilder createPatternSegmentBuilder(Element node, IXmlStateSystemContainer container);
}
*
* Unless this attribute is a location, in which case the quark must exist,
* the quark will be added to the state system if the state system is in
- * builder mode.
+ * builder mode. This state attribute path uses runtime data queried using
+ * the current event.
*
* @param event
* The current event being handled
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.Map.Entry;
+
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider.XmlPatternStateProvider;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+
+/**
+ * This action will reset the value of each stored values to a null
+ * {@link ITmfStateValue} in the state system
+ *
+ * @since 2.0
+ */
+public class ResetStoredFieldsAction implements ITmfXmlAction {
+
+ private final IXmlStateSystemContainer fParent;
+
+ /**
+ * Constructor
+ *
+ * @param parent
+ * The state system container this action belongs to
+ */
+ public ResetStoredFieldsAction(IXmlStateSystemContainer parent) {
+ fParent = parent;
+ }
+
+ @Override
+ public void execute(ITmfEvent event, TmfXmlScenarioInfo scenarioInfo) {
+ if (fParent instanceof XmlPatternStateProvider) {
+ for (Entry<String, String> entry : ((XmlPatternStateProvider) fParent).getStoredFields().entrySet()) {
+ ((XmlPatternStateProvider) fParent).getHistoryBuilder().resetStoredFields(fParent, entry.getValue(), scenarioInfo, event);
+ }
+ }
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider.XmlPatternStateProvider;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.XmlUtils;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
+import org.w3c.dom.Element;
+
+/**
+ * This Class implements an action tree in the XML-defined state system.
+ * An action is a collection of {@link ITmfXmlAction} that are executed when necessary.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class TmfXmlAction implements ITmfXmlAction {
+
+ private final IXmlStateSystemContainer fParent;
+ private final String fId;
+ private final List<ITmfXmlAction> fActionList = new ArrayList<>();
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this action
+ * @param container
+ * The state system container this action belongs to
+ */
+ public TmfXmlAction(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
+ fParent = container;
+ fId = NonNullUtils.checkNotNull(node.getAttribute(TmfXmlStrings.ID));
+ List<@Nullable Element> childElements = XmlUtils.getChildElements(node);
+ for (Element child : childElements) {
+ final @NonNull Element nonNullChild = NonNullUtils.checkNotNull(child);
+ switch (nonNullChild.getNodeName()) {
+ case TmfXmlStrings.STATE_CHANGE:
+ fActionList.add(new StateChange(modelFactory, nonNullChild, fParent));
+ break;
+ case TmfXmlStrings.FSM_SCHEDULE_ACTION:
+ fActionList.add(new ScheduleNewScenario(modelFactory, nonNullChild, fParent));
+ break;
+ case TmfXmlStrings.SEGMENT:
+ fActionList.add(new GeneratePatternSegment(modelFactory, nonNullChild, fParent));
+ break;
+ case TmfXmlStrings.ACTION:
+ fActionList.add(new TmfXmlAction(modelFactory, nonNullChild, fParent));
+ break;
+ default:
+ Activator.logError("Invalid action type : " + nonNullChild.getNodeName()); //$NON-NLS-1$
+ }
+ }
+
+ }
+
+ /**
+ * Get the ID of this action
+ *
+ * @return The id of this action
+ */
+ public String getId() {
+ return fId;
+ }
+
+ @Override
+ public void execute(@NonNull ITmfEvent event, TmfXmlScenarioInfo scenarioInfo) {
+ // the order of the actions is important, do not parallelize.
+ for (ITmfXmlAction action : fActionList) {
+ action.execute(event, scenarioInfo);
+ }
+ }
+
+ /**
+ * Private class for an action that will create a state change in the state
+ * system
+ */
+ private class StateChange implements ITmfXmlAction {
+
+ private final TmfXmlStateChange fStateChange;
+
+ public StateChange(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer parent) {
+ fStateChange = modelFactory.createStateChange(node, parent);
+ }
+
+ @Override
+ public void execute(@NonNull ITmfEvent event, TmfXmlScenarioInfo scenarioInfo) {
+ try {
+ fStateChange.handleEvent(event, scenarioInfo);
+ } catch (StateValueTypeException | AttributeNotFoundException e) {
+ Activator.logError("Exception when executing action state change", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Private class for an action that will instantiate and schedule a new instance of
+ * an fsm
+ */
+ private static class ScheduleNewScenario implements ITmfXmlAction {
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this action
+ * @param container
+ * The state system container this action belongs to
+ */
+ public ScheduleNewScenario(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
+ }
+
+ @Override
+ public void execute(ITmfEvent event, TmfXmlScenarioInfo scenarioInfo) {
+ // TODO This action needs to be implemented
+ throw new UnsupportedOperationException("Schedule an FSM is not yet supported"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Private class for an action that will generate pattern segment
+ */
+ private static class GeneratePatternSegment implements ITmfXmlAction {
+
+ private final TmfXmlPatternSegmentBuilder fSegmentBuilder;
+ private final XmlPatternStateProvider fProvider;
+
+ public GeneratePatternSegment(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer parent) {
+ fProvider = ((XmlPatternStateProvider) parent);
+ fSegmentBuilder = modelFactory.createPatternSegmentBuilder(node, parent);
+ }
+
+ @Override
+ public void execute(ITmfEvent event, TmfXmlScenarioInfo scenarioInfo) {
+ long ts = fProvider.getHistoryBuilder().getStartTime(fProvider, scenarioInfo, event);
+ // FIXME Should the scale always be nanoseconds?
+ ITmfTimestamp start = new TmfNanoTimestamp(ts);
+ ITmfTimestamp end = event.getTimestamp();
+ fSegmentBuilder.generatePatternSegment(event, start, end, scenarioInfo);
+ }
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.w3c.dom.Element;
+
+/**
+ * Implementation of a basic transition in the XML file
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class TmfXmlBasicTransition {
+
+ private static final Pattern WILDCARD_PATTERN = Pattern.compile("\\*"); //$NON-NLS-1$
+
+ private final List<String> fCond;
+ private final List<Pattern> fAcceptedEvents;
+
+
+ /**
+ * Constructor
+ *
+ * @param element
+ * the XML basic transition element
+ */
+ public TmfXmlBasicTransition(Element element) {
+ final @NonNull String events = element.getAttribute(TmfXmlStrings.EVENT);
+ fAcceptedEvents = new ArrayList<>();
+ for (String eventName : Arrays.asList(events.split(TmfXmlStrings.OR_SEPARATOR))) {
+ String name = WILDCARD_PATTERN.matcher(eventName).replaceAll(".*"); //$NON-NLS-1$
+ fAcceptedEvents.add(Pattern.compile(name));
+ }
+ final @NonNull String conditions = element.getAttribute(TmfXmlStrings.COND);
+ fCond = conditions.isEmpty() ? new ArrayList<>() : Arrays.asList(conditions.split(TmfXmlStrings.AND_SEPARATOR));
+ }
+
+ /**
+ * Validate the transition with the current event
+ *
+ * @param event
+ * The active event
+ * @param scenarioInfo
+ * The active scenario details.
+ * @param tests
+ * The map of test in the XML file
+ * @return true if the transition is validate false if not
+ */
+ public boolean test(ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo, Map<String, TmfXmlTransitionValidator> tests) {
+ if (!validateEvent(event)) {
+ return false;
+ }
+
+ for (String cond : fCond) {
+ TmfXmlTransitionValidator test = tests.get(cond);
+ if (test == null) {
+ throw new IllegalStateException("Failed to find cond " + cond); //$NON-NLS-1$
+ }
+ if (!test.test(event, scenarioInfo)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean validateEvent(ITmfEvent event) {
+ String eventName = event.getName();
+
+ /*
+ * This validates the event name with the accepted regular expressions
+ */
+ for (Pattern nameRegex : fAcceptedEvents) {
+ if (nameRegex.matcher(eventName).matches()) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
*
* @author Florian Wininger
*/
-public class TmfXmlCondition {
+public class TmfXmlCondition implements ITmfXmlCondition {
private final List<TmfXmlCondition> fConditions = new ArrayList<>();
private final List<ITmfXmlStateValue> fStateValues;
private final LogicalOperator fOperator;
private final IXmlStateSystemContainer fContainer;
private final ConditionOperator fConditionOperator;
+ private ConditionType fType;
+ private @Nullable TmfXmlTimestampCondition fTimeCondition;
private enum LogicalOperator {
NONE,
NOT,
AND,
- OR,
+ OR
}
private enum ConditionOperator {
LT
}
+ // TODO The XmlCondition needs to be split into several classes of condition
+ // instead of using an enum
+ private enum ConditionType {
+ DATA,
+ TIME,
+ NONE
+ }
+
/**
- * Constructor
+ * Factory to create {@link TmfXmlCondition}
*
* @param modelFactory
* The factory used to create XML model elements
* The XML root of this condition
* @param container
* The state system container this condition belongs to
+ * @return The new {@link TmfXmlCondition}
+ * @since 2.0
*/
- public TmfXmlCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
- fContainer = container;
-
+ public static TmfXmlCondition create(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
Element rootNode = node;
/* Process the conditions: in each case, only process Element nodes */
List<@Nullable Element> childElements = XmlUtils.getChildElements(rootNode);
childElements = XmlUtils.getChildElements(rootNode);
}
+ List<@NonNull TmfXmlCondition> conditions = new ArrayList<>();
switch (rootNode.getNodeName()) {
case TmfXmlStrings.CONDITION:
- int size = rootNode.getElementsByTagName(TmfXmlStrings.STATE_VALUE).getLength();
- fStateValues = new ArrayList<>(size);
- fOperator = LogicalOperator.NONE;
- if (size == 1) {
- fConditionOperator = getConditionOperator(rootNode);
- getStateValuesForXmlCondition(modelFactory, NonNullUtils.checkNotNull(childElements));
- } else {
- // No need to test if the childElements size is actually 2. The
- // XSD validation do this check already.
- fConditionOperator = ConditionOperator.EQ;
- fStateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(0)), fContainer, new ArrayList<ITmfXmlStateAttribute>()));
- fStateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(1)), fContainer, new ArrayList<ITmfXmlStateAttribute>()));
- }
- break;
+ return createPatternCondition(modelFactory, container, rootNode, childElements);
case TmfXmlStrings.NOT:
- fStateValues = new ArrayList<>();
- fOperator = LogicalOperator.NOT;
- fConditionOperator = ConditionOperator.NONE;
- Element element = NonNullUtils.checkNotNull(childElements.get(0));
- fConditions.add(modelFactory.createCondition(element, fContainer));
- break;
+ return createMultipleCondition(modelFactory, container, childElements, LogicalOperator.NOT, conditions);
case TmfXmlStrings.AND:
- fStateValues = new ArrayList<>();
- fOperator = LogicalOperator.AND;
- fConditionOperator = ConditionOperator.NONE;
- for (Element condition : childElements) {
- if (condition == null) {
- continue;
- }
- fConditions.add(modelFactory.createCondition(condition, fContainer));
- }
- break;
+ return createMultipleCondition(modelFactory, container, childElements, LogicalOperator.AND, conditions);
case TmfXmlStrings.OR:
- fStateValues = new ArrayList<>();
- fOperator = LogicalOperator.OR;
- fConditionOperator = ConditionOperator.NONE;
- for (Element condition : childElements) {
- if (condition == null) {
- continue;
- }
- fConditions.add(modelFactory.createCondition(condition, fContainer));
- }
- break;
+ return createMultipleCondition(modelFactory, container, childElements, LogicalOperator.OR, conditions);
default:
- throw new IllegalArgumentException("TmfXmlCondition constructor: XML node is of the wrong type"); //$NON-NLS-1$
+ throw new IllegalArgumentException("TmfXmlCondition constructor: XML node " + rootNode.getNodeName() + " is of the wrong type"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
- private void getStateValuesForXmlCondition(ITmfXmlModelFactory modelFactory, List<@Nullable Element> childElements) {
+ private static TmfXmlCondition createPatternCondition(ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, Element rootNode, List<@Nullable Element> childElements) {
+ ArrayList<ITmfXmlStateValue> stateValues;
+ ConditionOperator conditionOperator;
+ TmfXmlTimestampCondition timeCondition = null;
+ int size = rootNode.getElementsByTagName(TmfXmlStrings.STATE_VALUE).getLength();
+ if (size != 0) {
+ stateValues = new ArrayList<>(size);
+ if (size == 1) {
+ conditionOperator = getConditionOperator(rootNode);
+ getStateValuesForXmlCondition(modelFactory, NonNullUtils.checkNotNull(childElements), stateValues, container);
+ } else {
+ // No need to test if the childElements size is actually 2.
+ // The XSD validation do this check already.
+ conditionOperator = ConditionOperator.EQ;
+ stateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(0)), container, new ArrayList<ITmfXmlStateAttribute>()));
+ stateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(1)), container, new ArrayList<ITmfXmlStateAttribute>()));
+ }
+ return new TmfXmlCondition(ConditionType.DATA, stateValues, LogicalOperator.NONE, conditionOperator, null, new ArrayList<>(), container);
+ }
+ final Element firstElement = NonNullUtils.checkNotNull(childElements.get(0));
+ timeCondition = modelFactory.createTimestampsCondition(firstElement, container);
+ return new TmfXmlCondition(ConditionType.TIME, new ArrayList<>(), LogicalOperator.NONE, ConditionOperator.EQ, timeCondition, new ArrayList<>(), container);
+ }
+
+ private static TmfXmlCondition createMultipleCondition(ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, List<@Nullable Element> childElements, LogicalOperator op,
+ List<@NonNull TmfXmlCondition> conditions) {
+ for (Element condition : childElements) {
+ if (condition == null) {
+ continue;
+ }
+ conditions.add(modelFactory.createCondition(condition, container));
+ }
+ return new TmfXmlCondition(ConditionType.NONE, new ArrayList<>(), op, ConditionOperator.NONE, null, conditions, container);
+ }
+
+ private TmfXmlCondition(ConditionType type, ArrayList<@NonNull ITmfXmlStateValue> stateValues, LogicalOperator operator, ConditionOperator conditionOperator, @Nullable TmfXmlTimestampCondition timeCondition, List<@NonNull TmfXmlCondition> conditions,
+ IXmlStateSystemContainer container) {
+ fType = type;
+ fStateValues = stateValues;
+ fOperator = operator;
+ fTimeCondition = timeCondition;
+ fContainer = container;
+ fConditions.addAll(conditions);
+ fConditionOperator = conditionOperator;
+ }
+
+ private static void getStateValuesForXmlCondition(ITmfXmlModelFactory modelFactory, List<@Nullable Element> childElements, List<ITmfXmlStateValue> stateValues, IXmlStateSystemContainer container) {
Element stateValueElement = NonNullUtils.checkNotNull(childElements.remove(childElements.size() - 1));
/*
* A state value is either preceded by an eventField or a number of
final Element firstElement = NonNullUtils.checkNotNull(childElements.get(0));
if (childElements.size() == 1 && firstElement.getNodeName().equals(TmfXmlStrings.ELEMENT_FIELD)) {
String attribute = firstElement.getAttribute(TmfXmlStrings.NAME);
- fStateValues.add(modelFactory.createStateValue(stateValueElement, fContainer, attribute));
+ stateValues.add(modelFactory.createStateValue(stateValueElement, container, attribute));
} else {
List<ITmfXmlStateAttribute> attributes = new ArrayList<>();
for (Element element : childElements) {
if (!element.getNodeName().equals(TmfXmlStrings.STATE_ATTRIBUTE)) {
throw new IllegalArgumentException("TmfXmlCondition: a condition either has a eventField element or a number of TmfXmlStateAttribute elements before the state value"); //$NON-NLS-1$
}
- ITmfXmlStateAttribute attribute = modelFactory.createStateAttribute(element, fContainer);
+ ITmfXmlStateAttribute attribute = modelFactory.createStateAttribute(element, container);
attributes.add(attribute);
}
- fStateValues.add(modelFactory.createStateValue(stateValueElement, fContainer, attributes));
+ stateValues.add(modelFactory.createStateValue(stateValueElement, container, attributes));
}
}
}
/**
- * Test the result of the condition for an event
- *
- * @param event
- * The event on which to test the condition
- * @param scenarioInfo
- * The active scenario details. Or <code>null</code> if there is
- * no scenario.
- * @return Whether the condition is true or not
- * @throws AttributeNotFoundException
- * The state attribute was not found
* @since 2.0
*/
- public boolean testForEvent(ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo) throws AttributeNotFoundException {
+ @Override
+ public boolean test(ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo) {
ITmfStateSystem ss = fContainer.getStateSystem();
- if (!fStateValues.isEmpty()) {
- return testForEvent(event, NonNullUtils.checkNotNull(ss), scenarioInfo);
+ if (fType == ConditionType.DATA) {
+ try {
+ return testForEvent(event, NonNullUtils.checkNotNull(ss), scenarioInfo);
+ } catch (AttributeNotFoundException e) {
+ Activator.logError("Attribute not found", e); //$NON-NLS-1$
+ return false;
+ }
+ } else if (fType == ConditionType.TIME) {
+ if (fTimeCondition != null) {
+ return fTimeCondition.test(event, scenarioInfo);
+ }
} else if (!fConditions.isEmpty()) {
/* Verify a condition tree */
switch (fOperator) {
case AND:
- for (TmfXmlCondition childCondition : fConditions) {
- if (!childCondition.testForEvent(event, scenarioInfo)) {
+ for (ITmfXmlCondition childCondition : fConditions) {
+ if (!childCondition.test(event, scenarioInfo)) {
return false;
}
}
case NONE:
break;
case NOT:
- return !fConditions.get(0).testForEvent(event, scenarioInfo);
+ return !fConditions.get(0).test(event, scenarioInfo);
case OR:
- for (TmfXmlCondition childCondition : fConditions) {
- if (childCondition.testForEvent(event, scenarioInfo)) {
+ for (ITmfXmlCondition childCondition : fConditions) {
+ if (childCondition.test(event, scenarioInfo)) {
return true;
}
}
*/
public boolean compare(ITmfStateValue source, ITmfStateValue dest, ConditionOperator comparisonOperator) {
switch (comparisonOperator) {
- //TODO The comparison operator should have a compareHelper that calls compare
+ // TODO The comparison operator should have a compareHelper that calls compare
case EQ:
return (source.compareTo(dest) == 0);
case NE:
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlScenarioHistoryBuilder.ScenarioStatusType;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * This Class implements a state machine (FSM) tree in the XML-defined state
+ * system.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class TmfXmlFsm {
+
+ private final Map<String, TmfXmlState> fStatesMap;
+ private final List<TmfXmlScenario> fActiveScenariosList;
+ private final List<TmfXmlBasicTransition> fPreconditions;
+ private final String fId;
+ private final ITmfXmlModelFactory fModelFactory;
+ private final IXmlStateSystemContainer fContainer;
+ private final String fFinalStateId;
+ private final String fAbandonStateId;
+ private final boolean fInstanceMultipleEnabled;
+ private final String fInitialStateId;
+ private int fTotalScenarios;
+
+ /**
+ * Factory to create a {@link TmfXmlFsm}
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this fsm
+ * @param container
+ * The state system container this fsm belongs to
+ * @return The new {@link TmfXmlFsm}
+ */
+ public static TmfXmlFsm create(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
+ String id = node.getAttribute(TmfXmlStrings.ID);
+ boolean instanceMultipleEnabled = node.getAttribute(TmfXmlStrings.MULTIPLE).isEmpty() ? true : Boolean.parseBoolean(node.getAttribute(TmfXmlStrings.MULTIPLE));
+ final List<@NonNull TmfXmlBasicTransition> preconditions = new ArrayList<>();
+
+ // Get the preconditions
+ NodeList nodesPreconditions = node.getElementsByTagName(TmfXmlStrings.PRECONDITION);
+ for (int i = 0; i < nodesPreconditions.getLength(); i++) {
+ preconditions.add(new TmfXmlBasicTransition(((Element) NonNullUtils.checkNotNull(nodesPreconditions.item(i)))));
+ }
+
+ // Get the initial state and the preconditions
+ String initialState = node.getAttribute(TmfXmlStrings.INITIAL);
+ if (initialState.isEmpty()) {
+ NodeList nodesInitialState = node.getElementsByTagName(TmfXmlStrings.INITIAL);
+ if (nodesInitialState.getLength() == 1) {
+ NodeList nodesTransition = ((Element) nodesInitialState.item(0)).getElementsByTagName(TmfXmlStrings.TRANSITION);
+ if (nodesInitialState.getLength() != 1) {
+ throw new IllegalArgumentException("initial state : there should be one and only one initial state."); //$NON-NLS-1$
+ }
+ initialState = ((Element) nodesTransition.item(0)).getAttribute(TmfXmlStrings.TARGET);
+ }
+ }
+
+ Map<@NonNull String, @NonNull TmfXmlState> statesMap = new HashMap<>();
+ // Get the FSM states
+ NodeList nodesState = node.getElementsByTagName(TmfXmlStrings.STATE);
+ for (int i = 0; i < nodesState.getLength(); i++) {
+ Element element = (Element) NonNullUtils.checkNotNull(nodesState.item(i));
+ TmfXmlState state = modelFactory.createState(element, container, null);
+ statesMap.put(state.getId(), state);
+
+ // If the initial state was not already set, we use the first state
+ // declared in the fsm description as initial state
+ if (initialState.isEmpty()) {
+ initialState = state.getId();
+ }
+ }
+
+ if (initialState.isEmpty()) {
+ throw new IllegalStateException("No initial state has been declared in fsm " + id); //$NON-NLS-1$
+ }
+
+ // Get the FSM final state
+ String finalStateId = TmfXmlStrings.NULL;
+ NodeList nodesFinalState = node.getElementsByTagName(TmfXmlStrings.FINAL);
+ if (nodesFinalState.getLength() == 1) {
+ final Element finalElement = NonNullUtils.checkNotNull((Element) nodesFinalState.item(0));
+ finalStateId = finalElement.getAttribute(TmfXmlStrings.ID);
+ if (!finalStateId.isEmpty()) {
+ TmfXmlState finalState = modelFactory.createState(finalElement, container, null);
+ statesMap.put(finalState.getId(), finalState);
+ }
+ }
+
+ // Get the FSM abandon state
+ String abandonStateId = TmfXmlStrings.NULL;
+ NodeList nodesAbandonState = node.getElementsByTagName(TmfXmlStrings.ABANDON_STATE);
+ if (nodesAbandonState.getLength() == 1) {
+ final Element abandonElement = NonNullUtils.checkNotNull((Element) nodesAbandonState.item(0));
+ abandonStateId = abandonElement.getAttribute(TmfXmlStrings.ID);
+ if (!abandonStateId.isEmpty()) {
+ TmfXmlState abandonState = modelFactory.createState(abandonElement, container, null);
+ statesMap.put(abandonState.getId(), abandonState);
+ }
+ }
+ return new TmfXmlFsm(modelFactory, container, id, instanceMultipleEnabled, initialState, finalStateId, abandonStateId, preconditions, statesMap);
+ }
+
+ private TmfXmlFsm(ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, String id, boolean multiple,
+ String initialState, String finalState, String abandonState, List<TmfXmlBasicTransition> preconditions,
+ Map<String, TmfXmlState> states) {
+ fModelFactory = modelFactory;
+ fTotalScenarios = 0;
+ fContainer = container;
+ fId = id;
+ fInstanceMultipleEnabled = multiple;
+ fInitialStateId = initialState;
+ fFinalStateId = finalState;
+ fAbandonStateId = abandonState;
+ fPreconditions = ImmutableList.copyOf(preconditions);
+ fStatesMap = ImmutableMap.copyOf(states);
+ fActiveScenariosList = new ArrayList<>();
+ }
+
+ /**
+ * Get the fsm ID
+ *
+ * @return the id of this fsm
+ */
+ public String getId() {
+ return fId;
+ }
+
+ /**
+ * Get the initial state ID of this fsm
+ *
+ * @return the id of the initial state of this finite state machine
+ */
+ public String getInitialStateId() {
+ return fInitialStateId;
+ }
+
+ /**
+ * Get the final state ID of this fsm
+ *
+ * @return the id of the final state of this finite state machine
+ */
+ public String getFinalStateId() {
+ return fFinalStateId;
+ }
+
+ /**
+ * Get the abandon state ID fo this fsm
+ *
+ * @return the id of the abandon state of this finite state machine
+ */
+ public String getAbandonStateId() {
+ return fAbandonStateId;
+ }
+
+ /**
+ * Get the states table of this fsm in map
+ *
+ * @return The map containing all state definition for this fsm
+ */
+ public Map<String, TmfXmlState> getStatesMap() {
+ return Collections.unmodifiableMap(fStatesMap);
+ }
+
+ /**
+ * Process the active event and determine the next step of this fsm
+ *
+ * @param event
+ * The event to process
+ * @param tests
+ * The list of possible transitions of the state machine
+ * @param scenarioInfo
+ * The active scenario details.
+ * @return A pair containing the next state of the state machine and the
+ * actions to execute
+ */
+ public @Nullable TmfXmlStateTransition next(ITmfEvent event, Map<String, TmfXmlTransitionValidator> tests, TmfXmlScenarioInfo scenarioInfo) {
+ boolean matched = false;
+ TmfXmlStateTransition stateTransition = null;
+ TmfXmlState state = NonNullUtils.checkNotNull(fStatesMap.get(scenarioInfo.getActiveState()));
+ for (int i = 0; i < state.getTransitionList().size() && !matched; i++) {
+ stateTransition = state.getTransitionList().get(i);
+ matched = stateTransition.test(event, scenarioInfo, tests);
+ }
+ return matched ? stateTransition : null;
+ }
+
+
+
+ /**
+ * Validate the preconditions of this fsm. If not validate, the fsm will
+ * skip the active event.
+ *
+ * @param event
+ * The current event
+ * @param tests
+ * The transition inputs
+ * @return True if one of the precondition is validated, false otherwise
+ */
+ private boolean validatePreconditions(ITmfEvent event, Map<String, TmfXmlTransitionValidator> tests) {
+ if (fPreconditions.isEmpty()) {
+ return true;
+ }
+ for (TmfXmlBasicTransition precondition : fPreconditions) {
+ if (precondition.test(event, null, tests)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Handle the current event
+ *
+ * @param event
+ * The current event
+ * @param transitionMap
+ * The transitions of the pattern
+ */
+ public void handleEvent(ITmfEvent event, Map<String, TmfXmlTransitionValidator> transitionMap) {
+ if (!validatePreconditions(event, transitionMap)) {
+ return;
+ }
+ for (Iterator<TmfXmlScenario> currentItr = fActiveScenariosList.iterator(); currentItr.hasNext();) {
+ TmfXmlScenario scenario = currentItr.next();
+ // Remove inactive scenarios or handle the active ones.
+ if (!scenario.isActive()) {
+ currentItr.remove();
+ } else {
+ handleScenario(scenario, event);
+ }
+ }
+ }
+
+ /**
+ * Abandon all ongoing scenarios
+ */
+ public void dispose() {
+ for (TmfXmlScenario scenario : fActiveScenariosList) {
+ if (scenario.isActive()) {
+ scenario.cancel();
+ }
+ }
+ }
+
+ private static void handleScenario(TmfXmlScenario scenario, ITmfEvent event) {
+ if (scenario.isActive()) {
+ scenario.handleEvent(event);
+ }
+ }
+
+ /**
+ * Create a new scenario of this fsm
+ *
+ * @param event
+ * The current event, null if not
+ * @param eventHandler
+ * The event handler this fsm belongs
+ * @param force
+ * True to force the creation of the scenario, false otherwise
+ */
+ public synchronized void createScenario(@Nullable ITmfEvent event, TmfXmlPatternEventHandler eventHandler, boolean force) {
+ if (force || isNewScenarioAllowed()) {
+ TmfXmlScenario scenario = new TmfXmlScenario(event, eventHandler, fId, fContainer, fModelFactory);
+ fTotalScenarios++;
+ fActiveScenariosList.add(scenario);
+ }
+ }
+
+ /**
+ * Check if we have the right to create a new scenario. A new scenario could
+ * be created if it is not the first scenario of an FSM and the FSM is not a
+ * singleton and the status of the last created scenario is not PENDING.
+ *
+ * @return True if the start of a new scenario is allowed, false otherwise
+ */
+ public synchronized boolean isNewScenarioAllowed() {
+ return !fActiveScenariosList.get(fActiveScenariosList.size() - 1).getScenarioInfos().getStatus().equals(ScenarioStatusType.PENDING)
+ && fInstanceMultipleEnabled && fTotalScenarios > 0;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider.XmlPatternStateProvider;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * This Class implements a pattern handler tree in the XML-defined state system.
+ * It receives events and dispatches it to Active finite state machines.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class TmfXmlPatternEventHandler {
+
+ /* list of states changes */
+ private final XmlPatternStateProvider fParent;
+
+ private final List<String> fInitialFsm;
+ private final Map<String, TmfXmlTransitionValidator> fTestMap = new HashMap<>();
+ private final Map<String, ITmfXmlAction> fActionMap = new HashMap<>();
+ private final Map<String, TmfXmlFsm> fFsmMap = new HashMap<>();
+ private final List<TmfXmlFsm> fActiveFsmList = new ArrayList<>();
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this event handler
+ * @param parent
+ * The state system container this event handler belongs to
+ */
+ public TmfXmlPatternEventHandler(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer parent) {
+ fParent = (XmlPatternStateProvider) parent;
+ String initialFsm = node.getAttribute(TmfXmlStrings.INITIAL);
+ fInitialFsm = initialFsm.isEmpty() ? Collections.EMPTY_LIST : Arrays.asList(initialFsm.split(TmfXmlStrings.AND_SEPARATOR));
+
+ NodeList nodesTest = node.getElementsByTagName(TmfXmlStrings.TEST);
+ /* load transition input */
+ for (int i = 0; i < nodesTest.getLength(); i++) {
+ Element element = (Element) nodesTest.item(i);
+ if (element == null) {
+ throw new IllegalArgumentException();
+ }
+ TmfXmlTransitionValidator test = modelFactory.createTransitionValidator(element, fParent);
+ fTestMap.put(test.getId(), test);
+ }
+
+ NodeList nodesAction = node.getElementsByTagName(TmfXmlStrings.ACTION);
+ /* load actions */
+ for (int i = 0; i < nodesAction.getLength(); i++) {
+ Element element = (Element) nodesAction.item(i);
+ if (element == null) {
+ throw new IllegalArgumentException();
+ }
+ ITmfXmlAction action = modelFactory.createAction(element, fParent);
+ fActionMap.put(((TmfXmlAction) action).getId(), action);
+ }
+ fActionMap.put(TmfXmlStrings.CONSTANT_PREFIX + ITmfXmlAction.CLEAR_STORED_FIELDS_STRING, new ResetStoredFieldsAction(fParent));
+ fActionMap.put(TmfXmlStrings.CONSTANT_PREFIX + ITmfXmlAction.SAVE_STORED_FIELDS_STRING, new UpdateStoredFieldsAction(fParent));
+
+ NodeList nodesFsm = node.getElementsByTagName(TmfXmlStrings.FSM);
+ /* load fsm */
+ for (int i = 0; i < nodesFsm.getLength(); i++) {
+ Element element = (Element) nodesFsm.item(i);
+ if (element == null) {
+ throw new IllegalArgumentException();
+ }
+ TmfXmlFsm fsm = modelFactory.createFsm(element, fParent);
+ fFsmMap.put(fsm.getId(), fsm);
+ }
+ }
+
+ /**
+ * Start a new scenario for this specific fsm id. If the fsm support only a
+ * single instance and this instance already exist, no new scenario is then
+ * started. If the scenario is created we handle the current event directly.
+ *
+ * @param fsmIds
+ * The IDs of the fsm to start
+ * @param event
+ * The current event
+ * @param force
+ * True to force the creation of the scenario, false otherwise
+ */
+ public void startScenario(List<String> fsmIds, @Nullable ITmfEvent event, boolean force) {
+ for (String fsmId : fsmIds) {
+ TmfXmlFsm fsm = NonNullUtils.checkNotNull(fFsmMap.get(fsmId));
+ if (!fActiveFsmList.contains(fsm)) {
+ fActiveFsmList.add(fsm);
+ }
+ fsm.createScenario(event, this, force);
+ }
+ }
+
+ /**
+ * Get all the defined transition tests
+ *
+ * @return The tests in a map
+ */
+ public Map<String, TmfXmlTransitionValidator> getTestMap() {
+ return ImmutableMap.copyOf(fTestMap);
+ }
+
+ /**
+ * Get all the defined actions
+ *
+ * @return The actions
+ */
+ public Map<String, ITmfXmlAction> getActionMap() {
+ return ImmutableMap.copyOf(fActionMap);
+ }
+
+ /**
+ * If the pattern handler can handle the event, it send the event to all
+ * finite state machines with ongoing scenarios
+ *
+ * @param event
+ * The trace event to handle
+ */
+ public void handleEvent(ITmfEvent event) {
+ /*
+ * Order is important so cannot be parallelized
+ */
+ final @NonNull List<@NonNull TmfXmlFsm> activeFsmList = fActiveFsmList;
+ final @NonNull Map<@NonNull String, @NonNull TmfXmlFsm> fsmMap = fFsmMap;
+ if (activeFsmList.isEmpty()) {
+ List<String> fsmIds = fInitialFsm;
+ if (fsmIds.isEmpty()) {
+ fsmIds = new ArrayList<>();
+ for (TmfXmlFsm fsm : fsmMap.values()) {
+ fsmIds.add(fsm.getId());
+ }
+ }
+ if (!fsmIds.isEmpty()) {
+ startScenario(fsmIds, null, true);
+ }
+ } else {
+ List<String> fsmToStart = new ArrayList<>();
+ for (Map.Entry<String, TmfXmlFsm> entry : fsmMap.entrySet()) {
+ if (entry.getValue().isNewScenarioAllowed()) {
+ fsmToStart.add(entry.getKey());
+ }
+ }
+ if (!fsmToStart.isEmpty()) {
+ startScenario(fsmToStart, null, false);
+ }
+ }
+ for (TmfXmlFsm fsm : activeFsmList) {
+ fsm.handleEvent(event, fTestMap);
+ }
+ }
+
+ /**
+ * Abandon all the ongoing scenarios
+ */
+ public void dispose() {
+ for (TmfXmlFsm fsm : fActiveFsmList) {
+ fsm.dispose();
+ }
+ }
+
+ /**
+ * Get the fsm corresponding to the specified id
+ *
+ * @param fsmId
+ * The id of the fsm
+ * @return The fsm found, null if nothing found
+ */
+ public @Nullable TmfXmlFsm getFsm(String fsmId) {
+ return fFsmMap.get(fsmId);
+ }
+}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
for (TmfXmlPatternSegmentField field : fFields) {
fields.put(field.getName(), field.getValue(event, scenarioInfo));
}
+ if (scenarioInfo != null) {
+ addStoredFieldsContent(event, fields, scenarioInfo);
+ }
+ }
+
+ /**
+ * Query the stored fields path and add them to the content of the pattern
+ * segment. This is specific to pattern analysis.
+ *
+ * @param event
+ * The active event
+ * @param fields
+ * The segment fields
+ * @param info
+ * The active scenario details
+ */
+ protected void addStoredFieldsContent(ITmfEvent event, Map<String, ITmfStateValue> fields, final TmfXmlScenarioInfo info) {
+ if (fContainer instanceof XmlPatternStateProvider) {
+ for (Entry<String, String> entry : ((XmlPatternStateProvider) fContainer).getStoredFields().entrySet()) {
+ ITmfStateValue value = ((XmlPatternStateProvider) fContainer).getHistoryBuilder().getStoredFieldValue(fContainer, entry.getValue(), info, event);
+ if (!value.isNull()) {
+ fields.put(entry.getValue(), value);
+ }
+ }
+ }
}
private static ITmfStateValue getStateValueFromConstant(String constantValue, String type) {
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider.XmlPatternStateProvider;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlScenarioHistoryBuilder.ScenarioStatusType;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+
+/**
+ * This Class implements a Scenario in the XML-defined state system
+ *
+ * @since 2.0
+ */
+public class TmfXmlScenario {
+
+ private final IXmlStateSystemContainer fContainer;
+ private final TmfXmlFsm fFsm;
+ private TmfXmlPatternEventHandler fPatternHandler;
+ private TmfXmlScenarioInfo fScenarioInfo;
+ TmfXmlScenarioHistoryBuilder fHistoryBuilder;
+
+ /**
+ * Constructor
+ *
+ * @param event
+ * The event at which this scenario is created
+ * @param patternHandler
+ * The filter handler
+ * @param fsmId
+ * the id of the fsm executed by this scenario
+ * @param container
+ * The state system container this scenario belongs to
+ * @param modelFactory
+ * The model factory
+ */
+ public TmfXmlScenario(@Nullable ITmfEvent event, TmfXmlPatternEventHandler patternHandler, String fsmId, IXmlStateSystemContainer container, ITmfXmlModelFactory modelFactory) {
+ TmfXmlFsm fsm = patternHandler.getFsm(fsmId);
+ if (fsm == null) {
+ throw new IllegalArgumentException(fsmId + "has not been declared."); //$NON-NLS-1$
+ }
+ fFsm = fsm;
+ fContainer = container;
+ fHistoryBuilder = ((XmlPatternStateProvider) container).getHistoryBuilder();
+ fPatternHandler = patternHandler;
+ int quark = fHistoryBuilder.assignScenarioQuark(fContainer, fsmId);
+ int statusQuark = fHistoryBuilder.getScenarioStatusQuark(fContainer, quark);
+ fScenarioInfo = new TmfXmlScenarioInfo(fFsm.getInitialStateId(), ScenarioStatusType.PENDING, quark, statusQuark, fFsm);
+ fHistoryBuilder.update(fContainer, fScenarioInfo, event);
+ }
+
+ /**
+ * Get this scenario infos
+ *
+ * @return The scenario info
+ */
+ public TmfXmlScenarioInfo getScenarioInfos() {
+ return fScenarioInfo;
+ }
+
+ /**
+ * Cancel the execution of this scenario
+ */
+ public void cancel() {
+ fScenarioInfo.setStatus(ScenarioStatusType.ABANDONED);
+ if (fScenarioInfo.getStatus() != ScenarioStatusType.PENDING) {
+ fHistoryBuilder.completeScenario(fContainer, fScenarioInfo, null);
+ }
+ }
+
+ /**
+ * Test if the scenario is active or not
+ *
+ * @return True if the scenario is active, false otherwise
+ */
+ public boolean isActive() {
+ return fScenarioInfo.getStatus().equals(ScenarioStatusType.PENDING) || fScenarioInfo.getStatus().equals(ScenarioStatusType.IN_PROGRESS);
+ }
+
+ /**
+ * Handle the ongoing event
+ *
+ * @param event
+ * The ongoing event
+ */
+ public void handleEvent(ITmfEvent event) {
+
+ TmfXmlStateTransition out = fFsm.next(event, fPatternHandler.getTestMap(), fScenarioInfo);
+ if (out == null) {
+ return;
+ }
+
+ // Processing the actions in the transition
+ final List<String> actions = out.getAction();
+ for (String actionId : actions) {
+ ITmfXmlAction action = fPatternHandler.getActionMap().get(actionId);
+ if (action != null) {
+ action.execute(event, fScenarioInfo);
+ } else {
+ throw new IllegalStateException("Action " + actionId + " cannot be found."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ // Change the activeState
+ final @NonNull String nextState = out.getTarget();
+ if (fScenarioInfo.getStatus().equals(ScenarioStatusType.PENDING)) {
+ fScenarioInfo.setStatus(ScenarioStatusType.IN_PROGRESS);
+ fHistoryBuilder.startScenario(fContainer, fScenarioInfo, event);
+ } else if (nextState.equals(fFsm.getAbandonStateId())) {
+ fScenarioInfo.setStatus(ScenarioStatusType.ABANDONED);
+ fHistoryBuilder.completeScenario(fContainer, fScenarioInfo, event);
+ } else if (nextState.equals(fFsm.getFinalStateId())) {
+ fScenarioInfo.setStatus(ScenarioStatusType.MATCHED);
+ fHistoryBuilder.completeScenario(fContainer, fScenarioInfo, event);
+ }
+ fScenarioInfo.setActiveState(nextState);
+ fHistoryBuilder.update(fContainer, fScenarioInfo, event);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.statesystem.TmfAttributePool;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableBiMap;
+
+/**
+ * This class is responsible for creating scenarios, updating their status and
+ * data, and saving the scenario data to the state system
+ *
+ * @since 2.0
+ */
+public class TmfXmlScenarioHistoryBuilder {
+
+ /** The string 'status' */
+ public static final String STATUS = "status"; //$NON-NLS-1$
+ /** The string for "nbScenarios" */
+ public static final String SCENARIO_COUNT = "nbScenarios"; //$NON-NLS-1$
+
+ /** The string for start time */
+ private static final String START_TIME = "startTime"; //$NON-NLS-1$
+ /** Error message */
+ private static final String ERROR_MESSAGE = "The state system is null"; //$NON-NLS-1$
+
+ private final Map<String, TmfAttributePool> fFsmPools = new HashMap<>();
+
+ /**
+ * All possible types of status for a scenario
+ */
+ public enum ScenarioStatusType {
+ /**
+ * scenario pending for start point
+ */
+ PENDING,
+ /**
+ * scenario in progress
+ */
+ IN_PROGRESS,
+ /**
+ * scenario abandoned
+ */
+ ABANDONED,
+ /**
+ * scenario match with the pattern
+ */
+ MATCHED
+ }
+
+ /**
+ * Cache the available status in a map
+ */
+ protected static final BiMap<ScenarioStatusType, ITmfStateValue> STATUS_MAP = NonNullUtils.checkNotNull(ImmutableBiMap.of(
+ ScenarioStatusType.PENDING, TmfStateValue.newValueInt(0),
+ ScenarioStatusType.IN_PROGRESS, TmfStateValue.newValueInt(1),
+ ScenarioStatusType.MATCHED, TmfStateValue.newValueInt(2),
+ ScenarioStatusType.ABANDONED, TmfStateValue.newValueInt(3)));
+
+ /**
+ * Get the scenario matched process start time
+ *
+ * @param container
+ * The state system container this class use
+ * @param info
+ * The scenario details
+ * @param event
+ * The current event
+ *
+ * @return The start time of the matching process for the specified scenario
+ */
+ public long getStartTime(final IXmlStateSystemContainer container, final TmfXmlScenarioInfo info, final ITmfEvent event) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = getTimestamp(event, ss);
+ try {
+ int attributeQuark = getQuarkRelativeAndAdd(ss, info.getQuark(), START_TIME);
+ ITmfStateInterval state = ss.querySingleState(ts, attributeQuark);
+ return state.getStartTime();
+ } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+ Activator.logError("failed to get the start time of the scenario", e); //$NON-NLS-1$
+ }
+ return -1L;
+ }
+
+ /**
+ * Save the stored fields
+ *
+ * @param container
+ * The state system container this class use
+ * @param attributeName
+ * The name of the attribute to save
+ * @param value
+ * The value of the attribute to save
+ * @param info
+ * The scenario details
+ * @param event
+ * The current event
+ */
+ public void updateStoredFields(final IXmlStateSystemContainer container, final String attributeName, final ITmfStateValue value, final TmfXmlScenarioInfo info, final ITmfEvent event) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = getTimestamp(event, ss);
+ try {
+ int attributeQuark = getQuarkRelativeAndAdd(ss, info.getQuark(), TmfXmlStrings.STORED_FIELDS, attributeName);
+ ss.modifyAttribute(ts, value, attributeQuark);
+ } catch (StateValueTypeException | AttributeNotFoundException e) {
+ Activator.logError("failed to save the stored field " + attributeName, e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Clear the special fields
+ *
+ * @param container
+ * The state system container this class use
+ * @param attributeName
+ * The name of the attribute to save
+ * @param info
+ * The scenario details
+ * @param event
+ * The current event
+ */
+ public void resetStoredFields(final IXmlStateSystemContainer container, final String attributeName, final TmfXmlScenarioInfo info, final ITmfEvent event) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = getTimestamp(event, ss);
+ ITmfStateValue value = TmfStateValue.nullValue();
+ try {
+ int attributeQuark = getQuarkRelativeAndAdd(ss, info.getQuark(), TmfXmlStrings.STORED_FIELDS, attributeName);
+ ss.modifyAttribute(ts, value, attributeQuark);
+ } catch (StateValueTypeException | AttributeNotFoundException e) {
+ Activator.logError("failed to clear the stored fields", e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Get the value of a special field in the state system
+ *
+ * @param container
+ * The state system container this class use
+ * @param attributeName
+ * The attribute name of the special field
+ * @param info
+ * The scenario details
+ * @param event
+ * The current event
+ *
+ * @return The value of a special field saved into the state system
+ */
+ public ITmfStateValue getStoredFieldValue(IXmlStateSystemContainer container, String attributeName, final TmfXmlScenarioInfo info, ITmfEvent event) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = event.getTimestamp().toNanos();
+ ITmfStateInterval state = null;
+ try {
+ int attributeQuark = getQuarkRelativeAndAdd(ss, info.getQuark(), TmfXmlStrings.STORED_FIELDS, attributeName);
+ state = ss.querySingleState(ts, attributeQuark);
+ } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+ Activator.logError("failed to get the value of the stored field " + attributeName, e); //$NON-NLS-1$
+ }
+ return (state != null) ? NonNullUtils.checkNotNull(state.getStateValue()) : TmfStateValue.nullValue();
+ }
+
+ /**
+ * Get the attribute pool for this fsm
+ *
+ * @param container
+ * The state system container
+ * @param fsmId
+ * The ID of the FSM
+ * @return The attribute pool associated with this FSM
+ */
+ protected TmfAttributePool getPoolFor(IXmlStateSystemContainer container, String fsmId) {
+ TmfAttributePool pool = fFsmPools.get(fsmId);
+ if (pool != null) {
+ return pool;
+ }
+ ITmfStateSystemBuilder ss = NonNullUtils.checkNotNull((ITmfStateSystemBuilder) container.getStateSystem());
+ String[] fsmPath = new String[] { TmfXmlStrings.SCENARIOS, fsmId };
+ int quark = getQuarkAbsoluteAndAdd(ss, fsmPath);
+ pool = new TmfAttributePool(ss, quark);
+ fFsmPools.put(fsmId, pool);
+ return pool;
+ }
+
+ /**
+ * Get the scenario quark
+ *
+ * @param container
+ * The state system container this class use
+ * @param fsmId
+ * Id of the fsm this scenario is associated to
+ * @return The scenario quark
+ */
+ public int assignScenarioQuark(IXmlStateSystemContainer container, String fsmId) {
+ TmfAttributePool pool = getPoolFor(container, fsmId);
+ return pool.getAvailable();
+ }
+
+ /**
+ * Get the scenario status quark
+ *
+ * @param container
+ * The state system container this class use
+ * @param scenarioQuark
+ * The scenario quark
+ * @return The scenario quark
+ */
+ public int getScenarioStatusQuark(IXmlStateSystemContainer container, int scenarioQuark) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ return getQuarkRelativeAndAdd(ss, scenarioQuark, STATUS);
+ }
+
+ /**
+ * Get the start time of a specific state of the scenario
+ *
+ * @param container
+ * The state system container this class use
+ * @param stateName
+ * The name of the current state of the scenario
+ * @param info
+ * The scenario details
+ * @param event
+ * The current event
+ *
+ * @return The start time for the specified state
+ */
+ public long getSpecificStateStartTime(final IXmlStateSystemContainer container, final String stateName, final TmfXmlScenarioInfo info, final ITmfEvent event) {
+ long ts = event.getTimestamp().getValue();
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ try {
+ int attributeQuark = getQuarkRelativeAndAdd(ss, info.getQuark(), TmfXmlStrings.STATE, stateName, START_TIME);
+ ITmfStateInterval state = ss.querySingleState(ts, attributeQuark);
+ return state.getStartTime();
+ } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+ Activator.logError("failed the start time of the state " + stateName, e); //$NON-NLS-1$
+ }
+ return -1l;
+ }
+
+ /**
+ * Basic quark-retrieving method. Pass an attribute in parameter as an array
+ * of strings, the matching quark will be returned. If the attribute does
+ * not exist, it will add the quark to the state system if the context
+ * allows it.
+ *
+ * See {@link ITmfStateSystemBuilder#getQuarkAbsoluteAndAdd(String...)}
+ *
+ * @param ss
+ * The state system the attribute belongs to
+ * @param path
+ * Full path to the attribute
+ * @return The quark for this attribute
+ */
+ private static int getQuarkAbsoluteAndAdd(@Nullable ITmfStateSystemBuilder ss, String... path) {
+ if (ss == null) {
+ throw new NullPointerException(ERROR_MESSAGE);
+ }
+ return ss.getQuarkAbsoluteAndAdd(path);
+ }
+
+ /**
+ * Quark-retrieving method, but the attribute is queried starting from the
+ * startNodeQuark. If the attribute does not exist, it will add it to the
+ * state system if the context allows it.
+ *
+ * See {@link ITmfStateSystemBuilder#getQuarkRelativeAndAdd(int, String...)}
+ *
+ ** @param ss
+ * The state system the attribute belongs to
+ * @param startNodeQuark
+ * The quark of the attribute from which 'path' originates.
+ * @param path
+ * Relative path to the attribute
+ * @return The quark for this attribute
+ */
+ private static int getQuarkRelativeAndAdd(@Nullable ITmfStateSystemBuilder ss, int startNodeQuark, String... path) {
+ if (ss == null) {
+ throw new NullPointerException(ERROR_MESSAGE);
+ }
+ return ss.getQuarkRelativeAndAdd(startNodeQuark, path);
+ }
+
+ /**
+ * Update the scenario internal data
+ *
+ * @param container
+ * The state system container this class use
+ * @param info
+ * The scenario details
+ * @param event
+ * The current event
+ */
+ public void update(final IXmlStateSystemContainer container, final TmfXmlScenarioInfo info, final @Nullable ITmfEvent event) {
+ updateScenarioSpecificStateStartTime(event, container, info);
+ updateScenarioState(event, container, info);
+ updateScenarioStatus(event, container, info);
+ }
+
+ private static void updateScenarioStatus(@Nullable ITmfEvent event, IXmlStateSystemContainer container, final TmfXmlScenarioInfo info) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = getTimestamp(event, ss);
+ ITmfStateValue value;
+ try {
+ // save the status
+ switch (info.getStatus()) {
+ case IN_PROGRESS:
+ value = STATUS_MAP.get(ScenarioStatusType.IN_PROGRESS);
+ break;
+ case ABANDONED:
+ value = STATUS_MAP.get(ScenarioStatusType.ABANDONED);
+ break;
+ case MATCHED:
+ value = STATUS_MAP.get(ScenarioStatusType.MATCHED);
+ break;
+ case PENDING:
+ value = STATUS_MAP.get(ScenarioStatusType.PENDING);
+ break;
+ default:
+ value = TmfStateValue.nullValue();
+ break;
+ }
+ ss.modifyAttribute(ts, value, info.getStatusQuark());
+ } catch (StateValueTypeException | AttributeNotFoundException e) {
+ Activator.logError("failed to update scenario status"); //$NON-NLS-1$
+ }
+ }
+
+ private static long getTimestamp(@Nullable ITmfEvent event, @Nullable ITmfStateSystemBuilder ss) {
+ if (event != null) {
+ return event.getTimestamp().toNanos();
+ }
+ if (ss != null) {
+ return ss.getCurrentEndTime();
+ }
+ throw new IllegalArgumentException("Event and state system cannot be null at the same time."); //$NON-NLS-1$
+ }
+
+ private static void updateScenarioState(final @Nullable ITmfEvent event, final IXmlStateSystemContainer container, final TmfXmlScenarioInfo info) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = getTimestamp(event, ss);
+ try {
+ // save the status
+ ITmfStateValue value = TmfStateValue.newValueString(info.getActiveState());
+ int attributeQuark = ss.getQuarkRelativeAndAdd(info.getQuark(), TmfXmlStrings.STATE);
+ ss.modifyAttribute(ts, value, attributeQuark);
+ } catch (StateValueTypeException | AttributeNotFoundException e) {
+ Activator.logError("failed to update scenario state"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Update the start time of specified state
+ *
+ * @param event
+ * The current event
+ * @param container
+ * The state system container this class use
+ * @param info
+ * The scenario details
+ */
+ private static void updateScenarioSpecificStateStartTime(final @Nullable ITmfEvent event, final IXmlStateSystemContainer container, final TmfXmlScenarioInfo info) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = getTimestamp(event, ss);
+ try {
+ int stateQuark = ss.getQuarkRelativeAndAdd(info.getQuark(), TmfXmlStrings.STATE);
+ String activeState = ss.queryOngoingState(stateQuark).unboxStr();
+ if (activeState.compareTo(info.getActiveState()) != 0) {
+ int attributeQuark = ss.getQuarkRelativeAndAdd(stateQuark, info.getActiveState(), START_TIME);
+ ITmfStateValue value = TmfStateValue.newValueLong(ts);
+ ss.modifyAttribute(ts, value, attributeQuark);
+ }
+ } catch (StateValueTypeException | AttributeNotFoundException e) {
+ Activator.logError("failed to update the start time of the state"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Start the scenario, sets the start time for the time of the event
+ *
+ * @param container
+ * The state system container this class use
+ * @param info
+ * The scenario details. The value should be null if there is no
+ * scenario
+ * @param event
+ * The active event
+ */
+ public void startScenario(final IXmlStateSystemContainer container, final TmfXmlScenarioInfo info, final ITmfEvent event) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = getTimestamp(event, ss);
+ try {
+ // save the status
+ ITmfStateValue value = TmfStateValue.newValueLong(ts);
+ int attributeQuark = ss.getQuarkRelativeAndAdd(info.getQuark(), START_TIME);
+ ss.modifyAttribute(ts, value, attributeQuark);
+ } catch (StateValueTypeException | AttributeNotFoundException e) {
+ Activator.logError("failed to update the start time of the scenario"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Set the end time of the scenario to the time of the event, or current
+ * state system end time if null, and recycle the attribute quark
+ *
+ * @param container
+ * The state system container this class use
+ * @param info
+ * The scenario details. The value should be null if there is no
+ * scenario
+ * @param event
+ * The active event
+ */
+ public void completeScenario(final IXmlStateSystemContainer container, final TmfXmlScenarioInfo info, final @Nullable ITmfEvent event) {
+ ITmfStateSystemBuilder ss = (ITmfStateSystemBuilder) container.getStateSystem();
+ long ts = getTimestamp(event, ss);
+ TmfAttributePool pool = getPoolFor(container, info.getFsmId());
+ pool.recycle(info.getQuark(), ts);
+ }
+}
******************************************************************************/
package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlScenarioHistoryBuilder.ScenarioStatusType;
+
/**
* This class gives basic details about a scenario (quark, scenarioName, ...)
*
* @since 2.0
*/
public class TmfXmlScenarioInfo {
- private final String fScenarioName;
+
private final int fQuark;
+ private final TmfXmlFsm fFsm;
+ private final int fStatusQuark;
private String fActiveState;
+ private ScenarioStatusType fStatus;
/**
* Constructor
*
- * @param scenarioName
- * The scenario name
* @param activeState
* The active state
+ * @param status
+ * The scenario status
* @param quark
* The scenario quark
+ * @param statusQuark
+ * The scenario status quark
+ * @param fsm
+ * The FSM this scenario is part of
*/
- public TmfXmlScenarioInfo(String scenarioName, String activeState, int quark) {
- fScenarioName = scenarioName;
+ public TmfXmlScenarioInfo(String activeState, ScenarioStatusType status, int quark, int statusQuark, TmfXmlFsm fsm) {
fActiveState = activeState;
fQuark = quark;
+ fStatus = status;
+ fStatusQuark = statusQuark;
+ fFsm = fsm;
}
/**
}
/**
- * Get the scenario quark
+ * Set the status of this active scenario
*
- * @return The quark
+ * @param status
+ * The scenario status
*/
- public int getQuark() {
- return fQuark;
+ public void setStatus(ScenarioStatusType status) {
+ fStatus = status;
}
/**
- * Get the scenario name
+ * Get the scenario quark
*
- * @return The name
+ * @return The quark
*/
- public String getScenarioName() {
- return fScenarioName;
+ public int getQuark() {
+ return fQuark;
}
/**
public String getActiveState() {
return fActiveState;
}
+
+ /**
+ * Get the active scenario status
+ *
+ * @return The status
+ */
+ public ScenarioStatusType getStatus() {
+ return fStatus;
+ }
+
+ /**
+ * Get the scenario status quark
+ *
+ * @return The quark
+ */
+ public int getStatusQuark() {
+ return fStatusQuark;
+ }
+
+ /**
+ * Get the ID of the FSM this scenario is part of
+ *
+ * @return The ID of the FSM
+ */
+ public String getFsmId() {
+ return fFsm.getId();
+ }
}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * This class implements a state tree described in XML-defined pattern
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class TmfXmlState {
+
+ private final String fId;
+ private final IXmlStateSystemContainer fContainer;
+ private final List<TmfXmlStateTransition> fTransitions;
+ private @Nullable TmfXmlState fparent;
+ private List<String> fOnEntryActions;
+ private List<String> fOnExitActions;
+ //TODO Sub-state are not yet supported.
+ private Map<String, TmfXmlState> fChildren;
+ private @Nullable TmfXmlStateTransition fInitialTransition;
+ private @Nullable String fInitialStateId;
+ private @Nullable String fFinalStateId;
+ private Type fType;
+
+ /**
+ * Enum for the type of state
+ */
+ public enum Type {
+ /**
+ * Final state type
+ */
+ FINAL,
+ /**
+ * Initial state type
+ */
+ INITIAL,
+ /**
+ * Fail state type, the pattern has failed to match
+ */
+ FAIL,
+ /**
+ * This is the normal state type, for states that are not the first,
+ * final or failing state
+ */
+ DEFAULT
+ }
+
+ private TmfXmlState(IXmlStateSystemContainer container, Type type, String id, @Nullable TmfXmlState parent, List<@NonNull TmfXmlStateTransition> transitions, Map<@NonNull String, @NonNull TmfXmlState> children, List<String> onentryActions, List<String> onexitActions) {
+ fContainer = container;
+ fType = type;
+ fId = id;
+ fparent = parent;
+ fTransitions = transitions;
+ fChildren = children;
+ fOnEntryActions = onentryActions;
+ fOnExitActions = onexitActions;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this state
+ * @param container
+ * The state system container this state definition belongs to
+ * @param parent
+ * The parent state of this state
+ * @return The new {@link TmfXmlState}
+ */
+ public static TmfXmlState create(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container, @Nullable TmfXmlState parent) {
+ Type type = getStateType(node);
+ String id = node.getAttribute(TmfXmlStrings.ID);
+ List<TmfXmlStateTransition> transitions = getTransitions(modelFactory, container, node);
+
+ NodeList nodesOnentry = node.getElementsByTagName(TmfXmlStrings.ONENTRY);
+ List<String> onentryActions = nodesOnentry.getLength() > 0 ? Arrays.asList(((Element) nodesOnentry.item(0)).getAttribute(TmfXmlStrings.ACTION).split(TmfXmlStrings.AND_SEPARATOR)) : Collections.EMPTY_LIST;
+
+ NodeList nodesOnexit = node.getElementsByTagName(TmfXmlStrings.ONEXIT);
+ List<String> onexitActions = nodesOnexit.getLength() > 0 ? Arrays.asList(((Element) nodesOnexit.item(0)).getAttribute(TmfXmlStrings.ACTION).split(TmfXmlStrings.AND_SEPARATOR)) : Collections.EMPTY_LIST;
+
+ TmfXmlState state = new TmfXmlState(container, type, id, parent, transitions, new HashMap<>(), onentryActions, onexitActions);
+ initState(state, modelFactory, container, node);
+
+ return state;
+ }
+
+ private static void getFinalState(TmfXmlState parentState, ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, Element node) {
+ NodeList nodesFinal = node.getElementsByTagName(TmfXmlStrings.FINAL);
+ String finalStateId = null;
+ if (nodesFinal.getLength() > 0) {
+ final Element finalElement = NonNullUtils.checkNotNull((Element) nodesFinal.item(0));
+ finalStateId = nodesFinal.getLength() > 0 ? finalElement.getAttribute(TmfXmlStrings.ID) : null;
+ TmfXmlState finalState = modelFactory.createState(finalElement, container, parentState);
+ parentState.getChildren().put(finalState.getId(), finalState);
+ }
+ parentState.fFinalStateId = finalStateId;
+ }
+
+ private static void getSubStates(TmfXmlState parentState, ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, Element node) {
+ String initial = node.getAttribute(TmfXmlStrings.INITIAL);
+ TmfXmlStateTransition initialTransition = null;
+ if (initial.isEmpty()) {
+ NodeList nodesInitial = node.getElementsByTagName(TmfXmlStrings.INITIAL);
+ if (nodesInitial.getLength() == 1) {
+ final @NonNull Element transitionElement = NonNullUtils.checkNotNull((Element) ((Element) nodesInitial.item(0)).getElementsByTagName(TmfXmlStrings.TRANSITION).item(0));
+ initialTransition = modelFactory.createStateTransition(transitionElement, container);
+ initial = initialTransition.getTarget();
+ }
+ }
+
+ NodeList nodesState = node.getElementsByTagName(TmfXmlStrings.STATE);
+ for (int i = 0; i < nodesState.getLength(); i++) {
+ TmfXmlState child = modelFactory.createState(NonNullUtils.checkNotNull((Element) nodesState.item(i)), container, parentState);
+ parentState.getChildren().put(child.getId(), child);
+
+ if (i == 0 && initial.isEmpty()) {
+ initial = child.getId();
+ }
+ }
+ parentState.fInitialStateId = initial.isEmpty() ? null : initial;
+ parentState.fInitialTransition = initialTransition;
+ }
+
+ private static void initState(TmfXmlState state, ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, Element node) {
+ getSubStates(state, modelFactory, container, node);
+ getFinalState(state, modelFactory, container, node);
+ }
+
+ /**
+ * Get the List of transitions for this state
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this state definition
+ * @return The list of transitions
+ */
+ private static List<@NonNull TmfXmlStateTransition> getTransitions(ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, Element node) {
+ List<@NonNull TmfXmlStateTransition> transitions = new ArrayList<>();
+ NodeList nodesTransition = node.getElementsByTagName(TmfXmlStrings.TRANSITION);
+ for (int i = 0; i < nodesTransition.getLength(); i++) {
+ final Element element = (Element) nodesTransition.item(i);
+ if (element == null) {
+ throw new IllegalArgumentException();
+ }
+ TmfXmlStateTransition transition = modelFactory.createStateTransition(element, container);
+ transitions.add(transition);
+ }
+ return transitions;
+ }
+
+ /**
+ * Get the state type from its XML definition
+ * @param node
+ * The XML definition of the state
+ * @return The state type
+ */
+ private static Type getStateType(Element node) {
+ switch (node.getNodeName()) {
+ case TmfXmlStrings.FINAL:
+ return Type.FINAL;
+ case TmfXmlStrings.INITIAL:
+ return Type.INITIAL;
+ case TmfXmlStrings.ABANDON:
+ return Type.FAIL;
+ case TmfXmlStrings.STATE:
+ default:
+ return Type.DEFAULT;
+ }
+ }
+
+ /**
+ * Get the state id
+ *
+ * @return The state id
+ */
+ public String getId() {
+ return fId;
+ }
+
+ /**
+ * Get the container
+ *
+ * @return The container
+ */
+ public IXmlStateSystemContainer getContainer() {
+ return fContainer;
+ }
+
+ /**
+ * The list of transitions of this state
+ *
+ * @return The list of transitions
+ */
+ public List<TmfXmlStateTransition> getTransitionList() {
+ return fTransitions;
+ }
+
+ /**
+ * Get the actions to execute when entering this state, in an array
+ *
+ * @return The array of actions
+ */
+ public List<String> getOnEntryActions() {
+ return fOnEntryActions;
+ }
+
+ /**
+ * Get the actions to execute when leaving this state, in an array
+ *
+ * @return The array of actions
+ */
+ public List<String> getOnExitActions() {
+ return fOnExitActions;
+ }
+
+ /**
+ * Get children states of this state into a map
+ *
+ * @return The map of children state
+ */
+ public Map<String, TmfXmlState> getChildren() {
+ return fChildren;
+ }
+
+ /**
+ * Get the initial transition of this state
+ *
+ * @return The initial transition
+ */
+ public @Nullable TmfXmlStateTransition getInitialTransition() {
+ return fInitialTransition;
+ }
+
+ /**
+ * Get the initial state ID
+ *
+ * @return The initial state ID
+ */
+ public @Nullable String getInitialStateId() {
+ return fInitialStateId;
+ }
+
+ /**
+ * Get the final state ID
+ *
+ * @return The final state ID
+ */
+ public @Nullable String getFinalStateId() {
+ return fFinalStateId;
+ }
+
+ /**
+ * Get the parent state
+ *
+ * @return The parent state
+ */
+ public @Nullable TmfXmlState getParent() {
+ return fparent;
+ }
+
+ /**
+ * Get the type of this state
+ *
+ * @return The type of the state
+ */
+ public Type getType() {
+ return fType;
+ }
+}
EVENTNAME
}
- private final String SCENARIO_NAME = "#scenarioName"; //$NON-NLS-1$
-
private final String CURRENT_STATE = "#currentState"; //$NON-NLS-1$
+ private final String CURRENT_SCENARIO = "#CurrentScenario"; //$NON-NLS-1$
+
/** Type of attribute */
private final StateAttributeType fType;
if (name.length() > 0 && name.charAt(0) == '#' && scenarioInfo == null) {
throw new IllegalStateException("XML Attribute needs " + fName + " but the data is not available."); //$NON-NLS-1$//$NON-NLS-2$
}
- name = name.equals(SCENARIO_NAME) ? checkNotNull(scenarioInfo).getScenarioName() : name.equals(CURRENT_STATE) ? checkNotNull(scenarioInfo).getActiveState() : fName;
+ name = name.equals(CURRENT_STATE) ? checkNotNull(scenarioInfo).getActiveState()
+ : fName;
try {
switch (fType) {
if (name == null) {
throw new IllegalStateException("Invalid attribute name"); //$NON-NLS-1$
}
+ if (name.equals(CURRENT_SCENARIO)) {
+ return checkNotNull(scenarioInfo).getQuark();
+ }
if (startQuark == IXmlStateSystemContainer.ROOT_QUARK) {
quark = getQuarkAbsoluteAndAdd(name);
} else {
* Conditional state change with a condition to verify
*/
private class XmlConditionalChange implements IXmlStateChange {
- private final TmfXmlCondition fCondition;
+ private final ITmfXmlCondition fCondition;
private final TmfXmlStateChange fThenChange;
private final @Nullable TmfXmlStateChange fElseChange;
@Override
public void handleEvent(@NonNull ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo) throws AttributeNotFoundException, StateValueTypeException, TimeRangeException {
TmfXmlStateChange toExecute = fThenChange;
- try {
- if (!fCondition.testForEvent(event, scenarioInfo)) {
- toExecute = fElseChange;
- }
- } catch (AttributeNotFoundException e) {
- /*
- * An attribute in the condition did not exist (yet), return
- * from the state change
- */
- return;
+ if (!fCondition.test(event, scenarioInfo)) {
+ toExecute = fElseChange;
}
if (toExecute == null) {
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.w3c.dom.Element;
+
+/**
+ * This Class implements a state transition tree in the XML-defined state
+ * system.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class TmfXmlStateTransition extends TmfXmlBasicTransition {
+
+ private static final String SAVED_STORED_FIELDS_ACTION_STRING = TmfXmlStrings.CONSTANT_PREFIX + ITmfXmlAction.SAVE_STORED_FIELDS_STRING;
+ private static final String CLEAR_STORED_FIELDS_ACTION_STRINGS = TmfXmlStrings.CONSTANT_PREFIX + ITmfXmlAction.CLEAR_STORED_FIELDS_STRING;
+
+ private final String fTarget;
+ private final List<String> fAction;
+ private final boolean fStoredFieldsToBeSaved;
+ private final boolean fStoredFieldsToBeCleared;
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this state transition
+ * @param container
+ * The state system container this state transition belongs to
+ */
+ public TmfXmlStateTransition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
+ super(node);
+ String target = node.getAttribute(TmfXmlStrings.TARGET);
+ if (target.isEmpty()) {
+ throw new IllegalStateException("No target state has been specified."); //$NON-NLS-1$
+ }
+ fTarget = target;
+ String action = node.getAttribute(TmfXmlStrings.ACTION);
+ List<String> actions = action.equals(TmfXmlStrings.NULL) ? Collections.EMPTY_LIST : Arrays.asList(action.split(TmfXmlStrings.AND_SEPARATOR));
+ fStoredFieldsToBeSaved = (node.getAttribute(TmfXmlStrings.SAVE_STORED_FIELDS).equals(TmfXmlStrings.EMPTY_STRING) ? false : Boolean.parseBoolean(node.getAttribute(TmfXmlStrings.SAVE_STORED_FIELDS)));
+ fStoredFieldsToBeCleared = (node.getAttribute(TmfXmlStrings.CLEAR_STORED_FIELDS).equals(TmfXmlStrings.EMPTY_STRING) ? false : Boolean.parseBoolean(node.getAttribute(TmfXmlStrings.CLEAR_STORED_FIELDS)));
+ fAction = new ArrayList<>();
+ if (fStoredFieldsToBeSaved) {
+ fAction.add(SAVED_STORED_FIELDS_ACTION_STRING);
+ }
+ fAction.addAll(actions);
+ if (fStoredFieldsToBeCleared) {
+ fAction.add(CLEAR_STORED_FIELDS_ACTION_STRINGS);
+ }
+ }
+
+ /**
+ * The next state of the state machine this state transition belongs to.
+ *
+ * @return the next state this transition try to reach
+ */
+ public String getTarget() {
+ return fTarget;
+ }
+
+ /**
+ * The action to be executed when the input of this state transition is
+ * validated
+ *
+ * @return the action to execute if the input is validate
+ */
+ public List<String> getAction() {
+ return fAction;
+ }
+
+ /**
+ * Tell if the stored fields have to be saved at this step of the scenario
+ *
+ * @return If the stored fields have to be saved or not
+ */
+ public boolean isStoredFieldsToBeSaved() {
+ return fStoredFieldsToBeSaved;
+ }
+
+ /**
+ * Tell if the stored fields have to be cleared at this moment of this scenario
+ *
+ * @return If the stored fields have to cleared or not
+ */
+ public boolean isStoredFieldsToBeCleared() {
+ return fStoredFieldsToBeCleared;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider.XmlPatternStateProvider;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.XmlUtils;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.w3c.dom.Element;
+
+/**
+ * This Class implements a timestamp condition tree in the XML-defined state
+ * system.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class TmfXmlTimestampCondition implements ITmfXmlCondition {
+
+ private enum TimeRangeOperator {
+ IN,
+ OUT,
+ OTHER
+ }
+
+ private enum ElapsedTimeOperator {
+ LESS,
+ EQUAL,
+ MORE,
+ NONE
+ }
+
+ private static final long US = 1000l;
+ private final IXmlTimestampsCondition fTimestampsCondition;
+ private final IXmlStateSystemContainer fParent;
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this timestamp condition
+ * @param container
+ * The state system container this timestamp condition belongs to
+ */
+ public TmfXmlTimestampCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
+ fParent = container;
+ String type = node.getNodeName();
+ switch (type) {
+ case TmfXmlStrings.TIME_RANGE:
+ fTimestampsCondition = new TmfXmlTimeRangeCondition(modelFactory, node, fParent);
+ break;
+ case TmfXmlStrings.ELAPSED_TIME:
+ fTimestampsCondition = new TmfXmlElapsedTimeCondition(modelFactory, node, fParent);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid timestampsChecker declaration in XML : Type should be timeRange or elapsedTime"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Normalize the value into a nanosecond time value
+ *
+ * @param timestamp
+ * The timestamp value
+ * @param unit
+ * The initial unit of the timestamp
+ * @return The value of the timestamp in nanoseconds
+ */
+ public static long valueToNanoseconds(long timestamp, String unit) {
+ switch (unit) {
+ case TmfXmlStrings.NS:
+ return timestamp;
+ case TmfXmlStrings.US:
+ return timestamp * US;
+ case TmfXmlStrings.MS:
+ return timestamp * US * US;
+ case TmfXmlStrings.S:
+ return timestamp * US * US * US;
+ default:
+ throw new IllegalArgumentException("The time unit is not yet supporting."); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Validate the event
+ *
+ * @param event
+ * The current event
+ * @param scenarioInfo
+ * The active scenario details. The value should be null if there
+ * is no scenario
+ * @return True if the test succeed, false otherwise
+ */
+ @Override
+ public boolean test(ITmfEvent event,@Nullable TmfXmlScenarioInfo scenarioInfo) {
+ return fTimestampsCondition.test(event, scenarioInfo);
+ }
+
+ private interface IXmlTimestampsCondition extends ITmfXmlCondition {
+ }
+
+ private class TmfXmlTimeRangeCondition implements IXmlTimestampsCondition {
+
+ private final TimeRangeOperator fType;
+ private final String fUnit;
+ private final String fBegin;
+ private final String fEnd;
+ private final IXmlStateSystemContainer fContainer;
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this time range condition transition
+ * @param container
+ * The state system container this time range condition
+ * belongs to
+ */
+ public TmfXmlTimeRangeCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
+ fContainer = container;
+ String unit = node.getAttribute(TmfXmlStrings.UNIT);
+ fUnit = unit;
+ List<@Nullable Element> childElements = NonNullUtils.checkNotNull(XmlUtils.getChildElements(node));
+ if (childElements.size() != 1) {
+ throw new IllegalArgumentException("Invalid timestampsChecker declaration in XML : Only one timing condition is allowed"); //$NON-NLS-1$
+ }
+ final Element firstElement = NonNullUtils.checkNotNull(childElements.get(0));
+ String type = firstElement.getNodeName();
+ switch (type) {
+ case TmfXmlStrings.IN:
+ fType = TimeRangeOperator.IN;
+ break;
+ case TmfXmlStrings.OUT:
+ fType = TimeRangeOperator.OUT;
+ break;
+ default:
+ fType = TimeRangeOperator.OTHER;
+ break;
+ }
+
+ final String begin = firstElement.getAttribute(TmfXmlStrings.BEGIN);
+ final String end = firstElement.getAttribute(TmfXmlStrings.END);
+ fBegin = begin;
+ fEnd = end;
+ }
+
+ @Override
+ public boolean test(ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo) {
+ ITmfStateSystem ss = fContainer.getStateSystem();
+
+ long begin;
+ begin = valueToNanoseconds(Long.parseLong(fBegin), fUnit);
+
+ long end;
+ end = valueToNanoseconds(Long.parseLong(fEnd), fUnit);
+
+ // swap the value if begin > end
+ if (begin > end) {
+ begin = begin ^ end;
+ end = begin ^ end;
+ begin = begin ^ end;
+ }
+
+ begin = Math.max(ss.getStartTime(), begin);
+ end = Math.min(ss.getCurrentEndTime(), end);
+ begin = Math.min(begin, end);
+
+ long ts = event.getTimestamp().toNanos();
+ switch (fType) {
+ case IN:
+ return intersects(begin, end, ts);
+ case OUT:
+ return !intersects(begin, end, ts);
+ case OTHER:
+ default:
+ return false;
+ }
+ }
+
+ private boolean intersects(long begin, long end, long ts) {
+ return ts >= begin && ts <= end;
+ }
+
+ }
+
+ private class TmfXmlElapsedTimeCondition implements IXmlTimestampsCondition {
+
+ private final IXmlStateSystemContainer fContainer;
+ private final ElapsedTimeOperator fType;
+ private final String fUnit;
+ private final String fValue;
+ private final String fReferenceState;
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this elapsed time condition
+ * @param container
+ * The state system container this elapsed time condition
+ * belongs to
+ */
+ public TmfXmlElapsedTimeCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
+ fContainer = container;
+ String unit = node.getAttribute(TmfXmlStrings.UNIT);
+ fUnit = unit;
+ List<@Nullable Element> childElements = XmlUtils.getChildElements(node);
+ if (childElements.size() != 1) {
+ throw new IllegalArgumentException("Invalid timestampsChecker declaration in XML : Only one timing condition is allowed"); //$NON-NLS-1$
+ }
+ final Element firstElement = NonNullUtils.checkNotNull(childElements.get(0));
+ String type = firstElement.getNodeName();
+ switch (type) {
+ case TmfXmlStrings.LESS:
+ fType = ElapsedTimeOperator.LESS;
+ break;
+ case TmfXmlStrings.EQUAL:
+ fType = ElapsedTimeOperator.EQUAL;
+ break;
+ case TmfXmlStrings.MORE:
+ fType = ElapsedTimeOperator.MORE;
+ break;
+ default:
+ fType = ElapsedTimeOperator.NONE;
+ break;
+ }
+ final String reference = firstElement.getAttribute(TmfXmlStrings.SINCE);
+ final String value = firstElement.getAttribute(TmfXmlStrings.VALUE);
+ fReferenceState = reference;
+ fValue = value;
+ }
+
+ @Override
+ public boolean test(ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo) {
+ if (scenarioInfo == null) {
+ Activator.logError("Elapse time conditions require scenarioInfos and scenarioInfos is null"); //$NON-NLS-1$
+ return false;
+ }
+ boolean success;
+ long ts = event.getTimestamp().toNanos();
+ long referenceTimestamps = ((XmlPatternStateProvider) fContainer).getHistoryBuilder().getSpecificStateStartTime(fContainer, fReferenceState, scenarioInfo, event);
+ if (ts < referenceTimestamps) {
+ throw new IllegalArgumentException("Timestamp is inferior to reference time"); //$NON-NLS-1$
+ }
+ switch (fType) {
+ case LESS:
+ success = (ts - referenceTimestamps) < valueToNanoseconds(Long.parseLong(fValue), fUnit);
+ break;
+ case EQUAL:
+ success = (ts - referenceTimestamps) == valueToNanoseconds(Long.parseLong(fValue), fUnit);
+ break;
+ case MORE:
+ success = (ts - referenceTimestamps) > valueToNanoseconds(Long.parseLong(fValue), fUnit);
+ break;
+ case NONE:
+ default:
+ success = false;
+ break;
+ }
+ return success;
+ }
+
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.XmlUtils;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * This Class implements a transition input tree in the XML-defined state
+ * system.
+ *
+ * TODO We should merge this class with the current TmfXmlCondition, that should
+ * be kept as is for compatibility with current stateProvider
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class TmfXmlTransitionValidator implements ITmfXmlCondition {
+
+ IXmlStateSystemContainer fParent;
+ private final String fId;
+ private final ITmfXmlCondition fCondition;
+
+ /**
+ * Constructor
+ *
+ * @param modelFactory
+ * The factory used to create XML model elements
+ * @param node
+ * The XML root of this transition input
+ * @param parent
+ * The state system container this transition input belongs to
+ */
+ public TmfXmlTransitionValidator(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer parent) {
+ fParent = parent;
+ fId = node.getAttribute(TmfXmlStrings.ID);
+
+ List<@Nullable Element> childElements = XmlUtils.getChildElements(node);
+ Node child = NonNullUtils.checkNotNull(childElements.get(0));
+ fCondition = modelFactory.createCondition((Element) child, parent);
+ }
+
+ /**
+ * Get the ID of this transition input
+ *
+ * @return The id of this transition input
+ */
+ public String getId() {
+ return fId;
+ }
+
+ @Override
+ public boolean test(ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo) {
+ return fCondition.test(event, scenarioInfo);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import java.util.Map.Entry;
+
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider.XmlPatternStateProvider;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
+
+/**
+ * This action will update the value of the stored fields in the state system
+ * based on the current event data.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ */
+public class UpdateStoredFieldsAction implements ITmfXmlAction {
+
+ private final IXmlStateSystemContainer fParent;
+
+ /**
+ * Constructor
+ *
+ * @param parent
+ * The state system container this action belongs to
+ */
+ public UpdateStoredFieldsAction(IXmlStateSystemContainer parent) {
+ fParent = parent;
+ }
+
+ @Override
+ public void execute(ITmfEvent event, TmfXmlScenarioInfo scenarioInfo) {
+ if (fParent instanceof XmlPatternStateProvider) {
+ for (Entry<String, String> entry : ((XmlPatternStateProvider) fParent).getStoredFields().entrySet()) {
+ ITmfEventField eventField = event.getContent().getField(entry.getKey());
+ ITmfStateValue stateValue = null;
+ if (eventField != null) {
+ final String alias = entry.getValue();
+ Object field = eventField.getValue();
+ if (field instanceof String) {
+ stateValue = TmfStateValue.newValueString((String) field);
+ } else if (field instanceof Long) {
+ stateValue = TmfStateValue.newValueLong(((Long) field).longValue());
+ } else if (field instanceof Integer) {
+ stateValue = TmfStateValue.newValueInt(((Integer) field).intValue());
+ } else if (field instanceof Double) {
+ stateValue = TmfStateValue.newValueDouble(((Double) field).doubleValue());
+ }
+ if (stateValue == null) {
+ throw new IllegalStateException("State value is null. Invalid type."); //$NON-NLS-1$
+ }
+ ((XmlPatternStateProvider) fParent).getHistoryBuilder().updateStoredFields(fParent, alias, stateValue, scenarioInfo, event);
+ }
+ }
+ }
+ }
+}
import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlStateAttribute;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlStateValue;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlAction;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlCondition;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlEventHandler;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlFsm;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlLocation;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlPatternEventHandler;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlPatternSegmentBuilder;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlState;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlStateChange;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlStateTransition;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlTransitionValidator;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlTimestampCondition;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
import org.w3c.dom.Element;
@Override
public TmfXmlCondition createCondition(Element node, IXmlStateSystemContainer container) {
- return new TmfXmlCondition(this, node, container);
+ return TmfXmlCondition.create(this, node, container);
}
@Override
return new TmfXmlLocation(this, node, container);
}
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlPatternEventHandler createPatternEventHandler(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlPatternEventHandler(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlTransitionValidator createTransitionValidator(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlTransitionValidator(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlAction createAction(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlAction(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlFsm createFsm(Element node, IXmlStateSystemContainer container) {
+ return TmfXmlFsm.create(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public @NonNull TmfXmlState createState(Element node, IXmlStateSystemContainer container, @Nullable TmfXmlState parent) {
+ return TmfXmlState.create(this, node, container, parent);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlStateTransition createStateTransition(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlStateTransition(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlTimestampCondition createTimestampsCondition(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlTimestampCondition(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlPatternSegmentBuilder createPatternSegmentBuilder(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlPatternSegmentBuilder(this, node, container);
+ }
}
import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlStateAttribute;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlStateValue;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlAction;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlCondition;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlEventHandler;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlFsm;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlLocation;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlPatternEventHandler;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlPatternSegmentBuilder;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlState;
import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlStateChange;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlStateTransition;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlTransitionValidator;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlTimestampCondition;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
import org.w3c.dom.Element;
@Override
public TmfXmlCondition createCondition(Element node, IXmlStateSystemContainer container) {
- return new TmfXmlCondition(this, node, container);
+ return TmfXmlCondition.create(this, node, container);
}
@Override
return new TmfXmlLocation(this, node, container);
}
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlPatternEventHandler createPatternEventHandler(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlPatternEventHandler(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlTransitionValidator createTransitionValidator(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlTransitionValidator(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlAction createAction(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlAction(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlFsm createFsm(Element node, IXmlStateSystemContainer container) {
+ return TmfXmlFsm.create(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public @NonNull TmfXmlState createState(Element node, IXmlStateSystemContainer container, @Nullable TmfXmlState parent) {
+ return TmfXmlState.create(this, node, container, parent);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlStateTransition createStateTransition(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlStateTransition(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlTimestampCondition createTimestampsCondition(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlTimestampCondition(this, node, container);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public TmfXmlPatternSegmentBuilder createPatternSegmentBuilder(Element node, IXmlStateSystemContainer container) {
+ return new TmfXmlPatternSegmentBuilder(this, node, container);
+ }
}
* The parent element to get children from
* @return The list of children Element of the parent
*/
- public static List<@Nullable Element> getChildElements(Element parent) {
+ public static @NonNull List<@Nullable Element> getChildElements(Element parent) {
NodeList childNodes = parent.getChildNodes();
List<@Nullable Element> childElements = new ArrayList<>();
for (int index = 0; index < childNodes.getLength(); index++) {
<xs:annotation>
<xs:documentation>Defines a finite state machine that will describe the behavior or a part of the behavior of a pattern. The FSM uses the transitions described to modify its behavior and can execute actions. Each pattern could have one or several FSMs to describe its behavior.</xs:documentation></xs:annotation></xs:element>
</xs:sequence>
- <xs:attribute name="initial" type="xs:string" use="required">
+ <xs:attribute name="initial" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Lists the state machines (FSMs) that will start directly at the beginning of the analysis. For instance, if the pattern need to start with both FSM A and B, the value of this attribute will be "A:B"</xs:documentation></xs:annotation></xs:attribute>
</xs:complexType>
*/
String PATTERN = "pattern";
+ /**
+ * @since 2.0
+ */
+ String STORED_FIELD = "storedField";
+
+ /**
+ * @since 2.0
+ */
+ String STORED_FIELDS = "storedFields";
+
+ /**
+ * @since 2.0
+ */
+ String PATTERN_HANDLER = "patternHandler";
+
/* XML synthetic event elements */
/**
* @since 2.0
*/
String SEGMENT_FIELD = "segField";
+ /**
+ * @since 2.0
+ */
+ String INITIAL = "initial";
+ /**
+ * @since 2.0
+ */
+ String TEST = "test";
+ /**
+ * @since 2.0
+ */
+ String ACTION = "action";
+ /**
+ * @since 2.0
+ */
+ String FSM = "fsm";
+ /**
+ * @since 2.0
+ */
+ String STATE = "state";
+ /**
+ * @since 2.0
+ */
+ String EVENT_INFO = "eventInfo";
+ /**
+ * @since 2.0
+ */
+ String TIME_INFO = "timeInfo";
+ /**
+ * @since 2.0
+ */
+ String EVENT = "event";
+ /**
+ * @since 2.0
+ */
+ String CONSTANT_PREFIX = "#";
+ /**
+ * @since 2.0
+ */
+ String FSM_SCHEDULE_ACTION = "fsmScheduleAction";
+ /**
+ * @since 2.0
+ */
+ String MULTIPLE = "multiple";
+ /**
+ * @since 2.0
+ */
+ String PRECONDITION = "precondition";
+ /**
+ * @since 2.0
+ */
+ String COND = "cond";
+ /**
+ * @since 2.0
+ */
+ String FINAL = "final";
+ /**
+ * @since 2.0
+ */
+ String ABANDON_STATE = "abandonState";
+ /**
+ * @since 2.0
+ */
+ String STATE_TABLE = "stateTable";
+ /**
+ * @since 2.0
+ */
+ String STATE_DEFINITION = "stateDefinition";
+ /**
+ * @since 2.0
+ */
+ String EMPTY_STRING = "";
+ /**
+ * @since 2.0
+ */
+ String TRANSITION = "transition";
+ /**
+ * @since 2.0
+ */
+ String TARGET = "target";
+ /**
+ * @since 2.0
+ */
+ String SAVE_STORED_FIELDS = "saveStoredFields";
+ /**
+ * @since 2.0
+ */
+ String CLEAR_STORED_FIELDS = "clearStoredFields";
+ /**
+ * @since 2.0
+ */
+ String TIME_RANGE = "timerange";
+ /**
+ * @since 2.0
+ */
+ String ELAPSED_TIME = "elapsedTime";
+ /**
+ * @since 2.0
+ */
+ String NS = "ns";
+ /**
+ * @since 2.0
+ */
+ String US = "us";
+ /**
+ * @since 2.0
+ */
+ String MS = "ms";
+ /**
+ * @since 2.0
+ */
+ String S = "s";
+ /**
+ * @since 2.0
+ */
+ String UNIT = "unit";
+ /**
+ * @since 2.0
+ */
+ String IN = "in";
+ /**
+ * @since 2.0
+ */
+ String OUT = "out";
+ /**
+ * @since 2.0
+ */
+ String BEGIN = "begin";
+ /**
+ * @since 2.0
+ */
+ String END = "end";
+ /**
+ * @since 2.0
+ */
+ String LESS = "less";
+ /**
+ * @since 2.0
+ */
+ String EQUAL = "equal";
+ /**
+ * @since 2.0
+ */
+ String MORE = "more";
+ /**
+ * @since 2.0
+ */
+ String SINCE = "since";
+ /**
+ * @since 2.0
+ */
+ String ARG = "arg";
+ /**
+ * @since 2.0
+ */
+ String SCENARIOS = "scenarios";
+ /**
+ * @since 2.0
+ */
+ String ONENTRY = "onentry";
+ /**
+ * @since 2.0
+ */
+ String ONEXIT = "onexit";
+ /**
+ * @since 2.0
+ */
+ String OR_SEPARATOR = "\\|";
+ /**
+ * @since 2.0
+ */
+ String AND_SEPARATOR = ":";
+ /**
+ * @since 2.0
+ */
+ String ALIAS = "alias";
+ /**
+ * @since 2.0
+ */
+ String ABANDON = "abandon";
}
\ No newline at end of file