lttng.ust: Add the build-ID to the key of cache of addr2line calls
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.analysis.xml.core / src / org / eclipse / tracecompass / tmf / analysis / xml / core / model / TmfXmlFsm.java
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.Collections;
13 import java.util.HashMap;
14 import java.util.Iterator;
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.tmf.analysis.xml.core.model.TmfXmlScenarioHistoryBuilder.ScenarioStatusType;
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.ImmutableList;
29 import com.google.common.collect.ImmutableMap;
30
31 /**
32 * This Class implements a state machine (FSM) tree in the XML-defined state
33 * system.
34 *
35 * @author Jean-Christian Kouame
36 * @since 2.0
37 */
38 public class TmfXmlFsm {
39
40 private final Map<String, TmfXmlState> fStatesMap;
41 private final List<TmfXmlScenario> fActiveScenariosList;
42 private final List<TmfXmlBasicTransition> fPreconditions;
43 private final String fId;
44 private final ITmfXmlModelFactory fModelFactory;
45 private final IXmlStateSystemContainer fContainer;
46 private final String fFinalStateId;
47 private final String fAbandonStateId;
48 private final boolean fInstanceMultipleEnabled;
49 private final String fInitialStateId;
50 private int fTotalScenarios;
51
52 /**
53 * Factory to create a {@link TmfXmlFsm}
54 *
55 * @param modelFactory
56 * The factory used to create XML model elements
57 * @param node
58 * The XML root of this fsm
59 * @param container
60 * The state system container this fsm belongs to
61 * @return The new {@link TmfXmlFsm}
62 */
63 public static TmfXmlFsm create(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
64 String id = node.getAttribute(TmfXmlStrings.ID);
65 boolean instanceMultipleEnabled = node.getAttribute(TmfXmlStrings.MULTIPLE).isEmpty() ? true : Boolean.parseBoolean(node.getAttribute(TmfXmlStrings.MULTIPLE));
66 final List<@NonNull TmfXmlBasicTransition> preconditions = new ArrayList<>();
67
68 // Get the preconditions
69 NodeList nodesPreconditions = node.getElementsByTagName(TmfXmlStrings.PRECONDITION);
70 for (int i = 0; i < nodesPreconditions.getLength(); i++) {
71 preconditions.add(new TmfXmlBasicTransition(((Element) NonNullUtils.checkNotNull(nodesPreconditions.item(i)))));
72 }
73
74 // Get the initial state and the preconditions
75 String initialState = node.getAttribute(TmfXmlStrings.INITIAL);
76 if (initialState.isEmpty()) {
77 NodeList nodesInitialState = node.getElementsByTagName(TmfXmlStrings.INITIAL);
78 if (nodesInitialState.getLength() == 1) {
79 NodeList nodesTransition = ((Element) nodesInitialState.item(0)).getElementsByTagName(TmfXmlStrings.TRANSITION);
80 if (nodesInitialState.getLength() != 1) {
81 throw new IllegalArgumentException("initial state : there should be one and only one initial state."); //$NON-NLS-1$
82 }
83 initialState = ((Element) nodesTransition.item(0)).getAttribute(TmfXmlStrings.TARGET);
84 }
85 }
86
87 Map<@NonNull String, @NonNull TmfXmlState> statesMap = new HashMap<>();
88 // Get the FSM states
89 NodeList nodesState = node.getElementsByTagName(TmfXmlStrings.STATE);
90 for (int i = 0; i < nodesState.getLength(); i++) {
91 Element element = (Element) NonNullUtils.checkNotNull(nodesState.item(i));
92 TmfXmlState state = modelFactory.createState(element, container, null);
93 statesMap.put(state.getId(), state);
94
95 // If the initial state was not already set, we use the first state
96 // declared in the fsm description as initial state
97 if (initialState.isEmpty()) {
98 initialState = state.getId();
99 }
100 }
101
102 if (initialState.isEmpty()) {
103 throw new IllegalStateException("No initial state has been declared in fsm " + id); //$NON-NLS-1$
104 }
105
106 // Get the FSM final state
107 String finalStateId = TmfXmlStrings.NULL;
108 NodeList nodesFinalState = node.getElementsByTagName(TmfXmlStrings.FINAL);
109 if (nodesFinalState.getLength() == 1) {
110 final Element finalElement = NonNullUtils.checkNotNull((Element) nodesFinalState.item(0));
111 finalStateId = finalElement.getAttribute(TmfXmlStrings.ID);
112 if (!finalStateId.isEmpty()) {
113 TmfXmlState finalState = modelFactory.createState(finalElement, container, null);
114 statesMap.put(finalState.getId(), finalState);
115 }
116 }
117
118 // Get the FSM abandon state
119 String abandonStateId = TmfXmlStrings.NULL;
120 NodeList nodesAbandonState = node.getElementsByTagName(TmfXmlStrings.ABANDON_STATE);
121 if (nodesAbandonState.getLength() == 1) {
122 final Element abandonElement = NonNullUtils.checkNotNull((Element) nodesAbandonState.item(0));
123 abandonStateId = abandonElement.getAttribute(TmfXmlStrings.ID);
124 if (!abandonStateId.isEmpty()) {
125 TmfXmlState abandonState = modelFactory.createState(abandonElement, container, null);
126 statesMap.put(abandonState.getId(), abandonState);
127 }
128 }
129 return new TmfXmlFsm(modelFactory, container, id, instanceMultipleEnabled, initialState, finalStateId, abandonStateId, preconditions, statesMap);
130 }
131
132 private TmfXmlFsm(ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, String id, boolean multiple,
133 String initialState, String finalState, String abandonState, List<TmfXmlBasicTransition> preconditions,
134 Map<String, TmfXmlState> states) {
135 fModelFactory = modelFactory;
136 fTotalScenarios = 0;
137 fContainer = container;
138 fId = id;
139 fInstanceMultipleEnabled = multiple;
140 fInitialStateId = initialState;
141 fFinalStateId = finalState;
142 fAbandonStateId = abandonState;
143 fPreconditions = ImmutableList.copyOf(preconditions);
144 fStatesMap = ImmutableMap.copyOf(states);
145 fActiveScenariosList = new ArrayList<>();
146 }
147
148 /**
149 * Get the fsm ID
150 *
151 * @return the id of this fsm
152 */
153 public String getId() {
154 return fId;
155 }
156
157 /**
158 * Get the initial state ID of this fsm
159 *
160 * @return the id of the initial state of this finite state machine
161 */
162 public String getInitialStateId() {
163 return fInitialStateId;
164 }
165
166 /**
167 * Get the final state ID of this fsm
168 *
169 * @return the id of the final state of this finite state machine
170 */
171 public String getFinalStateId() {
172 return fFinalStateId;
173 }
174
175 /**
176 * Get the abandon state ID fo this fsm
177 *
178 * @return the id of the abandon state of this finite state machine
179 */
180 public String getAbandonStateId() {
181 return fAbandonStateId;
182 }
183
184 /**
185 * Get the states table of this fsm in map
186 *
187 * @return The map containing all state definition for this fsm
188 */
189 public Map<String, TmfXmlState> getStatesMap() {
190 return Collections.unmodifiableMap(fStatesMap);
191 }
192
193 /**
194 * Process the active event and determine the next step of this fsm
195 *
196 * @param event
197 * The event to process
198 * @param tests
199 * The list of possible transitions of the state machine
200 * @param scenarioInfo
201 * The active scenario details.
202 * @return A pair containing the next state of the state machine and the
203 * actions to execute
204 */
205 public @Nullable TmfXmlStateTransition next(ITmfEvent event, Map<String, TmfXmlTransitionValidator> tests, TmfXmlScenarioInfo scenarioInfo) {
206 boolean matched = false;
207 TmfXmlStateTransition stateTransition = null;
208 TmfXmlState state = NonNullUtils.checkNotNull(fStatesMap.get(scenarioInfo.getActiveState()));
209 for (int i = 0; i < state.getTransitionList().size() && !matched; i++) {
210 stateTransition = state.getTransitionList().get(i);
211 matched = stateTransition.test(event, scenarioInfo, tests);
212 }
213 return matched ? stateTransition : null;
214 }
215
216
217
218 /**
219 * Validate the preconditions of this fsm. If not validate, the fsm will
220 * skip the active event.
221 *
222 * @param event
223 * The current event
224 * @param tests
225 * The transition inputs
226 * @return True if one of the precondition is validated, false otherwise
227 */
228 private boolean validatePreconditions(ITmfEvent event, Map<String, TmfXmlTransitionValidator> tests) {
229 if (fPreconditions.isEmpty()) {
230 return true;
231 }
232 for (TmfXmlBasicTransition precondition : fPreconditions) {
233 if (precondition.test(event, null, tests)) {
234 return true;
235 }
236 }
237 return false;
238 }
239
240 /**
241 * Handle the current event
242 *
243 * @param event
244 * The current event
245 * @param transitionMap
246 * The transitions of the pattern
247 */
248 public void handleEvent(ITmfEvent event, Map<String, TmfXmlTransitionValidator> transitionMap) {
249 if (!validatePreconditions(event, transitionMap)) {
250 return;
251 }
252 for (Iterator<TmfXmlScenario> currentItr = fActiveScenariosList.iterator(); currentItr.hasNext();) {
253 TmfXmlScenario scenario = currentItr.next();
254 // Remove inactive scenarios or handle the active ones.
255 if (!scenario.isActive()) {
256 currentItr.remove();
257 } else {
258 handleScenario(scenario, event);
259 }
260 }
261 }
262
263 /**
264 * Abandon all ongoing scenarios
265 */
266 public void dispose() {
267 for (TmfXmlScenario scenario : fActiveScenariosList) {
268 if (scenario.isActive()) {
269 scenario.cancel();
270 }
271 }
272 }
273
274 private static void handleScenario(TmfXmlScenario scenario, ITmfEvent event) {
275 if (scenario.isActive()) {
276 scenario.handleEvent(event);
277 }
278 }
279
280 /**
281 * Create a new scenario of this fsm
282 *
283 * @param event
284 * The current event, null if not
285 * @param eventHandler
286 * The event handler this fsm belongs
287 * @param force
288 * True to force the creation of the scenario, false otherwise
289 */
290 public synchronized void createScenario(@Nullable ITmfEvent event, TmfXmlPatternEventHandler eventHandler, boolean force) {
291 if (force || isNewScenarioAllowed()) {
292 TmfXmlScenario scenario = new TmfXmlScenario(event, eventHandler, fId, fContainer, fModelFactory);
293 fTotalScenarios++;
294 fActiveScenariosList.add(scenario);
295 }
296 }
297
298 /**
299 * Check if we have the right to create a new scenario. A new scenario could
300 * be created if it is not the first scenario of an FSM and the FSM is not a
301 * singleton and the status of the last created scenario is not PENDING.
302 *
303 * @return True if the start of a new scenario is allowed, false otherwise
304 */
305 public synchronized boolean isNewScenarioAllowed() {
306 return !fActiveScenariosList.get(fActiveScenariosList.size() - 1).getScenarioInfos().getStatus().equals(ScenarioStatusType.PENDING)
307 && fInstanceMultipleEnabled && fTotalScenarios > 0;
308 }
309 }
This page took 0.038895 seconds and 5 git commands to generate.