You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by js...@apache.org on 2007/03/22 10:03:45 UTC

svn commit: r521156 - in /activemq/camel/trunk/camel-core/src: main/java/org/apache/camel/ main/java/org/apache/camel/builder/ main/java/org/apache/camel/builder/xpath/ test/ide-resources/ test/java/org/apache/camel/builder/xpath/

Author: jstrachan
Date: Thu Mar 22 02:03:43 2007
New Revision: 521156

URL: http://svn.apache.org/viewvc?view=rev&rev=521156
Log:
added an XPath builder with test case

Added:
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/RuntimeExpressionException.java   (with props)
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/DefaultNamespaceContext.java   (with props)
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/ExchangeXPathExpression.java   (with props)
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/InvalidXPathExpression.java   (with props)
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/MessageVariableResolver.java   (with props)
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/XPathBuilder.java   (with props)
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/package.html   (with props)
    activemq/camel/trunk/camel-core/src/test/ide-resources/
    activemq/camel/trunk/camel-core/src/test/ide-resources/log4j.properties   (with props)
    activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/
    activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/XPathTest.java   (with props)
Modified:
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java

Added: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/RuntimeExpressionException.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/RuntimeExpressionException.java?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/RuntimeExpressionException.java (added)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/RuntimeExpressionException.java Thu Mar 22 02:03:43 2007
@@ -0,0 +1,38 @@
+/**
+ *
+ * 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.camel;
+
+/**
+ * @version $Revision$
+ */
+public class RuntimeExpressionException extends RuntimeCamelException {
+
+	private static final long serialVersionUID = -8417806626073055262L;
+
+    public RuntimeExpressionException(String message) {
+        super(message);
+    }
+
+    public RuntimeExpressionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public RuntimeExpressionException(Throwable cause) {
+        super(cause);
+    }
+}

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/RuntimeExpressionException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/RuntimeExpressionException.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/RuntimeExpressionException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java?view=diff&rev=521156&r1=521155&r2=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java (original)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java Thu Mar 22 02:03:43 2007
@@ -120,6 +120,23 @@
     }
 
     /**
+     * Returns an expression which converts the given expression to the given type
+     */
+    public static <E extends Exchange> Expression<E> convertTo(final Expression expression, final Class type) {
+        return new Expression<E>() {
+            public Object evaluate(E exchange) {
+                Object value = expression.evaluate(exchange);
+                return exchange.getContext().getTypeConverter().convertTo(type, value);
+            }
+
+            @Override
+            public String toString() {
+                return "convertTo(" + expression + ", " + type + ")";
+            }
+        };
+    }
+
+    /**
      * Returns a tokenize expression which will tokenize the string with the given token
      */
     public static <E extends Exchange> Expression<E> tokenizeExpression(final Expression<E> expression, final String token) {

Modified: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java?view=diff&rev=521156&r1=521155&r2=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java (original)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java Thu Mar 22 02:03:43 2007
@@ -87,8 +87,6 @@
         return PredicateBuilder.isNotNull(expression);
     }
 
-
-
     @Fluent
     public ValueBuilder<E> tokenize() {
         return tokenize("\n");
@@ -98,5 +96,27 @@
     public ValueBuilder<E> tokenize(@FluentArg("token") String token) {
         Expression<E> newExp = ExpressionBuilder.tokenizeExpression(expression, token);
         return new ValueBuilder<E>(newExp);
+    }
+
+    /**
+     * Converts the current value to the given type using the registered type converters
+     *
+     * @param type the type to convert the value to
+     * @return the current builder
+     */
+    @Fluent
+    public ValueBuilder<E> convertTo(@FluentArg("type") Class type) {
+        Expression<E> newExp = ExpressionBuilder.convertTo(expression, type);
+        return new ValueBuilder<E>(newExp);
+    }
+
+    /**
+     * Converts the current value a String using the registered type converters
+     *
+     * @return the current builder
+     */
+    @Fluent
+    public ValueBuilder<E> convertToString() {
+        return convertTo(String.class);
     }
 }

