This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 39a7631d33d46fec6ba749f1d42c1c7f7f01c9b4
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Fri Jan 12 10:46:27 2018 +0100

    CAMEL-11599: XPath with Saxon should load Saxon using their preferred way.
---
 camel-core/pom.xml                                 |  1 +
 .../org/apache/camel/builder/xml/XPathBuilder.java | 42 ++++++++++--
 .../camel/model/language/ExpressionDefinition.java |  9 +++
 .../camel/util/ExpressionToPredicateAdapter.java   | 21 +++++-
 .../xpath/XPathHeaderEnableSaxonJavaDslTest.java   | 74 ++++++++++++++++++++++
 .../language/xpath/XPathHeaderEnableSaxonTest.java | 29 +++++++++
 .../language/xpath/XPathHeaderEnableSaxonTest.xml  | 46 ++++++++++++++
 7 files changed, 213 insertions(+), 9 deletions(-)

diff --git a/camel-core/pom.xml b/camel-core/pom.xml
index c92265c..0b6baa3 100644
--- a/camel-core/pom.xml
+++ b/camel-core/pom.xml
@@ -56,6 +56,7 @@
       javax.xml.transform.stax;resolution:=optional,
       net.sf.saxon.event;resolution:=optional,
       net.sf.saxon.serialize;resolution:=optional,
+      net.sf.saxon.xpath;resolution:=optional,
       *
     </camel.osgi.import>
     <camel.osgi.export.service>
diff --git 
a/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java 
b/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java
index da3279c..165842f 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java
@@ -44,6 +44,7 @@ import org.w3c.dom.NodeList;
 import org.xml.sax.InputSource;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.NoTypeConversionAvailableException;
@@ -83,7 +84,7 @@ import static 
org.apache.camel.builder.xml.Namespaces.isMatchingNamespaceOrEmpty
  *
  * @see XPathConstants#NODESET
  */
