| /* |
| * 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.obj.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.obj.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"); |
| Object ret = retVal.get(0); |
| |
| if (ret instanceof Double && !((Double)ret).isNaN()) { |
| // safely convert a double into a long if they are numerically equal. This |
| // makes 1 from 1.0, which is more reliable when calling web services. |
| if (Double.compare((Double)ret, Math.ceil((Double)ret)) == 0) { |
| // the double is actually an int/long |
| ret = ((Double)ret).longValue(); |
| } |
| } |
| Text text = d.createTextNode(ret.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 || retVal.size() > 1) { |
| StringBuffer msg = new StringBuffer((retVal.size() == 0) ? "No results for expression: '" : "Multiple results for expression: '"); |
| if (cexp instanceof OXPath10Expression) { |
| msg.append(((OXPath10Expression)cexp).getXpath()); |
| } else { |
| msg.append(cexp.toString()); |
| } |
| msg.append("'"); |
| if (ctx.getRootNode() != null) { |
| msg.append(" against '"); |
| msg.append(DOMUtils.domToString(ctx.getRootNode())); |
| msg.append("'"); |
| } |
| throw new FaultException(cexp.getOwner().getConstants().getQnSelectionFailure(), msg.toString()); |
| } |
| |
| 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().getConstants().getQnInvalidExpressionValue(), 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().getConstants().getQnInvalidExpressionValue(), errmsg); |
| } |
| } |
| |
| private Context createContext(OXPath10Expression oxpath, EvaluationContext ctx) { |
| JaxenContexts bpelSupport = new JaxenContexts(oxpath, _extensionFunctions, ctx); |
| ContextSupport support = new ContextSupport(new JaxenNamespaceContextAdapter(oxpath.getNamespaceCtx()), 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.getXpath()); |
| if (xpath == null) { |
| xpath = new DOMXPath(exp.getXpath()); |
| synchronized (_compiledExpressions) { |
| _compiledExpressions.put(exp.getXpath(), 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); |
| } |
| |
| } |
| } |