/*******************************************************************************
* 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.parser;
import java.util.ArrayList;
import java.util.List;
import net.sf.jacclog.api.domain.LogEntryBuilder;
import net.sf.jacclog.api.domain.ReadonlyLogEntry;
import net.sf.jacclog.logformat.LogFormat;
import net.sf.jacclog.service.importer.api.parser.LogEntryPostProcessor;
import net.sf.jacclog.service.importer.api.parser.LogParser;
/**
* This is a NCSA-conform log parser.<br>
* <br>
* The NCSA log formats are based on NCSA httpd and are widely accepted as standard among HTTP server vendors.<br>
* <br>
* This implementation is inspired from Salmon Run. More information can be found at <a
* href="http://sujitpal.blogspot.com/2009/06/some-access-log-parsers.html#char"
* >http://sujitpal.blogspot.com/2009/06/some-access-log-parsers.html#char</a>.
*
* @author André Rouél
*/
public class NcsaLogParser implements LogParser<ReadonlyLogEntry> {
public static List<String> parse(final String line) {
final List<String> tokens = new ArrayList<String>();
StringBuilder buffer = new StringBuilder();
final char[] character = line.toCharArray();
boolean inQuotes = false;
boolean inBrackets = false;
for (int i = 0; i < character.length; i++) {
if (character[i] == '"') {
inQuotes = inQuotes ? false : true;
} else if (character[i] == '[') {
inBrackets = true;
} else if (character[i] == ']') {
if (inBrackets) {
inBrackets = false;
}
} else if (character[i] == ' ' && (!inQuotes) && (!inBrackets)) {
tokens.add(buffer.toString());
buffer = new StringBuilder();
} else {
buffer.append(character[i]);
}
}
if (buffer.length() > 0) {
tokens.add(buffer.toString());
}
return tokens;
}
private final LogFormat format;
/**
* Post processor for an log entry
*/
private LogEntryPostProcessor postProcessor;
public NcsaLogParser(final LogFormat format) {
if (format == null) {
throw new IllegalArgumentException("Argument 'format' can not be null.");
}
this.format = format;
}
/**
* Parses a line of a log file.
* <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 parseLine(final String line) {
if (line == null) {
throw new IllegalArgumentException("Argument 'line' can not be null.");
}
final List<String> tokens = parse(line);
final LogEntryBuilder builder = TokensToLogEntryMapper.map(format, tokens);
if (postProcessor != null) {
postProcessor.process(builder);
}
return builder.build();
}
@Override
public void setPostProcessor(final LogEntryPostProcessor processor) {
postProcessor = processor;
}
}