|
What this is
This file is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Other links
The source code
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.log4j.helpers;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.AbsoluteTimeDateFormat;
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.LocationInfo;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
// Contributors: Nelson Minar <(nelson@monkey.org>
// Igor E. Poteryaev
// Reinhard Deschler
/**
Most of the work of the {@link org.apache.log4j.PatternLayout} class
is delegated to the PatternParser class.
It is this class that parses conversion patterns and creates
a chained list of {@link OptionConverter OptionConverters}.
@author James P. Cakalic
@author Ceki Gülcü
@author Anders Kristensen
@since 0.8.2
*/
public class PatternParser {
private static final char ESCAPE_CHAR = '%';
private static final int LITERAL_STATE = 0;
private static final int CONVERTER_STATE = 1;
private static final int MINUS_STATE = 2;
private static final int DOT_STATE = 3;
private static final int MIN_STATE = 4;
private static final int MAX_STATE = 5;
static final int FULL_LOCATION_CONVERTER = 1000;
static final int METHOD_LOCATION_CONVERTER = 1001;
static final int CLASS_LOCATION_CONVERTER = 1002;
static final int LINE_LOCATION_CONVERTER = 1003;
static final int FILE_LOCATION_CONVERTER = 1004;
static final int RELATIVE_TIME_CONVERTER = 2000;
static final int THREAD_CONVERTER = 2001;
static final int LEVEL_CONVERTER = 2002;
static final int NDC_CONVERTER = 2003;
static final int MESSAGE_CONVERTER = 2004;
int state;
protected StringBuffer currentLiteral = new StringBuffer(32);
protected int patternLength;
protected int i;
PatternConverter head;
PatternConverter tail;
protected FormattingInfo formattingInfo = new FormattingInfo();
protected String pattern;
public
PatternParser(String pattern) {
this.pattern = pattern;
patternLength = pattern.length();
state = LITERAL_STATE;
}
private
void addToList(PatternConverter pc) {
if(head == null) {
head = tail = pc;
} else {
tail.next = pc;
tail = pc;
}
}
protected
String extractOption() {
if((i < patternLength) && (pattern.charAt(i) == '{')) {
int end = pattern.indexOf('}', i);
if (end > i) {
String r = pattern.substring(i + 1, end);
i = end+1;
return r;
}
}
return null;
}
/**
The option is expected to be in decimal and positive. In case of
error, zero is returned. */
protected
int extractPrecisionOption() {
String opt = extractOption();
int r = 0;
if(opt != null) {
try {
r = Integer.parseInt(opt);
if(r <= 0) {
LogLog.error(
"Precision option (" + opt + ") isn't a positive integer.");
r = 0;
}
}
catch (NumberFormatException e) {
LogLog.error("Category option \""+opt+"\" not a decimal integer.", e);
}
}
return r;
}
public
PatternConverter parse() {
char c;
i = 0;
while(i < patternLength) {
c = pattern.charAt(i++);
switch(state) {
case LITERAL_STATE:
// In literal state, the last char is always a literal.
if(i == patternLength) {
currentLiteral.append(c);
continue;
}
if(c == ESCAPE_CHAR) {
// peek at the next char.
switch(pattern.charAt(i)) {
case ESCAPE_CHAR:
currentLiteral.append(c);
i++; // move pointer
break;
case 'n':
currentLiteral.append(Layout.LINE_SEP);
i++; // move pointer
break;
default:
if(currentLiteral.length() != 0) {
addToList(new LiteralPatternConverter(
currentLiteral.toString()));
//LogLog.debug("Parsed LITERAL converter: \""
// +currentLiteral+"\".");
}
currentLiteral.setLength(0);
currentLiteral.append(c); // append %
state = CONVERTER_STATE;
formattingInfo.reset();
}
}
else {
currentLiteral.append(c);
}
break;
case CONVERTER_STATE:
currentLiteral.append(c);
switch(c) {
case '-':
formattingInfo.leftAlign = true;
break;
case '.':
state = DOT_STATE;
break;
default:
if(c >= '0' && c <= '9') {
formattingInfo.min = c - '0';
state = MIN_STATE;
}
else
finalizeConverter(c);
} // switch
break;
case MIN_STATE:
currentLiteral.append(c);
if(c >= '0' && c <= '9')
formattingInfo.min = formattingInfo.min*10 + (c - '0');
else if(c == '.')
state = DOT_STATE;
else {
finalizeConverter(c);
}
break;
case DOT_STATE:
currentLiteral.append(c);
if(c >= '0' && c <= '9') {
formattingInfo.max = c - '0';
state = MAX_STATE;
}
else {
LogLog.error("Error occured in position "+i
+".\n Was expecting digit, instead got char \""+c+"\".");
state = LITERAL_STATE;
}
break;
case MAX_STATE:
currentLiteral.append(c);
if(c >= '0' && c <= '9')
formattingInfo.max = formattingInfo.max*10 + (c - '0');
else {
finalizeConverter(c);
state = LITERAL_STATE;
}
break;
} // switch
} // while
if(currentLiteral.length() != 0) {
addToList(new LiteralPatternConverter(currentLiteral.toString()));
//LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
}
return head;
}
protected
void finalizeConverter(char c) {
PatternConverter pc = null;
switch(c) {
case 'c':
pc = new CategoryPatternConverter(formattingInfo,
extractPrecisionOption());
//LogLog.debug("CATEGORY converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'C':
pc = new ClassNamePatternConverter(formattingInfo,
extractPrecisionOption());
//LogLog.debug("CLASS_NAME converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'd':
String dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT;
DateFormat df;
String dOpt = extractOption();
if(dOpt != null)
dateFormatStr = dOpt;
if(dateFormatStr.equalsIgnoreCase(
AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT))
df = new ISO8601DateFormat();
else if(dateFormatStr.equalsIgnoreCase(
AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT))
df = new AbsoluteTimeDateFormat();
else if(dateFormatStr.equalsIgnoreCase(
AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT))
df = new DateTimeDateFormat();
else {
try {
df = new SimpleDateFormat(dateFormatStr);
}
catch (IllegalArgumentException e) {
LogLog.error("Could not instantiate SimpleDateFormat with " +
dateFormatStr, e);
df = (DateFormat) OptionConverter.instantiateByClassName(
"org.apache.log4j.helpers.ISO8601DateFormat",
DateFormat.class, null);
}
}
pc = new DatePatternConverter(formattingInfo, df);
//LogLog.debug("DATE converter {"+dateFormatStr+"}.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'F':
pc = new LocationPatternConverter(formattingInfo,
FILE_LOCATION_CONVERTER);
//LogLog.debug("File name converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'l':
pc = new LocationPatternConverter(formattingInfo,
FULL_LOCATION_CONVERTER);
//LogLog.debug("Location converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'L':
pc = new LocationPatternConverter(formattingInfo,
LINE_LOCATION_CONVERTER);
//LogLog.debug("LINE NUMBER converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'm':
pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);
//LogLog.debug("MESSAGE converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'M':
pc = new LocationPatternConverter(formattingInfo,
METHOD_LOCATION_CONVERTER);
//LogLog.debug("METHOD converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'p':
pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);
//LogLog.debug("LEVEL converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'r':
pc = new BasicPatternConverter(formattingInfo,
RELATIVE_TIME_CONVERTER);
//LogLog.debug("RELATIVE time converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 't':
pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);
//LogLog.debug("THREAD converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
/*case 'u':
if(i < patternLength) {
char cNext = pattern.charAt(i);
if(cNext >= '0' && cNext <= '9') {
pc = new UserFieldPatternConverter(formattingInfo, cNext - '0');
LogLog.debug("USER converter ["+cNext+"].");
formattingInfo.dump();
currentLiteral.setLength(0);
i++;
}
else
LogLog.error("Unexpected char" +cNext+" at position "+i);
}
break;*/
case 'x':
pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER);
//LogLog.debug("NDC converter.");
currentLiteral.setLength(0);
break;
case 'X':
String xOpt = extractOption();
pc = new MDCPatternConverter(formattingInfo, xOpt);
currentLiteral.setLength(0);
break;
default:
LogLog.error("Unexpected char [" +c+"] at position "+i
+" in conversion patterrn.");
pc = new LiteralPatternConverter(currentLiteral.toString());
currentLiteral.setLength(0);
}
addConverter(pc);
}
protected
void addConverter(PatternConverter pc) {
currentLiteral.setLength(0);
// Add the pattern converter to the list.
addToList(pc);
// Next pattern is assumed to be a literal.
state = LITERAL_STATE;
// Reset formatting info
formattingInfo.reset();
}
// ---------------------------------------------------------------------
// PatternConverters
// ---------------------------------------------------------------------
private static class BasicPatternConverter extends PatternConverter {
int type;
BasicPatternConverter(FormattingInfo formattingInfo, int type) {
super(formattingInfo);
this.type = type;
}
public
String convert(LoggingEvent event) {
switch(type) {
case RELATIVE_TIME_CONVERTER:
return (Long.toString(event.timeStamp - LoggingEvent.getStartTime()));
case THREAD_CONVERTER:
return event.getThreadName();
case LEVEL_CONVERTER:
return event.getLevel().toString();
case NDC_CONVERTER:
return event.getNDC();
case MESSAGE_CONVERTER: {
return event.getRenderedMessage();
}
default: return null;
}
}
}
private static class LiteralPatternConverter extends PatternConverter {
private String literal;
LiteralPatternConverter(String value) {
literal = value;
}
public
final
void format(StringBuffer sbuf, LoggingEvent event) {
sbuf.append(literal);
}
public
String convert(LoggingEvent event) {
return literal;
}
}
private static class DatePatternConverter extends PatternConverter {
private DateFormat df;
private Date date;
DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) {
super(formattingInfo);
date = new Date();
this.df = df;
}
public
String convert(LoggingEvent event) {
date.setTime(event.timeStamp);
String converted = null;
try {
converted = df.format(date);
}
catch (Exception ex) {
LogLog.error("Error occured while converting date.", ex);
}
return converted;
}
}
private static class MDCPatternConverter extends PatternConverter {
private String key;
MDCPatternConverter(FormattingInfo formattingInfo, String key) {
super(formattingInfo);
this.key = key;
}
public
String convert(LoggingEvent event) {
Object val = event.getMDC(key);
if(val == null) {
return null;
} else {
return val.toString();
}
}
}
private class LocationPatternConverter extends PatternConverter {
int type;
LocationPatternConverter(FormattingInfo formattingInfo, int type) {
super(formattingInfo);
this.type = type;
}
public
String convert(LoggingEvent event) {
LocationInfo locationInfo = event.getLocationInformation();
switch(type) {
case FULL_LOCATION_CONVERTER:
return locationInfo.fullInfo;
case METHOD_LOCATION_CONVERTER:
return locationInfo.getMethodName();
case LINE_LOCATION_CONVERTER:
return locationInfo.getLineNumber();
case FILE_LOCATION_CONVERTER:
return locationInfo.getFileName();
default: return null;
}
}
}
private static abstract class NamedPatternConverter extends PatternConverter {
int precision;
NamedPatternConverter(FormattingInfo formattingInfo, int precision) {
super(formattingInfo);
this.precision = precision;
}
abstract
String getFullyQualifiedName(LoggingEvent event);
public
String convert(LoggingEvent event) {
String n = getFullyQualifiedName(event);
if(precision <= 0)
return n;
else {
int len = n.length();
// We substract 1 from 'len' when assigning to 'end' to avoid out of
// bounds exception in return r.substring(end+1, len). This can happen if
// precision is 1 and the category name ends with a dot.
int end = len -1 ;
for(int i = precision; i > 0; i--) {
end = n.lastIndexOf('.', end-1);
if(end == -1)
return n;
}
return n.substring(end+1, len);
}
}
}
private class ClassNamePatternConverter extends NamedPatternConverter {
ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) {
super(formattingInfo, precision);
}
String getFullyQualifiedName(LoggingEvent event) {
return event.getLocationInformation().getClassName();
}
}
private class CategoryPatternConverter extends NamedPatternConverter {
CategoryPatternConverter(FormattingInfo formattingInfo, int precision) {
super(formattingInfo, precision);
}
String getFullyQualifiedName(LoggingEvent event) {
return event.getLoggerName();
}
}
}
|