1 package org.daisy.pipeline.common.saxon.impl; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import com.google.common.base.CharMatcher; 7 8 import net.sf.saxon.expr.XPathContext; 9 import net.sf.saxon.lib.ExtensionFunctionCall; 10 import net.sf.saxon.lib.ExtensionFunctionDefinition; 11 import net.sf.saxon.om.Item; 12 import net.sf.saxon.om.Sequence; 13 import net.sf.saxon.om.SequenceIterator; 14 import net.sf.saxon.om.StructuredQName; 15 import net.sf.saxon.trans.XPathException; 16 import net.sf.saxon.value.EmptySequence; 17 import net.sf.saxon.value.SequenceType; 18 19 import org.osgi.service.component.annotations.Component; 20 21 import org.slf4j.Logger; 22 import org.slf4j.LoggerFactory; 23 24 @Component( 25 name = "pf:message", 26 service = { ExtensionFunctionDefinition.class } 27 ) 28 @SuppressWarnings("serial") 29 public class MessageDefinition extends ExtensionFunctionDefinition { 30 31 private static final StructuredQName funcname = new StructuredQName("pf", 32 "http://www.daisy.org/ns/pipeline/functions", "message"); 33 34 public StructuredQName getFunctionQName() { 35 return funcname; 36 } 37 38 @Override 39 public int getMinimumNumberOfArguments() { 40 return 2; 41 } 42 43 @Override 44 public int getMaximumNumberOfArguments() { 45 return 3; 46 } 47 48 public SequenceType[] getArgumentTypes() { 49 return new SequenceType[] { 50 SequenceType.SINGLE_STRING, 51 SequenceType.SINGLE_STRING, 52 SequenceType.ATOMIC_SEQUENCE 53 }; 54 } 55 56 public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { 57 return SequenceType.EMPTY_SEQUENCE; 58 } 59 60 private enum Level { 61 ERROR, 62 WARN, 63 INFO, 64 DEBUG, 65 TRACE 66 } 67 68 private static final Sequence VOID = EmptySequence.getInstance(); 69 70 public ExtensionFunctionCall makeCallExpression() { 71 return new ExtensionFunctionCall() { 72 public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException { 73 try { 74 Level level = Level.valueOf(arguments[0].head().getStringValue().toUpperCase()); 75 String msg = CharMatcher.WHITESPACE.trimAndCollapseFrom( 76 arguments[1].head().getStringValue(), ' '); 77 String[] args = arguments.length > 1 78 ? MessageDefinition.sequenceToArray(arguments[2]) 79 : new String[]{}; 80 log(level, msg, args); 81 return VOID; } 82 catch (Throwable e) { 83 throw new XPathException("Unexpected error in pf:message", e); } 84 } 85 }; 86 } 87 88 private static void log(Level level, String message, Object[] args) { 89 switch (level) { 90 case ERROR: 91 logger.error(message, (Object[])args); 92 break; 93 case WARN: 94 logger.warn(message, (Object[])args); 95 break; 96 case INFO: 97 logger.info(message, (Object[])args); 98 break; 99 case DEBUG: 100 logger.debug(message, (Object[])args); 101 break; 102 case TRACE: 103 logger.trace(message, (Object[])args); 104 break; 105 default: 106 } 107 } 108 109 static String[] sequenceToArray(Sequence seq) throws XPathException { 110 List<String> list = new ArrayList<String>(); 111 SequenceIterator iterator = seq.iterate(); 112 for (Item item = iterator.next(); item != null; item = iterator.next()) 113 list.add(item.getStringValue()); 114 return list.toArray(new String[list.size()]); 115 } 116 117 private static final Logger logger = LoggerFactory.getLogger(MessageDefinition.class); 118 119 }