/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.ode.bpel.elang.xpath20.compiler; import java.lang.reflect.Modifier; import java.util.List; import javax.xml.namespace.QName; import javax.xml.xpath.XPathFunction; import javax.xml.xpath.XPathFunctionException; import javax.xml.xpath.XPathFunctionResolver; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ode.bpel.compiler.api.CompilationException; import org.apache.ode.bpel.compiler.api.CompilerContext; import org.apache.ode.bpel.elang.xpath10.compiler.XPathMessages; import org.apache.ode.bpel.elang.xpath10.compiler.XslCompileUriResolver; import org.apache.ode.bpel.elang.xpath20.o.OXPath20ExpressionBPEL20; import org.apache.ode.bpel.o.OProcess; import org.apache.ode.bpel.o.OScope; import org.apache.ode.bpel.o.OXslSheet; import org.apache.ode.utils.NSContext; import org.apache.ode.utils.Namespaces; import org.apache.ode.utils.msg.MessageBundle; import org.apache.ode.utils.xsl.XslTransformHandler; /** * @author mriou <mriou at apache dot org> */ public class JaxpFunctionResolver implements XPathFunctionResolver { private static final XPathMessages __msgs = MessageBundle.getMessages(XPathMessages.class); private CompilerContext _cctx; private OXPath20ExpressionBPEL20 _out; private NSContext _nsContext; private String _bpelNS; private static final String JAVA_PREFIX = "java:"; private static final Log __log = LogFactory.getLog(JaxpFunctionResolver.class); public JaxpFunctionResolver(CompilerContext cctx, OXPath20ExpressionBPEL20 out, NSContext nsContext, String bpelNS) { _cctx = cctx; _bpelNS = bpelNS; _nsContext = nsContext; _bpelNS = bpelNS; _out = out; } public XPathFunction resolveFunction(QName functionName, int arity) { if (functionName.getNamespaceURI() == null) { throw new WrappedResolverException("Undeclared namespace for " + functionName); } else if (functionName.getNamespaceURI().equals(_bpelNS)) { String localName = functionName.getLocalPart(); if (Constants.EXT_FUNCTION_GETVARIABLEPROPERTY.equals(localName)) { return new GetVariableProperty(); } else if (Constants.EXT_FUNCTION_DOXSLTRANSFORM.equals(localName)) { return new DoXslTransform(); } else { throw new WrappedResolverException(__msgs.errUnknownBpelFunction(localName)); } } else if (functionName.getNamespaceURI().equals(Namespaces.ODE_EXTENSION_NS)) { String localName = functionName.getLocalPart(); if (Constants.NON_STDRD_FUNCTION_SPLIT_TO_ELEMENTS.equals(localName) || Constants.NON_STDRD_FUNCTION_DEPRECATED_SPLIT_TO_ELEMENTS.equals(localName)) { return new SplitToElements(); } else if (Constants.NON_STDRD_FUNCTION_COMBINE_URL.equals(localName) || Constants.NON_STDRD_FUNCTION_DEPRECATED_COMBINE_URL.equals(localName)) { return new CombineUrl(); } else if (Constants.NON_STDRD_FUNCTION_COMPOSE_URL.equals(localName) || Constants.NON_STDRD_FUNCTION_EXPAND_TEMPLATE.equals(localName) || Constants.NON_STDRD_FUNCTION_DEPRECATED_COMPOSE_URL.equals(localName) || Constants.NON_STDRD_FUNCTION_DEPRECATED_EXPAND_TEMPLATE.equals(localName)) { return new ComposeUrl(); } else if (Constants.NON_STDRD_FUNCTION_DOM_TO_STRING.equals(localName) || Constants.NON_STDRD_FUNCTION_DEPRECATED_DOM_TO_STRING.equals(localName)) { return new DomToString(); } else if (Constants.NON_STDRD_FUNCTION_INSERT_AFTER.equals(localName)) { return new InsertAfter(); } else if (Constants.NON_STDRD_FUNCTION_INSERT_AS_FIRST_INTO.equals(localName)) { return new InsertAsFirstInto(); } else if (Constants.NON_STDRD_FUNCTION_INSERT_AS_LAST_INTO.equals(localName)) { return new InsertAsLastInto(); } else if (Constants.NON_STDRD_FUNCTION_INSERT_BEFORE.equals(localName)) { return new InsertBefore(); } else if (Constants.NON_STDRD_FUNCTION_DELETE.equals(localName)) { return new Delete(); } else if (Constants.NON_STDRD_FUNCTION_RENAME.equals(localName)) { return new Rename(); } else if (Constants.NON_STDRD_FUNCTION_PROCESS_PROPERTY.equals(localName)) { return new ProcessProperty(); } } else if (functionName.getNamespaceURI().equals(Namespaces.DEPRECATED_XDT_NS)) { String localName = functionName.getLocalPart(); if (Constants.NON_STDRD_FUNCTION_DAY_TIME_DURATION.equals(localName)) { return new DayTimeDuration(); } else if (Constants.NON_STDRD_FUNCTION_YEAR_MONTH_DURATION.equals(localName)) { return new YearMonthDuration(); } } else if (functionName.getNamespaceURI().startsWith(JAVA_PREFIX)) { return new JavaFunction(functionName); } return null; } public class GetVariableProperty implements XPathFunction { public Object evaluate(List params) throws XPathFunctionException { if (params.size() != 2) { throw new CompilationException( __msgs.errInvalidNumberOfArguments(Constants.EXT_FUNCTION_GETVARIABLEPROPERTY)); } String varName = (String) params.get(0); OScope.Variable v = _cctx.resolveVariable(varName); _out.vars.put(varName, v); String propName = (String) params.get(1); QName qname = _nsContext.derefQName(propName); if (qname == null) throw new CompilationException( __msgs.errInvalidQName(propName)); OProcess.OProperty property = _cctx.resolveProperty(qname); // Make sure we can... _cctx.resolvePropertyAlias(v, qname); _out.properties.put(propName, property); _out.vars.put(varName, v); return ""; } } public class DoXslTransform implements XPathFunction { public Object evaluate(List params) throws XPathFunctionException { if (params.size() < 2 || params.size() % 2 != 0) { throw new CompilationException( __msgs.errInvalidNumberOfArguments(Constants.EXT_FUNCTION_DOXSLTRANSFORM)); } String xslUri = (String) params.get(0); OXslSheet xslSheet = _cctx.compileXslt(xslUri); try { XslTransformHandler.getInstance().parseXSLSheet(_cctx.getOProcess().getQName(), xslSheet.uri, xslSheet.sheetBody, new XslCompileUriResolver(_cctx, _out)); } catch (Exception e) { throw new CompilationException(__msgs.errXslCompilation(xslUri, e.toString())); } _out.setXslSheet(xslSheet.uri, xslSheet); return ""; } } /** * Compile time checking for the non standard ode:splitToElements function. */ public static class SplitToElements implements XPathFunction { public Object evaluate(List params) throws XPathFunctionException { if (params.size() < 3 || params.size() > 4) { throw new CompilationException( __msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_SPLIT_TO_ELEMENTS)); } return ""; } } public static class CombineUrl implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() != 2) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_COMBINE_URL)); } return ""; } } public static class DomToString implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() != 1) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_DOM_TO_STRING)); } return ""; } } public static class ComposeUrl implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { boolean separareParameteters; if (args.size() != 2 && (args.size() <= 2 || args.size() % 2 != 1)) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_COMPOSE_URL)); } return ""; } } public static class InsertInto implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() != 3) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_INSERT_AFTER)); } return ""; } } public static class InsertAfter implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() < 2 || args.size() > 3) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_INSERT_AFTER)); } return ""; } } public static class InsertBefore implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() < 2 || args.size() > 3) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_INSERT_BEFORE)); } return ""; } } public static class InsertAsFirstInto implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() != 2) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_INSERT_AS_FIRST_INTO)); } return ""; } } public static class InsertAsLastInto implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() != 2) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_INSERT_AS_LAST_INTO)); } return ""; } } public static class Delete implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() < 1 || args.size() > 2) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_DELETE)); } return ""; } } public static class Rename implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() < 2) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_RENAME)); } return ""; } } public static class ProcessProperty implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() != 1) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_PROCESS_PROPERTY)); } return ""; } } public static class DayTimeDuration implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() != 1) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_DAY_TIME_DURATION)); } return ""; } } public static class YearMonthDuration implements XPathFunction { public Object evaluate(List args) throws XPathFunctionException { if (args.size() != 1) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(Constants.NON_STDRD_FUNCTION_YEAR_MONTH_DURATION)); } return ""; } } public class JavaFunction implements XPathFunction { private java.lang.reflect.Method _method=null; private QName _functionName=null; public JavaFunction(QName functionName) { _functionName = functionName; String javaClassName=functionName.getNamespaceURI().substring(JAVA_PREFIX.length()); try { Class<?> cls=Class.forName(javaClassName); for (java.lang.reflect.Method m : cls.getMethods()) { if (m.getName().equals(functionName.getLocalPart())) { _method = m; break; } } if (_method != null && (_method.getModifiers() & Modifier.STATIC) == 0) { __log.error("Java method implementing XPath function '"+functionName+"' is not static"); _method = null; } } catch (Exception e) { __log.error("Unable to locate XPath function '"+functionName+"'", e); } } public Object evaluate(List params) throws XPathFunctionException { if (_method == null) { throw new CompilationException(__msgs.errUnknownBpelFunction(_functionName.toString())); } // Check number of parameters is the same if (params.size() != _method.getParameterTypes().length) { // Check whether length difference is based on one context parameter // i.e. the process name. if (!(_method.getParameterTypes().length > 0 && _method.getParameterTypes().length == params.size()+1 && _method.getParameterTypes()[0] == QName.class)) { throw new CompilationException(__msgs.errInvalidNumberOfArguments(_functionName.toString())); } } else if (_method.getParameterTypes().length > 0 && _method.getParameterTypes()[0] == QName.class) { // First parameter is supposed to be an implicit process name property, // so actually parameter number does not match throw new CompilationException(__msgs.errInvalidNumberOfArguments(_functionName.toString())); } return ""; } } }