/* * 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.explang.ConfigurationException; import org.apache.ode.bpel.explang.EvaluationContext; import org.apache.ode.bpel.explang.EvaluationException; import org.apache.ode.bpel.explang.ExpressionLanguageRuntime; import org.apache.ode.bpel.o.OExpression; import org.apache.ode.utils.DOMUtils; import org.apache.ode.utils.ISO8601DateParser; import org.apache.ode.utils.xsd.Duration; import org.apache.ode.utils.xsl.XslTransformHandler; import org.jaxen.Context; import org.jaxen.ContextSupport; import org.jaxen.JaxenException; import org.jaxen.XPath; import org.jaxen.dom.DOMXPath; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.Text; import javax.xml.transform.TransformerFactory; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * XPath 1.0 Expression Language run-time subsytem. */ public class XPath10ExpressionRuntime implements ExpressionLanguageRuntime { /** Class-level logger. */ private static final Log __log = LogFactory.getLog(XPath10ExpressionRuntime.class); /** Compiled expression cache. */ private final Map<String, XPath> _compiledExpressions = new HashMap<String, XPath>(); /** Registered extension functions. */ private final Map _extensionFunctions = new HashMap(); public void initialize(Map properties) throws ConfigurationException { TransformerFactory trsf = new net.sf.saxon.TransformerFactoryImpl(); XslTransformHandler.getInstance().setTransformerFactory(trsf); } public String evaluateAsString(OExpression cexp, EvaluationContext ctx) throws FaultException, EvaluationException { try { return compile((OXPath10Expression) cexp).stringValueOf(createContext((OXPath10Expression) cexp, ctx)); } catch (JaxenException e) { handleJaxenException(e); } throw new AssertionError("UNREACHABLE"); } public boolean evaluateAsBoolean(OExpression cexp, EvaluationContext ctx) throws FaultException, EvaluationException { try { return compile((OXPath10Expression) cexp).booleanValueOf(createContext((OXPath10Expression) cexp, ctx)); } catch (JaxenException e) { handleJaxenException(e); } throw new AssertionError("UNREACHABLE"); } public Number evaluateAsNumber(OExpression cexp, EvaluationContext ctx) throws FaultException, EvaluationException { try { return compile((OXPath10Expression) cexp).numberValueOf(createContext((OXPath10Expression) cexp, ctx)); } catch (JaxenException e) { handleJaxenException(e); } throw new AssertionError("UNREACHABLE"); } public List evaluate(OExpression cexp, EvaluationContext ctx) throws FaultException, EvaluationException { try { XPath compiledXPath = compile((OXPath10Expression) cexp); Context context = createContext((OXPath10Expression) cexp, ctx); List retVal = compiledXPath.selectNodes(context); if ((retVal.size() == 1) && !(retVal.get(0) instanceof Node)) { Document d = DOMUtils.newDocument(); // Giving our node a parent just in case it's an LValue // expression Element wrapper = d.createElement("wrapper"); Text text = d.createTextNode(retVal.get(0).toString()); wrapper.appendChild(text); d.appendChild(wrapper); retVal = Collections.singletonList(text); } return retVal; } catch (JaxenException je) { handleJaxenException(je); } throw new AssertionError("UNREACHABLE"); } public Node evaluateNode(OExpression cexp, EvaluationContext ctx) throws FaultException, EvaluationException { List retVal = evaluate(cexp, ctx); if (retVal.size() == 0) throw new FaultException(cexp.getOwner().constants.qnSelectionFailure, "No results for expression: " + cexp); if (retVal.size() > 1) throw new FaultException(cexp.getOwner().constants.qnSelectionFailure, "Multiple results for expression: " + cexp); return (Node) retVal.get(0); } public Calendar evaluateAsDate(OExpression cexp, EvaluationContext context) throws FaultException, EvaluationException { String literal = evaluateAsString(cexp, context); try { return ISO8601DateParser.parseCal(literal); } catch (Exception ex) { String errmsg = "Invalid date: " + literal; __log.error(errmsg, ex); throw new FaultException(cexp.getOwner().constants.qnInvalidExpressionValue, errmsg); } } public Duration evaluateAsDuration(OExpression cexp, EvaluationContext context) throws FaultException, EvaluationException { String literal = this.evaluateAsString(cexp, context); try { Duration duration = new org.apache.ode.utils.xsd.Duration(literal); return duration; } catch (Exception ex) { String errmsg = "Invalid duration: " + literal; __log.error(errmsg, ex); throw new FaultException(cexp.getOwner().constants.qnInvalidExpressionValue, errmsg); } } private Context createContext(OXPath10Expression oxpath, EvaluationContext ctx) { JaxenContexts bpelSupport = new JaxenContexts(oxpath, _extensionFunctions, ctx); ContextSupport support = new ContextSupport(new JaxenNamespaceContextAdapter(oxpath.namespaceCtx), bpelSupport, bpelSupport, new BpelDocumentNavigator(ctx.getRootNode())); Context jctx = new Context(support); if (ctx.getRootNode() != null) jctx.setNodeSet(Collections.singletonList(ctx.getRootNode())); return jctx; } private XPath compile(OXPath10Expression exp) throws JaxenException { XPath xpath = _compiledExpressions.get(exp.xpath); if (xpath == null) { xpath = new DOMXPath(exp.xpath); synchronized (_compiledExpressions) { _compiledExpressions.put(exp.xpath, xpath); } } return xpath; } private void handleJaxenException(JaxenException je) throws EvaluationException, FaultException { if (je instanceof WrappedFaultException) { throw ((WrappedFaultException) je).getFaultException(); } else if (je.getCause() instanceof WrappedFaultException) { throw ((WrappedFaultException) je.getCause()).getFaultException(); } else { throw new EvaluationException(je.getMessage(), je); } } }