blob: b8c51394faaa3bb25aeea04fd1f8d308c38bb64b [file] [log] [blame]
/*
* 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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ode.bpel.common.FaultException;
import org.apache.ode.bpel.elang.xpath10.o.OXPath10Expression;
import org.apache.ode.bpel.elang.xpath10.o.OXPath10ExpressionBPEL20;
import org.apache.ode.bpel.explang.EvaluationContext;
import org.apache.ode.bpel.o.OLink;
import org.apache.ode.bpel.o.OMessageVarType;
import org.apache.ode.bpel.o.OProcess;
import org.apache.ode.bpel.o.OScope;
import org.apache.ode.bpel.o.OVarType;
import org.apache.ode.bpel.o.OXsdTypeVarType;
import org.apache.ode.bpel.o.OXslSheet;
import org.apache.ode.utils.DOMUtils;
import org.apache.ode.utils.xsd.XSTypes;
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.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.xml.namespace.QName;
import javax.xml.transform.dom.DOMSource;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.saxon.dom.NodeWrapper;
/**
* 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 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.qname_getVariableProperty))
return _getVariableProperty;
if (fnQName.equals(_oxpath.qname_getVariableData))
return _getVariableData;
if (fnQName.equals(_oxpath.qname_getLinkStatus))
return _getLinkStatus;
if (_oxpath instanceof OXPath10ExpressionBPEL20) {
OXPath10ExpressionBPEL20 oxpath20 = (OXPath10ExpressionBPEL20) _oxpath;
if (fnQName.equals(oxpath20.qname_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.isJoinExpression){
OLink olink = _oxpath.links.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.vars.get(varName);
OMessageVarType.Part part = partName == null ? null : ((OMessageVarType)variable.type).parts.get(partName);
try{
Node variableNode = _xpathEvalCtx.readVariable(variable, part);
if (variableNode == null)
throw new WrappedFaultException.JaxenUnresolvableException(
new FaultException(variable.getOwner().constants.qnSelectionFailure,
"Unknown variable " + localName));
OVarType type = variable.type;
if (type instanceof OMessageVarType) {
OMessageVarType.Part typePart = ((OMessageVarType)type).parts.get(partName);
if (typePart == null) {
throw new WrappedFaultException.JaxenUnresolvableException(
new FaultException(variable.getOwner().constants.qnSelectionFailure,
"Unknown part " + partName + " for variable " + localName));
}
type = typePart.type;
}
if (_xpathEvalCtx.narrowTypes() && type instanceof OXsdTypeVarType && ((OXsdTypeVarType)type).simple) {
return variableNode.getTextContent();
} 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.variable, sig.part);
if (sig.location != null)
ret = _xpathEvalCtx.evaluateQuery(ret, sig.location);
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);
}
}
}
/**
* 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.vars.get(args.get(0));
OProcess.OProperty property = _oxpath.properties.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.links.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().constants.qnXsltInvalidSource,
"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().constants.qnXsltInvalidSource,
"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().constants.qnXsltInvalidSource,
"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.namespaceCtx.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.getBaseResourceURI(), xslUri, xslSheet.sheetBody, resolver);
try {
result = XslTransformHandler.getInstance().transform(_xpathEvalCtx.getBaseResourceURI(), xslUri, source, parametersMap, resolver);
} catch (Exception e) {
throw new WrappedFaultException.JaxenFunctionException(
new FaultException(_oxpath.getOwner().constants.qnSubLanguageExecutionFault,
e.toString()));
}
return result;
}
}
}