Added: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/DefaultNamespaceContext.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/DefaultNamespaceContext.java?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/DefaultNamespaceContext.java (added)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/DefaultNamespaceContext.java Thu Mar 22 02:03:43 2007
@@ -0,0 +1,96 @@
+/**
+ *
+ * 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.camel.builder.xpath;
+
+
+import javax.xml.xpath.*;
+import javax.xml.namespace.NamespaceContext;
+
+import java.util.*;
+
+/**
+ * An implementation of {@link NamespaceContext} which uses a simple Map where
+ * the keys are the prefixes and the values are the URIs
+ *
+ * @version $Revision: $
+ */
+public class DefaultNamespaceContext implements NamespaceContext {
+
+    private final Map map;
+    private final NamespaceContext parent;
+
+    public DefaultNamespaceContext() {
+        this(XPathFactory.newInstance());
+    }
+
+    public DefaultNamespaceContext(XPathFactory factory) {
+        this.parent = factory.newXPath().getNamespaceContext();
+        this.map = new HashMap();
+    }
+
+    public DefaultNamespaceContext(NamespaceContext parent, Map map) {
+        this.parent = parent;
+        this.map = map;
+    }
+
+    /**
+     * A helper method to make it easy to create newly populated instances
+     */
+    public DefaultNamespaceContext add(String prefix, String uri) {
+        map.put(prefix, uri);
+        return this;
+    }
+
+    public String getNamespaceURI(String prefix) {
+        String answer = (String) map.get(prefix);
+        if (answer == null && parent != null) {
+            return parent.getNamespaceURI(prefix);
+        }
+        return answer;
+    }
+
+    public String getPrefix(String namespaceURI) {
+        for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            if (namespaceURI.equals(entry.getValue())) {
+                return (String) entry.getKey();
+            }
+        }
+        if (parent != null) {
+            return parent.getPrefix(namespaceURI);
+        }
+        return null;
+    }
+
+    public Iterator getPrefixes(String namespaceURI) {
+        Set set = new HashSet();
+        for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            if (namespaceURI.equals(entry.getValue())) {
+                set.add(entry.getKey());
+            }
+        }
+        if (parent != null) {
+            Iterator iter = parent.getPrefixes(namespaceURI);
+            while (iter.hasNext()) {
+                set.add(iter.next());
+            }
+        }
+        return set.iterator();
+    }
+}

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/DefaultNamespaceContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/DefaultNamespaceContext.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/DefaultNamespaceContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/ExchangeXPathExpression.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/ExchangeXPathExpression.java?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/ExchangeXPathExpression.java (added)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/ExchangeXPathExpression.java Thu Mar 22 02:03:43 2007
@@ -0,0 +1,118 @@
+/**
+ *
+ * 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.camel.builder.xpath;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.Message;
+import org.xml.sax.InputSource;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import java.io.StringReader;
+
+/**
+ * An {@link Expression} which uses XPath to perform the evaluation
+ *
+ * @version $Revision$
+ */
+public class ExchangeXPathExpression<E extends Exchange> implements Expression<E> {
+    private final XPathExpression expression;
+    private final MessageVariableResolver variableResolver;
+    private Class documentType;
+    private String text;
+    private QName resultType;
+
+    public ExchangeXPathExpression(XPathBuilder builder, XPathExpression expression, MessageVariableResolver variableResolver) {
+        this.expression = expression;
+        this.variableResolver = variableResolver;
+        this.documentType = builder.getDocumentType();
+        this.text = builder.getText();
+        this.resultType = builder.getResultType();
+    }
+
+    public Object evaluate(E exchange) {
+        return evaluateAs(exchange, resultType);
+    }
+
+    public Class getDocumentType() {
+        return documentType;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public MessageVariableResolver getVariableResolver() {
+        return variableResolver;
+    }
+
+    /**
+     * Evaluates the expression as the given result type
+     */
+    protected synchronized Object evaluateAs(E exchange, QName resultType) {
+        variableResolver.setExchange(exchange);
+        try {
+            Object document = getDocument(exchange);
+            if (resultType != null) {
+                if (document instanceof InputSource) {
+                    InputSource inputSource = (InputSource) document;
+                    return expression.evaluate(inputSource, resultType);
+                }
+                else {
+                    return expression.evaluate(document, resultType);
+                }
+            }
+            else {
+                if (document instanceof InputSource) {
+                    InputSource inputSource = (InputSource) document;
+                    return expression.evaluate(inputSource);
+                }
+                else {
+                    return expression.evaluate(document);
+                }
+            }
+        }
+        catch (XPathExpressionException e) {
+            throw new InvalidXPathExpression(getText(), e);
+        }
+    }
+
+    /**
+     * Strategy method to extract the document from the exchange
+     */
+    protected Object getDocument(E exchange) {
+        Message in = exchange.getIn();
+        Class type = getDocumentType();
+        Object answer = null;
+        if (type != null) {
+            answer = in.getBody(type);
+        }
+        if (answer == null) {
+            answer = in.getBody();
+        }
+
+        // lets try coerce some common types into something JAXP can deal with
+        if (answer instanceof String) {
+            answer = new InputSource(new StringReader(answer.toString()));
+        }
+        return answer;
+    }
+}
+

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/ExchangeXPathExpression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/ExchangeXPathExpression.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/ExchangeXPathExpression.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/InvalidXPathExpression.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/InvalidXPathExpression.java?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/InvalidXPathExpression.java (added)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/InvalidXPathExpression.java Thu Mar 22 02:03:43 2007
@@ -0,0 +1,41 @@
+/**
+ *
+ * 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.camel.builder.xpath;
+
+import org.apache.camel.RuntimeExpressionException;
+
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathException;
+
+/**
+ * An exception thrown if am XPath expression could not be parsed or evaluated
+ *
+ * @version $Revision$
+ */
+public class InvalidXPathExpression extends RuntimeExpressionException {
+    private final String xpath;
+
+    public InvalidXPathExpression(String xpath, XPathException e) {
+        super("Invalid xpath: " + xpath + ". Reason: " + e, e);
+        this.xpath = xpath;
+    }
+
+    public String getXpath() {
+        return xpath;
+    }
+}

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/InvalidXPathExpression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/InvalidXPathExpression.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/InvalidXPathExpression.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/MessageVariableResolver.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/MessageVariableResolver.java?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/MessageVariableResolver.java (added)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/MessageVariableResolver.java Thu Mar 22 02:03:43 2007
@@ -0,0 +1,70 @@
+/**
+ *
+ * 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.camel.builder.xpath;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathVariableResolver;
+
+/**
+ * A variable resolver for XPath expressions which support properties on the messge, exchange as well
+ * as making system properties and environment properties available.
+ *
+ * @version $Revision$
+ */
+public class MessageVariableResolver implements XPathVariableResolver {
+    public static final String SYSTEM_PROPERTIES_NAMESPACE = "http://camel.apache.org/xml/variables/system-properties";
+    public static final String ENVIRONMENT_VARIABLES = "http://camel.apache.org/xml/variables/environment-variables";
+
+    private Exchange exchange;
+
+    public Exchange getExchange() {
+        return exchange;
+    }
+
+    public void setExchange(Exchange exchange) {
+        this.exchange = exchange;
+    }
+
+    public Object resolveVariable(QName name) {
+        // should we use other namespaces maybe?
+        String uri = name.getNamespaceURI();
+        String localPart = name.getLocalPart();
+
+        Object answer = null;
+
+        if (uri == null || uri.length() == 0) {
+            Message message = exchange.getIn();
+            if (message != null) {
+                answer = message.getHeaders().getHeader(localPart);
+            }
+            if (answer == null) {
+                answer = exchange.getHeaders().getHeader(localPart);
+            }
+        }
+        else if (uri.equals(SYSTEM_PROPERTIES_NAMESPACE)) {
+            answer = System.getProperty(localPart);
+        }
+        else if (uri.equals(ENVIRONMENT_VARIABLES)) {
+            answer = System.getenv().get(localPart);
+        }
+        return answer;
+    }
+}

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/MessageVariableResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/MessageVariableResolver.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/MessageVariableResolver.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/XPathBuilder.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/XPathBuilder.java?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/XPathBuilder.java (added)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/XPathBuilder.java Thu Mar 22 02:03:43 2007
@@ -0,0 +1,220 @@
+/**
+ *
+ * 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.camel.builder.xpath;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.RuntimeExpressionException;
+import org.w3c.dom.Document;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPathFactoryConfigurationException;
+import javax.xml.xpath.XPathException;
+import javax.xml.xpath.XPathFunctionResolver;
+
+/**
+ * Creates an XPath expression builder
+ *
+ * @version $Revision$
+ */
+public class XPathBuilder<E extends Exchange> {
+    private final String text;
+    private XPathFactory xpathFactory;
+    private Class documentType = Document.class;
+    private QName resultType = null;
+    private String objectModelUri = null;
+    private DefaultNamespaceContext namespaceContext;
+    private XPathFunctionResolver functionResolver;
+
+    public static XPathBuilder xpath(String text) {
+        return new XPathBuilder(text);
+    }
+
+    public XPathBuilder(String text) {
+        this.text = text;
+    }
+
+    public Expression<E> createExpression() {
+        try {
+            MessageVariableResolver variableResolver = new MessageVariableResolver();
+            XPathExpression expression = createXPathExpression(variableResolver);
+            return new ExchangeXPathExpression<E>(this, expression, variableResolver);
+        }
+        catch (XPathException e) {
+            throw new InvalidXPathExpression(text, e);
+        }
+    }
+
+    // Builder methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Sets the expression result type to boolean
+     *
+     * @return the current builder
+     */
+    public XPathBuilder<E> booleanResult() {
+        resultType = XPathConstants.BOOLEAN;
+        return this;
+    }
+
+    /**
+     * Sets the expression result type to boolean
+     *
+     * @return the current builder
+     */
+    public XPathBuilder<E> nodeResult() {
+        resultType = XPathConstants.NODE;
+        return this;
+    }
+
+    /**
+     * Sets the expression result type to boolean
+     *
+     * @return the current builder
+     */
+    public XPathBuilder<E> nodeSetResult() {
+        resultType = XPathConstants.NODESET;
+        return this;
+    }
+
+    /**
+     * Sets the expression result type to boolean
+     *
+     * @return the current builder
+     */
+    public XPathBuilder<E> numberResult() {
+        resultType = XPathConstants.NUMBER;
+        return this;
+    }
+
+    /**
+     * Sets the expression result type to boolean
+     *
+     * @return the current builder
+     */
+    public XPathBuilder<E> stringResult() {
+        resultType = XPathConstants.STRING;
+        return this;
+    }
+
+    /**
+     * Sets the object model URI to use
+     *
+     * @return the current builder
+     */
+    public XPathBuilder<E> objectModel(String uri) {
+        this.objectModelUri = uri;
+        return this;
+    }
+
+    /**
+     * Sets the {@link XPathFunctionResolver} instance to use on these XPath expressions
+     *
+     * @return the current builder
+     */
+    public XPathBuilder<E> functionResolver(XPathFunctionResolver functionResolver) {
+        this.functionResolver = functionResolver;
+        return this;
+    }
+
+    /**
+     * Registers the namespace prefix and URI with the builder so that the prefix can be used in XPath expressions
+     *
+     * @param prefix is the namespace prefix that can be used in the XPath expressions
+     * @param uri is the namespace URI to which the prefix refers
+     * @return the current builder
+     */
+    public XPathBuilder<E> namespace(String prefix, String uri) {
+        getNamespaceContext().add(prefix, uri);
+        return this;
+    }
+
+    // Properties
+    //-------------------------------------------------------------------------
+    public XPathFactory getXPathFactory() throws XPathFactoryConfigurationException {
+        if (xpathFactory == null) {
+            if (objectModelUri != null) {
+                xpathFactory = XPathFactory.newInstance(objectModelUri);
+            }
+            xpathFactory = XPathFactory.newInstance();
+        }
+        return xpathFactory;
+    }
+
+    public void setXPathFactory(XPathFactory xpathFactory) {
+        this.xpathFactory = xpathFactory;
+    }
+
+    public Class getDocumentType() {
+        return documentType;
+    }
+
+    public void setDocumentType(Class documentType) {
+        this.documentType = documentType;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public QName getResultType() {
+        return resultType;
+    }
+
+    public DefaultNamespaceContext getNamespaceContext() {
+        if (namespaceContext == null) {
+            try {
+                namespaceContext = new DefaultNamespaceContext(getXPathFactory());
+            }
+            catch (XPathFactoryConfigurationException e) {
+                throw new RuntimeExpressionException(e);
+            }
+        }
+        return namespaceContext;
+    }
+
+    public void setNamespaceContext(DefaultNamespaceContext namespaceContext) {
+        this.namespaceContext = namespaceContext;
+    }
+
+    public XPathFunctionResolver getFunctionResolver() {
+        return functionResolver;
+    }
+
+    public void setFunctionResolver(XPathFunctionResolver functionResolver) {
+        this.functionResolver = functionResolver;
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+    protected XPathExpression createXPathExpression(MessageVariableResolver variableResolver) throws XPathExpressionException, XPathFactoryConfigurationException {
+        XPath xPath = getXPathFactory().newXPath();
+        xPath.setNamespaceContext(getNamespaceContext());
+        xPath.setXPathVariableResolver(variableResolver);
+        if (functionResolver != null) {
+            xPath.setXPathFunctionResolver(functionResolver);
+        }
+        return xPath.compile(text);
+    }
+}

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/XPathBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/XPathBuilder.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/XPathBuilder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/package.html
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/package.html?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/package.html (added)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/package.html Thu Mar 22 02:03:43 2007
@@ -0,0 +1,26 @@
+<!--
+    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.
+-->
+<html>
+<head>
+</head>
+<body>
+
+Support for XPath based <a href="http://activemq.apache.org/camel/expression.html">Expressions</a>
+and <a href="http://activemq.apache.org/camel/predicate.html">Predicates</a>
+
+</body>
+</html>

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/package.html
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xpath/package.html
------------------------------------------------------------------------------
    svn:mime-type = text/html

Added: activemq/camel/trunk/camel-core/src/test/ide-resources/log4j.properties
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/test/ide-resources/log4j.properties?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/test/ide-resources/log4j.properties (added)
+++ activemq/camel/trunk/camel-core/src/test/ide-resources/log4j.properties Thu Mar 22 02:03:43 2007
@@ -0,0 +1,30 @@
+## ------------------------------------------------------------------------
+## 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.
+## ------------------------------------------------------------------------
+
+#
+# The logging properties used for eclipse testing, We want to see debug output on the console.
+#
+log4j.rootLogger=INFO, out
+
+#log4j.logger.org.apache.activemq=DEBUG
+log4j.logger.org.apache.camel=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n

Propchange: activemq/camel/trunk/camel-core/src/test/ide-resources/log4j.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/test/ide-resources/log4j.properties
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/test/ide-resources/log4j.properties
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/XPathTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/XPathTest.java?view=auto&rev=521156
==============================================================================
--- activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/XPathTest.java (added)
+++ activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/XPathTest.java Thu Mar 22 02:03:43 2007
@@ -0,0 +1,92 @@
+/**
+ *
+ * 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.camel.builder.xpath;
+
+import junit.framework.TestCase;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.Message;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.xml.xpath.XPathFunctionResolver;
+
+/**
+ * @version $Revision$
+ */
+public class XPathTest extends TestCase {
+    private static final transient Log log = LogFactory.getLog(XPathTest.class);
+
+    public void testXPath() throws Exception {
+        assertExpression("/foo/bar/@xyz", "cheese", "<foo><bar xyz='cheese'/></foo>");
+        assertExpression("$name", "James", "<foo><bar xyz='cheese'/></foo>");
+        assertExpression("foo/bar", "cheese", "<foo><bar>cheese</bar></foo>");
+        assertExpression("foo/bar/text()", "cheese", "<foo><bar>cheese</bar></foo>");
+    }
+
+    public void testUsingJavaExtensions() throws Exception {
+        Object instance = null;
+
+        // we may not have Xalan on the classpath
+        try {
+            instance = Class.forName("org.apache.xalan.extensions.XPathFunctionResolverImpl").newInstance();
+        }
+        catch (Throwable e) {
+            log.info("Could not find Xalan on the classpath so ignoring this test case: " + e);
+        }
+        
+        if (instance instanceof XPathFunctionResolver) {
+            XPathFunctionResolver functionResolver = (XPathFunctionResolver) instance;
+
+            XPathBuilder builder = XPathBuilder.xpath("java:"
+                    + getClass().getName() + ".func(string(/header/value))")
+                    .namespace("java", "http://xml.apache.org/xalan/java")
+                    .functionResolver(functionResolver);
+
+            String xml = "<header><value>12</value></header>";
+            Object value = assertExpression(builder.createExpression(), "modified12", xml);
+            log.debug("Evaluated xpath: " + builder.getText() + " on XML: " + xml + " result: " + value);
+        }
+    }
+
+    public static String func(String s) {
+        return "modified" + s;
+    }
+
+    protected void assertExpression(String xpath, String expected, String xml) {
+        Expression expression = XPathBuilder.xpath(xpath).createExpression();
+        Object value = assertExpression(expression, expected, xml);
+
+        log.debug("Evaluated xpath: " + xpath + " on XML: " + xml + " result: " + value);
+    }
+
+    protected Object assertExpression(Expression expression, String expected, String xml) {
+        CamelContext context = new DefaultCamelContext();
+        Exchange exchange = new DefaultExchange(context);
+        Message message = exchange.getIn();
+        message.getHeaders().setHeader("name", "James");
+        message.setBody(xml);
+
+        Object value = expression.evaluate(exchange);
+        assertEquals("Expression: " + expression, expected, value);
+        return value;
+    }
+}

Propchange: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/XPathTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/XPathTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xpath/XPathTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain