1 /*******************************************************************************
2 * Copyright (c) 2017 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
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.tmf
.core
.markers
;
16 import java
.io
.IOException
;
17 import java
.net
.URISyntaxException
;
19 import java
.nio
.file
.Files
;
20 import java
.nio
.file
.StandardCopyOption
;
21 import java
.util
.ArrayList
;
22 import java
.util
.Arrays
;
23 import java
.util
.Collections
;
24 import java
.util
.List
;
26 import javax
.xml
.parsers
.DocumentBuilder
;
27 import javax
.xml
.parsers
.DocumentBuilderFactory
;
28 import javax
.xml
.parsers
.ParserConfigurationException
;
30 import org
.eclipse
.core
.runtime
.FileLocator
;
31 import org
.eclipse
.core
.runtime
.IPath
;
32 import org
.eclipse
.jdt
.annotation
.NonNull
;
33 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
34 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.markers
.Marker
.PeriodicMarker
;
35 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.markers
.SubMarker
.SplitMarker
;
36 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.markers
.SubMarker
.WeightedMarker
;
37 import org
.w3c
.dom
.Document
;
38 import org
.w3c
.dom
.Element
;
39 import org
.w3c
.dom
.Node
;
40 import org
.w3c
.dom
.NodeList
;
41 import org
.xml
.sax
.ErrorHandler
;
42 import org
.xml
.sax
.SAXException
;
43 import org
.xml
.sax
.SAXParseException
;
45 import com
.google
.common
.collect
.ImmutableRangeSet
;
46 import com
.google
.common
.collect
.Range
;
47 import com
.google
.common
.collect
.RangeSet
;
48 import com
.google
.common
.collect
.TreeRangeSet
;
51 * XML Parser for periodic marker configuration
53 public class MarkerConfigXmlParser
{
55 /** Default marker configuration file URL */
56 private static final URL DEFAULT_MARKER_CONFIG_URL
= MarkerConfigXmlParser
.class.getResource("/templates/markers.xml"); //$NON-NLS-1$
57 /** Marker configuration file name */
58 public static final IPath MARKER_CONFIG_PATH
= Activator
.getDefault().getStateLocation().addTrailingSeparator().append("markers.xml"); //$NON-NLS-1$
59 /** Marker configuration file */
60 private static final File MARKER_CONFIG_FILE
= MARKER_CONFIG_PATH
.toFile();
61 /** Default marker label */
62 private static final String DEFAULT_LABEL
= "%d"; //$NON-NLS-1$
64 private static final @NonNull String ELLIPSIS
= ".."; //$NON-NLS-1$
67 * Get the marker sets from the marker configuration file.
69 * @return the list of marker sets
71 public static @NonNull List
<MarkerSet
> getMarkerSets() {
72 if (!MARKER_CONFIG_FILE
.exists()) {
73 return Collections
.EMPTY_LIST
;
75 return parse(MARKER_CONFIG_FILE
.getAbsolutePath());
79 * Initialize the marker configuration file in the plug-in state location.
81 public static void initMarkerSets() {
82 if (!MARKER_CONFIG_FILE
.exists()) {
84 File defaultConfigFile
= new File(FileLocator
.toFileURL(DEFAULT_MARKER_CONFIG_URL
).toURI());
85 Files
.copy(defaultConfigFile
.toPath(), MARKER_CONFIG_FILE
.toPath(), StandardCopyOption
.REPLACE_EXISTING
);
86 } catch (URISyntaxException
| IOException e
) {
87 Activator
.logError("Error copying " + DEFAULT_MARKER_CONFIG_URL
+ " to " + MARKER_CONFIG_FILE
.getAbsolutePath(), e
); //$NON-NLS-1$ //$NON-NLS-2$
93 * Parse a periodic marker configuration file
96 * the path to the configuration file
97 * @return the list of marker sets
99 public static @NonNull List
<MarkerSet
> parse(String path
) {
101 List
<MarkerSet
> markerSets
= new ArrayList
<>();
103 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
104 dbf
.setValidating(false);
105 DocumentBuilder db
= dbf
.newDocumentBuilder();
107 // The following catches xml parsing exceptions
108 db
.setErrorHandler(new ErrorHandler() {
110 public void error(SAXParseException saxparseexception
) throws SAXException
{
111 throw saxparseexception
;
115 public void warning(SAXParseException saxparseexception
) throws SAXException
{
116 throw saxparseexception
;
120 public void fatalError(SAXParseException saxparseexception
) throws SAXException
{
121 throw saxparseexception
;
125 File file
= new File(path
);
126 if (!file
.canRead()) {
129 Document doc
= db
.parse(file
);
131 Element root
= doc
.getDocumentElement();
132 if (!root
.getNodeName().equals(IMarkerConstants
.MARKER_SETS
)) {
136 NodeList markerSetsList
= root
.getElementsByTagName(IMarkerConstants
.MARKER_SET
);
137 for (int i
= 0; i
< markerSetsList
.getLength(); i
++) {
139 Element markerSetElem
= (Element
) markerSetsList
.item(i
);
140 String name
= markerSetElem
.getAttribute(IMarkerConstants
.NAME
);
141 String id
= markerSetElem
.getAttribute(IMarkerConstants
.ID
);
142 MarkerSet markerSet
= new MarkerSet(name
, id
);
143 List
<Marker
> markers
= getMarkers(markerSetElem
);
144 for (Marker marker
: markers
) {
145 markerSet
.addMarker(marker
);
147 markerSets
.add(markerSet
);
148 } catch (IllegalArgumentException e
) {
149 Activator
.logError("Error parsing " + path
, e
); //$NON-NLS-1$
154 } catch (ParserConfigurationException
| SAXException
| IOException e
) {
155 Activator
.logError("Error parsing " + path
, e
); //$NON-NLS-1$
160 private static List
<Marker
> getMarkers(Element markerSet
) {
161 List
<Marker
> markers
= new ArrayList
<>();
162 NodeList markerList
= markerSet
.getElementsByTagName(IMarkerConstants
.MARKER
);
163 for (int i
= 0; i
< markerList
.getLength(); i
++) {
164 Element markerElem
= (Element
) markerList
.item(i
);
165 String name
= markerElem
.getAttribute(IMarkerConstants
.NAME
);
166 String label
= parseLabel(markerElem
.getAttribute(IMarkerConstants
.LABEL
));
167 String id
= markerElem
.getAttribute(IMarkerConstants
.ID
);
168 String color
= markerElem
.getAttribute(IMarkerConstants
.COLOR
);
169 double period
= parsePeriod(markerElem
.getAttribute(IMarkerConstants
.PERIOD
));
170 String unit
= parseUnit(markerElem
.getAttribute(IMarkerConstants
.UNIT
));
171 Range
<Long
> range
= parseRange(markerElem
.getAttribute(IMarkerConstants
.RANGE
));
172 long offset
= parseOffset(markerElem
.getAttribute(IMarkerConstants
.OFFSET
));
173 RangeSet
<Long
> indexRange
= parseRangeSet(markerElem
.getAttribute(IMarkerConstants
.INDEX
));
174 PeriodicMarker marker
= new PeriodicMarker(name
, label
, id
, color
, period
, unit
, range
, offset
, indexRange
);
175 parseSubMarkers(markerElem
, marker
);
181 private static void parseSubMarkers(Element marker
, Marker parent
) {
182 NodeList nodeList
= marker
.getChildNodes();
183 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
184 Node node
= nodeList
.item(i
);
185 if (node
.getNodeType() == Node
.ELEMENT_NODE
) {
186 if (node
.getNodeName().equals(IMarkerConstants
.SUBMARKER
)) {
187 Element subMarkerElem
= (Element
) node
;
188 String name
= subMarkerElem
.getAttribute(IMarkerConstants
.NAME
);
189 String label
= parseLabel(subMarkerElem
.getAttribute(IMarkerConstants
.LABEL
));
190 String id
= subMarkerElem
.getAttribute(IMarkerConstants
.ID
);
191 String color
= subMarkerElem
.getAttribute(IMarkerConstants
.COLOR
);
192 if (color
.isEmpty()) {
193 color
= parent
.getColor();
195 String rangeAttr
= subMarkerElem
.getAttribute(IMarkerConstants
.RANGE
);
196 Range
<Long
> range
= parseRange(rangeAttr
);
197 if (!range
.hasLowerBound() || !range
.hasUpperBound()) {
198 throw new IllegalArgumentException("Unsupported unbound range: " + range
); //$NON-NLS-1$
200 RangeSet
<Long
> indexRange
= parseRangeSet(subMarkerElem
.getAttribute(IMarkerConstants
.INDEX
));
201 SplitMarker subMarker
= new SplitMarker(name
, label
, id
, color
, range
, indexRange
);
202 parent
.addSubMarker(subMarker
);
203 parseSubMarkers(subMarkerElem
, subMarker
);
204 } else if (node
.getNodeName().equals(IMarkerConstants
.SEGMENTS
)) {
205 Element segmentsElem
= (Element
) node
;
206 String name
= segmentsElem
.getAttribute(IMarkerConstants
.NAME
);
207 WeightedMarker subMarker
= new WeightedMarker(name
);
208 parent
.addSubMarker(subMarker
);
209 parseSegments(segmentsElem
, subMarker
);
210 parseSubMarkers(segmentsElem
, subMarker
);
216 private static void parseSegments(Element marker
, WeightedMarker parent
) {
217 NodeList nodeList
= marker
.getChildNodes();
218 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
219 Node node
= nodeList
.item(i
);
220 if (node
.getNodeType() == Node
.ELEMENT_NODE
&& node
.getNodeName().equals(IMarkerConstants
.SEGMENT
)) {
221 Element segmentElem
= (Element
) node
;
222 String label
= parseLabel(segmentElem
.getAttribute(IMarkerConstants
.LABEL
));
223 String id
= segmentElem
.getAttribute(IMarkerConstants
.ID
);
224 String color
= segmentElem
.getAttribute(IMarkerConstants
.COLOR
);
225 String lengthAttr
= segmentElem
.getAttribute(IMarkerConstants
.LENGTH
);
226 int length
= Integer
.parseInt(lengthAttr
);
228 throw new IllegalArgumentException("Unsupported length: " + lengthAttr
); //$NON-NLS-1$
230 MarkerSegment segment
= new MarkerSegment(label
, id
, color
, length
);
231 parent
.addSegment(segment
);
232 parseSubMarkers(segmentElem
, segment
);
237 private static String
parseLabel(String labelAttr
) {
238 if (labelAttr
.isEmpty()) {
239 return DEFAULT_LABEL
;
244 private static double parsePeriod(String periodAttr
) {
245 double period
= Double
.parseDouble(periodAttr
);
247 throw new IllegalArgumentException("Unsupported period: " + periodAttr
); //$NON-NLS-1$
252 private static String
parseUnit(String unitAttr
) {
253 if (Arrays
.asList(IMarkerConstants
.MS
, IMarkerConstants
.US
, IMarkerConstants
.NS
).contains(unitAttr
)) {
256 throw new IllegalArgumentException("Unsupported unit: " + unitAttr
); //$NON-NLS-1$
259 private static Range
<Long
> parseRange(String rangeAttr
) {
260 int index
= rangeAttr
.indexOf(ELLIPSIS
);
262 long min
= Long
.parseLong(rangeAttr
.substring(0, index
));
263 index
+= ELLIPSIS
.length();
264 if (index
< rangeAttr
.length()) {
265 long max
= Long
.parseLong(rangeAttr
.substring(index
));
266 return Range
.closed(min
, max
);
268 return Range
.atLeast(min
);
271 index
+= ELLIPSIS
.length();
272 if (index
< rangeAttr
.length()) {
273 long max
= Long
.parseLong(rangeAttr
.substring(index
));
274 return Range
.atMost(max
);
278 if (!rangeAttr
.isEmpty()) {
279 long val
= Long
.parseLong(rangeAttr
);
280 return Range
.singleton(val
);
282 return Range
.atLeast(0L);
285 private static RangeSet
<Long
> parseRangeSet(String rangeSetAttr
) {
286 if (rangeSetAttr
.isEmpty()) {
287 return ImmutableRangeSet
.of(Range
.all());
289 RangeSet
<Long
> rangeSet
= TreeRangeSet
.create();
290 String
[] ranges
= rangeSetAttr
.split(","); //$NON-NLS-1$
291 if (ranges
.length
== 0) {
292 rangeSet
.add(Range
.all());
294 for (String range
: ranges
) {
295 rangeSet
.add(parseRange(range
));
301 private static long parseOffset(String offset
) {
302 if (offset
.isEmpty()) {
305 return Long
.parseLong(offset
);