/*
* $Id$
*
* Copyright 2006, The jCoderZ.org Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the jCoderZ.org Project nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jcoderz.commons.logging;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* This implements a reader reading from log files. It can be used for reading
* the next entry from the log file, which matches the filter criteria or
* skipping a number of log file entries.
*
*/
public class LogReader
{
private final List mBufferedLines = new ArrayList();
private final BufferedReader mReader;
private final File mFile;
private final List mFilters = new ArrayList();
/**
* Creates a new LogReader for reading from the supplied file.
*
* @param fileName The name of the file to read.
*
* @throws InstantiationException in case there is an error opening the file
* for reading.
*/
LogReader (final String fileName)
throws InstantiationException
{
try
{
mFile = new File(fileName);
mReader = new BufferedReader(new FileReader(mFile));
}
catch (Exception ex)
{
final InstantiationException iex = new InstantiationException(
"Cannot install LogReader for file '" + fileName + "'.");
iex.initCause(ex);
throw iex;
}
}
/**
* Installs a new filter for filtering log file entries.
*
* @param filter The filter to add to the already stored filters.
*/
void addFilter (final Filter filter)
{
mFilters.add(filter);
}
/**
* Gets the next LogFileEntry from the log file, which passes all installed
* filters. If end of file is reached before an entry has been found matching
* all criteria, this returns null.
* Each LogFileEntry instance being returned by this should be released if it
* is not needed anymore.
*
* @return the next LogFileEnbtry passing all filters or null if no such
* available.
* @throws LoggingException if an error occurs.
*/
LogFileEntry readLogFileEntry ()
throws LoggingException
{
LogFileEntry rc = null;
final LogFileEntry currentEntry = LogFileEntry.getLogFileEntry();
int numBufferedLines = mBufferedLines.size();
int bufferedLine = 0;
boolean readBuffered;
boolean consumedLine = false;
while (((bufferedLine < numBufferedLines) || available()) && (rc == null))
{
final StringBuffer currentLine;
if (bufferedLine < numBufferedLines)
{
currentLine = (StringBuffer) mBufferedLines.get(bufferedLine++);
readBuffered = true;
}
else
{
currentLine = readLine();
readBuffered = false;
}
if (currentLine != null)
{
try
{
if (currentEntry.addLogLine(currentLine))
{
if (! readBuffered)
{
mBufferedLines.add(currentLine);
}
consumedLine = true;
}
else
{
mBufferedLines.clear();
mBufferedLines.add(currentLine);
numBufferedLines = 1;
bufferedLine = 0;
consumedLine = false;
if (passesFilters(currentEntry))
{
rc = currentEntry;
}
else
{
currentEntry.reset();
}
}
}
catch (Exception ex)
{
/* in case of exception the entry currently in process is
returned and the current log line is discarded */
System.err.println("Got an exception when processing line: "
+ currentLine);
System.err.println(ex);
ex.printStackTrace();
mBufferedLines.clear();
numBufferedLines = 0;
bufferedLine = 0;
if (consumedLine && passesFilters(currentEntry))
{
rc = currentEntry;
}
}
}
}
if ((rc == null) && consumedLine && passesFilters(currentEntry))
{
rc = currentEntry;
mBufferedLines.clear();
}
if (rc != currentEntry)
{
currentEntry.release();
}
return rc;
}
/**
* Checks whether more data is to read from the log file.
*
* @return true if the log file contains data not already read by this;
* false, else.
*
* TODO: Add some more criteria, e.g. modification time to detect log file
* switches etc.
*/
boolean available ()
{
boolean rc = false;
try
{
rc = mReader.ready();
}
catch (IOException iex)
{
System.err.println(
"Error while checking whether more data is available");
iex.printStackTrace();
}
return rc;
}
/**
* Checks whether the LogFileEntry passes all filters. An implicit filter is
* that the type of the entry has been successfully parsed.
*
* @param entry The LogFileEntry to check.
*
* @return true if <code>entry</code>passes all filters.
*/
private boolean passesFilters (final LogFileEntry entry)
{
boolean rc = entry.getType() != null;
for (final Iterator filterIterator = mFilters.iterator();
filterIterator.hasNext() && rc; )
{
final Filter filter = (Filter) filterIterator.next();
rc = filter.isPassable(entry);
}
return rc;
}
/**
* Reads the current line from the log file.
*
* @return line wrapped in a StringBuffer
*/
private StringBuffer readLine ()
{
StringBuffer rc = null;
try
{
final String line = mReader.readLine();
if (line != null)
{
rc = new StringBuffer(line);
}
}
catch (Exception ex)
{
System.err.println("Caught an exception reading the current log line");
ex.printStackTrace();
}
return rc;
}
void close ()
{
if (mReader != null)
{
try
{
mReader.close();
}
catch (IOException iex)
{
System.err.println("Error closing this:" + iex);
iex.printStackTrace();
}
}
}
}