1 /*******************************************************************************
2 * Copyright (c) 2010, 2013 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
.internal
.tmf
.ui
.parsers
.custom
;
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
;
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
.ui
.Activator
;
30 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.parsers
.custom
.CustomTxtTraceDefinition
.InputLine
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.io
.BufferedRandomAccessFile
;
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
.indexer
.ITmfPersistentlyIndexable
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfTraceIndexer
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.TmfBTreeTraceIndexer
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.checkpoint
.ITmfCheckpoint
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.checkpoint
.TmfCheckpoint
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.ITmfLocation
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.TmfLongLocation
;
48 * Base class for custom plain text traces.
50 * @author Patrick Tassé
52 public class CustomTxtTrace
extends TmfTrace
implements ITmfEventParser
, ITmfPersistentlyIndexable
{
54 private static final TmfLongLocation NULL_LOCATION
= new TmfLongLocation((Long
) null);
55 private static final int DEFAULT_CACHE_SIZE
= 100;
57 private final CustomTxtTraceDefinition fDefinition
;
58 private final CustomTxtEventType fEventType
;
59 private BufferedRandomAccessFile fFile
;
65 * Text trace definition
67 public CustomTxtTrace(final CustomTxtTraceDefinition definition
) {
68 fDefinition
= definition
;
69 fEventType
= new CustomTxtEventType(fDefinition
);
70 setCacheSize(DEFAULT_CACHE_SIZE
);
79 * Text trace definition
81 * Path to the trace file
84 * @throws TmfTraceException
85 * If we couldn't open the trace at 'path'
87 public CustomTxtTrace(final IResource resource
,
88 final CustomTxtTraceDefinition definition
, final String path
,
89 final int cacheSize
) throws TmfTraceException
{
91 setCacheSize((cacheSize
> 0) ? cacheSize
: DEFAULT_CACHE_SIZE
);
92 initTrace(resource
, path
, CustomTxtEvent
.class);
96 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> eventType
) throws TmfTraceException
{
97 super.initTrace(resource
, path
, eventType
);
99 fFile
= new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
100 } catch (IOException e
) {
101 throw new TmfTraceException(e
.getMessage(), e
);
106 public synchronized void dispose() {
111 } catch (IOException e
) {
119 public ITmfTraceIndexer
getIndexer() {
120 return super.getIndexer();
124 public synchronized TmfContext
seekEvent(final ITmfLocation location
) {
125 final CustomTxtTraceContext context
= new CustomTxtTraceContext(NULL_LOCATION
, ITmfContext
.UNKNOWN_RANK
);
126 if (NULL_LOCATION
.equals(location
) || fFile
== null) {
130 if (location
== null) {
132 } else if (location
.getLocationInfo() instanceof Long
) {
133 fFile
.seek((Long
) location
.getLocationInfo());
136 long rawPos
= fFile
.getFilePointer();
137 while ((line
= fFile
.getNextLine()) != null) {
138 for (final InputLine input
: getFirstLines()) {
139 final Matcher matcher
= input
.getPattern().matcher(line
);
140 if (matcher
.find()) {
141 context
.setLocation(new TmfLongLocation(rawPos
));
142 context
.firstLineMatcher
= matcher
;
143 context
.firstLine
= line
;
144 context
.nextLineLocation
= fFile
.getFilePointer();
145 context
.inputLine
= input
;
149 rawPos
= fFile
.getFilePointer();
152 } catch (final FileNotFoundException e
) {
153 Activator
.getDefault().logError("Error seeking event. File not found: " + getPath(), e
); //$NON-NLS-1$
155 } catch (final IOException e
) {
156 Activator
.getDefault().logError("Error seeking event. File: " + getPath(), e
); //$NON-NLS-1$
163 public synchronized TmfContext
seekEvent(final double ratio
) {
165 return new CustomTxtTraceContext(NULL_LOCATION
, ITmfContext
.UNKNOWN_RANK
);
168 long pos
= Math
.round(ratio
* fFile
.length());
171 if (fFile
.read() == '\n') {
176 final ITmfLocation location
= new TmfLongLocation(pos
);
177 final TmfContext context
= seekEvent(location
);
178 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
180 } catch (final IOException e
) {
181 Activator
.getDefault().logError("Error seeking event. File: " + getPath(), e
); //$NON-NLS-1$
182 return new CustomTxtTraceContext(NULL_LOCATION
, ITmfContext
.UNKNOWN_RANK
);
187 public synchronized double getLocationRatio(final ITmfLocation location
) {
192 if (location
.getLocationInfo() instanceof Long
) {
193 return (double) ((Long
) location
.getLocationInfo()) / fFile
.length();
195 } catch (final IOException e
) {
196 Activator
.getDefault().logError("Error seeking event. File: " + getPath(), e
); //$NON-NLS-1$
202 public ITmfLocation
getCurrentLocation() {
203 // TODO Auto-generated method stub
208 public synchronized CustomTxtEvent
parseEvent(final ITmfContext tmfContext
) {
209 ITmfContext context
= seekEvent(tmfContext
.getLocation());
210 return parse(context
);
214 public synchronized CustomTxtEvent
getNext(final ITmfContext context
) {
215 final ITmfContext savedContext
= new TmfContext(context
.getLocation(), context
.getRank());
216 final CustomTxtEvent event
= parse(context
);
218 updateAttributes(savedContext
, event
.getTimestamp());
219 context
.increaseRank();
224 private synchronized CustomTxtEvent
parse(final ITmfContext tmfContext
) {
228 if (!(tmfContext
instanceof CustomTxtTraceContext
)) {
232 final CustomTxtTraceContext context
= (CustomTxtTraceContext
) tmfContext
;
233 if (context
.getLocation() == null || !(context
.getLocation().getLocationInfo() instanceof Long
) || NULL_LOCATION
.equals(context
.getLocation())) {
237 CustomTxtEvent event
= parseFirstLine(context
);
239 final HashMap
<InputLine
, Integer
> countMap
= new HashMap
<InputLine
, Integer
>();
240 InputLine currentInput
= null;
241 if (context
.inputLine
.childrenInputs
!= null && context
.inputLine
.childrenInputs
.size() > 0) {
242 currentInput
= context
.inputLine
.childrenInputs
.get(0);
243 countMap
.put(currentInput
, 0);
247 if (fFile
.getFilePointer() != context
.nextLineLocation
) {
248 fFile
.seek(context
.nextLineLocation
);
251 long rawPos
= fFile
.getFilePointer();
252 while ((line
= fFile
.getNextLine()) != null) {
253 boolean processed
= false;
254 if (currentInput
== null) {
255 for (final InputLine input
: getFirstLines()) {
256 final Matcher matcher
= input
.getPattern().matcher(line
);
257 if (matcher
.find()) {
258 context
.setLocation(new TmfLongLocation(rawPos
));
259 context
.firstLineMatcher
= matcher
;
260 context
.firstLine
= line
;
261 context
.nextLineLocation
= fFile
.getFilePointer();
262 context
.inputLine
= input
;
267 if (countMap
.get(currentInput
) >= currentInput
.getMinCount()) {
268 final List
<InputLine
> nextInputs
= currentInput
.getNextInputs(countMap
);
269 if (nextInputs
.size() == 0 || nextInputs
.get(nextInputs
.size() - 1).getMinCount() == 0) {
270 for (final InputLine input
: getFirstLines()) {
271 final Matcher matcher
= input
.getPattern().matcher(line
);
272 if (matcher
.find()) {
273 context
.setLocation(new TmfLongLocation(rawPos
));
274 context
.firstLineMatcher
= matcher
;
275 context
.firstLine
= line
;
276 context
.nextLineLocation
= fFile
.getFilePointer();
277 context
.inputLine
= input
;
282 for (final InputLine input
: nextInputs
) {
283 final Matcher matcher
= input
.getPattern().matcher(line
);
284 if (matcher
.find()) {
285 event
.processGroups(input
, matcher
);
286 currentInput
= input
;
287 if (countMap
.get(currentInput
) == null) {
288 countMap
.put(currentInput
, 1);
290 countMap
.put(currentInput
, countMap
.get(currentInput
) + 1);
292 Iterator
<InputLine
> iter
= countMap
.keySet().iterator();
293 while (iter
.hasNext()) {
294 final InputLine inputLine
= iter
.next();
295 if (inputLine
.level
> currentInput
.level
) {
299 if (currentInput
.childrenInputs
!= null && currentInput
.childrenInputs
.size() > 0) {
300 currentInput
= currentInput
.childrenInputs
.get(0);
301 countMap
.put(currentInput
, 0);
302 } else if (countMap
.get(currentInput
) >= currentInput
.getMaxCount()) {
303 if (currentInput
.getNextInputs(countMap
).size() > 0) {
304 currentInput
= currentInput
.getNextInputs(countMap
).get(0);
305 if (countMap
.get(currentInput
) == null) {
306 countMap
.put(currentInput
, 0);
308 iter
= countMap
.keySet().iterator();
309 while (iter
.hasNext()) {
310 final InputLine inputLine
= iter
.next();
311 if (inputLine
.level
> currentInput
.level
) {
324 if (!processed
&& currentInput
!= null) {
325 final Matcher matcher
= currentInput
.getPattern().matcher(line
);
326 if (matcher
.find()) {
327 event
.processGroups(currentInput
, matcher
);
328 countMap
.put(currentInput
, countMap
.get(currentInput
) + 1);
329 if (currentInput
.childrenInputs
!= null && currentInput
.childrenInputs
.size() > 0) {
330 currentInput
= currentInput
.childrenInputs
.get(0);
331 countMap
.put(currentInput
, 0);
332 } else if (countMap
.get(currentInput
) >= currentInput
.getMaxCount()) {
333 if (currentInput
.getNextInputs(countMap
).size() > 0) {
334 currentInput
= currentInput
.getNextInputs(countMap
).get(0);
335 if (countMap
.get(currentInput
) == null) {
336 countMap
.put(currentInput
, 0);
338 final Iterator
<InputLine
> iter
= countMap
.keySet().iterator();
339 while (iter
.hasNext()) {
340 final InputLine inputLine
= iter
.next();
341 if (inputLine
.level
> currentInput
.level
) {
350 ((StringBuffer
) event
.getContent().getValue()).append("\n").append(line
); //$NON-NLS-1$
353 rawPos
= fFile
.getFilePointer();
355 } catch (final IOException e
) {
356 Activator
.getDefault().logError("Error seeking event. File: " + getPath(), e
); //$NON-NLS-1$
358 for (final Entry
<InputLine
, Integer
> entry
: countMap
.entrySet()) {
359 if (entry
.getValue() < entry
.getKey().getMinCount()) {
363 context
.setLocation(NULL_LOCATION
);
368 * @return The first few lines of the text file
370 public List
<InputLine
> getFirstLines() {
371 return fDefinition
.inputs
;
375 * Parse the first line of the trace (to recognize the type).
379 * @return The first event
381 public CustomTxtEvent
parseFirstLine(final CustomTxtTraceContext context
) {
382 final CustomTxtEvent event
= new CustomTxtEvent(fDefinition
, this, TmfTimestamp
.ZERO
, "", fEventType
, ""); //$NON-NLS-1$ //$NON-NLS-2$
383 event
.processGroups(context
.inputLine
, context
.firstLineMatcher
);
384 event
.setContent(new CustomEventContent(event
, new StringBuffer(context
.firstLine
)));
389 * Get the trace definition.
391 * @return The trace definition
393 public CustomTraceDefinition
getDefinition() {
398 public IStatus
validate(IProject project
, String path
) {
399 File file
= new File(path
);
400 if (file
.exists() && file
.isFile() && file
.canRead() && file
.length() > 0) {
401 return Status
.OK_STATUS
;
403 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CustomTrace_FileNotFound
+ ": " + path
); //$NON-NLS-1$
406 private static int fCheckpointSize
= -1;
409 public synchronized int getCheckpointSize() {
410 if (fCheckpointSize
== -1) {
411 TmfCheckpoint c
= new TmfCheckpoint(TmfTimestamp
.ZERO
, new TmfLongLocation(0L), 0);
412 ByteBuffer b
= ByteBuffer
.allocate(ITmfCheckpoint
.MAX_SERIALIZE_SIZE
);
415 fCheckpointSize
= b
.position();
418 return fCheckpointSize
;
422 public ITmfLocation
restoreLocation(ByteBuffer bufferIn
) {
423 return new TmfLongLocation(bufferIn
);
427 protected ITmfTraceIndexer
createIndexer(int interval
) {
428 return new TmfBTreeTraceIndexer(this, interval
);