tmf : Add pattern analysis behavior
authorJean-Christian Kouame <jean-christian.kouame@ericsson.com>
Wed, 9 Mar 2016 19:25:39 +0000 (14:25 -0500)
committerMatthew Khouzam <matthew.khouzam@ericsson.com>
Tue, 19 Apr 2016 18:57:14 +0000 (14:57 -0400)
This patch defines the behavior of the pattern analysis state provider
and defines all the models needed.

Change-Id: I6561feb02b06627ef5059d777a25a8bde56a70be
Signed-off-by: Jean-Christian Kouame <jean-christian.kouame@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/65751
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-by: Hudson CI
27 files changed:
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternStateProvider.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlAction.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlCondition.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlModelFactory.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlStateAttribute.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ResetStoredFieldsAction.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlAction.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlBasicTransition.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlCondition.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlFsm.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternEventHandler.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternSegmentBuilder.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenario.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioHistoryBuilder.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioInfo.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlState.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateAttribute.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateChange.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateTransition.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlTimestampCondition.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlTransitionValidator.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/UpdateStoredFieldsAction.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readonly/TmfXmlReadOnlyModelFactory.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readwrite/TmfXmlReadWriteModelFactory.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/XmlUtils.java
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/xmlPatternStateProvider.xsd
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/stateprovider/TmfXmlStrings.java

index d87a09a2fd9bfdf15f0407c65a62e4b95179b56b..8374b020a54ec73ebeef9f1ab8b46896c8eb190e 100644 (file)
@@ -8,15 +8,23 @@
  ******************************************************************************/
 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;
@@ -25,6 +33,7 @@ import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
 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
@@ -37,11 +46,21 @@ public class XmlPatternStateProvider extends AbstractTmfStateProvider implements
 
     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
@@ -58,18 +77,77 @@ public class XmlPatternStateProvider extends AbstractTmfStateProvider implements
         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
@@ -103,6 +181,7 @@ public class XmlPatternStateProvider extends AbstractTmfStateProvider implements
 
     @Override
     protected void eventHandle(@NonNull ITmfEvent event) {
+        fHandler.handleEvent(event);
     }
 
     /**
@@ -116,7 +195,18 @@ public class XmlPatternStateProvider extends AbstractTmfStateProvider implements
 
     @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
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlAction.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlAction.java
new file mode 100644 (file)
index 0000000..cd1b191
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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);
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlCondition.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlCondition.java
new file mode 100644 (file)
index 0000000..677203c
--- /dev/null
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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
index 72d0ea68bdd6bf861496fdc2629a8cdccd9d9fc9..cfeeb8192e4c9cc8f1772e3e2c971219fc28184f 100644 (file)
@@ -14,6 +14,7 @@ package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
 
 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;
 
@@ -109,4 +110,101 @@ public interface ITmfXmlModelFactory {
      */
     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);
 }
index 8763b0af21b0a1f885f9d2346648bf4838e05329..d74fcc715b2952dc682758e28c1c73ae5dce1400 100644 (file)
@@ -48,7 +48,8 @@ public interface ITmfXmlStateAttribute {
      *
      * 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
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ResetStoredFieldsAction.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ResetStoredFieldsAction.java
new file mode 100644 (file)
index 0000000..0a1a7e1
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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);
+            }
+        }
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlAction.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlAction.java
new file mode 100644 (file)
index 0000000..cc38801
--- /dev/null
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * 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);
+        }
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlBasicTransition.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlBasicTransition.java
new file mode 100644 (file)
index 0000000..c23e610
--- /dev/null
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * 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;
+    }
+}
index f76627f39ec5b08f06d85a2aa526fc552b8d9f23..573123f6a7fe295830c7a965757a819703a1eb75 100644 (file)
@@ -18,8 +18,10 @@ 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.statesystem.core.ITmfStateSystem;
 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
@@ -49,19 +51,21 @@ import org.w3c.dom.Element;
  *
  * @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 {
@@ -74,8 +78,16 @@ public class TmfXmlCondition {
         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
@@ -83,10 +95,10 @@ public class TmfXmlCondition {
      *            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);
@@ -104,57 +116,68 @@ public class TmfXmlCondition {
             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
@@ -163,7 +186,7 @@ public class TmfXmlCondition {
         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) {
@@ -173,10 +196,10 @@ public class TmfXmlCondition {
                 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));
         }
     }
 
@@ -203,28 +226,28 @@ public class TmfXmlCondition {
     }
 
     /**
-     * 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;
                     }
                 }
@@ -232,10 +255,10 @@ public class TmfXmlCondition {
             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;
                     }
                 }
@@ -313,7 +336,7 @@ public class TmfXmlCondition {
      */
     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:
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlFsm.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlFsm.java
new file mode 100644 (file)
index 0000000..be8bf40
--- /dev/null
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * 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;
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternEventHandler.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternEventHandler.java
new file mode 100644 (file)
index 0000000..9c7cb5d
--- /dev/null
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * 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);
+    }
+}
index 848cd6db9afef93ff58791a0e9af263af0fd1e8a..7b6c1771078672aa08b52ed026c90f664d43f2ad 100644 (file)
@@ -14,6 +14,7 @@ import java.util.ArrayList;
 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;
