1 /*******************************************************************************
2 * Copyright (c) 2016 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
.tmf
.analysis
.xml
.core
.model
;
11 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
13 import java
.util
.ArrayList
;
14 import java
.util
.HashMap
;
15 import java
.util
.List
;
17 import java
.util
.Map
.Entry
;
19 import org
.eclipse
.jdt
.annotation
.Nullable
;
20 import org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.Activator
;
21 import org
.eclipse
.tracecompass
.internal
.tmf
.analysis
.xml
.core
.pattern
.stateprovider
.XmlPatternStateProvider
;
22 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
23 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateValueTypeException
;
24 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
25 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
26 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.module
.IXmlStateSystemContainer
;
27 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.segment
.TmfXmlPatternSegment
;
28 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.stateprovider
.TmfXmlStrings
;
29 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
30 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
31 import org
.w3c
.dom
.Element
;
32 import org
.w3c
.dom
.NodeList
;
35 * This class defines a pattern segment builder. It will use the XML description
36 * of the pattern segment to generate it at runtime.
38 * @author Jean-Christian Kouame
42 public class TmfXmlPatternSegmentBuilder
{
47 public static final String UNKNOWN_STRING
= "unknown"; //$NON-NLS-1$
49 * Prefix for the pattern segment name
51 public static final String PATTERN_SEGMENT_NAME_PREFIX
= "seg_"; //$NON-NLS-1$
52 private final ITmfXmlModelFactory fModelFactory
;
53 private final IXmlStateSystemContainer fContainer
;
54 private final List
<TmfXmlPatternSegmentField
> fFields
= new ArrayList
<>();
55 private final TmfXmlPatternSegmentType fSegmentType
;
59 * The factory used to create XML model elements
61 * XML element of the pattern segment builder
63 * The state system container this pattern segment builder
66 public TmfXmlPatternSegmentBuilder(ITmfXmlModelFactory modelFactory
, Element node
, IXmlStateSystemContainer parent
) {
67 fModelFactory
= modelFactory
;
70 //Set the XML type of the segment
71 NodeList nodesSegmentType
= node
.getElementsByTagName(TmfXmlStrings
.SEGMENT_TYPE
);
72 Element element
= (Element
) nodesSegmentType
.item(0);
73 if (element
== null) {
74 throw new IllegalArgumentException();
76 fSegmentType
= new TmfXmlPatternSegmentType(element
);
78 //Set the XML content of the segment
79 NodeList nodesSegmentContent
= node
.getElementsByTagName(TmfXmlStrings
.SEGMENT_CONTENT
);
80 Element fContentElement
= (Element
) nodesSegmentContent
.item(0);
81 if (fContentElement
!= null) {
82 NodeList nodesSegmentField
= fContentElement
.getElementsByTagName(TmfXmlStrings
.SEGMENT_FIELD
);
83 for (int i
= 0; i
< nodesSegmentField
.getLength(); i
++) {
84 fFields
.add(new TmfXmlPatternSegmentField(checkNotNull((Element
) nodesSegmentField
.item(i
))));
90 * Generate a pattern segment
95 * Start time of the pattern segment to generate
97 * End time of the pattern segment to generate
99 * The active scenario details. Or <code>null</code> if there is
101 * @return The pattern segment generated
103 public TmfXmlPatternSegment
generatePatternSegment(ITmfEvent event
, ITmfTimestamp start
, ITmfTimestamp end
, @Nullable TmfXmlScenarioInfo scenarioInfo
) {
104 int scale
= event
.getTimestamp().getScale();
105 long startValue
= start
.toNanos();
106 long endValue
= end
.toNanos();
107 String segmentName
= getPatternSegmentName(event
, scenarioInfo
);
108 Map
<String
, ITmfStateValue
> fields
= new HashMap
<>();
109 setPatternSegmentContent(event
, start
, end
, fields
, scenarioInfo
);
110 TmfXmlPatternSegment segment
= new TmfXmlPatternSegment(startValue
, endValue
, scale
, segmentName
, fields
);
111 if (fContainer
instanceof XmlPatternStateProvider
) {
112 ((XmlPatternStateProvider
) fContainer
).getListener().onNewSegment(segment
);
118 * Get the pattern segment name
122 * @param scenarioInfo
123 * The active scenario details. Or <code>null</code> if there is
125 * @return The name of the segment
127 private String
getPatternSegmentName(ITmfEvent event
, @Nullable TmfXmlScenarioInfo scenarioInfo
) {
128 return fSegmentType
.getName(event
, scenarioInfo
);
132 * Compute all the fields and their values for this pattern segment. The
133 * fields could be constant values or values queried from the state system.
138 * The start timestamp of this segment
140 * The end timestamp of this segment
142 * The map that will contained all the fields
143 * @param scenarioInfo
144 * The active scenario details. Or <code>null</code> if there is
147 private void setPatternSegmentContent(ITmfEvent event
, ITmfTimestamp start
, ITmfTimestamp end
, Map
<String
, ITmfStateValue
> fields
, @Nullable TmfXmlScenarioInfo scenarioInfo
) {
148 for (TmfXmlPatternSegmentField field
: fFields
) {
149 fields
.put(field
.getName().intern(), field
.getValue(event
, scenarioInfo
));
151 if (scenarioInfo
!= null) {
152 addStoredFieldsContent(event
, fields
, scenarioInfo
);
157 * Query the stored fields path and add them to the content of the pattern
158 * segment. This is specific to pattern analysis.
165 * The active scenario details
167 protected void addStoredFieldsContent(ITmfEvent event
, Map
<String
, ITmfStateValue
> fields
, final TmfXmlScenarioInfo info
) {
168 if (fContainer
instanceof XmlPatternStateProvider
) {
169 for (Entry
<String
, String
> entry
: ((XmlPatternStateProvider
) fContainer
).getStoredFields().entrySet()) {
170 ITmfStateValue value
= ((XmlPatternStateProvider
) fContainer
).getHistoryBuilder().getStoredFieldValue(fContainer
, entry
.getValue(), info
, event
);
171 if (!value
.isNull()) {
172 fields
.put(entry
.getValue().intern(), value
);
178 private static ITmfStateValue
getStateValueFromConstant(String constantValue
, String type
) {
180 case TmfXmlStrings
.TYPE_INT
:
181 return TmfStateValue
.newValueInt(Integer
.parseInt(constantValue
));
182 case TmfXmlStrings
.TYPE_LONG
:
183 return TmfStateValue
.newValueLong(Long
.parseLong(constantValue
));
184 case TmfXmlStrings
.TYPE_STRING
:
185 return TmfStateValue
.newValueString(constantValue
);
186 case TmfXmlStrings
.TYPE_NULL
:
187 return TmfStateValue
.nullValue();
189 throw new IllegalArgumentException("Invalid type of field : " + type
); //$NON-NLS-1$
193 private static void getNameFromXmlStateValue(ITmfEvent event
, StringBuilder builder
, ITmfXmlStateValue xmlStateValue
, @Nullable TmfXmlScenarioInfo scenarioInfo
) {
195 ITmfStateValue value
= xmlStateValue
.getValue(event
, scenarioInfo
);
196 switch (value
.getType()) {
198 builder
.append(value
.unboxDouble());
201 builder
.append(value
.unboxInt());
204 builder
.append(value
.unboxLong());
207 builder
.append(UNKNOWN_STRING
);
210 builder
.append(value
.unboxStr());
213 throw new StateValueTypeException("Invalid type of state value"); //$NON-NLS-1$
215 } catch (AttributeNotFoundException e
) {
216 Activator
.logInfo("Impossible to get the state value", e
); //$NON-NLS-1$
221 * This class represents the segment fields described in the XML. The real
222 * value of the field will be set at runtime using the active event.
224 * @author Jean-Christian Kouame
227 private class TmfXmlPatternSegmentField
{
228 private final String fName
;
229 private final String fType
;
230 private final @Nullable ITmfStateValue fStateValue
;
231 private final @Nullable ITmfXmlStateValue fXmlStateValue
;
237 * The pattern segment field node
239 public TmfXmlPatternSegmentField(Element element
) {
240 // The name, the type and the value of each field could respectively
241 // be found from the attributes name, type and value. If the value
242 // attribute is not available, try to find it from the child state
244 fName
= element
.getAttribute(TmfXmlStrings
.NAME
);
245 fType
= element
.getAttribute(TmfXmlStrings
.TYPE
);
246 String constantValue
= element
.getAttribute(TmfXmlStrings
.VALUE
);
247 if (constantValue
.isEmpty() && !fType
.equals(TmfXmlStrings
.TYPE_NULL
)) {
249 Element elementFieldStateValue
= (Element
) element
.getElementsByTagName(TmfXmlStrings
.STATE_VALUE
).item(0);
250 if (elementFieldStateValue
== null) {
251 throw new IllegalArgumentException("The value of the field " + fName
+ " is missing"); //$NON-NLS-1$ //$NON-NLS-2$
253 fXmlStateValue
= fModelFactory
.createStateValue(elementFieldStateValue
, fContainer
, new ArrayList
<>());
255 fStateValue
= getStateValueFromConstant(constantValue
, fType
);
256 fXmlStateValue
= null;
261 * Get the real value of the XML pattern segment field
265 * @return The state value representing the value of the XML pattern
267 * @param scenarioInfo
268 * The active scenario details. Or <code>null</code> if there
271 public ITmfStateValue
getValue(ITmfEvent event
, @Nullable TmfXmlScenarioInfo scenarioInfo
) {
272 if (fStateValue
!= null) {
276 return checkNotNull(fXmlStateValue
).getValue(event
, scenarioInfo
);
277 } catch (AttributeNotFoundException e
) {
278 Activator
.logError("Failed to get the state value", e
); //$NON-NLS-1$
280 throw new IllegalStateException("Failed to get the value for the segment field " + fName
); //$NON-NLS-1$
284 * Get the name of the XML pattern segment field
288 public String
getName() {
294 * This class represents the segment type described in XML.
296 * @author Jean-Christian Kouame
299 private class TmfXmlPatternSegmentType
{
300 private final String fSegmentNameAttribute
;
301 private final @Nullable ITmfXmlStateValue fNameStateValue
;
307 * The pattern segment type node
309 public TmfXmlPatternSegmentType(Element element
) {
310 // Try to find the segment name from the name attribute. If
311 // attribute not available, try to find it from the child state value
312 fSegmentNameAttribute
= element
.getAttribute(TmfXmlStrings
.SEGMENT_NAME
);
313 if (!fSegmentNameAttribute
.isEmpty()) {
314 fNameStateValue
= null;
316 Element elementSegmentNameStateValue
= (Element
) element
.getElementsByTagName(TmfXmlStrings
.STATE_VALUE
).item(0);
317 if (elementSegmentNameStateValue
== null) {
318 throw new IllegalArgumentException("Failed to get the segment name. A state value is needed."); //$NON-NLS-1$
320 fNameStateValue
= fModelFactory
.createStateValue(elementSegmentNameStateValue
, fContainer
, new ArrayList
<>());
325 * Get the name of the segment
329 * @param scenarioInfo
330 * The active scenario details. Or <code>null</code> if there
332 * @return The segment name
334 public String
getName(ITmfEvent event
, @Nullable TmfXmlScenarioInfo scenarioInfo
) {
335 StringBuilder name
= new StringBuilder(PATTERN_SEGMENT_NAME_PREFIX
);
336 if (fNameStateValue
!= null) {
337 getNameFromXmlStateValue(event
, name
, fNameStateValue
, scenarioInfo
);
339 name
.append(fSegmentNameAttribute
);
341 return name
.toString().intern();