Commit | Line | Data |
---|---|---|
1d7e62f9 GB |
1 | /******************************************************************************* |
2 | * Copyright (c) 2014 École Polytechnique de Montréal | |
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 | * Contributors: | |
10 | * Geneviève Bastien - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | ||
2bdf0193 | 13 | package org.eclipse.tracecompass.tmf.analysis.xml.core.model.readwrite; |
1d7e62f9 GB |
14 | |
15 | import java.util.ArrayList; | |
16 | import java.util.List; | |
17 | ||
9411fd5b | 18 | import org.eclipse.jdt.annotation.Nullable; |
2bdf0193 | 19 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator; |
e894a508 AM |
20 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; |
21 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; | |
acec47ce | 22 | import org.eclipse.tracecompass.statesystem.core.StateSystemBuilderUtils; |
e894a508 AM |
23 | import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; |
24 | import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; | |
25 | import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; | |
26 | import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; | |
27 | import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; | |
2bdf0193 AM |
28 | import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlModelFactory; |
29 | import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlStateAttribute; | |
30 | import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlStateValue; | |
31 | import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer; | |
32 | import org.eclipse.tracecompass.tmf.analysis.xml.core.module.XmlUtils; | |
33 | import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings; | |
34 | import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; | |
1d7e62f9 GB |
35 | import org.w3c.dom.Element; |
36 | ||
37 | /** | |
38 | * Implements a state value in a read write mode. See {@link TmfXmlStateValue} | |
39 | * for the syntax of the state value. | |
40 | * | |
41 | * In read/write mode, a state value can be considered as an assignation where | |
42 | * the state value is assigned to the quark represented by the state attributes | |
43 | * | |
44 | * @author Geneviève Bastien | |
45 | */ | |
b1ebf44e | 46 | public class TmfXmlReadWriteStateValue extends TmfXmlStateValue { |
1d7e62f9 | 47 | |
a194b17a JCK |
48 | private static final String ILLEGAL_STATE_EXCEPTION_MESSAGE = "The state system hasn't been initialized yet"; //$NON-NLS-1$ |
49 | ||
1d7e62f9 GB |
50 | /** |
51 | * Constructor where the path to the value is a list of state attributes | |
52 | * | |
53 | * @param modelFactory | |
54 | * The factory used to create XML model elements | |
55 | * @param node | |
56 | * The state value XML element | |
57 | * @param container | |
58 | * The state system container this state value belongs to | |
59 | * @param attributes | |
60 | * The attributes representing the path to this value | |
61 | */ | |
b1ebf44e | 62 | public TmfXmlReadWriteStateValue(TmfXmlReadWriteModelFactory modelFactory, Element node, IXmlStateSystemContainer container, List<ITmfXmlStateAttribute> attributes) { |
1d7e62f9 GB |
63 | this(modelFactory, node, container, attributes, null); |
64 | } | |
65 | ||
66 | /** | |
67 | * Constructor where the path to the value is an event field | |
68 | * | |
69 | * @param modelFactory | |
70 | * The factory used to create XML model elements | |
71 | * @param node | |
72 | * The state value XML element | |
73 | * @param container | |
74 | * The state system container this state value belongs to | |
75 | * @param eventField | |
76 | * The event field where to get the value | |
77 | */ | |
b1ebf44e | 78 | public TmfXmlReadWriteStateValue(TmfXmlReadWriteModelFactory modelFactory, Element node, IXmlStateSystemContainer container, String eventField) { |
1d7e62f9 GB |
79 | this(modelFactory, node, container, new ArrayList<ITmfXmlStateAttribute>(), eventField); |
80 | } | |
81 | ||
12685851 | 82 | private TmfXmlReadWriteStateValue(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container, List<ITmfXmlStateAttribute> attributes, @Nullable String eventField) { |
1d7e62f9 GB |
83 | super(modelFactory, node, container, attributes, eventField); |
84 | } | |
85 | ||
86 | @Override | |
12685851 | 87 | protected @Nullable ITmfStateSystemBuilder getStateSystem() { |
1d7e62f9 GB |
88 | return (ITmfStateSystemBuilder) super.getStateSystem(); |
89 | } | |
90 | ||
91 | @Override | |
92 | protected TmfXmlStateValueBase initializeStateValue(ITmfXmlModelFactory modelFactory, Element node) { | |
93 | TmfXmlStateValueBase stateValueType = null; | |
94 | /* Process the XML Element state value */ | |
95 | String type = node.getAttribute(TmfXmlStrings.TYPE); | |
96 | String value = getSsContainer().getAttributeValue(node.getAttribute(TmfXmlStrings.VALUE)); | |
12685851 GB |
97 | if (value == null) { |
98 | throw new IllegalStateException(); | |
99 | } | |
1d7e62f9 GB |
100 | |
101 | switch (type) { | |
102 | case TmfXmlStrings.TYPE_INT: { | |
103 | /* Integer value */ | |
104 | ITmfStateValue stateValue = TmfStateValue.newValueInt(Integer.parseInt(value)); | |
105 | stateValueType = new TmfXmlStateValueTmf(stateValue); | |
106 | break; | |
107 | } | |
108 | case TmfXmlStrings.TYPE_LONG: { | |
109 | /* Long value */ | |
110 | ITmfStateValue stateValue = TmfStateValue.newValueLong(Long.parseLong(value)); | |
111 | stateValueType = new TmfXmlStateValueTmf(stateValue); | |
112 | break; | |
113 | } | |
114 | case TmfXmlStrings.TYPE_STRING: { | |
115 | /* String value */ | |
116 | ITmfStateValue stateValue = TmfStateValue.newValueString(value); | |
117 | stateValueType = new TmfXmlStateValueTmf(stateValue); | |
118 | break; | |
119 | } | |
120 | case TmfXmlStrings.TYPE_NULL: { | |
121 | /* Null value */ | |
122 | ITmfStateValue stateValue = TmfStateValue.nullValue(); | |
123 | stateValueType = new TmfXmlStateValueTmf(stateValue); | |
124 | break; | |
125 | } | |
126 | case TmfXmlStrings.EVENT_FIELD: | |
127 | /* Event field */ | |
128 | stateValueType = new TmfXmlStateValueEventField(value); | |
129 | break; | |
130 | case TmfXmlStrings.TYPE_EVENT_NAME: | |
131 | /* The value is the event name */ | |
132 | stateValueType = new TmfXmlStateValueEventName(); | |
133 | break; | |
134 | case TmfXmlStrings.TYPE_DELETE: | |
135 | /* Deletes the value of an attribute */ | |
136 | stateValueType = new TmfXmlStateValueDelete(); | |
137 | break; | |
138 | case TmfXmlStrings.TYPE_QUERY: | |
139 | /* Value is the result of a query */ | |
4c4e2816 | 140 | List<@Nullable Element> children = XmlUtils.getChildElements(node); |
1d7e62f9 GB |
141 | List<ITmfXmlStateAttribute> childAttributes = new ArrayList<>(); |
142 | for (Element child : children) { | |
12685851 GB |
143 | if (child == null) { |
144 | continue; | |
145 | } | |
1d7e62f9 GB |
146 | ITmfXmlStateAttribute queryAttribute = modelFactory.createStateAttribute(child, getSsContainer()); |
147 | childAttributes.add(queryAttribute); | |
148 | } | |
149 | stateValueType = new TmfXmlStateValueQuery(childAttributes); | |
150 | break; | |
151 | default: | |
152 | throw new IllegalArgumentException(String.format("TmfXmlStateValue constructor: unexpected element %s for stateValue type", type)); //$NON-NLS-1$ | |
153 | } | |
154 | return stateValueType; | |
155 | } | |
156 | ||
157 | // ---------------------------------------------------------- | |
158 | // Internal state value classes for the different types | |
159 | // ---------------------------------------------------------- | |
160 | ||
161 | /** | |
162 | * Base class for all state value. Contain default methods to handle event, | |
163 | * process or increment the value | |
164 | */ | |
165 | protected abstract class TmfXmlStateValueTypeReadWrite extends TmfXmlStateValueBase { | |
166 | ||
167 | @Override | |
168 | public final void handleEvent(ITmfEvent event, int quark, long timestamp) throws StateValueTypeException, TimeRangeException, AttributeNotFoundException { | |
169 | if (isIncrement()) { | |
170 | incrementValue(event, quark, timestamp); | |
171 | } else { | |
172 | ITmfStateValue value = getValue(event); | |
173 | processValue(quark, timestamp, value); | |
174 | } | |
175 | } | |
176 | ||
177 | @Override | |
178 | protected void processValue(int quark, long timestamp, ITmfStateValue value) throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { | |
12685851 GB |
179 | ITmfStateSystemBuilder ss = getStateSystem(); |
180 | if (ss == null) { | |
a194b17a | 181 | throw new IllegalStateException(ILLEGAL_STATE_EXCEPTION_MESSAGE); |
12685851 | 182 | } |
1d7e62f9 GB |
183 | switch (getStackType()) { |
184 | case POP: | |
12685851 | 185 | ss.popAttribute(timestamp, quark); |
1d7e62f9 GB |
186 | break; |
187 | case PUSH: | |
12685851 | 188 | ss.pushAttribute(timestamp, value, quark); |
1d7e62f9 GB |
189 | break; |
190 | case NULL: | |
191 | case PEEK: | |
192 | default: | |
12685851 | 193 | ss.modifyAttribute(timestamp, value, quark); |
1d7e62f9 GB |
194 | break; |
195 | } | |
196 | } | |
197 | ||
198 | @Override | |
199 | protected void incrementValue(ITmfEvent event, int quark, long timestamp) throws StateValueTypeException, TimeRangeException, AttributeNotFoundException { | |
12685851 GB |
200 | ITmfStateSystemBuilder ss = getStateSystem(); |
201 | if (ss == null) { | |
a194b17a | 202 | throw new IllegalStateException(ILLEGAL_STATE_EXCEPTION_MESSAGE); |
12685851 | 203 | } |
acec47ce | 204 | StateSystemBuilderUtils.incrementAttributeInt(ss, timestamp, quark, 1); |
1d7e62f9 GB |
205 | } |
206 | } | |
207 | ||
b1e4ea44 | 208 | private static @Nullable ITmfStateValue incrementByType(int quark, ITmfStateSystem ss, ITmfStateValue stateValue) throws AttributeNotFoundException { |
9411fd5b MK |
209 | ITmfStateValue value = null; |
210 | switch (stateValue.getType()) { | |
211 | case LONG: { | |
212 | long incrementLong = stateValue.unboxLong(); | |
213 | ITmfStateValue currentState = ss.queryOngoingState(quark); | |
214 | long currentValue = (currentState.isNull() ? 0 : currentState.unboxLong()); | |
215 | value = TmfStateValue.newValueLong(incrementLong + currentValue); | |
216 | return value; | |
217 | } | |
218 | case INTEGER: { | |
219 | int increment = stateValue.unboxInt(); | |
220 | ITmfStateValue currentState = ss.queryOngoingState(quark); | |
221 | int currentValue = (currentState.isNull() ? 0 : currentState.unboxInt()); | |
222 | value = TmfStateValue.newValueInt(increment + currentValue); | |
223 | return value; | |
224 | } | |
225 | case DOUBLE: | |
226 | case NULL: | |
227 | case STRING: | |
228 | default: | |
229 | } | |
230 | return value; | |
231 | } | |
232 | ||
1d7e62f9 GB |
233 | /* This state value uses a constant value, defined in the XML */ |
234 | private class TmfXmlStateValueTmf extends TmfXmlStateValueTypeReadWrite { | |
235 | ||
236 | private final ITmfStateValue fValue; | |
237 | ||
238 | public TmfXmlStateValueTmf(ITmfStateValue value) { | |
239 | fValue = value; | |
240 | } | |
241 | ||
242 | @Override | |
12685851 | 243 | public ITmfStateValue getValue(@Nullable ITmfEvent event) { |
1d7e62f9 GB |
244 | return fValue; |
245 | } | |
246 | ||
247 | @Override | |
248 | public void incrementValue(ITmfEvent event, int quark, long timestamp) throws StateValueTypeException, TimeRangeException, AttributeNotFoundException { | |
249 | ITmfStateSystem ss = getStateSystem(); | |
12685851 | 250 | if (ss == null) { |
a194b17a | 251 | throw new IllegalStateException(ILLEGAL_STATE_EXCEPTION_MESSAGE); |
12685851 | 252 | } |
b1e4ea44 | 253 | ITmfStateValue value = incrementByType(quark, ss, fValue); |
9411fd5b | 254 | if (value != null) { |
1d7e62f9 | 255 | processValue(quark, timestamp, value); |
9411fd5b | 256 | } else { |
1d7e62f9 | 257 | Activator.logWarning("TmfXmlStateValue: The increment value is not a number type"); //$NON-NLS-1$ |
1d7e62f9 GB |
258 | } |
259 | } | |
9411fd5b | 260 | |
cbac1ac1 JCK |
261 | @Override |
262 | public String toString() { | |
263 | return "Value=" + fValue; //$NON-NLS-1$ | |
264 | } | |
265 | ||
1d7e62f9 GB |
266 | } |
267 | ||
268 | /* The state value uses the value of an event field */ | |
269 | private class TmfXmlStateValueEventField extends TmfXmlStateValueTypeReadWrite { | |
270 | ||
271 | private final String fFieldName; | |
272 | ||
273 | public TmfXmlStateValueEventField(String field) { | |
274 | fFieldName = field; | |
275 | } | |
276 | ||
277 | @Override | |
12685851 | 278 | public ITmfStateValue getValue(@Nullable ITmfEvent event) { |
1d7e62f9 GB |
279 | if (event == null) { |
280 | Activator.logWarning("XML State value: requested an event field, but event is null"); //$NON-NLS-1$ | |
281 | return TmfStateValue.nullValue(); | |
282 | } | |
283 | return getEventFieldValue(event, fFieldName); | |
284 | } | |
285 | ||
286 | @Override | |
287 | public void incrementValue(ITmfEvent event, int quark, long timestamp) throws StateValueTypeException, TimeRangeException, AttributeNotFoundException { | |
288 | ITmfStateSystem ss = getSsContainer().getStateSystem(); | |
12685851 | 289 | if (ss == null) { |
a194b17a | 290 | throw new IllegalStateException(ILLEGAL_STATE_EXCEPTION_MESSAGE); |
12685851 | 291 | } |
1d7e62f9 | 292 | ITmfStateValue incrementValue = getValue(event); |
b1e4ea44 | 293 | ITmfStateValue value = incrementByType(quark, ss, incrementValue); |
9411fd5b | 294 | if (value != null) { |
1d7e62f9 | 295 | processValue(quark, timestamp, value); |
9411fd5b | 296 | } else { |
1d7e62f9 | 297 | Activator.logWarning(String.format("TmfXmlStateValue: The event field increment %s is not a number type but a %s", fFieldName, incrementValue.getType())); //$NON-NLS-1$ |
1d7e62f9 GB |
298 | } |
299 | } | |
cbac1ac1 JCK |
300 | |
301 | @Override | |
302 | public String toString() { | |
303 | return "Event Field=" + fFieldName; //$NON-NLS-1$ | |
304 | } | |
1d7e62f9 GB |
305 | } |
306 | ||
307 | /* The state value is the event name */ | |
308 | private class TmfXmlStateValueEventName extends TmfXmlStateValueTypeReadWrite { | |
309 | ||
310 | @Override | |
12685851 | 311 | public ITmfStateValue getValue(@Nullable ITmfEvent event) { |
1d7e62f9 GB |
312 | if (event == null) { |
313 | Activator.logWarning("XML State value: request event name, but event is null"); //$NON-NLS-1$ | |
314 | return TmfStateValue.nullValue(); | |
315 | } | |
578716e6 | 316 | return TmfStateValue.newValueString(event.getName()); |
1d7e62f9 GB |
317 | } |
318 | ||
cbac1ac1 JCK |
319 | @Override |
320 | public String toString() { | |
321 | return "Event name"; //$NON-NLS-1$ | |
322 | } | |
323 | ||
1d7e62f9 GB |
324 | } |
325 | ||
326 | /* The state value deletes an attribute */ | |
327 | private class TmfXmlStateValueDelete extends TmfXmlStateValueTypeReadWrite { | |
328 | ||
329 | @Override | |
12685851 | 330 | public ITmfStateValue getValue(@Nullable ITmfEvent event) throws AttributeNotFoundException { |
1d7e62f9 GB |
331 | return TmfStateValue.nullValue(); |
332 | } | |
333 | ||
334 | @Override | |
335 | protected void processValue(int quark, long timestamp, ITmfStateValue value) throws TimeRangeException, AttributeNotFoundException { | |
336 | ITmfStateSystem ss = getStateSystem(); | |
337 | if (!(ss instanceof ITmfStateSystemBuilder)) { | |
338 | throw new IllegalStateException("incrementValue should never be called when not building the state system"); //$NON-NLS-1$ | |
339 | } | |
340 | ITmfStateSystemBuilder builder = (ITmfStateSystemBuilder) ss; | |
341 | builder.removeAttribute(timestamp, quark); | |
342 | } | |
343 | ||
cbac1ac1 JCK |
344 | @Override |
345 | public String toString() { | |
346 | return "Delete"; //$NON-NLS-1$ | |
347 | } | |
1d7e62f9 GB |
348 | } |
349 | ||
350 | /* The state value uses the result of a query */ | |
351 | private class TmfXmlStateValueQuery extends TmfXmlStateValueTypeReadWrite { | |
352 | ||
353 | private final List<ITmfXmlStateAttribute> fQueryValue; | |
354 | ||
355 | public TmfXmlStateValueQuery(List<ITmfXmlStateAttribute> childAttributes) { | |
356 | fQueryValue = childAttributes; | |
357 | } | |
358 | ||
359 | @Override | |
12685851 | 360 | public ITmfStateValue getValue(@Nullable ITmfEvent event) throws AttributeNotFoundException { |
1d7e62f9 GB |
361 | /* Query the state system for the value */ |
362 | ITmfStateValue value = TmfStateValue.nullValue(); | |
363 | int quarkQuery = IXmlStateSystemContainer.ROOT_QUARK; | |
364 | ITmfStateSystem ss = getStateSystem(); | |
12685851 | 365 | if (ss == null) { |
a194b17a | 366 | throw new IllegalStateException(ILLEGAL_STATE_EXCEPTION_MESSAGE); |
12685851 | 367 | } |
1d7e62f9 GB |
368 | |
369 | for (ITmfXmlStateAttribute attribute : fQueryValue) { | |
370 | quarkQuery = attribute.getAttributeQuark(event, quarkQuery); | |
371 | if (quarkQuery == IXmlStateSystemContainer.ERROR_QUARK) { | |
372 | /* the query is not valid, we stop the state change */ | |
373 | break; | |
374 | } | |
375 | } | |
376 | /* | |
377 | * the query can fail : for example, if a value is requested but has | |
378 | * not been set yet | |
379 | */ | |
380 | if (quarkQuery != IXmlStateSystemContainer.ERROR_QUARK) { | |
381 | value = ss.queryOngoingState(quarkQuery); | |
12685851 GB |
382 | if (value == null) { |
383 | throw new IllegalStateException(); | |
384 | } | |
1d7e62f9 GB |
385 | } |
386 | return value; | |
387 | } | |
388 | ||
389 | @Override | |
390 | public void incrementValue(ITmfEvent event, int quark, long timestamp) throws StateValueTypeException, TimeRangeException, AttributeNotFoundException { | |
391 | ITmfStateSystem ss = getStateSystem(); | |
12685851 | 392 | if (ss == null) { |
a194b17a | 393 | throw new IllegalStateException(ILLEGAL_STATE_EXCEPTION_MESSAGE); |
12685851 GB |
394 | } |
395 | ||
1d7e62f9 | 396 | ITmfStateValue incrementValue = getValue(event); |
b1e4ea44 | 397 | ITmfStateValue value = incrementByType(quark, ss, incrementValue); |
9411fd5b | 398 | if (value != null) { |
1d7e62f9 | 399 | processValue(quark, timestamp, value); |
9411fd5b | 400 | } else { |
1d7e62f9 | 401 | Activator.logWarning("TmfXmlStateValue: The query result increment is not a number type"); //$NON-NLS-1$ |
1d7e62f9 GB |
402 | } |
403 | } | |
cbac1ac1 JCK |
404 | |
405 | @Override | |
406 | public String toString() { | |
407 | return "Query=" + fQueryValue; //$NON-NLS-1$ | |
408 | } | |
1d7e62f9 GB |
409 | } |
410 | ||
411 | } |