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 }