tmf: Have TmfTrace implement ITmfEventParser
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / trace / text / TextTrace.java
CommitLineData
bcb8c2cb
PT
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
738a2796 11 * Marc-Andre Laperle - Add persistent index support
bcb8c2cb
PT
12 *******************************************************************************/
13
2bdf0193 14package org.eclipse.tracecompass.tmf.core.trace.text;
bcb8c2cb
PT
15
16import java.io.File;
17import java.io.IOException;
738a2796 18import java.nio.ByteBuffer;
543e2b1e
BH
19import java.util.Collections;
20import java.util.List;
bcb8c2cb
PT
21import java.util.regex.Matcher;
22import java.util.regex.Pattern;
23
24import org.eclipse.core.resources.IProject;
25import org.eclipse.core.resources.IResource;
26import org.eclipse.core.runtime.IStatus;
27import org.eclipse.core.runtime.Status;
2bdf0193
AM
28import org.eclipse.tracecompass.internal.tmf.core.Activator;
29import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
30import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
31import org.eclipse.tracecompass.tmf.core.io.BufferedRandomAccessFile;
32import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
33import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
2bdf0193
AM
34import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
35import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
36import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
37import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
38import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
39import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
40import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
41import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
42import org.eclipse.tracecompass.tmf.core.trace.location.TmfLongLocation;
bcb8c2cb
PT
43
44/**
45 * Extension of TmfTrace for handling of line-based text traces parsed using
46 * regular expressions. Each line that matches the first line pattern indicates
47 * the start of a new event. The subsequent lines can contain additional
48 * information that is added to the current event.
49 *
50 * @param <T>
51 * TmfEvent class returned by this trace
52 *
53 * @since 3.0
54 */
5733be39 55public abstract class TextTrace<T extends TextTraceEvent> extends TmfTrace implements ITmfPersistentlyIndexable {
bcb8c2cb 56
661becf8 57 private static final TmfLongLocation NULL_LOCATION = new TmfLongLocation(-1L);
bcb8c2cb
PT
58 private static final int MAX_LINES = 100;
59 private static final int MAX_CONFIDENCE = 100;
60
61 /** The default separator used for multi-line fields */
62 protected static final String SEPARATOR = " | "; //$NON-NLS-1$
63
64 /** The text file */
65 protected BufferedRandomAccessFile fFile;
66
67 /**
68 * Constructor
69 */
70 public TextTrace() {
71 }
72
73 /**
74 * {@inheritDoc}
75 * <p>
543e2b1e
BH
76 * The default implementation computes the confidence as the sum of weighted
77 * values of the first 100 lines of the file which match any of the provided
78 * validation patterns. For each matching line a weighted value between 1.5
79 * and 2.0 is assigned based on the group count of the matching patterns.
80 * The higher the group count, the closer the weighted value will be to 2.0.
bcb8c2cb
PT
81 */
82 @Override
83 public IStatus validate(IProject project, String path) {
84 File file = new File(path);
85 if (!file.exists()) {
86 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "File not found: " + path); //$NON-NLS-1$
87 }
88 if (!file.isFile()) {
89 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Not a file. It's a directory: " + path); //$NON-NLS-1$
90 }
91 int confidence = 0;
92 try (BufferedRandomAccessFile rafile = new BufferedRandomAccessFile(path, "r")) { //$NON-NLS-1$
93 int lineCount = 0;
918551aa 94 double matches = 0.0;
bcb8c2cb 95 String line = rafile.getNextLine();
543e2b1e 96 List<Pattern> validationPatterns = getValidationPatterns();
bcb8c2cb 97 while ((line != null) && (lineCount++ < MAX_LINES)) {
543e2b1e
BH
98 for(Pattern pattern : validationPatterns) {
99 Matcher matcher = pattern.matcher(line);
100 if (matcher.matches()) {
101 int groupCount = matcher.groupCount();
102 matches += (1.0 + groupCount / ((double) groupCount + 1));
103 }
bcb8c2cb 104 }
918551aa 105 confidence = (int) (MAX_CONFIDENCE * matches / lineCount);
bcb8c2cb
PT
106 line = rafile.getNextLine();
107 }
108 } catch (IOException e) {
109 Activator.logError("Error validating file: " + path, e); //$NON-NLS-1$
110 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "IOException validating file: " + path, e); //$NON-NLS-1$
111 }
112
113 return new TraceValidationStatus(confidence, Activator.PLUGIN_ID);
114
115 }
bcb8c2cb
PT
116 @Override
117 public void initTrace(IResource resource, String path, Class<? extends ITmfEvent> type) throws TmfTraceException {
118 super.initTrace(resource, path, type);
119 try {
120 fFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
121 } catch (IOException e) {
122 throw new TmfTraceException(e.getMessage(), e);
123 }
124 }
125
126 @Override
127 public synchronized void dispose() {
128 super.dispose();
129 if (fFile != null) {
130 try {
131 fFile.close();
132 } catch (IOException e) {
133 } finally {
134 fFile = null;
135 }
136 }
137 }
138
139 @Override
5ece050b 140 public synchronized TextTraceContext seekEvent(ITmfLocation location) {
bcb8c2cb
PT
141 TextTraceContext context = new TextTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
142 if (NULL_LOCATION.equals(location) || fFile == null) {
143 return context;
144 }
145 try {
146 if (location == null) {
147 fFile.seek(0);
148 } else if (location.getLocationInfo() instanceof Long) {
149 fFile.seek((Long) location.getLocationInfo());
150 }
151 long rawPos = fFile.getFilePointer();
152 String line = fFile.getNextLine();
153 while (line != null) {
154 Matcher matcher = getFirstLinePattern().matcher(line);
13797536
MK
155 if (matcher.matches()) {
156 setupContext(context, rawPos, line, matcher);
bcb8c2cb
PT
157 return context;
158 }
159 rawPos = fFile.getFilePointer();
160 line = fFile.getNextLine();
161 }
162 return context;
163 } catch (IOException e) {
164 Activator.logError("Error seeking file: " + getPath(), e); //$NON-NLS-1$
165 return context;
166 }
167 }
168
13797536
MK
169 private void setupContext(TextTraceContext context, long rawPos, String line, Matcher matcher) throws IOException {
170 context.setLocation(new TmfLongLocation(rawPos));
171 context.firstLineMatcher = matcher;
172 context.firstLine = line;
173 context.nextLineLocation = fFile.getFilePointer();
174 }
175
bcb8c2cb 176 @Override
5ece050b 177 public synchronized TextTraceContext seekEvent(double ratio) {
bcb8c2cb
PT
178 if (fFile == null) {
179 return new TextTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
180 }
181 try {
182 long pos = (long) (ratio * fFile.length());
183 while (pos > 0) {
184 fFile.seek(pos - 1);
185 if (fFile.read() == '\n') {
186 break;
187 }
188 pos--;
189 }
190 ITmfLocation location = new TmfLongLocation(Long.valueOf(pos));
5ece050b 191 TextTraceContext context = seekEvent(location);
bcb8c2cb
PT
192 context.setRank(ITmfContext.UNKNOWN_RANK);
193 return context;
194 } catch (IOException e) {
195 Activator.logError("Error seeking file: " + getPath(), e); //$NON-NLS-1$
196 return new TextTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
197 }
198 }
199
200 @Override
201 public double getLocationRatio(ITmfLocation location) {
202 if (fFile == null) {
203 return 0;
204 }
205 try {
206 long length = fFile.length();
207 if (length == 0) {
208 return 0;
209 }
210 if (location.getLocationInfo() instanceof Long) {
211 return (double) ((Long) location.getLocationInfo()) / length;
212 }
213 } catch (IOException e) {
214 Activator.logError("Error reading file: " + getPath(), e); //$NON-NLS-1$
215 }
216 return 0;
217 }
218
219 @Override
220 public ITmfLocation getCurrentLocation() {
221 return null;
222 }
223
224 @Override
5ece050b
AM
225 public TextTraceEvent parseEvent(ITmfContext tmfContext) {
226 TextTraceContext context = seekEvent(tmfContext.getLocation());
bcb8c2cb
PT
227 return parse(context);
228 }
229
230 @Override
231 public synchronized T getNext(ITmfContext context) {
5ece050b
AM
232 if (!(context instanceof TextTraceContext)) {
233 throw new IllegalArgumentException();
234 }
235 TextTraceContext savedContext = new TextTraceContext(context.getLocation(), context.getRank());
236 T event = parse((TextTraceContext) context);
bcb8c2cb
PT
237 if (event != null) {
238 updateAttributes(savedContext, event.getTimestamp());
239 context.increaseRank();
240 }
241 return event;
242 }
243
244 /**
245 * Parse the next event. The context is advanced.
246 *
247 * @param tmfContext
248 * the context
249 * @return the next event or null
250 */
5ece050b 251 protected synchronized T parse(TextTraceContext tmfContext) {
bcb8c2cb
PT
252 if (fFile == null) {
253 return null;
254 }
5ece050b 255 TextTraceContext context = tmfContext;
bcb8c2cb
PT
256 if (context.getLocation() == null || !(context.getLocation().getLocationInfo() instanceof Long) || NULL_LOCATION.equals(context.getLocation())) {
257 return null;
258 }
259
260 T event = parseFirstLine(context.firstLineMatcher, context.firstLine);
261
262 try {
263 if (fFile.getFilePointer() != context.nextLineLocation) {
264 fFile.seek(context.nextLineLocation);
265 }
266 long rawPos = fFile.getFilePointer();
267 String line = fFile.getNextLine();
268 while (line != null) {
269 Matcher matcher = getFirstLinePattern().matcher(line);
13797536
MK
270 if (matcher.matches()) {
271 setupContext(context, rawPos, line, matcher);
bcb8c2cb
PT
272 return event;
273 }
274 parseNextLine(event, line);
275 rawPos = fFile.getFilePointer();
276 line = fFile.getNextLine();
277 }
278 } catch (IOException e) {
279 Activator.logError("Error reading file: " + getPath(), e); //$NON-NLS-1$
280 }
281
282 context.setLocation(NULL_LOCATION);
283 return event;
284 }
285
286 /**
287 * Gets the first line pattern.
288 *
289 * @return The first line pattern
290 */
291 protected abstract Pattern getFirstLinePattern();
292
293 /**
6b44794a
MK
294 * Parses the first line data and returns a new event. When constructing the
295 * event, the concrete trace should use the trace's timestamp transform to
296 * create the timestamp, by either transforming the parsed time value
297 * directly or by using the method {@link #createTimestamp(long)}.
bcb8c2cb
PT
298 *
299 * @param matcher
300 * The matcher
301 * @param line
302 * The line to parse
303 * @return The parsed event
304 */
305 protected abstract T parseFirstLine(Matcher matcher, String line);
306
307 /**
308 * Parses the next line data for the current event.
309 *
310 * @param event
311 * The current event being parsed
312 * @param line
313 * The line to parse
314 */
315 protected abstract void parseNextLine(T event, String line);
316
543e2b1e
BH
317 /**
318 * Returns a ordered list of validation patterns that will be used in
319 * the default {@link #validate(IProject, String)} method to match
320 * the first 100 to compute the confidence level
321 *
322 * @return collection of patterns to validate against
a465519a 323 * @since 3.2
543e2b1e
BH
324 */
325 protected List<Pattern> getValidationPatterns() {
326 return Collections.singletonList(getFirstLinePattern());
327 }
328
bcb8c2cb
PT
329 // ------------------------------------------------------------------------
330 // Helper methods
331 // ------------------------------------------------------------------------
332
333 /**
334 * Strip quotes surrounding a string
335 *
336 * @param input
337 * The input string
338 * @return The string without quotes
339 */
340 protected static String replaceQuotes(String input) {
341 String out = input.replaceAll("^\"|(\"\\s*)$", ""); //$NON-NLS-1$//$NON-NLS-2$
342 return out;
343 }
344
345 /**
346 * Strip brackets surrounding a string
347 *
348 * @param input
349 * The input string
350 * @return The string without brackets
351 */
352 protected static String replaceBrackets(String input) {
353 String out = input.replaceAll("^\\{|(\\}\\s*)$", ""); //$NON-NLS-1$//$NON-NLS-2$
354 return out;
355 }
356
738a2796
MAL
357 private static int fCheckpointSize = -1;
358
359 @Override
360 public synchronized int getCheckpointSize() {
361 if (fCheckpointSize == -1) {
362 TmfCheckpoint c = new TmfCheckpoint(TmfTimestamp.ZERO, new TmfLongLocation(0L), 0);
363 ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
364 b.clear();
365 c.serialize(b);
366 fCheckpointSize = b.position();
367 }
368
369 return fCheckpointSize;
370 }
371
372 @Override
373 protected ITmfTraceIndexer createIndexer(int interval) {
374 return new TmfBTreeTraceIndexer(this, interval);
375 }
376
377 @Override
378 public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
379 return new TmfLongLocation(bufferIn);
380 }
bcb8c2cb 381}
This page took 0.074108 seconds and 5 git commands to generate.