From: Jean-Christian Kouame Date: Wed, 9 Mar 2016 19:25:39 +0000 (-0500) Subject: tmf : Add pattern analysis behavior X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=3a5f73a1164f560257346afa36d69b7d64bd988b;p=deliverable%2Ftracecompass.git tmf : Add pattern analysis behavior 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 Reviewed-on: https://git.eclipse.org/r/65751 Reviewed-by: Genevieve Bastien Tested-by: Genevieve Bastien Reviewed-by: Matthew Khouzam Reviewed-by: Hudson CI --- diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternStateProvider.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternStateProvider.java index d87a09a2fd..8374b020a5 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternStateProvider.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternStateProvider.java @@ -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 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 index 0000000000..cd1b191df9 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlAction.java @@ -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 null 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 index 0000000000..677203cdb2 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlCondition.java @@ -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 null 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 diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlModelFactory.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlModelFactory.java index 72d0ea68bd..cfeeb8192e 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlModelFactory.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlModelFactory.java @@ -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); } diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlStateAttribute.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlStateAttribute.java index 8763b0af21..d74fcc715b 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlStateAttribute.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ITmfXmlStateAttribute.java @@ -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 index 0000000000..0a1a7e18f4 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/ResetStoredFieldsAction.java @@ -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 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 index 0000000000..cc38801e57 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlAction.java @@ -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 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 index 0000000000..c23e610d43 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlBasicTransition.java @@ -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 fCond; + private final List 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 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; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlCondition.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlCondition.java index f76627f39e..573123f6a7 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlCondition.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlCondition.java @@ -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 fConditions = new ArrayList<>(); private final List 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())); - fStateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(1)), fContainer, new ArrayList())); - } - 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 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())); + stateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(1)), container, new ArrayList())); + } + 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 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 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 null 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 index 0000000000..be8bf40311 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlFsm.java @@ -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 fStatesMap; + private final List fActiveScenariosList; + private final List 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 preconditions, + Map 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 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 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 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 transitionMap) { + if (!validatePreconditions(event, transitionMap)) { + return; + } + for (Iterator 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 index 0000000000..9c7cb5d4df --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternEventHandler.java @@ -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 fInitialFsm; + private final Map fTestMap = new HashMap<>(); + private final Map fActionMap = new HashMap<>(); + private final Map fFsmMap = new HashMap<>(); + private final List 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 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 getTestMap() { + return ImmutableMap.copyOf(fTestMap); + } + + /** + * Get all the defined actions + * + * @return The actions + */ + public Map 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 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 fsmToStart = new ArrayList<>(); + for (Map.Entry 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); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternSegmentBuilder.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternSegmentBuilder.java index 848cd6db9a..7b6c177107 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternSegmentBuilder.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternSegmentBuilder.java @@ -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 fields, final TmfXmlScenarioInfo info) { + if (fContainer instanceof XmlPatternStateProvider) { + for (Entry 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 index 0000000000..249d60e314 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenario.java @@ -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 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 index 0000000000..9f87600ada --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioHistoryBuilder.java @@ -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 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 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); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioInfo.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioInfo.java index c6132e3a79..c181b6f09b 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioInfo.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlScenarioInfo.java @@ -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 index 0000000000..b84df18b7b --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlState.java @@ -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 fTransitions; + private @Nullable TmfXmlState fparent; + private List fOnEntryActions; + private List fOnExitActions; + //TODO Sub-state are not yet supported. + private Map 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 onentryActions, List 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 transitions = getTransitions(modelFactory, container, node); + + NodeList nodesOnentry = node.getElementsByTagName(TmfXmlStrings.ONENTRY); + List 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 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 getTransitionList() { + return fTransitions; + } + + /** + * Get the actions to execute when entering this state, in an array + * + * @return The array of actions + */ + public List getOnEntryActions() { + return fOnEntryActions; + } + + /** + * Get the actions to execute when leaving this state, in an array + * + * @return The array of actions + */ + public List getOnExitActions() { + return fOnExitActions; + } + + /** + * Get children states of this state into a map + * + * @return The map of children state + */ + public Map 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; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateAttribute.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateAttribute.java index 5aafea46ce..6e9e6caad9 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateAttribute.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateAttribute.java @@ -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 { diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateChange.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateChange.java index 63662ebe36..25028b3867 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateChange.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateChange.java @@ -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 index 0000000000..16d47e065b --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlStateTransition.java @@ -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 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 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 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 index 0000000000..422c1264f1 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlTimestampCondition.java @@ -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 index 0000000000..7fe1dc07c3 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlTransitionValidator.java @@ -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 index 0000000000..bea8ab5896 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/UpdateStoredFieldsAction.java @@ -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 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); + } + } + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readonly/TmfXmlReadOnlyModelFactory.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readonly/TmfXmlReadOnlyModelFactory.java index c57cdda1ee..75292b7f5c 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readonly/TmfXmlReadOnlyModelFactory.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readonly/TmfXmlReadOnlyModelFactory.java @@ -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); + } } diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readwrite/TmfXmlReadWriteModelFactory.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readwrite/TmfXmlReadWriteModelFactory.java index 84acc89405..1cfe63c69c 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readwrite/TmfXmlReadWriteModelFactory.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/readwrite/TmfXmlReadWriteModelFactory.java @@ -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); + } } diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/XmlUtils.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/XmlUtils.java index 601266e7ca..fbefde251e 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/XmlUtils.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/XmlUtils.java @@ -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++) { diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/xmlPatternStateProvider.xsd b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/xmlPatternStateProvider.xsd index 9a41c44bf2..042fa1925d 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/xmlPatternStateProvider.xsd +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/module/xmlPatternStateProvider.xsd @@ -89,7 +89,7 @@ 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. - + 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" diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/stateprovider/TmfXmlStrings.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/stateprovider/TmfXmlStrings.java index d151efa4ec..b40d714d30 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/stateprovider/TmfXmlStrings.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/stateprovider/TmfXmlStrings.java @@ -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