1 /*******************************************************************************
2 * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 ******************************************************************************/
9 package org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.model
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Arrays
;
13 import java
.util
.Collections
;
14 import java
.util
.HashMap
;
15 import java
.util
.LinkedHashMap
;
16 import java
.util
.List
;
19 import org
.eclipse
.jdt
.annotation
.NonNull
;
20 import org
.eclipse
.jdt
.annotation
.Nullable
;
21 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
22 import org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.module
.IXmlStateSystemContainer
;
23 import org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.pattern
.stateprovider
.XmlPatternStateProvider
;
24 import org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.stateprovider
.TmfXmlStrings
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
26 import org
.w3c
.dom
.Element
;
27 import org
.w3c
.dom
.NodeList
;
29 import com
.google
.common
.collect
.ImmutableMap
;
30 import com
.google
.common
.collect
.ImmutableMap
.Builder
;
33 * This Class implements a pattern handler tree in the XML-defined state system.
34 * It receives events and dispatches it to Active finite state machines.
36 * @author Jean-Christian Kouame
38 public class TmfXmlPatternEventHandler
{
40 /* list of states changes */
41 private final XmlPatternStateProvider fParent
;
43 private final List
<String
> fInitialFsm
;
44 private final Map
<String
, TmfXmlTransitionValidator
> fTestMap
;
45 private final Map
<String
, ITmfXmlAction
> fActionMap
;
46 private final Map
<String
, TmfXmlFsm
> fFsmMap
= new LinkedHashMap
<>();
47 private final List
<TmfXmlFsm
> fActiveFsmList
= new ArrayList
<>();
53 * The factory used to create XML model elements
55 * The XML root of this event handler
57 * The state system container this event handler belongs to
59 public TmfXmlPatternEventHandler(ITmfXmlModelFactory modelFactory
, Element node
, IXmlStateSystemContainer parent
) {
60 fParent
= (XmlPatternStateProvider
) parent
;
61 String initialFsm
= node
.getAttribute(TmfXmlStrings
.INITIAL
);
62 fInitialFsm
= initialFsm
.isEmpty() ? Collections
.EMPTY_LIST
: Arrays
.asList(initialFsm
.split(TmfXmlStrings
.AND_SEPARATOR
));
64 Map
<String
, TmfXmlTransitionValidator
> testMap
= new HashMap
<>();
65 NodeList nodesTest
= node
.getElementsByTagName(TmfXmlStrings
.TEST
);
66 /* load transition input */
67 for (int i
= 0; i
< nodesTest
.getLength(); i
++) {
68 Element element
= (Element
) nodesTest
.item(i
);
69 if (element
== null) {
70 throw new IllegalArgumentException();
72 TmfXmlTransitionValidator test
= modelFactory
.createTransitionValidator(element
, fParent
);
73 testMap
.put(test
.getId(), test
);
75 fTestMap
= Collections
.unmodifiableMap(testMap
);
77 @NonNull Builder
<String
, ITmfXmlAction
> builder
= ImmutableMap
.builder();
78 NodeList nodesAction
= node
.getElementsByTagName(TmfXmlStrings
.ACTION
);
80 for (int i
= 0; i
< nodesAction
.getLength(); i
++) {
81 Element element
= (Element
) nodesAction
.item(i
);
82 if (element
== null) {
83 throw new IllegalArgumentException();
85 TmfXmlAction action
= modelFactory
.createAction(element
, fParent
);
86 builder
.put(action
.getId(), action
);
88 builder
.put(TmfXmlStrings
.CONSTANT_PREFIX
+ ITmfXmlAction
.CLEAR_STORED_FIELDS_STRING
, new ResetStoredFieldsAction(fParent
));
89 builder
.put(TmfXmlStrings
.CONSTANT_PREFIX
+ ITmfXmlAction
.SAVE_STORED_FIELDS_STRING
, new UpdateStoredFieldsAction(fParent
));
90 fActionMap
= builder
.build();
92 NodeList nodesFsm
= node
.getElementsByTagName(TmfXmlStrings
.FSM
);
94 for (int i
= 0; i
< nodesFsm
.getLength(); i
++) {
95 Element element
= (Element
) nodesFsm
.item(i
);
96 if (element
== null) {
97 throw new IllegalArgumentException();
99 TmfXmlFsm fsm
= modelFactory
.createFsm(element
, fParent
);
100 fFsmMap
.put(fsm
.getId(), fsm
);
105 * Start a new scenario for this specific fsm id. If the fsm support only a
106 * single instance and this instance already exist, no new scenario is then
107 * started. If the scenario is created we handle the current event directly.
110 * The IDs of the fsm to start
114 * True to force the creation of the scenario, false otherwise
116 public void startScenario(List
<String
> fsmIds
, @Nullable ITmfEvent event
, boolean force
) {
117 for (String fsmId
: fsmIds
) {
118 TmfXmlFsm fsm
= NonNullUtils
.checkNotNull(fFsmMap
.get(fsmId
));
119 if (!fActiveFsmList
.contains(fsm
)) {
120 fActiveFsmList
.add(fsm
);
122 fsm
.createScenario(event
, this, force
);
127 * Get all the defined transition tests
129 * @return The tests in a map
131 public Map
<String
, TmfXmlTransitionValidator
> getTestMap() {
136 * Get all the defined actions
138 * @return The actions
140 public Map
<String
, ITmfXmlAction
> getActionMap() {
145 * If the pattern handler can handle the event, it send the event to all
146 * finite state machines with ongoing scenarios
149 * The trace event to handle
151 public void handleEvent(ITmfEvent event
) {
153 * Order is important so cannot be parallelized
155 final @NonNull List
<@NonNull TmfXmlFsm
> activeFsmList
= fActiveFsmList
;
156 final @NonNull Map
<@NonNull String
, @NonNull TmfXmlFsm
> fsmMap
= fFsmMap
;
157 if (activeFsmList
.isEmpty()) {
158 List
<String
> fsmIds
= fInitialFsm
;
159 if (fsmIds
.isEmpty()) {
160 fsmIds
= new ArrayList
<>();
161 for (TmfXmlFsm fsm
: fsmMap
.values()) {
162 fsmIds
.add(fsm
.getId());
165 if (!fsmIds
.isEmpty()) {
166 startScenario(fsmIds
, null, true);
169 List
<String
> fsmToStart
= new ArrayList
<>();
170 for (Map
.Entry
<String
, TmfXmlFsm
> entry
: fsmMap
.entrySet()) {
171 if (entry
.getValue().isNewScenarioAllowed()) {
172 fsmToStart
.add(entry
.getKey());
175 if (!fsmToStart
.isEmpty()) {
176 startScenario(fsmToStart
, null, false);
179 for (TmfXmlFsm fsm
: activeFsmList
) {
180 fsm
.handleEvent(event
, fTestMap
);
185 * Abandon all the ongoing scenarios
187 public void dispose() {
188 for (TmfXmlFsm fsm
: fActiveFsmList
) {
194 * Get the fsm corresponding to the specified id
198 * @return The fsm found, null if nothing found
200 public @Nullable TmfXmlFsm
getFsm(String fsmId
) {
201 return fFsmMap
.get(fsmId
);