package com.bagri.xquery.saxon.ext.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.xml.xquery.XQException;
import javax.xml.xquery.XQItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bagri.core.system.Function;
import com.bagri.core.system.Parameter;
import com.bagri.support.util.ReflectUtils;
import static com.bagri.xquery.saxon.SaxonUtils.*;
import net.sf.saxon.Configuration;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.SequenceTool;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.BuiltInAtomicType;
import net.sf.saxon.value.ObjectValue;
import net.sf.saxon.value.SequenceType;
@SuppressWarnings("rawtypes")
public class StaticFunctionExtension extends ExtensionFunctionDefinition {
private static final Logger logger = LoggerFactory.getLogger(StaticFunctionExtension.class);
private Function xdf;
private Class[] params;
private Configuration config;
public StaticFunctionExtension() {
// de-serialization ?
}
public StaticFunctionExtension(Function xdf, Configuration config) throws ClassNotFoundException {
this.xdf = xdf;
this.config = config;
params = buildParams();
}
@Override
public StructuredQName getFunctionQName() {
//return new StructuredQName(bg_schema, bg_ns, "store-document");
return new StructuredQName(xdf.getPrefix(), xdf.getClassName(), xdf.getMethod());
}
@Override
public SequenceType[] getArgumentTypes() {
SequenceType[] result = new SequenceType[xdf.getParameters().size()];
int idx = 0;
for (Parameter xdp: xdf.getParameters()) {
result[idx] = type2Sequence(xdp);
idx++;
}
return result;
}
@Override
public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
return type2Sequence(xdf.getResult());
}
@Override
public ExtensionFunctionCall makeCallExpression() {
return new ExtensionFunctionCall() {
private Object[] args2Params(Sequence[] args) throws XPathException {
Object[] result = new Object[args.length];
for (int i=0; i < args.length; i++) {
result[i] = sequence2Object(args[i]);
logger.trace("args2Params; args[{}]: {}:{}", i, result[i].getClass().getName(), result[i]);
}
return result;
}
private Object sequence2Object(Sequence seq) throws XPathException {
return itemToObject(seq.head());
//return SequenceTool.convertToJava(seq.head());
}
private Sequence object2Sequence(Object value) throws XPathException {
return objectToItem(value, StaticFunctionExtension.this.config);
}
@Override
public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
try {
Class cls = Class.forName(xdf.getClassName());
Method m = cls.getMethod(xdf.getMethod(), params);
m.setAccessible(true);
logger.trace("call; invoking: {}; params: {}", m, params);
Object result = m.invoke(null, args2Params(arguments));
return object2Sequence(result);
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException |
IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw new XPathException(ex);
}
}
};
}
private Class[] buildParams() throws ClassNotFoundException {
Class[] result = new Class[xdf.getParameters().size()];
int idx = 0;
for (Parameter xp: xdf.getParameters()) {
result[idx] = ReflectUtils.type2Class(xp.getType());
idx++;
}
return result;
}
}