package lux.functions;
import lux.xpath.FunCall;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.EmptySequence;
import net.sf.saxon.value.SequenceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <code>lux:log($message as xs:string+, $level as xs:string?) as empty-sequence()</code>
* <p>Writes a log message formed by joining the argument sequence
* with single spaces. The log level is INFO by default: valid values for $level
* are TRACE, DEBUG, INFO, WARN, ERROR, FATAL: these correspond to the slf4j log levels.
* The level argument is case-insensitive.</p>
*
*/
public class Log extends ExtensionFunctionDefinition {
private enum LogLevel { TRACE, DEBUG, INFO, WARN, ERROR, FATAL }
class LogCall extends ExtensionFunctionCall {
@Override
public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException
{
Logger logger = LoggerFactory.getLogger("lux.functions");
LogLevel level;
if (arguments.length > 1) {
String lvl = arguments[1].head().getStringValue();
try {
level = LogLevel.valueOf(lvl.toUpperCase());
} catch (IllegalArgumentException e) {
throw new XPathException("Undefined log level: " + lvl);
}
} else {
level = LogLevel.INFO;
}
if (! isLogEnabled(logger, level)) {
return EmptySequence.getInstance();
}
Sequence tokens = arguments[0];
StringBuilder message = new StringBuilder();
Item item;
SequenceIterator<? extends Item> tokenIter = tokens.iterate();
while ((item = tokenIter.next()) != null) {
message.append(item.getStringValue());
}
log (logger, level, message.toString());
return EmptySequence.getInstance();
}
}
private void log (Logger logger, LogLevel level, String message) {
switch (level) {
case TRACE: logger.trace(message); break;
case DEBUG: logger.debug(message); break;
case INFO: logger.info(message); break;
case WARN: logger.warn(message); break;
case ERROR: logger.error(message); break;
default:
case FATAL: logger.error(message); // slf4j doesn't seem to support fatal?
}
}
private boolean isLogEnabled (Logger logger, LogLevel level) {
switch (level) {
case TRACE: return logger.isTraceEnabled();
case DEBUG: return logger.isDebugEnabled();
case INFO: return logger.isInfoEnabled();
case WARN: return logger.isWarnEnabled();
case ERROR: return logger.isErrorEnabled();
case FATAL:
default: return true;
}
}
@Override
public StructuredQName getFunctionQName() {
return new StructuredQName("lux", FunCall.LUX_NAMESPACE, "log");
}
@Override
public net.sf.saxon.value.SequenceType[] getArgumentTypes() {
return new SequenceType[] {
SequenceType.ANY_SEQUENCE,
SequenceType.OPTIONAL_STRING
};
}
@Override
public net.sf.saxon.value.SequenceType getResultType(
net.sf.saxon.value.SequenceType[] suppliedArgumentTypes) {
return SequenceType.OPTIONAL_ITEM;
}
@Override
public ExtensionFunctionCall makeCallExpression() {
return new LogCall ();
}
@Override
public int getMinimumNumberOfArguments () {
return 1;
}
@Override
public int getMaximumNumberOfArguments () {
return 2;
}
}