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