@@ -147,6 +148,31 @@ public class TmfXmlPatternSegmentBuilder {
         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) {
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenario.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenario.java
new file mode 100644 (file)
index 0000000..249d60e
--- /dev/null
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * 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);
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioHistoryBuilder.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioHistoryBuilder.java
new file mode 100644 (file)
index 0000000..9f87600
--- /dev/null
@@ -0,0 +1,440 @@
+/*******************************************************************************
+ * 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);
+    }
+}
index c6132e3a79f6447301f6d7d6f72ef0e0f1e364fb..c181b6f09b28623309160eafe25272d8a427add2 100644 (file)
@@ -8,6 +8,8 @@
  ******************************************************************************/
 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, ...)
  *
@@ -15,24 +17,33 @@ package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
  * @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;
     }
 
     /**
@@ -46,21 +57,22 @@ public class TmfXmlScenarioInfo {
     }
 
     /**
-     * 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;
     }
 
     /**
@@ -71,4 +83,31 @@ public class TmfXmlScenarioInfo {
     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();
+    }
 }
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlState.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlState.java
new file mode 100644 (file)
index 0000000..b84df18
--- /dev/null
@@ -0,0 +1,294 @@
+/*******************************************************************************
+ * 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;
+    }
+}
index 5aafea46cedf275e043223bc5b3181db5d4266ce..6e9e6caad9d44949828f5828fb5b120e8fa01a3e 100644 (file)
@@ -63,10 +63,10 @@ public abstract class TmfXmlStateAttribute implements ITmfXmlStateAttribute {
         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;
 
@@ -196,7 +196,8 @@ public abstract class TmfXmlStateAttribute implements ITmfXmlStateAttribute {
         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) {
@@ -205,6 +206,9 @@ public abstract class TmfXmlStateAttribute implements ITmfXmlStateAttribute {
                 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 {
index 63662ebe36f11bcad674980452c76f444aa2510c..25028b38676515b23562d4049f96d81379ba5e22 100644 (file)
@@ -129,7 +129,7 @@ public class TmfXmlStateChange {
      * 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;
 
@@ -160,16 +160,8 @@ public class TmfXmlStateChange {
         @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) {
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateTransition.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateTransition.java
new file mode 100644 (file)
index 0000000..16d47e0
--- /dev/null
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * 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;
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlTimestampCondition.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlTimestampCondition.java
new file mode 100644 (file)
index 0000000..422c126
--- /dev/null
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * 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;
+        }
+
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlTransitionValidator.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlTransitionValidator.java
new file mode 100644 (file)
index 0000000..7fe1dc0
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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);
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/UpdateStoredFieldsAction.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/UpdateStoredFieldsAction.java
new file mode 100644 (file)
index 0000000..bea8ab5
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * 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);
+                }
+            }
+        }
+    }
+}
index c57cdda1eebcfe2a1801e43f6230d0006a100d38..75292b7f5cba7243a2f48eaeda0cb4e3e0437ccc 100644 (file)
@@ -14,14 +14,23 @@ package org.eclipse.tracecompass.tmf.analysis.xml.core.model.readonly;
 
 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;
 
@@ -65,7 +74,7 @@ public class TmfXmlReadOnlyModelFactory implements ITmfXmlModelFactory {
 
     @Override
     public TmfXmlCondition createCondition(Element node, IXmlStateSystemContainer container) {
-        return new TmfXmlCondition(this, node, container);
+        return TmfXmlCondition.create(this, node, container);
     }
 
     @Override
@@ -83,4 +92,67 @@ public class TmfXmlReadOnlyModelFactory implements ITmfXmlModelFactory {
         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);
+    }
 }
index 84acc894059ade414e745205aa2debb856857884..1cfe63c69c68f19a4a5fcfa72e85aef3dbfbc3c1 100644 (file)
@@ -14,14 +14,23 @@ package org.eclipse.tracecompass.tmf.analysis.xml.core.model.readwrite;
 
 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;
 
@@ -65,7 +74,7 @@ public class TmfXmlReadWriteModelFactory implements ITmfXmlModelFactory {
 
     @Override
     public TmfXmlCondition createCondition(Element node, IXmlStateSystemContainer container) {
-        return new TmfXmlCondition(this, node, container);
+        return TmfXmlCondition.create(this, node, container);
     }
 
     @Override
@@ -83,4 +92,67 @@ public class TmfXmlReadWriteModelFactory implements ITmfXmlModelFactory {
         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);
+    }
 }
index 601266e7ca3659a5c53bbb96a0b6e324ec8183aa..fbefde251ed45e287cc990d73187e6757253aaa3 100644 (file)
@@ -282,7 +282,7 @@ public class XmlUtils {
      *            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++) {
index 9a41c44bf2f8ca63b834056ffb30ad69f7531703..042fa1925db991aa3c84300abac492cee6b88aff 100644 (file)
@@ -89,7 +89,7 @@
                                <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>
index d151efa4ec59f723328736d7c2732dcb18e81a6c..b40d714d309a707e0ae33e885d6f63b79972adbd 100644 (file)
@@ -108,6 +108,21 @@ public interface TmfXmlStrings {
      */
     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
@@ -130,4 +145,184 @@ public interface TmfXmlStrings {
      */
     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
This page took 0.062652 seconds and 5 git commands to generate.