trace/traceviewer/com.nokia.traceviewer/src/com/nokia/traceviewer/engine/PlainTextReader.java
author Matti Laitinen <matti.t.laitinen@nokia.com>
Wed, 23 Jun 2010 14:49:59 +0300
changeset 11 5b9d4d8641ce
permissions -rw-r--r--
TraceViewer 2.6.0

/*
 * Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). 
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 *
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
 * Contributors:
 *
 * Description:
 *
 * Plain Text Reader
 *
 */
package com.nokia.traceviewer.engine;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.CharBuffer;

/**
 * Plain Text Reader
 */
public class PlainTextReader extends BaseDataReader {

	/**
	 * Running boolean
	 */
	private boolean running;

	/**
	 * Position of file
	 */
	private long filePos;

	/**
	 * File reader
	 */
	private BufferedReader input;

	/**
	 * File to read from
	 */
	private File file;

	/**
	 * Character buffer where chars are read
	 */
	private final CharBuffer cbuf;

	/**
	 * Remaining characters from the last read
	 */
	private int remainingChars;

	/**
	 * Temporary buffer for data
	 */
	private final CharBuffer tempBuffer;

	/**
	 * Paused boolean
	 */
	private boolean paused;

	/**
	 * Indicates that traces can be processed
	 */
	private boolean canProcessTraces;

	/**
	 * Possible middle of line break
	 */
	private boolean middleOfLineBreak;

