/*******************************************************************************
* Copyright 2011 André Rouél
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package net.sf.jacclog.service.importer.internal;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import net.sf.jacclog.api.domain.ReadonlyLogEntry;
import net.sf.jacclog.service.importer.api.LogFile;
import net.sf.jacclog.service.importer.api.parser.LogParser;
import net.sf.jacclog.service.importer.internal.parser.MappingException;
import net.sf.jacclog.service.importer.internal.parser.NcsaLogParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogFileReader implements net.sf.jacclog.service.importer.api.reader.LogReader<ReadonlyLogEntry> {
/**
* The logger
*/
private static final Logger LOG = LoggerFactory.getLogger(LogFileReader.class);
/**
* Sets a <code>LineNumberReader</code> by file input.
*
* @param file
*/
private static LineNumberReader createLineNumberReader(final File file) {
if (file == null) {
throw new IllegalArgumentException("Argument 'file' must be set.");
}
LineNumberReader result = null;
try {
final FileReader reader = new FileReader(file);
result = createLineNumberReader(reader);
} catch (final FileNotFoundException e) {
if (LOG.isWarnEnabled()) {
LOG.warn(e.getLocalizedMessage());
}
}
return result;
}
/**
* Creates a <code>LineNumberReader</code> from a <code>Reader</code> source.
*
* @param reader
*/
private static LineNumberReader createLineNumberReader(final Reader reader) {
if (reader == null) {
throw new IllegalArgumentException("Argument 'reader' must be set.");
}
final LineNumberReader result;
if (reader instanceof LineNumberReader) {
result = (LineNumberReader) reader;
} else {
result = new LineNumberReader(reader);
}
return result;
}
/**
* A log entry parser
*/
private final LogParser<ReadonlyLogEntry> parser;
/**
* A line number reader
*/
private final LineNumberReader reader;
/**
* Creates an access log reader.
*
* @param file
* An access log file
* @param parser
* A parser for the log entry lines
*/
public LogFileReader(final File file, final LogParser<ReadonlyLogEntry> parser) {
this(createLineNumberReader(file), parser);
}
/**
* Creates an access log reader.
*
* @param file
*/
public LogFileReader(final LogFile file) {
this(file.getFile(), new NcsaLogParser(file.getFormat()));
}
/**
* Creates an access log reader.
*
* @param reader
* A reader of a character-input stream
* @param parser
* A parser for the log entry lines
*/
public LogFileReader(final Reader reader, final LogParser<ReadonlyLogEntry> parser) {
if (reader == null) {
throw new IllegalArgumentException("Argument 'reader' can not be null.");
}
if (parser == null) {
throw new IllegalArgumentException("Argument 'parser' can not be null.");
}
this.parser = parser;
this.reader = createLineNumberReader(reader);
}
/**
* Returns the parser which interprets the log entries of a log-file.
*
* @return log parser
*/
public LogParser<ReadonlyLogEntry> getParser() {
return parser;
}
/**
* Gets the reader.
*
* @return Reader
*/
public LineNumberReader getReader() {
return reader;
}
@Override
public List<ReadonlyLogEntry> read(final int count) {
final List<ReadonlyLogEntry> entries = new ArrayList<ReadonlyLogEntry>();
int counter = 0;
ReadonlyLogEntry entry;
do {
entry = readEntry();
if (entry != null) {
entries.add(entry);
}
counter++;
} while (entry != null && counter < count);
return entries;
}
/**
* Reads one line within a <code>LineNumberReader</code> and converts it to a log entry.
* <p>
* If errors happen while mapping the tokens to the fields of a log entry, then a <code>MappingException</code> will
* be thrown.
* </p>
*/
@Override
public ReadonlyLogEntry readEntry() {
ReadonlyLogEntry entry = null;
if (reader != null) {
try {
final String line = reader.readLine();
if (line == null) {
reader.close();
} else {
try {
entry = parser.parseLine(line);
} catch (final MappingException e) {
final String prefix = "at line " + reader.getLineNumber() + ": ";
throw new MappingException(prefix + e.getLocalizedMessage());
}
}
} catch (final IOException e) {
LOG.warn(e.getLocalizedMessage());
}
}
return entry;
}
}