tmf: Add configurable marker event source
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / internal / tmf / core / markers / MarkerConfigXmlParser.java
1 /*******************************************************************************
2 * Copyright (c) 2017 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 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.internal.tmf.core.markers;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.net.URISyntaxException;
18 import java.net.URL;
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;
25
26 import javax.xml.parsers.DocumentBuilder;
27 import javax.xml.parsers.DocumentBuilderFactory;
28 import javax.xml.parsers.ParserConfigurationException;
29
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;
44
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;
49
50 /**
51 * XML Parser for periodic marker configuration
52 */
53 public class MarkerConfigXmlParser {
54
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$
63
64 private static final @NonNull String ELLIPSIS = ".."; //$NON-NLS-1$
65
66 /**
67 * Get the marker sets from the marker configuration file.
68 *
69 * @return the list of marker sets
70 */
71 public static @NonNull List<MarkerSet> getMarkerSets() {
72 if (!MARKER_CONFIG_FILE.exists()) {
73 return Collections.EMPTY_LIST;
74 }
75 return parse(MARKER_CONFIG_FILE.getAbsolutePath());
76 }
77
78 /**
79 * Initialize the marker configuration file in the plug-in state location.
80 */
81 public static void initMarkerSets() {
82 if (!MARKER_CONFIG_FILE.exists()) {
83 try {
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$
88 }
89 }
90 }
91
92 /**
93 * Parse a periodic marker configuration file
94 *
95 * @param path
96 * the path to the configuration file
97 * @return the list of marker sets
98 */
99 public static @NonNull List<MarkerSet> parse(String path) {
100
101 List<MarkerSet> markerSets = new ArrayList<>();
102 try {
103 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
104 dbf.setValidating(false);
105 DocumentBuilder db = dbf.newDocumentBuilder();
106
107 // The following catches xml parsing exceptions
108 db.setErrorHandler(new ErrorHandler() {
109 @Override
110 public void error(SAXParseException saxparseexception) throws SAXException {
111 throw saxparseexception;
112 }
113
114 @Override
115 public void warning(SAXParseException saxparseexception) throws SAXException {
116 throw saxparseexception;
117 }
118
119 @Override
120 public void fatalError(SAXParseException saxparseexception) throws SAXException {
121 throw saxparseexception;
122 }
123 });
124
125 File file = new File(path);
126 if (!file.canRead()) {
127 return markerSets;
128 }
129 Document doc = db.parse(file);
130
131 Element root = doc.getDocumentElement();
132 if (!root.getNodeName().equals(IMarkerConstants.MARKER_SETS)) {
133 return markerSets;
134 }
135
136 NodeList markerSetsList = root.getElementsByTagName(IMarkerConstants.MARKER_SET);
137 for (int i = 0; i < markerSetsList.getLength(); i++) {
138 try {
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);
146 }
147 markerSets.add(markerSet);
148 } catch (IllegalArgumentException e) {
149 Activator.logError("Error parsing " + path, e); //$NON-NLS-1$
150 }
151 }
152 return markerSets;
153
154 } catch (ParserConfigurationException | SAXException | IOException e) {
155 Activator.logError("Error parsing " + path, e); //$NON-NLS-1$
156 }
157 return markerSets;
158 }
159
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);
176 markers.add(marker);
177 }
178 return markers;
179 }
180
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();
194 }
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$
199 }
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);
211 }
212 }
213 }
214 }
215
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);
227 if (length <= 0) {
228 throw new IllegalArgumentException("Unsupported length: " + lengthAttr); //$NON-NLS-1$
229 }
230 MarkerSegment segment = new MarkerSegment(label, id, color, length);
231 parent.addSegment(segment);
232 parseSubMarkers(segmentElem, segment);
233 }
234 }
235 }
236
237 private static String parseLabel(String labelAttr) {
238 if (labelAttr.isEmpty()) {
239 return DEFAULT_LABEL;
240 }
241 return labelAttr;
242 }
243
244 private static double parsePeriod(String periodAttr) {
245 double period = Double.parseDouble(periodAttr);
246 if (period <= 0) {
247 throw new IllegalArgumentException("Unsupported period: " + periodAttr); //$NON-NLS-1$
248 }
249 return period;
250 }
251
252 private static String parseUnit(String unitAttr) {
253 if (Arrays.asList(IMarkerConstants.MS, IMarkerConstants.US, IMarkerConstants.NS).contains(unitAttr)) {
254 return unitAttr;
255 }
256 throw new IllegalArgumentException("Unsupported unit: " + unitAttr); //$NON-NLS-1$
257 }
258
259 private static Range<Long> parseRange(String rangeAttr) {
260 int index = rangeAttr.indexOf(ELLIPSIS);
261 if (index > 0) {
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);
267 }
268 return Range.atLeast(min);
269 }
270 if (index == 0) {
271 index += ELLIPSIS.length();
272 if (index < rangeAttr.length()) {
273 long max = Long.parseLong(rangeAttr.substring(index));
274 return Range.atMost(max);
275 }
276 return Range.all();
277 }
278 if (!rangeAttr.isEmpty()) {
279 long val = Long.parseLong(rangeAttr);
280 return Range.singleton(val);
281 }
282 return Range.atLeast(0L);
283 }
284
285 private static RangeSet<Long> parseRangeSet(String rangeSetAttr) {
286 if (rangeSetAttr.isEmpty()) {
287 return ImmutableRangeSet.of(Range.all());
288 }
289 RangeSet<Long> rangeSet = TreeRangeSet.create();
290 String[] ranges = rangeSetAttr.split(","); //$NON-NLS-1$
291 if (ranges.length == 0) {
292 rangeSet.add(Range.all());
293 } else {
294 for (String range : ranges) {
295 rangeSet.add(parseRange(range));
296 }
297 }
298 return rangeSet;
299 }
300
301 private static long parseOffset(String offset) {
302 if (offset.isEmpty()) {
303 return 0L;
304 }
305 return Long.parseLong(offset);
306 }
307 }
This page took 0.041717 seconds and 5 git commands to generate.