	/**
	 * Constructor
	 * 
	 * @param mediaCallback
	 *            callback
	 * @param configuration
	 *            trace configuration used in this reader
	 */
	public PlainTextReader(MediaCallback mediaCallback,
			TraceConfiguration configuration) {
		super();
		this.mediaCallback = mediaCallback;
		trace = new TraceProperties(configuration);
		traceConfiguration = configuration;
		cbuf = CharBuffer.allocate(RECEIVE_BUFFER_SIZE);
		tempBuffer = CharBuffer.allocate(MAX_MESSAGE_SIZE);

		running = true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataReader#start()
	 */
	@Override
	public void run() {
		try {
			file = new File(filePath);
			input = new BufferedReader(new FileReader(file));
			while (running) {
				canProcessTraces = true;
				if (!paused) {
					// Read from the file
					int chars = input.read(cbuf);
					if (chars > 0) {
						cbuf.limit(chars + remainingChars);
						remainingChars = 0;
						processBuffer();
					} else {
						// Inform callback for EOF
						mediaCallback.endOfFile(this);
						Thread.sleep(PAUSE_TIME);
					}
				} else {
					Thread.sleep(PAUSE_TIME);
				}
			}

		} catch (Throwable t) {
			t.printStackTrace();
		}

	}

	/**
	 * Process character buffer
	 */
	private void processBuffer() {
		canProcessTraces = true;
		cbuf.position(0);
		StringBuffer buf = new StringBuffer();
		int extra = 0;
		boolean traceReady = false;

		// Loop until there is characters left
		while (cbuf.hasRemaining()) {
			char c = cbuf.get();

			// If in the middle of a line break from previous buffer, skip first
			// character
			if (middleOfLineBreak && c == '\n' && cbuf.hasRemaining()) {
				c = cbuf.get();
			}
			middleOfLineBreak = false;

			// Check the character
			switch (c) {
			case '\n':
				extra = 1;
				traceReady = true;
				break;
			case '\r':
				if (!cbuf.hasRemaining()) {
					extra = 1;
					middleOfLineBreak = true;
				} else if ((cbuf.get()) == '\n') {
					extra = 2;
				} else {
					cbuf.position(cbuf.position() - 1);
					extra = 1;
				}

				traceReady = true;
				break;
			default:
				buf.append(c);
				traceReady = false;
			}

			// Trace is ready, insert it
			if (traceReady) {
				String traceString = buf.toString();
				buf.setLength(0);
				if (canProcessTraces) {
					processTrace(extra, traceString);
				}
				extra = 0;
				traceReady = false;
			}
		}
		remainingChars = buf.length();

		// If the end of the file and there is characters in the buffer, process
		// the remaining trace
		if ((filePos + remainingChars) >= file.length()
				&& buf.length() > 0
				&& !TraceViewerGlobals.getTraceViewer()
						.getDataProcessorAccess().getFilterProcessor()
						.isProcessingFilter()) {
			String traceString = buf.toString();
			if (canProcessTraces) {
				processTrace(extra, traceString);
			}
			remainingChars = 0;
		}

		// Copy the remaining characters to the start of the buffer
		copyRemainingToBufferStart();
	}

	/**
	 * Copy remaining characters to the start of the buffer
	 */
	private void copyRemainingToBufferStart() {
		if (remainingChars > 0 && canProcessTraces) {
			cbuf.position(cbuf.limit() - remainingChars);
			cbuf.limit(cbuf.limit());
			tempBuffer.position(0);
			tempBuffer.limit(MAX_MESSAGE_SIZE);
			tempBuffer.put(cbuf);

			cbuf.position(0);
			cbuf.limit(RECEIVE_BUFFER_SIZE);
			tempBuffer.position(0);
			tempBuffer.limit(remainingChars);

			cbuf.put(tempBuffer);
			cbuf.position(remainingChars);
		} else {
			remainingChars = 0;
			cbuf.position(0);
			cbuf.limit(RECEIVE_BUFFER_SIZE);
		}
	}

	/**
	 * Process trace
	 * 
	 * @param extra
	 *            number of extra linefeed characters to add to file position
	 * @param traceString
	 *            trace string
	 */
	private void processTrace(int extra, String traceString) {
		traceCount++;
		trace = new TraceProperties(traceConfiguration);
		trace.traceString = traceString;
		trace.traceNumber = traceCount;

		// Count the file position if trace is dividable by
		// blockSize
		if (traceCount % TraceViewerGlobals.blockSize == 1) {
			fileMap.insert(Long.valueOf(filePos));
		}
		filePos += trace.traceString.length() + extra;

		// Check if last trace
		checkLastTrace();

		mediaCallback.processTrace(trace);

	}

	/**
	 * Checks if last trace
	 */
	private void checkLastTrace() {
		if (filePos >= file.length()) {
			trace.lastTrace = true;
		} else {
			trace.lastTrace = false;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataReader#pause(boolean)
	 */
	public void pause(boolean pause) {
		paused = pause;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataReader#shutdown()
	 */
	public void shutdown() {
		running = false;
		// Close the stream
		try {
			if (input != null) {
				input.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataReader#setFilePosition(long)
	 */
	@Override
	public void setFilePosition(long filePos) {
		// Start from the beginning
		if (filePos == 0) {
			try {
				canProcessTraces = false;
				input.close();
				this.filePos = 0;
				remainingChars = 0;
				fileMap.clearMap();
				traceCount = 0;
				cbuf.clear();
				file = new File(filePath);
				input = new BufferedReader(new FileReader(file));
				paused = false;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataReader#clearFile()
	 */
	@Override
	public void clearFile() {
		super.clearFile();
		setFilePosition(0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.nokia.traceviewer.engine.BaseDataReader#createScrollReader(com.nokia
	 * .traceviewer.engine.MediaCallback,
	 * com.nokia.traceviewer.engine.TraceConfiguration)
	 */
	@Override
	public DataScrollReader createScrollReader(MediaCallback mediaCallback,
			TraceConfiguration conf) {
		return new PlainTextScrollReader(mediaCallback, conf);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataReader#isPaused()
	 */
	public boolean isPaused() {
		return paused;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataReader#getTracePositionInFile()
	 */
	public long getTracePositionInFile() {
		return filePos;
	}

	@Override
	protected byte[] setProtocolSpecificStuffToMultiPartTrace(byte[] byteArr,
			TraceProperties trace) {
		// There isn't any multipart traces in plain text
		return byteArr;
	}
}