1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 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
.linuxtools
.tmf
.core
.trace
.text
;
16 import java
.io
.IOException
;
17 import java
.util
.regex
.Matcher
;
18 import java
.util
.regex
.Pattern
;
20 import org
.eclipse
.core
.resources
.IProject
;
21 import org
.eclipse
.core
.resources
.IResource
;
22 import org
.eclipse
.core
.runtime
.IStatus
;
23 import org
.eclipse
.core
.runtime
.Status
;
24 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.Activator
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfEvent
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.io
.BufferedRandomAccessFile
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfContext
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfEventParser
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfContext
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTrace
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TraceValidationStatus
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.ITmfLocation
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.TmfLongLocation
;
38 * Extension of TmfTrace for handling of line-based text traces parsed using
39 * regular expressions. Each line that matches the first line pattern indicates
40 * the start of a new event. The subsequent lines can contain additional
41 * information that is added to the current event.
44 * TmfEvent class returned by this trace
48 public abstract class TextTrace
<T
extends TmfEvent
> extends TmfTrace
implements ITmfEventParser
{
50 private static final TmfLongLocation NULL_LOCATION
= new TmfLongLocation((Long
) null);
51 private static final int MAX_LINES
= 100;
52 private static final int MAX_CONFIDENCE
= 100;
54 /** The default separator used for multi-line fields */
55 protected static final String SEPARATOR
= " | "; //$NON-NLS-1$
58 protected BufferedRandomAccessFile fFile
;
69 * The default implementation computes the confidence as the percentage of
70 * lines in the first 100 lines of the file which match the first line
74 public IStatus
validate(IProject project
, String path
) {
75 File file
= new File(path
);
77 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, "File not found: " + path
); //$NON-NLS-1$
80 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, "Not a file. It's a directory: " + path
); //$NON-NLS-1$
83 try (BufferedRandomAccessFile rafile
= new BufferedRandomAccessFile(path
, "r")) { //$NON-NLS-1$
86 String line
= rafile
.getNextLine();
87 while ((line
!= null) && (lineCount
++ < MAX_LINES
)) {
88 Matcher matcher
= getFirstLinePattern().matcher(line
);
89 if (matcher
.matches()) {
92 confidence
= MAX_CONFIDENCE
* matches
/ lineCount
;
93 line
= rafile
.getNextLine();
95 } catch (IOException e
) {
96 Activator
.logError("Error validating file: " + path
, e
); //$NON-NLS-1$
97 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, "IOException validating file: " + path
, e
); //$NON-NLS-1$
100 return new TraceValidationStatus(confidence
, Activator
.PLUGIN_ID
);
105 public void initTrace(IResource resource
, String path
, Class
<?
extends ITmfEvent
> type
) throws TmfTraceException
{
106 super.initTrace(resource
, path
, type
);
108 fFile
= new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
109 } catch (IOException e
) {
110 throw new TmfTraceException(e
.getMessage(), e
);
115 public synchronized void dispose() {
120 } catch (IOException e
) {
128 public synchronized TmfContext
seekEvent(ITmfLocation location
) {
129 TextTraceContext context
= new TextTraceContext(NULL_LOCATION
, ITmfContext
.UNKNOWN_RANK
);
130 if (NULL_LOCATION
.equals(location
) || fFile
== null) {
134 if (location
== null) {
136 } else if (location
.getLocationInfo() instanceof Long
) {
137 fFile
.seek((Long
) location
.getLocationInfo());
139 long rawPos
= fFile
.getFilePointer();
140 String line
= fFile
.getNextLine();
141 while (line
!= null) {
142 Matcher matcher
= getFirstLinePattern().matcher(line
);
143 if (matcher
.matches()) {
144 setupContext(context
, rawPos
, line
, matcher
);
147 rawPos
= fFile
.getFilePointer();
148 line
= fFile
.getNextLine();
151 } catch (IOException e
) {
152 Activator
.logError("Error seeking file: " + getPath(), e
); //$NON-NLS-1$
157 private void setupContext(TextTraceContext context
, long rawPos
, String line
, Matcher matcher
) throws IOException
{
158 context
.setLocation(new TmfLongLocation(rawPos
));
159 context
.firstLineMatcher
= matcher
;
160 context
.firstLine
= line
;
161 context
.nextLineLocation
= fFile
.getFilePointer();
165 public synchronized TmfContext
seekEvent(double ratio
) {
167 return new TextTraceContext(NULL_LOCATION
, ITmfContext
.UNKNOWN_RANK
);
170 long pos
= (long) (ratio
* fFile
.length());
173 if (fFile
.read() == '\n') {
178 ITmfLocation location
= new TmfLongLocation(Long
.valueOf(pos
));
179 TmfContext context
= seekEvent(location
);
180 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
182 } catch (IOException e
) {
183 Activator
.logError("Error seeking file: " + getPath(), e
); //$NON-NLS-1$
184 return new TextTraceContext(NULL_LOCATION
, ITmfContext
.UNKNOWN_RANK
);
189 public double getLocationRatio(ITmfLocation location
) {
194 long length
= fFile
.length();
198 if (location
.getLocationInfo() instanceof Long
) {
199 return (double) ((Long
) location
.getLocationInfo()) / length
;
201 } catch (IOException e
) {
202 Activator
.logError("Error reading file: " + getPath(), e
); //$NON-NLS-1$
208 public ITmfLocation
getCurrentLocation() {
213 public ITmfEvent
parseEvent(ITmfContext tmfContext
) {
214 ITmfContext context
= seekEvent(tmfContext
.getLocation());
215 return parse(context
);
219 public synchronized T
getNext(ITmfContext context
) {
220 ITmfContext savedContext
= new TmfContext(context
.getLocation(), context
.getRank());
221 T event
= parse(context
);
223 updateAttributes(savedContext
, event
.getTimestamp());
224 context
.increaseRank();
230 * Parse the next event. The context is advanced.
234 * @return the next event or null
236 protected synchronized T
parse(ITmfContext tmfContext
) {
240 if (!(tmfContext
instanceof TextTraceContext
)) {
243 TextTraceContext context
= (TextTraceContext
) tmfContext
;
244 if (context
.getLocation() == null || !(context
.getLocation().getLocationInfo() instanceof Long
) || NULL_LOCATION
.equals(context
.getLocation())) {
248 T event
= parseFirstLine(context
.firstLineMatcher
, context
.firstLine
);
251 if (fFile
.getFilePointer() != context
.nextLineLocation
) {
252 fFile
.seek(context
.nextLineLocation
);
254 long rawPos
= fFile
.getFilePointer();
255 String line
= fFile
.getNextLine();
256 while (line
!= null) {
257 Matcher matcher
= getFirstLinePattern().matcher(line
);
258 if (matcher
.matches()) {
259 setupContext(context
, rawPos
, line
, matcher
);
262 parseNextLine(event
, line
);
263 rawPos
= fFile
.getFilePointer();
264 line
= fFile
.getNextLine();
266 } catch (IOException e
) {
267 Activator
.logError("Error reading file: " + getPath(), e
); //$NON-NLS-1$
270 context
.setLocation(NULL_LOCATION
);
275 * Gets the first line pattern.
277 * @return The first line pattern
279 protected abstract Pattern
getFirstLinePattern();
282 * Parses the first line data and returns a new event.
288 * @return The parsed event
290 protected abstract T
parseFirstLine(Matcher matcher
, String line
);
293 * Parses the next line data for the current event.
296 * The current event being parsed
300 protected abstract void parseNextLine(T event
, String line
);
302 // ------------------------------------------------------------------------
304 // ------------------------------------------------------------------------
307 * Strip quotes surrounding a string
311 * @return The string without quotes
313 protected static String
replaceQuotes(String input
) {
314 String out
= input
.replaceAll("^\"|(\"\\s*)$", ""); //$NON-NLS-1$//$NON-NLS-2$
319 * Strip brackets surrounding a string
323 * @return The string without brackets
325 protected static String
replaceBrackets(String input
) {
326 String out
= input
.replaceAll("^\\{|(\\}\\s*)$", ""); //$NON-NLS-1$//$NON-NLS-2$