You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2021/11/11 19:55:14 UTC

[camel] branch main updated: CAMEL-17187: camel-xpath - Allow to configure preCompile on @XPath annotation

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 5beb070  CAMEL-17187: camel-xpath - Allow to configure preCompile on @XPath annotation
5beb070 is described below

commit 5beb07094b3eaa34fd8576805a7e0967dc01d945
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Nov 11 20:54:35 2021 +0100

    CAMEL-17187: camel-xpath - Allow to configure preCompile on @XPath annotation
---
 .../org/apache/camel/language/xpath/xpath.json     |  2 +-
 .../org/apache/camel/language/xpath/XPath.java     | 16 ++++
 .../xpath/XPathAnnotationExpressionFactory.java    | 24 +++++-
 .../org/apache/camel/model/language/xpath.json     |  2 +-
 .../camel/model/language/XPathExpression.java      |  2 +-
 .../org/apache/camel/component/xslt/MyXPath.java   |  1 -
 .../BeanWithXPathInjectionPreCompileTest.java      | 97 ++++++++++++++++++++++
 7 files changed, 139 insertions(+), 5 deletions(-)

diff --git a/components/camel-xpath/src/generated/resources/org/apache/camel/language/xpath/xpath.json b/components/camel-xpath/src/generated/resources/org/apache/camel/language/xpath/xpath.json
index 3847db2..718df34 100644
--- a/components/camel-xpath/src/generated/resources/org/apache/camel/language/xpath/xpath.json
+++ b/components/camel-xpath/src/generated/resources/org/apache/camel/language/xpath/xpath.json
@@ -22,7 +22,7 @@
     "saxon": { "kind": "attribute", "displayName": "Saxon", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to use Saxon." },
     "factoryRef": { "kind": "attribute", "displayName": "Factory Ref", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "References to a custom XPathFactory to lookup in the registry" },
     "objectModel": { "kind": "attribute", "displayName": "Object Model", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The XPath object model to use" },
-    "logNamespaces": { "kind": "attribute", "displayName": "Log Namespaces", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to log namespaces which can assist during trouble shooting" },
+    "logNamespaces": { "kind": "attribute", "displayName": "Log Namespaces", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to log namespaces which can assist during troubleshooting" },
     "headerName": { "kind": "attribute", "displayName": "Header Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body" },
     "threadSafety": { "kind": "attribute", "displayName": "Thread Safety", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable thread-safety for the returned result of the xpath expression. This applies to when using NODESET as the result type, and the returned set has multiple elements. In this situation there can be thread-safety issues if you process th [...]
     "preCompile": { "kind": "attribute", "displayName": "Pre Compile", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to enable pre-compiling the xpath expression during initialization phase. pre-compile is enabled by default. This can be used to turn off, for example in cases the compilation phase is desired at the starting phase, such as if the application is  [...]
diff --git a/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPath.java b/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPath.java
index 48a1352..922259f 100644
--- a/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPath.java
+++ b/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPath.java
@@ -58,4 +58,20 @@ public @interface XPath {
      * be applied to the body instead.
      */
     String headerName() default "";
+
+    /**
+     * Whether to log namespaces which can assist during troubleshooting
+     */
+    boolean logNamespaces() default false;
+
+    /**
+     * Whether to enable pre-compiling the xpath expression during initialization phase. pre-compile is enabled by
+     * default.
+     *
+     * This can be used to turn off, for example in cases the compilation phase is desired at the starting phase, such
+     * as if the application is ahead of time compiled (for example with camel-quarkus) which would then load the xpath
+     * factory of the built operating system, and not a JVM runtime.
+     */
+    boolean preCompile() default true;
+
 }
diff --git a/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathAnnotationExpressionFactory.java b/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathAnnotationExpressionFactory.java
index d05d6b1..26aa250 100644
--- a/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathAnnotationExpressionFactory.java
+++ b/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathAnnotationExpressionFactory.java
@@ -42,6 +42,8 @@ public class XPathAnnotationExpressionFactory extends DefaultAnnotationExpressio
         }
 
         XPathBuilder builder = XPathBuilder.xpath(xpath, resultType);
+        builder.preCompile(isPreCompile(annotation));
+        builder.setLogNamespaces(isLogNamespaces(annotation));
         NamespacePrefix[] namespaces = getExpressionNameSpacePrefix(annotation);
         if (namespaces != null) {
             for (NamespacePrefix namespacePrefix : namespaces) {
@@ -71,7 +73,7 @@ public class XPathAnnotationExpressionFactory extends DefaultAnnotationExpressio
      * null if the annotation's method is not found.
      * 
      * @return If the annotation has the method 'header' then the name of the header we want to apply the XPath
-     *         expression to. Otherwise null will be returned
+     *         expression to. Otherwise, null will be returned
      */
     protected String getHeaderName(Annotation annotation) {
         String headerValue = null;
@@ -82,4 +84,24 @@ public class XPathAnnotationExpressionFactory extends DefaultAnnotationExpressio
         }
         return headerValue;
     }
+
+    protected boolean isLogNamespaces(Annotation annotation) {
+        // in case @XPath is extended in a custom annotation then it may not have the method
+        try {
+            return (boolean) getAnnotationObjectValue(annotation, "logNamespaces");
+        } catch (Exception e) {
+            // Do Nothing
+        }
+        return false;
+    }
+
+    protected boolean isPreCompile(Annotation annotation) {
+        // in case @XPath is extended in a custom annotation then it may not have the method
+        try {
+            return (boolean) getAnnotationObjectValue(annotation, "preCompile");
+        } catch (Exception e) {
+            // Do Nothing
+        }
+        return false;
+    }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/xpath.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/xpath.json
index 753269c..b5b3ab0 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/xpath.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/xpath.json
@@ -18,7 +18,7 @@
     "saxon": { "kind": "attribute", "displayName": "Saxon", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to use Saxon." },
     "factoryRef": { "kind": "attribute", "displayName": "Factory Ref", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "References to a custom XPathFactory to lookup in the registry" },
     "objectModel": { "kind": "attribute", "displayName": "Object Model", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The XPath object model to use" },
-    "logNamespaces": { "kind": "attribute", "displayName": "Log Namespaces", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to log namespaces which can assist during trouble shooting" },
+    "logNamespaces": { "kind": "attribute", "displayName": "Log Namespaces", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to log namespaces which can assist during troubleshooting" },
     "headerName": { "kind": "attribute", "displayName": "Header Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body" },
     "threadSafety": { "kind": "attribute", "displayName": "Thread Safety", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable thread-safety for the returned result of the xpath expression. This applies to when using NODESET as the result type, and the returned set has multiple elements. In this situation there can be thread-safety issues if you process th [...]
     "preCompile": { "kind": "attribute", "displayName": "Pre Compile", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to enable pre-compiling the xpath expression during initialization phase. pre-compile is enabled by default. This can be used to turn off, for example in cases the compilation phase is desired at the starting phase, such as if the application is  [...]
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/XPathExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/XPathExpression.java
index 2d7c987..e14cb7a 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/XPathExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/XPathExpression.java
@@ -168,7 +168,7 @@ public class XPathExpression extends NamespaceAwareExpression {
     }
 
     /**
-     * Whether to log namespaces which can assist during trouble shooting
+     * Whether to log namespaces which can assist during troubleshooting
      */
     public void setLogNamespaces(String logNamespaces) {
         this.logNamespaces = logNamespaces;
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/xslt/MyXPath.java b/core/camel-core/src/test/java/org/apache/camel/component/xslt/MyXPath.java
index 07ca1d2..a0d363f 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/xslt/MyXPath.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/xslt/MyXPath.java
@@ -17,7 +17,6 @@
 package org.apache.camel.component.xslt;
 
 // START SNIPPET: example
-// START SNIPPET: example
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/BeanWithXPathInjectionPreCompileTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/BeanWithXPathInjectionPreCompileTest.java
new file mode 100644
index 0000000..00586f3
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/BeanWithXPathInjectionPreCompileTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.processor;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.language.xpath.XPath;
+import org.apache.camel.spi.Registry;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class BeanWithXPathInjectionPreCompileTest extends ContextTestSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(BeanRouteTest.class);
+    protected MyBean myBean = new MyBean();
+
+    @Test
+    public void testSendMessage() throws Exception {
+        String expectedBody = "<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'><env:Body>"
+                              + "<foo>bar</foo></env:Body></env:Envelope>";
+
+        template.sendBodyAndHeader("direct:in", expectedBody, "foo", "bar");
+
+        assertEquals(expectedBody, myBean.body, "bean body: " + myBean);
+        assertEquals("bar", myBean.foo, "bean foo: " + myBean);
+    }
+
+    @Test
+    public void testSendTwoMessages() throws Exception {
+        // 1st message
+        String expectedBody = "<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'><env:Body>"
+                              + "<foo>bar</foo></env:Body></env:Envelope>";
+
+        template.sendBodyAndHeader("direct:in", expectedBody, "foo", "bar");
+
+        assertEquals(expectedBody, myBean.body, "bean body: " + myBean);
+        assertEquals("bar", myBean.foo, "bean foo: " + myBean);
+
+        // 2nd message
+        String expectedBody2 = "<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'><env:Body>"
+                               + "<foo>baz</foo></env:Body></env:Envelope>";
+
+        template.sendBodyAndHeader("direct:in", expectedBody2, "foo", "baz");
+
+        assertEquals(expectedBody2, myBean.body, "bean body: " + myBean);
+        assertEquals("baz", myBean.foo, "bean foo: " + myBean);
+    }
+
+    @Override
+    protected Registry createRegistry() throws Exception {
+        Registry answer = super.createRegistry();
+
+        answer.bind("myBean", myBean);
+        return answer;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:in").bean("myBean");
+            }
+        };
+    }
+
+    public static class MyBean {
+        public String body;
+        public String foo;
+
+        @Override
+        public String toString() {
+            return "MyBean[foo: " + foo + " body: " + body + "]";
+        }
+
+        public void read(String body, @XPath(value = "/soap:Envelope/soap:Body/foo/text()", preCompile = false) String foo) {
+            this.foo = foo;
+            this.body = body;
+            LOG.info("read() method called on " + this);
+        }
+    }
+}