Commit | Line | Data |
---|---|---|
3a5f73a1 JCK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson | |
3 | * | |
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.tmf.analysis.xml.core.model; | |
10 | ||
11 | import java.util.ArrayList; | |
12 | import java.util.Arrays; | |
13 | import java.util.Collections; | |
14 | import java.util.HashMap; | |
15 | import java.util.List; | |
16 | import java.util.Map; | |
17 | ||
18 | import org.eclipse.jdt.annotation.NonNull; | |
19 | import org.eclipse.jdt.annotation.Nullable; | |
20 | import org.eclipse.tracecompass.common.core.NonNullUtils; | |
21 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider.XmlPatternStateProvider; | |
22 | import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer; | |
23 | import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings; | |
24 | import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; | |
25 | import org.w3c.dom.Element; | |
26 | import org.w3c.dom.NodeList; | |
27 | ||
28 | import com.google.common.collect.ImmutableMap; | |
29 | ||
30 | /** | |
31 | * This Class implements a pattern handler tree in the XML-defined state system. | |
32 | * It receives events and dispatches it to Active finite state machines. | |
33 | * | |
34 | * @author Jean-Christian Kouame | |
35 | * @since 2.0 | |
36 | */ | |
37 | public class TmfXmlPatternEventHandler { | |
38 | ||
39 | /* list of states changes */ | |
40 | private final XmlPatternStateProvider fParent; | |
41 | ||
42 | private final List<String> fInitialFsm; | |
43 | private final Map<String, TmfXmlTransitionValidator> fTestMap = new HashMap<>(); | |
44 | private final Map<String, ITmfXmlAction> fActionMap = new HashMap<>(); | |
45 | private final Map<String, TmfXmlFsm> fFsmMap = new HashMap<>(); | |
46 | private final List<TmfXmlFsm> fActiveFsmList = new ArrayList<>(); | |
47 | ||
48 | /** | |
49 | * Constructor | |
50 | * | |
51 | * @param modelFactory | |
52 | * The factory used to create XML model elements | |
53 | * @param node | |
54 | * The XML root of this event handler | |
55 | * @param parent | |
56 | * The state system container this event handler belongs to | |
57 | */ | |
58 | public TmfXmlPatternEventHandler(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer parent) { | |
59 | fParent = (XmlPatternStateProvider) parent; | |
60 | String initialFsm = node.getAttribute(TmfXmlStrings.INITIAL); | |
61 | fInitialFsm = initialFsm.isEmpty() ? Collections.EMPTY_LIST : Arrays.asList(initialFsm.split(TmfXmlStrings.AND_SEPARATOR)); | |
62 | ||
63 | NodeList nodesTest = node.getElementsByTagName(TmfXmlStrings.TEST); | |
64 | /* load transition input */ | |
65 | for (int i = 0; i < nodesTest.getLength(); i++) { | |
66 | Element element = (Element) nodesTest.item(i); | |
67 | if (element == null) { | |
68 | throw new IllegalArgumentException(); | |
69 | } | |
70 | TmfXmlTransitionValidator test = modelFactory.createTransitionValidator(element, fParent); | |
71 | fTestMap.put(test.getId(), test); | |
72 | } | |
73 | ||
74 | NodeList nodesAction = node.getElementsByTagName(TmfXmlStrings.ACTION); | |
75 | /* load actions */ | |
76 | for (int i = 0; i < nodesAction.getLength(); i++) { | |
77 | Element element = (Element) nodesAction.item(i); | |
78 | if (element == null) { | |
79 | throw new IllegalArgumentException(); | |
80 | } | |
81 | ITmfXmlAction action = modelFactory.createAction(element, fParent); | |
82 | fActionMap.put(((TmfXmlAction) action).getId(), action); | |
83 | } | |
84 | fActionMap.put(TmfXmlStrings.CONSTANT_PREFIX + ITmfXmlAction.CLEAR_STORED_FIELDS_STRING, new ResetStoredFieldsAction(fParent)); | |
85 | fActionMap.put(TmfXmlStrings.CONSTANT_PREFIX + ITmfXmlAction.SAVE_STORED_FIELDS_STRING, new UpdateStoredFieldsAction(fParent)); | |
86 | ||
87 | NodeList nodesFsm = node.getElementsByTagName(TmfXmlStrings.FSM); | |
88 | /* load fsm */ | |
89 | for (int i = 0; i < nodesFsm.getLength(); i++) { | |
90 | Element element = (Element) nodesFsm.item(i); | |
91 | if (element == null) { | |
92 | throw new IllegalArgumentException(); | |
93 | } | |
94 | TmfXmlFsm fsm = modelFactory.createFsm(element, fParent); | |
95 | fFsmMap.put(fsm.getId(), fsm); | |
96 | } | |
97 | } | |
98 | ||
99 | /** | |
100 | * Start a new scenario for this specific fsm id. If the fsm support only a | |
101 | * single instance and this instance already exist, no new scenario is then | |
102 | * started. If the scenario is created we handle the current event directly. | |
103 | * | |
104 | * @param fsmIds | |
105 | * The IDs of the fsm to start | |
106 | * @param event | |
107 | * The current event | |
108 | * @param force | |
109 | * True to force the creation of the scenario, false otherwise | |
110 | */ | |
111 | public void startScenario(List<String> fsmIds, @Nullable ITmfEvent event, boolean force) { | |
112 | for (String fsmId : fsmIds) { | |
113 | TmfXmlFsm fsm = NonNullUtils.checkNotNull(fFsmMap.get(fsmId)); | |
114 | if (!fActiveFsmList.contains(fsm)) { | |
115 | fActiveFsmList.add(fsm); | |
116 | } | |
117 | fsm.createScenario(event, this, force); | |
118 | } | |
119 | } | |
120 | ||
121 | /** | |
122 | * Get all the defined transition tests | |
123 | * | |
124 | * @return The tests in a map | |
125 | */ | |
126 | public Map<String, TmfXmlTransitionValidator> getTestMap() { | |
127 | return ImmutableMap.copyOf(fTestMap); | |
128 | } | |
129 | ||
130 | /** | |
131 | * Get all the defined actions | |
132 | * | |
133 | * @return The actions | |
134 | */ | |
135 | public Map<String, ITmfXmlAction> getActionMap() { | |
136 | return ImmutableMap.copyOf(fActionMap); | |
137 | } | |
138 | ||
139 | /** | |
140 | * If the pattern handler can handle the event, it send the event to all | |
141 | * finite state machines with ongoing scenarios | |
142 | * | |
143 | * @param event | |
144 | * The trace event to handle | |
145 | */ | |
146 | public void handleEvent(ITmfEvent event) { | |
147 | /* | |
148 | * Order is important so cannot be parallelized | |
149 | */ | |
150 | final @NonNull List<@NonNull TmfXmlFsm> activeFsmList = fActiveFsmList; | |
151 | final @NonNull Map<@NonNull String, @NonNull TmfXmlFsm> fsmMap = fFsmMap; | |
152 | if (activeFsmList.isEmpty()) { | |
153 | List<String> fsmIds = fInitialFsm; | |
154 | if (fsmIds.isEmpty()) { | |
155 | fsmIds = new ArrayList<>(); | |
156 | for (TmfXmlFsm fsm : fsmMap.values()) { | |
157 | fsmIds.add(fsm.getId()); | |
158 | } | |
159 | } | |
160 | if (!fsmIds.isEmpty()) { | |
161 | startScenario(fsmIds, null, true); | |
162 | } | |
163 | } else { | |
164 | List<String> fsmToStart = new ArrayList<>(); | |
165 | for (Map.Entry<String, TmfXmlFsm> entry : fsmMap.entrySet()) { | |
166 | if (entry.getValue().isNewScenarioAllowed()) { | |
167 | fsmToStart.add(entry.getKey()); | |
168 | } | |
169 | } | |
170 | if (!fsmToStart.isEmpty()) { | |
171 | startScenario(fsmToStart, null, false); | |
172 | } | |
173 | } | |
174 | for (TmfXmlFsm fsm : activeFsmList) { | |
175 | fsm.handleEvent(event, fTestMap); | |
176 | } | |
177 | } | |
178 | ||
179 | /** | |
180 | * Abandon all the ongoing scenarios | |
181 | */ | |
182 | public void dispose() { | |
183 | for (TmfXmlFsm fsm : fActiveFsmList) { | |
184 | fsm.dispose(); | |
185 | } | |
186 | } | |
187 | ||
188 | /** | |
189 | * Get the fsm corresponding to the specified id | |
190 | * | |
191 | * @param fsmId | |
192 | * The id of the fsm | |
193 | * @return The fsm found, null if nothing found | |
194 | */ | |
195 | public @Nullable TmfXmlFsm getFsm(String fsmId) { | |
196 | return fFsmMap.get(fsmId); | |
197 | } | |
198 | } |