2cf0666b870ad603cac5205bed84f53bae2a3554
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / trace / text / TextTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 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.linuxtools.tmf.core.trace.text;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19
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;
36
37 /**
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.
42 *
43 * @param <T>
44 * TmfEvent class returned by this trace
45 *
46 * @since 3.0
47 */
48 public abstract class TextTrace<T extends TmfEvent> extends TmfTrace implements ITmfEventParser {
49
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;
53
54 /** The default separator used for multi-line fields */
55 protected static final String SEPARATOR = " | "; //$NON-NLS-1$
56
57 /** The text file */
58 protected BufferedRandomAccessFile fFile;
59
60 /**
61 * Constructor
62 */
63 public TextTrace() {
64 }
65
66 /**
67 * {@inheritDoc}
68 * <p>
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
71 * pattern.
72 */
73 @Override
74 public IStatus validate(IProject project, String path) {
75 File file = new File(path);
76 if (!file.exists()) {
77 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "File not found: " + path); //$NON-NLS-1$
78 }
79 if (!file.isFile()) {
80 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Not a file. It's a directory: " + path); //$NON-NLS-1$
81 }
82 int confidence = 0;
83 try (BufferedRandomAccessFile rafile = new BufferedRandomAccessFile(path, "r")) { //$NON-NLS-1$
84 int lineCount = 0;
85 int matches = 0;
86 String line = rafile.getNextLine();
87 while ((line != null) && (lineCount++ < MAX_LINES)) {
88 Matcher matcher = getFirstLinePattern().matcher(line);
89 if (matcher.matches()) {
90 matches++;
91 }
92 confidence = MAX_CONFIDENCE * matches / lineCount;
93 line = rafile.getNextLine();
94 }
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$
98 }
99
100 return new TraceValidationStatus(confidence, Activator.PLUGIN_ID);
101
102 }
103
104 @Override
105 public void initTrace(IResource resource, String path, Class<? extends ITmfEvent> type) throws TmfTraceException {
106 super.initTrace(resource, path, type);
107 try {
108 fFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
109 } catch (IOException e) {
110 throw new TmfTraceException(e.getMessage(), e);
111 }
112 }
113
114 @Override
115 public synchronized void dispose() {
116 super.dispose();
117 if (fFile != null) {
118 try {
119 fFile.close();
120 } catch (IOException e) {
121 } finally {
122 fFile = null;
123 }
124 }
125 }
126
127 @Override
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) {
131 return context;
132 }
133 try {
134 if (location == null) {
135 fFile.seek(0);
136 } else if (location.getLocationInfo() instanceof Long) {
137 fFile.seek((Long) location.getLocationInfo());
138 }
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);
145 return context;
146 }
147 rawPos = fFile.getFilePointer();
148 line = fFile.getNextLine();
149 }
150 return context;
151 } catch (IOException e) {
152 Activator.logError("Error seeking file: " + getPath(), e); //$NON-NLS-1$
153 return context;
154 }
155 }
156
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();
162 }
163
164 @Override
165 public synchronized TmfContext seekEvent(double ratio) {
166 if (fFile == null) {
167 return new TextTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
168 }
169 try {
170 long pos = (long) (ratio * fFile.length());
171 while (pos > 0) {
172 fFile.seek(pos - 1);
173 if (fFile.read() == '\n') {
174 break;
175 }
176 pos--;
177 }
178 ITmfLocation location = new TmfLongLocation(Long.valueOf(pos));
179 TmfContext context = seekEvent(location);
180 context.setRank(ITmfContext.UNKNOWN_RANK);
181 return context;
182 } catch (IOException e) {
183 Activator.logError("Error seeking file: " + getPath(), e); //$NON-NLS-1$
184 return new TextTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
185 }
186 }
187
188 @Override
189 public double getLocationRatio(ITmfLocation location) {
190 if (fFile == null) {
191 return 0;
192 }
193 try {
194 long length = fFile.length();
195 if (length == 0) {
196 return 0;
197 }
198 if (location.getLocationInfo() instanceof Long) {
199 return (double) ((Long) location.getLocationInfo()) / length;
200 }
201 } catch (IOException e) {
202 Activator.logError("Error reading file: " + getPath(), e); //$NON-NLS-1$
203 }
204 return 0;
205 }
206
207 @Override
208 public ITmfLocation getCurrentLocation() {
209 return null;
210 }
211
212 @Override
213 public ITmfEvent parseEvent(ITmfContext tmfContext) {
214 ITmfContext context = seekEvent(tmfContext.getLocation());
215 return parse(context);
216 }
217
218 @Override
219 public synchronized T getNext(ITmfContext context) {
220 ITmfContext savedContext = new TmfContext(context.getLocation(), context.getRank());
221 T event = parse(context);
222 if (event != null) {
223 updateAttributes(savedContext, event.getTimestamp());
224 context.increaseRank();
225 }
226 return event;
227 }
228
229 /**
230 * Parse the next event. The context is advanced.
231 *
232 * @param tmfContext
233 * the context
234 * @return the next event or null
235 */
236 protected synchronized T parse(ITmfContext tmfContext) {
237 if (fFile == null) {
238 return null;
239 }
240 if (!(tmfContext instanceof TextTraceContext)) {
241 return null;
242 }
243 TextTraceContext context = (TextTraceContext) tmfContext;
244 if (context.getLocation() == null || !(context.getLocation().getLocationInfo() instanceof Long) || NULL_LOCATION.equals(context.getLocation())) {
245 return null;
246 }
247
248 T event = parseFirstLine(context.firstLineMatcher, context.firstLine);
249
250 try {
251 if (fFile.getFilePointer() != context.nextLineLocation) {
252 fFile.seek(context.nextLineLocation);
253 }
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);
260 return event;
261 }
262 parseNextLine(event, line);
263 rawPos = fFile.getFilePointer();
264 line = fFile.getNextLine();
265 }
266 } catch (IOException e) {
267 Activator.logError("Error reading file: " + getPath(), e); //$NON-NLS-1$
268 }
269
270 context.setLocation(NULL_LOCATION);
271 return event;
272 }
273
274 /**
275 * Gets the first line pattern.
276 *
277 * @return The first line pattern
278 */
279 protected abstract Pattern getFirstLinePattern();
280
281 /**
282 * Parses the first line data and returns a new event.
283 *
284 * @param matcher
285 * The matcher
286 * @param line
287 * The line to parse
288 * @return The parsed event
289 */
290 protected abstract T parseFirstLine(Matcher matcher, String line);
291
292 /**
293 * Parses the next line data for the current event.
294 *
295 * @param event
296 * The current event being parsed
297 * @param line
298 * The line to parse
299 */
300 protected abstract void parseNextLine(T event, String line);
301
302 // ------------------------------------------------------------------------
303 // Helper methods
304 // ------------------------------------------------------------------------
305
306 /**
307 * Strip quotes surrounding a string
308 *
309 * @param input
310 * The input string
311 * @return The string without quotes
312 */
313 protected static String replaceQuotes(String input) {
314 String out = input.replaceAll("^\"|(\"\\s*)$", ""); //$NON-NLS-1$//$NON-NLS-2$
315 return out;
316 }
317
318 /**
319 * Strip brackets surrounding a string
320 *
321 * @param input
322 * The input string
323 * @return The string without brackets
324 */
325 protected static String replaceBrackets(String input) {
326 String out = input.replaceAll("^\\{|(\\}\\s*)$", ""); //$NON-NLS-1$//$NON-NLS-2$
327 return out;
328 }
329
330 }
This page took 0.038951 seconds and 4 git commands to generate.