-public class XPathBuilder extends ServiceSupport implements Expression, 
Predicate, NamespaceAware {
+public class XPathBuilder extends ServiceSupport implements CamelContextAware, 
Expression, Predicate, NamespaceAware {
     private static final Logger LOG = 
LoggerFactory.getLogger(XPathBuilder.class);
     private static final String SAXON_OBJECT_MODEL_URI = 
"http://saxon.sf.net/jaxp/xpath/om";;
     private static final String SAXON_FACTORY_CLASS_NAME = 
"net.sf.saxon.xpath.XPathFactoryImpl";
@@ -91,6 +92,7 @@ public class XPathBuilder extends ServiceSupport implements 
Expression, Predicat
 
     private static volatile XPathFactory defaultXPathFactory;
 
+    private CamelContext camelContext;
     private final Queue<XPathExpression> pool = new 
ConcurrentLinkedQueue<XPathExpression>();
     private final Queue<XPathExpression> poolLogNamespaces = new 
ConcurrentLinkedQueue<XPathExpression>();
     private final String text;
@@ -154,6 +156,16 @@ public class XPathBuilder extends ServiceSupport 
implements Expression, Predicat
         return "XPath: " + text;
     }
 
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
     public boolean matches(Exchange exchange) {
         try {
             Object booleanResult = evaluateAs(exchange, 
XPathConstants.BOOLEAN);
@@ -782,7 +794,6 @@ public class XPathBuilder extends ServiceSupport implements 
Expression, Predicat
     public void enableSaxon() {
         this.setObjectModelUri(SAXON_OBJECT_MODEL_URI);
         this.setFactoryClassName(SAXON_FACTORY_CLASS_NAME);
-
     }
 
     public String getObjectModelUri() {
@@ -1256,13 +1267,30 @@ public class XPathBuilder extends ServiceSupport 
implements Expression, Predicat
     protected synchronized XPathFactory createXPathFactory() throws 
XPathFactoryConfigurationException {
         if (objectModelUri != null) {
             String xpathFactoryClassName = factoryClassName;
-            if (objectModelUri.equals(SAXON_OBJECT_MODEL_URI) && 
ObjectHelper.isEmpty(xpathFactoryClassName)) {
-                xpathFactoryClassName = SAXON_FACTORY_CLASS_NAME;
+            if (objectModelUri.equals(SAXON_OBJECT_MODEL_URI) && 
(xpathFactoryClassName == null || 
SAXON_FACTORY_CLASS_NAME.equals(xpathFactoryClassName))) {
+                // from Saxon 9.7 onwards you should favour to create the 
class directly
+                // 
https://www.saxonica.com/html/documentation/xpath-api/jaxp-xpath/factory.html
+                try {
+                    if (camelContext != null) {
+                        Class<XPathFactory> clazz = 
camelContext.getClassResolver().resolveClass(SAXON_FACTORY_CLASS_NAME, 
XPathFactory.class);
+                        if (clazz != null) {
+                            xpathFactory = 
camelContext.getInjector().newInstance(clazz);
+                            LOG.debug("Created Saxon XPathFactory: {}", 
xpathFactory);
+                        }
+                    }
+                } catch (Throwable e) {
+                    LOG.warn("Attempted to create Saxon XPathFactory by 
creating a new instance of " + SAXON_FACTORY_CLASS_NAME
+                        + " failed. Will fallback and create XPathFactory via 
JDK API. This exception is ignored (stacktrace in DEBUG logging level).");
+                    LOG.debug("Error creating Saxon XPathFactory. This 
exception is ignored.", e);
+                }
             }
 
-            xpathFactory = ObjectHelper.isEmpty(xpathFactoryClassName)
-                ? XPathFactory.newInstance(objectModelUri)
-                : XPathFactory.newInstance(objectModelUri, 
xpathFactoryClassName, null);
+            if (xpathFactory == null) {
+                LOG.debug("Creating XPathFactory via JDK API using 
objectModelUri", objectModelUri);
+                xpathFactory = ObjectHelper.isEmpty(xpathFactoryClassName)
+                    ? XPathFactory.newInstance(objectModelUri)
+                    : XPathFactory.newInstance(objectModelUri, 
xpathFactoryClassName, null);
+            }
 
             LOG.info("Using objectModelUri " + objectModelUri + " when created 
XPathFactory {}", xpathFactory);
             return xpathFactory;
diff --git 
a/camel-core/src/main/java/org/apache/camel/model/language/ExpressionDefinition.java
 
b/camel-core/src/main/java/org/apache/camel/model/language/ExpressionDefinition.java
index 8333e94..9df5c44 100644
--- 
a/camel-core/src/main/java/org/apache/camel/model/language/ExpressionDefinition.java
+++ 
b/camel-core/src/main/java/org/apache/camel/model/language/ExpressionDefinition.java
@@ -31,6 +31,7 @@ import javax.xml.namespace.QName;
 
 import org.apache.camel.AfterPropertiesConfigured;
 import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.NoSuchLanguageException;
@@ -174,6 +175,10 @@ public class ExpressionDefinition implements Expression, 
Predicate, OtherAttribu
                 configurePredicate(camelContext, predicate);
             }
         }
+        // inject CamelContext if its aware
+        if (predicate instanceof CamelContextAware) {
+            ((CamelContextAware) predicate).setCamelContext(camelContext);
+        }
         return predicate;
     }
 
@@ -205,6 +210,10 @@ public class ExpressionDefinition implements Expression, 
Predicate, OtherAttribu
                 configureExpression(camelContext, getExpressionValue());
             }
         }
+        // inject CamelContext if its aware
+        if (getExpressionValue() instanceof CamelContextAware) {
+            ((CamelContextAware) 
getExpressionValue()).setCamelContext(camelContext);
+        }
         return getExpressionValue();
     }
 
diff --git 
a/camel-core/src/main/java/org/apache/camel/util/ExpressionToPredicateAdapter.java
 
b/camel-core/src/main/java/org/apache/camel/util/ExpressionToPredicateAdapter.java
index b81d665..7eb87b8 100644
--- 
a/camel-core/src/main/java/org/apache/camel/util/ExpressionToPredicateAdapter.java
+++ 
b/camel-core/src/main/java/org/apache/camel/util/ExpressionToPredicateAdapter.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.util;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.Predicate;
@@ -23,7 +25,7 @@ import org.apache.camel.Predicate;
 /**
  * To adapt {@link org.apache.camel.Expression} as a {@link Predicate}
  */
-public final class ExpressionToPredicateAdapter implements Predicate {
+public final class ExpressionToPredicateAdapter implements Predicate, 
CamelContextAware {
     private final Expression expression;
 
     public ExpressionToPredicateAdapter(Expression expression) {
@@ -50,5 +52,20 @@ public final class ExpressionToPredicateAdapter implements 
Predicate {
     public static Predicate toPredicate(final Expression expression) {
         return new ExpressionToPredicateAdapter(expression);
     }
-    
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        if (expression instanceof CamelContextAware) {
+            ((CamelContextAware) expression).setCamelContext(camelContext);
+        }
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        if (expression instanceof CamelContextAware) {
+            return ((CamelContextAware) expression).getCamelContext();
+        } else {
+            return null;
+        }
+    }
 }
\ No newline at end of file
diff --git 
a/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderEnableSaxonJavaDslTest.java
 
b/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderEnableSaxonJavaDslTest.java
new file mode 100644
index 0000000..a7d6fa9
--- /dev/null
+++ 
b/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderEnableSaxonJavaDslTest.java
@@ -0,0 +1,74 @@
+/**
+ * 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.language.xpath;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class XPathHeaderEnableSaxonJavaDslTest extends CamelTestSupport {
+
+    @Test
+    public void testChoiceWithHeaderSelectCamel() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:camel");
+        mock.expectedBodiesReceived("<name>King</name>");
+        mock.expectedHeaderReceived("type", "Camel");
+
+        template.sendBodyAndHeader("direct:in", "<name>King</name>", "type", 
"Camel");
+
+        mock.assertIsSatisfied();
+    }
+
+    @Test
+    public void testChoiceWithNoHeaderSelectDonkey() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:donkey");
+        mock.expectedBodiesReceived("<name>Kong</name>");
+
+        template.sendBody("direct:in", "<name>Kong</name>");
+
+        mock.assertIsSatisfied();
+    }
+
+    @Test
+    public void testChoiceWithNoHeaderSelectOther() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:other");
+        mock.expectedBodiesReceived("<name>Other</name>");
+
+        template.sendBody("direct:in", "<name>Other</name>");
+
+        mock.assertIsSatisfied();
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:in")
+                    .choice()
+                        .when(xpath("$type = 'Camel'").saxon())
+                            .to("mock:camel")
+                        .when(xpath("//name = 'Kong'").saxon())
+                            .to("mock:donkey")
+                        .otherwise()
+                            .to("mock:other");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderEnableSaxonTest.java
 
b/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderEnableSaxonTest.java
new file mode 100644
index 0000000..0fa3235
--- /dev/null
+++ 
b/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderEnableSaxonTest.java
@@ -0,0 +1,29 @@
+/**
+ * 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.language.xpath;
+
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class XPathHeaderEnableSaxonTest extends XPathHeaderTest {
+
+    @Override
+    protected AbstractXmlApplicationContext createApplicationContext() {
+        return new 
ClassPathXmlApplicationContext("org/apache/camel/language/xpath/XPathHeaderEnableSaxonTest.xml");
+    }
+
+}
diff --git 
a/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathHeaderEnableSaxonTest.xml
 
b/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathHeaderEnableSaxonTest.xml
new file mode 100644
index 0000000..c3de449
--- /dev/null
+++ 
b/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathHeaderEnableSaxonTest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://camel.apache.org/schema/spring 
http://camel.apache.org/schema/spring/camel-spring.xsd
+    ">
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring";>
+    <route>
+      <from uri="direct:in"/>
+      <choice>
+        <when>
+          <xpath saxon="true">$type = 'Camel'</xpath>
+          <to uri="mock:camel"/>
+        </when>
+        <when>
+          <xpath saxon="true">//name = 'Kong'</xpath>
+          <to uri="mock:donkey"/>
+        </when>
+        <otherwise>
+          <to uri="mock:other"/>
+        </otherwise>
+      </choice>
+    </route>
+  </camelContext>
+
+</beans>

-- 
To stop receiving notification emails like this one, please contact
"commits@camel.apache.org" <commits@camel.apache.org>.

Reply via email to