5d45ce359be3d9c6300d91406678070178a18f8a
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / parsers / custom / CustomTxtTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2010, 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.parsers.custom;
14
15 import java.io.File;
16 import java.io.FileNotFoundException;
17 import java.io.IOException;
18 import java.nio.ByteBuffer;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map.Entry;
23 import java.util.regex.Matcher;
24
25 import org.eclipse.core.resources.IProject;
26 import org.eclipse.core.resources.IResource;
27 import org.eclipse.core.runtime.IStatus;
28 import org.eclipse.core.runtime.Status;
29 import org.eclipse.linuxtools.internal.tmf.core.Activator;
30 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
31 import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
32 import org.eclipse.linuxtools.tmf.core.io.BufferedRandomAccessFile;
33 import org.eclipse.linuxtools.tmf.core.parsers.custom.CustomTxtTraceDefinition.InputLine;
34 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
35 import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
36 import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
37 import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
38 import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
39 import org.eclipse.linuxtools.tmf.core.trace.TraceValidationStatus;
40 import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
41 import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer;
42 import org.eclipse.linuxtools.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
43 import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
44 import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
45 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
46 import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
47
48 /**
49 * Base class for custom plain text traces.
50 *
51 * @author Patrick Tassé
52 * @since 3.0
53 */
54 public class CustomTxtTrace extends TmfTrace implements ITmfEventParser, ITmfPersistentlyIndexable {
55
56 private static final TmfLongLocation NULL_LOCATION = new TmfLongLocation(-1L);
57 private static final int DEFAULT_CACHE_SIZE = 100;
58 private static final int MAX_LINES = 100;
59 private static final int MAX_CONFIDENCE = 100;
60
61 private final CustomTxtTraceDefinition fDefinition;
62 private final CustomTxtEventType fEventType;
63 private BufferedRandomAccessFile fFile;
64
65 /**
66 * Basic constructor.
67 *
68 * @param definition
69 * Text trace definition
70 */
71 public CustomTxtTrace(final CustomTxtTraceDefinition definition) {
72 fDefinition = definition;
73 fEventType = new CustomTxtEventType(fDefinition);
74 setCacheSize(DEFAULT_CACHE_SIZE);
75 }
76
77 /**
78 * Full constructor.
79 *
80 * @param resource
81 * Trace's resource.
82 * @param definition
83 * Text trace definition
84 * @param path
85 * Path to the trace file
86 * @param cacheSize
87 * Cache size to use
88 * @throws TmfTraceException
89 * If we couldn't open the trace at 'path'
90 */
91 public CustomTxtTrace(final IResource resource,
92 final CustomTxtTraceDefinition definition, final String path,
93 final int cacheSize) throws TmfTraceException {
94 this(definition);
95 setCacheSize((cacheSize > 0) ? cacheSize : DEFAULT_CACHE_SIZE);
96 initTrace(resource, path, CustomTxtEvent.class);
97 }
98
99 @Override
100 public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> eventType) throws TmfTraceException {
101 super.initTrace(resource, path, eventType);
102 try {
103 fFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
104 } catch (IOException e) {
105 throw new TmfTraceException(e.getMessage(), e);
106 }
107 }
108
109 @Override
110 public synchronized void dispose() {
111 super.dispose();
112 if (fFile != null) {
113 try {
114 fFile.close();
115 } catch (IOException e) {
116 } finally {
117 fFile = null;
118 }
119 }
120 }
121
122 @Override
123 public ITmfTraceIndexer getIndexer() {
124 return super.getIndexer();
125 }
126
127 @Override
128 public synchronized TmfContext seekEvent(final ITmfLocation location) {
129 final CustomTxtTraceContext context = new CustomTxtTraceContext(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 for (final InputLine input : getFirstLines()) {
143 final Matcher matcher = input.getPattern().matcher(line);
144 if (matcher.matches()) {
145 context.setLocation(new TmfLongLocation(rawPos));
146 context.firstLineMatcher = matcher;
147 context.firstLine = line;
148 context.nextLineLocation = fFile.getFilePointer();
149 context.inputLine = input;
150 return context;
151 }
152 }
153 rawPos = fFile.getFilePointer();
154 line = fFile.getNextLine();
155 }
156 return context;
157 } catch (final FileNotFoundException e) {
158 Activator.logError("Error seeking event. File not found: " + getPath(), e); //$NON-NLS-1$
159 return context;
160 } catch (final IOException e) {
161 Activator.logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
162 return context;
163 }
164
165 }
166
167 @Override
168 public synchronized TmfContext seekEvent(final double ratio) {
169 if (fFile == null) {
170 return new CustomTxtTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
171 }
172 try {
173 long pos = Math.round(ratio * fFile.length());
174 while (pos > 0) {
175 fFile.seek(pos - 1);
176 if (fFile.read() == '\n') {
177 break;
178 }
179 pos--;
180 }
181 final ITmfLocation location = new TmfLongLocation(pos);
182 final TmfContext context = seekEvent(location);
183 context.setRank(ITmfContext.UNKNOWN_RANK);
184 return context;
185 } catch (final IOException e) {
186 Activator.logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
187 return new CustomTxtTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
188 }
189 }
190
191 @Override
192 public synchronized double getLocationRatio(final ITmfLocation location) {
193 if (fFile == null) {
194 return 0;
195 }
196 try {
197 if (location.getLocationInfo() instanceof Long) {
198 return ((Long) location.getLocationInfo()).doubleValue() / fFile.length();
199 }
200 } catch (final IOException e) {
201 Activator.logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
202 }
203 return 0;
204 }
205
206 @Override
207 public ITmfLocation getCurrentLocation() {
208 // TODO Auto-generated method stub
209 return null;
210 }
211
212 @Override
213 public synchronized CustomTxtEvent parseEvent(final ITmfContext tmfContext) {
214 ITmfContext context = seekEvent(tmfContext.getLocation());
215 return parse(context);
216 }
217
218 @Override
219 public synchronized CustomTxtEvent getNext(final ITmfContext context) {
220 final ITmfContext savedContext = new TmfContext(context.getLocation(), context.getRank());
221 final CustomTxtEvent event = parse(context);
222 if (event != null) {
223 updateAttributes(savedContext, event.getTimestamp());
224 context.increaseRank();
225 }
226 return event;
227 }
228
229 private synchronized CustomTxtEvent parse(final ITmfContext tmfContext) {
230 if (fFile == null) {
231 return null;
232 }
233 if (!(tmfContext instanceof CustomTxtTraceContext)) {
234 return null;
235 }
236
237 final CustomTxtTraceContext context = (CustomTxtTraceContext) tmfContext;
238 if (context.getLocation() == null || !(context.getLocation().getLocationInfo() instanceof Long) || NULL_LOCATION.equals(context.getLocation())) {
239 return null;
240 }
241
242 CustomTxtEvent event = parseFirstLine(context);
243
244 final HashMap<InputLine, Integer> countMap = new HashMap<>();
245 InputLine currentInput = null;
246 if (context.inputLine.childrenInputs != null && context.inputLine.childrenInputs.size() > 0) {
247 currentInput = context.inputLine.childrenInputs.get(0);
248 countMap.put(currentInput, 0);
249 }
250
251 try {
252 if (fFile.getFilePointer() != context.nextLineLocation) {
253 fFile.seek(context.nextLineLocation);
254 }
255 long rawPos = fFile.getFilePointer();
256 String line = fFile.getNextLine();
257 while (line != null) {
258 boolean processed = false;
259 if (currentInput == null) {
260 for (final InputLine input : getFirstLines()) {
261 final Matcher matcher = input.getPattern().matcher(line);
262 if (matcher.matches()) {
263 context.setLocation(new TmfLongLocation(rawPos));
264 context.firstLineMatcher = matcher;
265 context.firstLine = line;
266 context.nextLineLocation = fFile.getFilePointer();
267 context.inputLine = input;
268 return event;
269 }
270 }
271 } else {
272 if (countMap.get(currentInput) >= currentInput.getMinCount()) {
273 final List<InputLine> nextInputs = currentInput.getNextInputs(countMap);
274 if (nextInputs.size() == 0 || nextInputs.get(nextInputs.size() - 1).getMinCount() == 0) {
275 for (final InputLine input : getFirstLines()) {
276 final Matcher matcher = input.getPattern().matcher(line);
277 if (matcher.matches()) {
278 context.setLocation(new TmfLongLocation(rawPos));
279 context.firstLineMatcher = matcher;
280 context.firstLine = line;
281 context.nextLineLocation = fFile.getFilePointer();
282 context.inputLine = input;
283 return event;
284 }
285 }
286 }
287 for (final InputLine input : nextInputs) {
288 final Matcher matcher = input.getPattern().matcher(line);
289 if (matcher.matches()) {
290 event.processGroups(input, matcher);
291 currentInput = input;
292 if (countMap.get(currentInput) == null) {
293 countMap.put(currentInput, 1);
294 } else {
295 countMap.put(currentInput, countMap.get(currentInput) + 1);
296 }
297 Iterator<InputLine> iter = countMap.keySet().iterator();
298 while (iter.hasNext()) {
299 final InputLine inputLine = iter.next();
300 if (inputLine.level > currentInput.level) {
301 iter.remove();
302 }
303 }
304 if (currentInput.childrenInputs != null && currentInput.childrenInputs.size() > 0) {
305 currentInput = currentInput.childrenInputs.get(0);
306 countMap.put(currentInput, 0);
307 } else if (countMap.get(currentInput) >= currentInput.getMaxCount()) {
308 if (currentInput.getNextInputs(countMap).size() > 0) {
309 currentInput = currentInput.getNextInputs(countMap).get(0);
310 if (countMap.get(currentInput) == null) {
311 countMap.put(currentInput, 0);
312 }
313 iter = countMap.keySet().iterator();
314 while (iter.hasNext()) {
315 final InputLine inputLine = iter.next();
316 if (inputLine.level > currentInput.level) {
317 iter.remove();
318 }
319 }
320 } else {
321 currentInput = null;
322 }
323 }
324 processed = true;
325 break;
326 }
327 }
328 }
329 if (!processed && currentInput != null) {
330 final Matcher matcher = currentInput.getPattern().matcher(line);
331 if (matcher.matches()) {
332 event.processGroups(currentInput, matcher);
333 countMap.put(currentInput, countMap.get(currentInput) + 1);
334 if (currentInput.childrenInputs != null && currentInput.childrenInputs.size() > 0) {
335 currentInput = currentInput.childrenInputs.get(0);
336 countMap.put(currentInput, 0);
337 } else if (countMap.get(currentInput) >= currentInput.getMaxCount()) {
338 if (currentInput.getNextInputs(countMap).size() > 0) {
339 currentInput = currentInput.getNextInputs(countMap).get(0);
340 if (countMap.get(currentInput) == null) {
341 countMap.put(currentInput, 0);
342 }
343 final Iterator<InputLine> iter = countMap.keySet().iterator();
344 while (iter.hasNext()) {
345 final InputLine inputLine = iter.next();
346 if (inputLine.level > currentInput.level) {
347 iter.remove();
348 }
349 }
350 } else {
351 currentInput = null;
352 }
353 }
354 }
355 ((StringBuffer) event.getContent().getValue()).append("\n").append(line); //$NON-NLS-1$
356 }
357 }
358 rawPos = fFile.getFilePointer();
359 line = fFile.getNextLine();
360 }
361 } catch (final IOException e) {
362 Activator.logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
363 }
364 for (final Entry<InputLine, Integer> entry : countMap.entrySet()) {
365 if (entry.getValue() < entry.getKey().getMinCount()) {
366 event = null;
367 }
368 }
369 context.setLocation(NULL_LOCATION);
370 return event;
371 }
372
373 /**
374 * @return The first few lines of the text file
375 */
376 public List<InputLine> getFirstLines() {
377 return fDefinition.inputs;
378 }
379
380 /**
381 * Parse the first line of the trace (to recognize the type).
382 *
383 * @param context
384 * Trace context
385 * @return The first event
386 */
387 public CustomTxtEvent parseFirstLine(final CustomTxtTraceContext context) {
388 final CustomTxtEvent event = new CustomTxtEvent(fDefinition, this, TmfTimestamp.ZERO, "", fEventType, ""); //$NON-NLS-1$ //$NON-NLS-2$
389 event.processGroups(context.inputLine, context.firstLineMatcher);
390 event.setContent(new CustomEventContent(event, new StringBuffer(context.firstLine)));
391 return event;
392 }
393
394 /**
395 * Get the trace definition.
396 *
397 * @return The trace definition
398 */
399 public CustomTraceDefinition getDefinition() {
400 return fDefinition;
401 }
402
403 /**
404 * {@inheritDoc}
405 * <p>
406 * The default implementation computes the confidence as the percentage of
407 * lines in the first 100 lines of the file which match any of the root
408 * input line patterns.
409 */
410 @Override
411 public IStatus validate(IProject project, String path) {
412 File file = new File(path);
413 if (!file.exists() || !file.isFile() || !file.canRead()) {
414 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CustomTrace_FileNotFound + ": " + path); //$NON-NLS-1$
415 }
416 int confidence = 0;
417 try (BufferedRandomAccessFile rafile = new BufferedRandomAccessFile(path, "r")) { //$NON-NLS-1$
418 int lineCount = 0;
419 double matches = 0.0;
420 String line = rafile.getNextLine();
421 while ((line != null) && (lineCount++ < MAX_LINES)) {
422 for (InputLine inputLine : fDefinition.inputs) {
423 Matcher matcher = inputLine.getPattern().matcher(line);
424 if (matcher.matches()) {
425 int groupCount = matcher.groupCount();
426 matches += (1.0 + groupCount / ((double) groupCount + 1));
427 break;
428 }
429 }
430 confidence = (int) (MAX_CONFIDENCE * matches / lineCount);
431 line = rafile.getNextLine();
432 }
433 } catch (IOException e) {
434 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "IOException validating file: " + path, e); //$NON-NLS-1$
435 }
436 return new TraceValidationStatus(confidence, Activator.PLUGIN_ID);
437 }
438
439 private static int fCheckpointSize = -1;
440
441 @Override
442 public synchronized int getCheckpointSize() {
443 if (fCheckpointSize == -1) {
444 TmfCheckpoint c = new TmfCheckpoint(TmfTimestamp.ZERO, new TmfLongLocation(0L), 0);
445 ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
446 b.clear();
447 c.serialize(b);
448 fCheckpointSize = b.position();
449 }
450
451 return fCheckpointSize;
452 }
453
454 @Override
455 public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
456 return new TmfLongLocation(bufferIn);
457 }
458
459 @Override
460 protected ITmfTraceIndexer createIndexer(int interval) {
461 return new TmfBTreeTraceIndexer(this, interval);
462 }
463 }
This page took 0.074291 seconds and 4 git commands to generate.