Commit | Line | Data |
---|---|---|
c3c5c786 FC |
1 | /*******************************************************************************\r |
2 | * Copyright (c) 2010 Ericsson\r | |
3 | * \r | |
4 | * All rights reserved. This program and the accompanying materials are\r | |
5 | * made available under the terms of the Eclipse Public License v1.0 which\r | |
6 | * accompanies this distribution, and is available at\r | |
7 | * http://www.eclipse.org/legal/epl-v10.html\r | |
8 | * \r | |
9 | * Contributors:\r | |
10 | * Patrick Tasse - Initial API and implementation\r | |
11 | *******************************************************************************/\r | |
12 | \r | |
d34665f9 | 13 | package org.eclipse.linuxtools.internal.tmf.ui.parsers.custom;\r |
c3c5c786 FC |
14 | \r |
15 | import java.io.ByteArrayInputStream;\r | |
16 | import java.io.File;\r | |
17 | import java.io.FileNotFoundException;\r | |
18 | import java.io.IOException;\r | |
19 | import java.io.RandomAccessFile;\r | |
20 | \r | |
21 | import javax.xml.parsers.DocumentBuilder;\r | |
22 | import javax.xml.parsers.DocumentBuilderFactory;\r | |
23 | import javax.xml.parsers.ParserConfigurationException;\r | |
24 | \r | |
25e48683 | 25 | import org.eclipse.core.resources.IResource;\r |
d34665f9 FC |
26 | import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition.InputAttribute;\r |
27 | import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition.InputElement;\r | |
6c13869b | 28 | import org.eclipse.linuxtools.tmf.core.event.TmfEvent;\r |
6c13869b FC |
29 | import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;\r |
30 | import org.eclipse.linuxtools.tmf.core.io.BufferedRandomAccessFile;\r | |
31 | import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;\r | |
32 | import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;\r | |
6c13869b FC |
33 | import org.eclipse.linuxtools.tmf.core.trace.TmfContext;\r |
34 | import org.eclipse.linuxtools.tmf.core.trace.TmfLocation;\r | |
35 | import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;\r | |
c3c5c786 FC |
36 | import org.w3c.dom.Document;\r |
37 | import org.w3c.dom.Element;\r | |
38 | import org.w3c.dom.Node;\r | |
39 | import org.w3c.dom.NodeList;\r | |
40 | import org.xml.sax.EntityResolver;\r | |
41 | import org.xml.sax.ErrorHandler;\r | |
42 | import org.xml.sax.InputSource;\r | |
43 | import org.xml.sax.SAXException;\r | |
44 | import org.xml.sax.SAXParseException;\r | |
45 | \r | |
46 | public class CustomXmlTrace extends TmfTrace<CustomXmlEvent> {\r | |
47 | \r | |
d7fcacc9 | 48 | private static final TmfLocation<Long> NULL_LOCATION = new TmfLocation<Long>((Long) null);\r |
3118edf1 | 49 | private static final int DEFAULT_CACHE_SIZE = 100;\r |
1b70b6dc | 50 | \r |
25e48683 FC |
51 | private final CustomXmlTraceDefinition fDefinition;\r |
52 | private final CustomXmlEventType fEventType;\r | |
53 | private final InputElement fRecordInputElement;\r | |
54 | \r | |
55 | public CustomXmlTrace(final CustomXmlTraceDefinition definition) {\r | |
4bf17f4a | 56 | fDefinition = definition;\r |
57 | fEventType = new CustomXmlEventType(fDefinition);\r | |
58 | fRecordInputElement = getRecordInputElement(fDefinition.rootInputElement);\r | |
59 | }\r | |
60 | \r | |
25e48683 | 61 | public CustomXmlTrace(final IResource resource, final CustomXmlTraceDefinition definition, final String path, final int pageSize) throws FileNotFoundException {\r |
09e86496 | 62 | super(null, CustomXmlEvent.class, path, (pageSize > 0) ? pageSize : DEFAULT_CACHE_SIZE);\r |
c3c5c786 | 63 | fDefinition = definition;\r |
d7fcacc9 | 64 | fEventType = new CustomXmlEventType(fDefinition);\r |
c3c5c786 FC |
65 | fRecordInputElement = getRecordInputElement(fDefinition.rootInputElement);\r |
66 | }\r | |
67 | \r | |
1b70b6dc | 68 | @Override\r |
25e48683 FC |
69 | public void initTrace(final IResource resource, final String path, final Class<CustomXmlEvent> eventType) throws FileNotFoundException {\r |
70 | super.initTrace(resource, path, eventType);\r | |
1b70b6dc PT |
71 | }\r |
72 | \r | |
c3c5c786 | 73 | @Override\r |
25e48683 FC |
74 | public TmfContext seekLocation(final ITmfLocation<?> location) {\r |
75 | final CustomXmlTraceContext context = new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.INITIAL_RANK);\r | |
76 | if (NULL_LOCATION.equals(location) || !new File(getPath()).isFile())\r | |
c3c5c786 | 77 | return context;\r |
c3c5c786 | 78 | try {\r |
d7fcacc9 | 79 | context.raFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$\r |
09e86496 | 80 | if (location != null && location.getLocation() instanceof Long) {\r |
c3c5c786 | 81 | context.raFile.seek((Long)location.getLocation());\r |
09e86496 | 82 | }\r |
25e48683 | 83 | \r |
c3c5c786 | 84 | String line;\r |
25e48683 | 85 | final String recordElementStart = "<" + fRecordInputElement.elementName; //$NON-NLS-1$\r |
c3c5c786 | 86 | long rawPos = context.raFile.getFilePointer();\r |
25e48683 | 87 | \r |
d7fcacc9 | 88 | while ((line = context.raFile.getNextLine()) != null) {\r |
25e48683 | 89 | final int idx = line.indexOf(recordElementStart);\r |
c3c5c786 FC |
90 | if (idx != -1) {\r |
91 | context.setLocation(new TmfLocation<Long>(rawPos + idx));\r | |
92 | return context;\r | |
93 | }\r | |
94 | rawPos = context.raFile.getFilePointer();\r | |
95 | }\r | |
96 | return context;\r | |
25e48683 | 97 | } catch (final FileNotFoundException e) {\r |
c3c5c786 FC |
98 | e.printStackTrace();\r |
99 | return context;\r | |
25e48683 | 100 | } catch (final IOException e) {\r |
c3c5c786 FC |
101 | e.printStackTrace();\r |
102 | return context;\r | |
103 | }\r | |
25e48683 | 104 | \r |
c3c5c786 FC |
105 | }\r |
106 | \r | |
c76c54bb | 107 | @Override\r |
25e48683 FC |
108 | public TmfContext seekLocation(final double ratio) {\r |
109 | BufferedRandomAccessFile raFile = null;\r | |
c76c54bb | 110 | try {\r |
25e48683 | 111 | raFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$\r |
a79913eb FC |
112 | long pos = (long) (ratio * raFile.length());\r |
113 | while (pos > 0) {\r | |
114 | raFile.seek(pos - 1);\r | |
09e86496 FC |
115 | if (raFile.read() == '\n') {\r |
116 | break;\r | |
117 | }\r | |
a79913eb FC |
118 | pos--;\r |
119 | }\r | |
25e48683 FC |
120 | final ITmfLocation<?> location = new TmfLocation<Long>(pos);\r |
121 | final TmfContext context = seekLocation(location);\r | |
c76c54bb FC |
122 | context.setRank(ITmfContext.UNKNOWN_RANK);\r |
123 | return context;\r | |
25e48683 | 124 | } catch (final FileNotFoundException e) {\r |
c76c54bb FC |
125 | e.printStackTrace();\r |
126 | return new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.INITIAL_RANK);\r | |
25e48683 | 127 | } catch (final IOException e) {\r |
c76c54bb FC |
128 | e.printStackTrace();\r |
129 | return new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.INITIAL_RANK);\r | |
157906bb | 130 | } finally {\r |
09e86496 | 131 | if (raFile != null) {\r |
25e48683 FC |
132 | try {\r |
133 | raFile.close();\r | |
134 | } catch (final IOException e) {\r | |
135 | }\r | |
09e86496 | 136 | }\r |
c76c54bb FC |
137 | }\r |
138 | }\r | |
139 | \r | |
140 | @Override\r | |
25e48683 FC |
141 | public double getLocationRatio(final ITmfLocation<?> location) {\r |
142 | RandomAccessFile raFile = null;\r | |
c76c54bb FC |
143 | try {\r |
144 | if (location.getLocation() instanceof Long) {\r | |
25e48683 | 145 | raFile = new RandomAccessFile(getPath(), "r"); //$NON-NLS-1$\r |
c76c54bb FC |
146 | return (double) ((Long) location.getLocation()) / raFile.length();\r |
147 | }\r | |
25e48683 | 148 | } catch (final FileNotFoundException e) {\r |
c76c54bb | 149 | e.printStackTrace();\r |
25e48683 | 150 | } catch (final IOException e) {\r |
c76c54bb | 151 | e.printStackTrace();\r |
157906bb | 152 | } finally {\r |
09e86496 | 153 | if (raFile != null) {\r |
25e48683 FC |
154 | try {\r |
155 | raFile.close();\r | |
156 | } catch (final IOException e) {\r | |
157 | }\r | |
09e86496 | 158 | }\r |
c76c54bb FC |
159 | }\r |
160 | return 0;\r | |
161 | }\r | |
25e48683 | 162 | \r |
c3c5c786 FC |
163 | @Override\r |
164 | public ITmfLocation<?> getCurrentLocation() {\r | |
a79913eb FC |
165 | // TODO Auto-generated method stub\r |
166 | return null;\r | |
c3c5c786 FC |
167 | }\r |
168 | \r | |
169 | @Override\r | |
25e48683 FC |
170 | public synchronized TmfEvent getNextEvent(final ITmfContext context) {\r |
171 | final ITmfContext savedContext = context.clone();\r | |
172 | final TmfEvent event = parseEvent(context);\r | |
c3c5c786 FC |
173 | if (event != null) {\r |
174 | updateIndex(savedContext, savedContext.getRank(), event.getTimestamp());\r | |
cbdacf03 | 175 | context.increaseRank();\r |
c3c5c786 FC |
176 | }\r |
177 | return event;\r | |
178 | }\r | |
179 | \r | |
180 | @Override\r | |
25e48683 FC |
181 | public TmfEvent parseEvent(final ITmfContext tmfContext) {\r |
182 | if (!(tmfContext instanceof CustomXmlTraceContext))\r | |
c3c5c786 | 183 | return null;\r |
25e48683 FC |
184 | \r |
185 | final CustomXmlTraceContext context = (CustomXmlTraceContext) tmfContext;\r | |
186 | if (!(context.getLocation().getLocation() instanceof Long) || NULL_LOCATION.equals(context.getLocation()))\r | |
c3c5c786 | 187 | return null;\r |
c3c5c786 FC |
188 | \r |
189 | synchronized (context.raFile) {\r | |
190 | CustomXmlEvent event = null;\r | |
191 | try {\r | |
25e48683 | 192 | if (context.raFile.getFilePointer() != (Long)context.getLocation().getLocation() + 1)\r |
09e86496 | 193 | {\r |
c3c5c786 | 194 | context.raFile.seek((Long)context.getLocation().getLocation() + 1); // +1 is for the <\r |
09e86496 | 195 | }\r |
25e48683 | 196 | final StringBuffer elementBuffer = new StringBuffer("<"); //$NON-NLS-1$\r |
c3c5c786 | 197 | readElement(elementBuffer, context.raFile);\r |
25e48683 FC |
198 | final Element element = parseElementBuffer(elementBuffer);\r |
199 | \r | |
c3c5c786 | 200 | event = extractEvent(element, fRecordInputElement);\r |
4c564a2d | 201 | ((StringBuffer) event.getContent().getValue()).append(elementBuffer);\r |
25e48683 | 202 | \r |
c3c5c786 | 203 | String line;\r |
25e48683 | 204 | final String recordElementStart = "<" + fRecordInputElement.elementName; //$NON-NLS-1$\r |
c3c5c786 | 205 | long rawPos = context.raFile.getFilePointer();\r |
25e48683 | 206 | \r |
d7fcacc9 | 207 | while ((line = context.raFile.getNextLine()) != null) {\r |
25e48683 | 208 | final int idx = line.indexOf(recordElementStart);\r |
c3c5c786 FC |
209 | if (idx != -1) {\r |
210 | context.setLocation(new TmfLocation<Long>(rawPos + idx));\r | |
211 | return event;\r | |
212 | }\r | |
213 | rawPos = context.raFile.getFilePointer();\r | |
214 | }\r | |
25e48683 | 215 | } catch (final IOException e) {\r |
c3c5c786 FC |
216 | e.printStackTrace();\r |
217 | }\r | |
d7fcacc9 | 218 | context.setLocation(NULL_LOCATION);\r |
c3c5c786 FC |
219 | return event;\r |
220 | }\r | |
221 | }\r | |
222 | \r | |
25e48683 | 223 | private Element parseElementBuffer(final StringBuffer elementBuffer) {\r |
c3c5c786 | 224 | try {\r |
25e48683 FC |
225 | final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r |
226 | final DocumentBuilder db = dbf.newDocumentBuilder();\r | |
c3c5c786 FC |
227 | \r |
228 | // The following allows xml parsing without access to the dtd\r | |
25e48683 | 229 | final EntityResolver resolver = new EntityResolver () {\r |
d4011df2 | 230 | @Override\r |
25e48683 FC |
231 | public InputSource resolveEntity (final String publicId, final String systemId) {\r |
232 | final String empty = ""; //$NON-NLS-1$\r | |
233 | final ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());\r | |
c3c5c786 FC |
234 | return new InputSource(bais);\r |
235 | }\r | |
236 | };\r | |
237 | db.setEntityResolver(resolver);\r | |
238 | \r | |
239 | // The following catches xml parsing exceptions\r | |
240 | db.setErrorHandler(new ErrorHandler(){\r | |
d4011df2 | 241 | @Override\r |
25e48683 | 242 | public void error(final SAXParseException saxparseexception) throws SAXException {}\r |
d4011df2 | 243 | @Override\r |
25e48683 | 244 | public void warning(final SAXParseException saxparseexception) throws SAXException {}\r |
d4011df2 | 245 | @Override\r |
25e48683 | 246 | public void fatalError(final SAXParseException saxparseexception) throws SAXException {\r |
c3c5c786 FC |
247 | throw saxparseexception;\r |
248 | }});\r | |
25e48683 FC |
249 | \r |
250 | final Document doc = db.parse(new ByteArrayInputStream(elementBuffer.toString().getBytes()));\r | |
c3c5c786 | 251 | return doc.getDocumentElement();\r |
25e48683 | 252 | } catch (final ParserConfigurationException e) {\r |
c3c5c786 | 253 | e.printStackTrace();\r |
25e48683 | 254 | } catch (final SAXException e) {\r |
c3c5c786 | 255 | e.printStackTrace();\r |
25e48683 | 256 | } catch (final IOException e) {\r |
c3c5c786 FC |
257 | e.printStackTrace();\r |
258 | }\r | |
259 | return null;\r | |
260 | }\r | |
261 | \r | |
25e48683 | 262 | private void readElement(final StringBuffer buffer, final RandomAccessFile raFile) {\r |
c3c5c786 FC |
263 | try {\r |
264 | int numRead = 0;\r | |
265 | boolean startTagClosed = false;\r | |
266 | int i;\r | |
267 | while ((i = raFile.read()) != -1) {\r | |
268 | numRead++;\r | |
25e48683 | 269 | final char c = (char)i;\r |
c3c5c786 | 270 | buffer.append(c);\r |
09e86496 | 271 | if (c == '"') {\r |
c3c5c786 | 272 | readQuote(buffer, raFile, '"');\r |
09e86496 | 273 | } else if (c == '\'') {\r |
c3c5c786 | 274 | readQuote(buffer, raFile, '\'');\r |
09e86496 | 275 | } else if (c == '<') {\r |
c3c5c786 | 276 | readElement(buffer, raFile);\r |
09e86496 | 277 | } else if (c == '/' && numRead == 1) {\r |
c3c5c786 | 278 | break; // found "</"\r |
09e86496 | 279 | } else if (c == '-' && numRead == 3 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("!-")) {\r |
c3c5c786 | 280 | readComment(buffer, raFile); // found "<!--"\r |
09e86496 FC |
281 | } else if (i == '>')\r |
282 | if (buffer.charAt(buffer.length() - 2) == '/') {\r | |
c3c5c786 | 283 | break; // found "/>"\r |
09e86496 | 284 | } else if (startTagClosed) {\r |
c3c5c786 | 285 | break; // found "<...>...</...>"\r |
09e86496 FC |
286 | }\r |
287 | else {\r | |
c3c5c786 | 288 | startTagClosed = true; // found "<...>"\r |
09e86496 | 289 | }\r |
c3c5c786 FC |
290 | }\r |
291 | return;\r | |
25e48683 | 292 | } catch (final IOException e) {\r |
c3c5c786 FC |
293 | return;\r |
294 | }\r | |
295 | }\r | |
296 | \r | |
25e48683 | 297 | private void readQuote(final StringBuffer buffer, final RandomAccessFile raFile, final char eq) {\r |
c3c5c786 FC |
298 | try {\r |
299 | int i;\r | |
300 | while ((i = raFile.read()) != -1) {\r | |
25e48683 | 301 | final char c = (char)i;\r |
c3c5c786 | 302 | buffer.append(c);\r |
25e48683 | 303 | if (c == eq)\r |
09e86496 | 304 | {\r |
c3c5c786 | 305 | break; // found matching end-quote\r |
09e86496 | 306 | }\r |
c3c5c786 FC |
307 | }\r |
308 | return;\r | |
25e48683 | 309 | } catch (final IOException e) {\r |
c3c5c786 FC |
310 | return;\r |
311 | }\r | |
312 | }\r | |
313 | \r | |
25e48683 | 314 | private void readComment(final StringBuffer buffer, final RandomAccessFile raFile) {\r |
c3c5c786 FC |
315 | try {\r |
316 | int numRead = 0;\r | |
317 | int i;\r | |
318 | while ((i = raFile.read()) != -1) {\r | |
319 | numRead++;\r | |
25e48683 | 320 | final char c = (char)i;\r |
c3c5c786 | 321 | buffer.append(c);\r |
09e86496 FC |
322 | if (c == '>' && numRead >= 2 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("--"))\r |
323 | {\r | |
c3c5c786 | 324 | break; // found "-->"\r |
09e86496 | 325 | }\r |
c3c5c786 FC |
326 | }\r |
327 | return;\r | |
25e48683 | 328 | } catch (final IOException e) {\r |
c3c5c786 FC |
329 | return;\r |
330 | }\r | |
331 | }\r | |
332 | \r | |
25e48683 FC |
333 | public static StringBuffer parseElement(final Element parentElement, final StringBuffer buffer) {\r |
334 | final NodeList nodeList = parentElement.getChildNodes();\r | |
c3c5c786 FC |
335 | String separator = null;\r |
336 | for (int i = 0; i < nodeList.getLength(); i++) {\r | |
25e48683 | 337 | final Node node = nodeList.item(i);\r |
c3c5c786 | 338 | if (node.getNodeType() == Node.ELEMENT_NODE) {\r |
09e86496 | 339 | if (separator == null) {\r |
3b38ea61 | 340 | separator = " | "; //$NON-NLS-1$\r |
09e86496 | 341 | } else {\r |
c3c5c786 | 342 | buffer.append(separator);\r |
09e86496 | 343 | }\r |
25e48683 | 344 | final Element element = (Element) node;\r |
09e86496 | 345 | if (element.hasChildNodes() == false) {\r |
c3c5c786 | 346 | buffer.append(element.getNodeName());\r |
09e86496 | 347 | } else if (element.getChildNodes().getLength() == 1 && element.getFirstChild().getNodeType() == Node.TEXT_NODE) {\r |
3b38ea61 | 348 | buffer.append(element.getNodeName() + ":" + element.getFirstChild().getNodeValue().trim()); //$NON-NLS-1$\r |
09e86496 | 349 | } else {\r |
c3c5c786 | 350 | buffer.append(element.getNodeName());\r |
3b38ea61 | 351 | buffer.append(" [ "); //$NON-NLS-1$\r |
c3c5c786 | 352 | parseElement(element, buffer);\r |
3b38ea61 | 353 | buffer.append(" ]"); //$NON-NLS-1$\r |
c3c5c786 | 354 | }\r |
25e48683 | 355 | } else if (node.getNodeType() == Node.TEXT_NODE)\r |
09e86496 | 356 | if (node.getNodeValue().trim().length() != 0) {\r |
c3c5c786 | 357 | buffer.append(node.getNodeValue().trim());\r |
09e86496 | 358 | }\r |
c3c5c786 FC |
359 | }\r |
360 | return buffer;\r | |
361 | }\r | |
362 | \r | |
25e48683 FC |
363 | public InputElement getRecordInputElement(final InputElement inputElement) {\r |
364 | if (inputElement.logEntry)\r | |
c3c5c786 | 365 | return inputElement;\r |
09e86496 | 366 | else if (inputElement.childElements != null) {\r |
25e48683 FC |
367 | for (final InputElement childInputElement : inputElement.childElements) {\r |
368 | final InputElement recordInputElement = getRecordInputElement(childInputElement);\r | |
369 | if (recordInputElement != null)\r | |
c3c5c786 | 370 | return recordInputElement;\r |
c3c5c786 | 371 | }\r |
09e86496 | 372 | }\r |
c3c5c786 FC |
373 | return null;\r |
374 | }\r | |
25e48683 FC |
375 | \r |
376 | public CustomXmlEvent extractEvent(final Element element, final InputElement inputElement) {\r | |
377 | final CustomXmlEvent event = new CustomXmlEvent(fDefinition, this, TmfTimestamp.ZERO, "", fEventType,""); //$NON-NLS-1$ //$NON-NLS-2$\r | |
5a5c2fc7 | 378 | event.setContent(new CustomEventContent(event, "")); //$NON-NLS-1$\r |
c3c5c786 FC |
379 | parseElement(element, event, inputElement);\r |
380 | return event;\r | |
381 | }\r | |
25e48683 FC |
382 | \r |
383 | private void parseElement(final Element element, final CustomXmlEvent event, final InputElement inputElement) {\r | |
09e86496 | 384 | if (inputElement.inputName != null && !inputElement.inputName.equals(CustomXmlTraceDefinition.TAG_IGNORE)) {\r |
c3c5c786 | 385 | event.parseInput(parseElement(element, new StringBuffer()).toString(), inputElement.inputName, inputElement.inputAction, inputElement.inputFormat);\r |
09e86496 FC |
386 | }\r |
387 | if (inputElement.attributes != null) {\r | |
388 | for (final InputAttribute attribute : inputElement.attributes) {\r | |
c3c5c786 | 389 | event.parseInput(element.getAttribute(attribute.attributeName), attribute.inputName, attribute.inputAction, attribute.inputFormat);\r |
09e86496 FC |
390 | }\r |
391 | }\r | |
25e48683 | 392 | final NodeList childNodes = element.getChildNodes();\r |
09e86496 | 393 | if (inputElement.childElements != null) {\r |
c3c5c786 | 394 | for (int i = 0; i < childNodes.getLength(); i++) {\r |
25e48683 | 395 | final Node node = childNodes.item(i);\r |
09e86496 | 396 | if (node instanceof Element) {\r |
25e48683 | 397 | for (final InputElement child : inputElement.childElements)\r |
c3c5c786 FC |
398 | if (node.getNodeName().equals(child.elementName)) {\r |
399 | parseElement((Element) node, event, child);\r | |
400 | break;\r | |
401 | }\r | |
09e86496 | 402 | }\r |
c3c5c786 | 403 | }\r |
09e86496 | 404 | }\r |
c3c5c786 FC |
405 | return;\r |
406 | }\r | |
407 | \r | |
408 | public CustomTraceDefinition getDefinition() {\r | |
409 | return fDefinition;\r | |
410 | }\r | |
411 | }\r |