| /* |
| * 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.xpath10.runtime; |
| |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.xml.namespace.QName; |
| import javax.xml.transform.dom.DOMSource; |
| |
| import net.sf.saxon.dom.NodeWrapper; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.ode.bpel.common.FaultException; |
| import org.apache.ode.bpel.elang.XslRuntimeUriResolver; |
| import org.apache.ode.bpel.elang.xpath10.obj.OXPath10Expression; |
| import org.apache.ode.bpel.elang.xpath10.obj.OXPath10ExpressionBPEL20; |
| import org.apache.ode.bpel.explang.EvaluationContext; |
| import org.apache.ode.bpel.explang.EvaluationException; |
| import org.apache.ode.bpel.obj.OLink; |
| import org.apache.ode.bpel.obj.OMessageVarType; |
| import org.apache.ode.bpel.obj.OProcess; |
| import org.apache.ode.bpel.obj.OScope; |
| import org.apache.ode.bpel.obj.OVarType; |
| import org.apache.ode.bpel.obj.OXsdTypeVarType; |
| import org.apache.ode.bpel.obj.OXslSheet; |
| import org.apache.ode.utils.DOMUtils; |
| import org.apache.ode.utils.xsl.XslTransformHandler; |
| import org.jaxen.Context; |
| import org.jaxen.Function; |
| import org.jaxen.FunctionCallException; |
| import org.jaxen.FunctionContext; |
| import org.jaxen.UnresolvableException; |
| import org.jaxen.VariableContext; |
| import org.jaxen.XPathFunctionContext; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| |
| |
| /** |
| * Implementation of the various JAXEN evaluation contexts in terms of the |
| * {@link EvaluationContext}. |
| */ |
| class JaxenContexts implements FunctionContext, VariableContext { |
| private static final Log __log = LogFactory.getLog(JaxenContexts.class); |
| |
| /** Static, thread-safe singleton implementing default XPath functions */ |
| private static final FunctionContext __defaultXPathFunctions = XPathFunctionContext.getInstance(); |
| |
| private static final QName BOOLEAN = new QName("http://www.w3.org/2001/XMLSchema", "boolean"); |
| private static final QName BYTE = new QName("http://www.w3.org/2001/XMLSchema", "byte"); |
| private static final QName INT = new QName("http://www.w3.org/2001/XMLSchema", "int"); |
| private static final QName INTEGER = new QName("http://www.w3.org/2001/XMLSchema", "integer"); |
| private static final QName LONG = new QName("http://www.w3.org/2001/XMLSchema", "long"); |
| private static final QName SHORT = new QName("http://www.w3.org/2001/XMLSchema", "short"); |
| private static final QName UNSIGNED_INT = new QName("http://www.w3.org/2001/XMLSchema", "unsignedInt"); |
| private static final QName UNSIGNED_SHORT = new QName("http://www.w3.org/2001/XMLSchema", "unsignedShort"); |
| private static final QName UNSIGNED_BYTE = new QName("http://www.w3.org/2001/XMLSchema", "unsignedByte"); |
| private static final QName DECIMAL = new QName("http://www.w3.org/2001/XMLSchema", "decimal"); |
| private static final QName FLOAT = new QName("http://www.w3.org/2001/XMLSchema", "float"); |
| private static final QName DOUBLE = new QName("http://www.w3.org/2001/XMLSchema", "double"); |
| |
| |
| private OXPath10Expression _oxpath; |
| private EvaluationContext _xpathEvalCtx; |
| private Function _getVariableProperty; |
| private Function _getVariableData; |
| private Function _getLinkStatus; |
| private Function _doXslTransform; |
| private Map _extensionFunctions; |
| |
| public JaxenContexts(OXPath10Expression oxpath, |
| Map extensionFunctions, |
| EvaluationContext xpathEvalCtx) { |
| _oxpath = oxpath; |
| _xpathEvalCtx = xpathEvalCtx; |
| _extensionFunctions = extensionFunctions; |
| _getVariableProperty = new BpelVariablePropertyFunction(); |
| _getVariableData = new BpelVariableDataFunction(); |
| _getLinkStatus = new GetLinkStatusFunction(); |
| _doXslTransform = new DoXslTransformFunction(); |
| } |
| |
| /** |
| * @see org.jaxen.FunctionContext#getFunction(java.lang.String, |
| * java.lang.String, java.lang.String) |
| */ |
| public Function getFunction(String namespaceURI, String prefix, |
| String localName) |
| throws UnresolvableException { |
| if (__log.isDebugEnabled()) { |
| __log.debug("getFunction(" + namespaceURI + "," + prefix + "," |
| + localName); |
| } |
| |
| if ((namespaceURI != null)) { |
| QName fnQName = new QName(namespaceURI, localName); |
| |
| if (fnQName.equals(_oxpath.getQname_getVariableProperty())) |
| return _getVariableProperty; |
| if (fnQName.equals(_oxpath.getQname_getVariableData())) |
| return _getVariableData; |
| if (fnQName.equals(_oxpath.getQname_getLinkStatus())) |
| return _getLinkStatus; |
| if (_oxpath instanceof OXPath10ExpressionBPEL20) { |
| OXPath10ExpressionBPEL20 oxpath20 = (OXPath10ExpressionBPEL20) _oxpath; |
| if (fnQName.equals(oxpath20.getQname_doXslTransform())) { |
| return _doXslTransform; |
| } |
| } |
| Function f = (Function)_extensionFunctions.get(localName); |
| |
| if (f != null) { |
| return f; |
| } |
| } |
| |
| // Defer to the default XPath context. |
| return __defaultXPathFunctions.getFunction(null, prefix, localName); |
| } |
| |
| /** |
| * @see org.jaxen.VariableContext#getVariableValue(java.lang.String, |
| * java.lang.String, java.lang.String) |
| */ |
| public Object getVariableValue(String namespaceURI, String prefix, |
| String localName) |
| throws UnresolvableException { |
| if(!(_oxpath instanceof OXPath10ExpressionBPEL20)){ |
| throw new IllegalStateException("XPath variables not supported for bpel 1.1"); |
| } |
| |
| // Custom variables |
| if ("ode".equals(prefix)) { |
| if ("pid".equals(localName)) { |
| return _xpathEvalCtx.getProcessId(); |
| } |
| } |
| |
| OXPath10ExpressionBPEL20 expr = (OXPath10ExpressionBPEL20)_oxpath; |
| if(expr.isIsJoinExpression()){ |
| OLink olink = _oxpath.getLinks().get(localName); |
| |
| try { |
| return _xpathEvalCtx.isLinkActive(olink) ? Boolean.TRUE : Boolean.FALSE; |
| } catch (FaultException e) { |
| throw new WrappedFaultException.JaxenUnresolvableException(e); |
| } |
| }else{ |
| String varName; |
| String partName; |
| int dotloc = localName.indexOf('.'); |
| if (dotloc == -1) { |
| varName = localName; |
| partName = null; |
| } else { |
| varName = localName.substring(0, dotloc); |
| partName = localName.substring(dotloc + 1); |
| } |
| OScope.Variable variable = _oxpath.getVars().get(varName); |
| OMessageVarType.Part part = partName == null ? null : ((OMessageVarType)variable.getType()).getParts().get(partName); |
| |
| try{ |
| Node variableNode = _xpathEvalCtx.readVariable(variable, part); |
| if (variableNode == null) |
| throw new WrappedFaultException.JaxenUnresolvableException( |
| new FaultException(variable.getOwner().getConstants().getQnSelectionFailure(), |
| "Unknown variable " + localName)); |
| OVarType type = variable.getType(); |
| if (type instanceof OMessageVarType) { |
| OMessageVarType.Part typePart = ((OMessageVarType)type).getParts().get(partName); |
| if (typePart == null) { |
| throw new WrappedFaultException.JaxenUnresolvableException( |
| new FaultException(variable.getOwner().getConstants().getQnSelectionFailure(), |
| "Unknown part " + partName + " for variable " + localName)); |
| } |
| type = typePart.getType(); |
| } |
| |
| if (_xpathEvalCtx.narrowTypes() && type instanceof OXsdTypeVarType && ((OXsdTypeVarType)type).isSimple()) { |
| String value = variableNode.getTextContent(); |
| OXsdTypeVarType theType = (OXsdTypeVarType)type; |
| |
| // cast booleans to boolean |
| if (BOOLEAN.equals(theType.getXsdType())) { |
| return new Boolean(value) ; |
| } |
| |
| // and numbers to numbers (XPath only understands Double, so Double it shall be. |
| if (INT.equals(theType.getXsdType()) || UNSIGNED_SHORT.equals(theType.getXsdType()) || |
| INTEGER.equals(theType.getXsdType()) || |
| LONG.equals(theType.getXsdType()) || UNSIGNED_INT.equals(theType.getXsdType()) || |
| SHORT.equals(theType.getXsdType()) || UNSIGNED_BYTE.equals(theType.getXsdType()) || |
| BYTE.equals(theType.getXsdType()) || |
| DECIMAL.equals(theType.getXsdType()) || |
| FLOAT.equals(theType.getXsdType()) || |
| DOUBLE.equals(theType.getXsdType()) |
| ) { |
| return new Double(value); |
| } |
| |
| return value; |
| } else { |
| return variableNode; |
| } |
| }catch(FaultException e){ |
| __log.error("bpws:getVariableValue threw FaultException", e); |
| throw new WrappedFaultException.JaxenUnresolvableException(e); |
| } |
| } |
| } |
| |
| /** |
| * bpws:getVariableData() |
| */ |
| class BpelVariableDataFunction implements Function { |
| public Object call(Context context, List args) |
| throws FunctionCallException { |
| if (__log.isDebugEnabled()) { |
| __log.debug("call(context=" + context + " args=" + args + ")"); |
| } |
| |
| String varname = (String) args.get(0); |
| String partname = args.size() > 1 ? (String) args.get(1) : null; |
| String xpathStr = args.size() > 2 ? (String)args.get(2) : null; |
| |
| OXPath10Expression.OSigGetVariableData sig = _oxpath.resolveGetVariableDataSig(varname,partname,xpathStr); |
| if (sig == null) { |
| String msg = "InternalError: Attempt to use an unknown getVariableData signature: " + args; |
| if (__log.isFatalEnabled()) |
| __log.fatal(msg); |
| throw new FunctionCallException(msg); |
| } |
| |
| try { |
| Node ret = _xpathEvalCtx.readVariable(sig.getVariable(), sig.getPart()); |
| if (sig.getLocation() != null) |
| ret = _xpathEvalCtx.evaluateQuery(ret, sig.getLocation()); |
| |
| if (__log.isDebugEnabled()) { |
| __log.debug("bpws:getVariableData(" + args + ")' = " + ret); |
| } |
| |
| return ret; |
| } catch (FaultException e) { |
| __log.error("bpws:getVariableData(" + args + ") threw FaultException", e); |
| throw new WrappedFaultException.JaxenFunctionException(e); |
| } catch (EvaluationException e) { |
| __log.error("bpws:getVariableData(" + args + ") threw EvaluationException", e); |
| if (e.getCause() instanceof FaultException) { |
| throw new WrappedFaultException.JaxenFunctionException((FaultException) e.getCause()); |
| } else { |
| throw new FunctionCallException("SubLanguageException: Unable to evaluate query expression", e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * bpws:getVariableProperty() |
| */ |
| class BpelVariablePropertyFunction implements Function { |
| public Object call(Context context, List args) |
| throws FunctionCallException { |
| if (args.size() != 2) { |
| throw new FunctionCallException("missing required arguments"); |
| } |
| |
| OScope.Variable var = _oxpath.getVars().get(args.get(0)); |
| OProcess.OProperty property = _oxpath.getProperties().get(args.get(1)); |
| |
| if (__log.isDebugEnabled()) { |
| __log.debug("function call:'bpws:getVariableProperty(" + var + "," |
| + property + ")'"); |
| } |
| |
| try { |
| return _xpathEvalCtx.readMessageProperty(var, property); |
| } catch (FaultException e) { |
| __log.error("bpws:getVariableProperty(" + args + ") threw FaultException", e); |
| throw new WrappedFaultException.JaxenFunctionException(e); |
| } |
| } |
| } |
| |
| class GetLinkStatusFunction implements Function { |
| public Object call(Context context, List args) |
| throws FunctionCallException { |
| assert args.size() == 1; |
| |
| OLink olink = _oxpath.getLinks().get(args.get(0)); |
| |
| try { |
| return _xpathEvalCtx.isLinkActive(olink) ? Boolean.TRUE : Boolean.FALSE; |
| } catch (FaultException e) { |
| __log.error("bpws:getLinkStatus(" + args + ") threw FaultException", e); |
| throw new WrappedFaultException.JaxenFunctionException(e); |
| } |
| } |
| } |
| |
| class DoXslTransformFunction implements Function { |
| public Object call(Context context, List args) throws FunctionCallException { |
| assert args.size() >= 2; |
| assert args.size() % 2 == 0; |
| if (__log.isDebugEnabled()) { |
| __log.debug("call(context=" + context + " args=" + args + ")"); |
| } |
| if(!(_oxpath instanceof OXPath10ExpressionBPEL20)) { |
| throw new IllegalStateException("XPath function bpws:doXslTransform not supported in " + |
| "BPEL 1.1!"); |
| } |
| |
| Element varElmt; |
| try { |
| if (args.get(1) instanceof List) { |
| List elmts = (List)args.get(1); |
| if (elmts.size() != 1) throw new WrappedFaultException.JaxenFunctionException( |
| new FaultException(_oxpath.getOwner().getConstants().getQnXsltInvalidSource(), |
| "Second parameter of the bpws:doXslTransform function MUST point to a single " + |
| "element node.")); |
| varElmt = (Element) elmts.get(0); |
| } else { |
| if (args.get(1) instanceof NodeWrapper) |
| varElmt = (Element) ((NodeWrapper)args.get(1)).getUnderlyingNode(); |
| else varElmt = (Element) args.get(1); |
| |
| // varElmt = (Element) args.get(1); |
| } |
| } catch (ClassCastException e) { |
| throw new WrappedFaultException.JaxenFunctionException( |
| new FaultException(_oxpath.getOwner().getConstants().getQnXsltInvalidSource(), |
| "Second parameter of the bpws:doXslTransform function MUST point to a single " + |
| "element node.")); |
| } |
| |
| URI xslUri; |
| try { |
| xslUri = new URI((String) args.get(0)); |
| } catch (URISyntaxException use) { |
| // Shouldn't happen, checked at compilation time |
| throw new FunctionCallException("First parameter of the bpws:doXslTransform isn't a valid URI!", use); |
| } |
| OXslSheet xslSheet = _oxpath.getXslSheet(xslUri); |
| // Shouldn't happen, checked at compilation time |
| if (xslSheet == null) throw new FunctionCallException("Couldn't find the XSL sheet " + args.get(0) |
| + ", process compilation or deployment was probably incomplete!"); |
| |
| if (!(varElmt instanceof Element)) { |
| throw new WrappedFaultException.JaxenFunctionException( |
| new FaultException(_oxpath.getOwner().getConstants().getQnXsltInvalidSource(), |
| "Second parameter of the bpws:doXslTransform function MUST point to a single " + |
| "element node.")); |
| } |
| |
| HashMap<QName, Object> parametersMap = null; |
| if (args.size() > 2) { |
| parametersMap = new HashMap<QName, Object>(); |
| for (int idx = 2; idx < args.size(); idx+=2) { |
| QName keyQName = _oxpath.getNamespaceCtx().derefQName((String) args.get(idx)); |
| parametersMap.put(keyQName, args.get(idx + 1)); |
| } |
| } |
| |
| Document varDoc = DOMUtils.newDocument(); |
| varDoc.appendChild(varDoc.importNode(varElmt, true)); |
| |
| DOMSource source = new DOMSource(varDoc); |
| Object result; |
| XslRuntimeUriResolver resolver = new XslRuntimeUriResolver(_oxpath, _xpathEvalCtx.getBaseResourceURI()); |
| XslTransformHandler.getInstance().cacheXSLSheet(_xpathEvalCtx.getProcessQName(), xslUri, xslSheet.getSheetBody(), resolver); |
| try { |
| result = XslTransformHandler.getInstance().transform(_xpathEvalCtx.getProcessQName(), xslUri, source, parametersMap, resolver); |
| } catch (Exception e) { |
| throw new WrappedFaultException.JaxenFunctionException( |
| new FaultException(_oxpath.getOwner().getConstants().getQnSubLanguageExecutionFault(), |
| e.toString())); |
| } |
| return result; |
| } |
| } |
| |
| } |