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 2020/10/06 16:55:08 UTC

[camel] branch master updated: CAMEL-15643: camel-xpath - Add option to pre-compile xpath expression

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


The following commit(s) were added to refs/heads/master by this push:
     new e6a5226  CAMEL-15643: camel-xpath - Add option to pre-compile xpath expression
e6a5226 is described below

commit e6a5226f5428dfd0f7b8fc28ef5855e5b081c343
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Oct 6 17:15:53 2020 +0200

    CAMEL-15643: camel-xpath - Add option to pre-compile xpath expression
---
 .../apache/camel/catalog/docs/xpath-language.adoc  |  3 +-
 .../org/apache/camel/language/xpath/xpath.json     |  1 +
 .../camel-xpath/src/main/docs/xpath-language.adoc  |  3 +-
 .../apache/camel/language/xpath/XPathBuilder.java  | 43 ++++++++++++++++++----
 .../apache/camel/language/xpath/XPathLanguage.java | 17 +++++++++
 .../org/apache/camel/model/language/xpath.json     |  1 +
 .../camel/model/language/XPathExpression.java      | 19 ++++++++++
 .../reifier/language/XPathExpressionReifier.java   |  3 +-
 .../org/apache/camel/builder/xml/XPathTest.java    |  4 +-
 .../java/org/apache/camel/xml/in/ModelParser.java  |  1 +
 .../modules/languages/pages/xpath-language.adoc    |  3 +-
 11 files changed, 84 insertions(+), 14 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/xpath-language.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/xpath-language.adoc
index 3404897..049480c 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/xpath-language.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/xpath-language.adoc
@@ -45,7 +45,7 @@ from("queue:foo").
 == XPath Language options
 
 // language options: START
-The XPath language supports 9 options, which are listed below.
+The XPath language supports 10 options, which are listed below.
 
 
 
@@ -60,6 +60,7 @@ The XPath language supports 9 options, which are listed below.
 | logNamespaces | false | Boolean | Whether to log namespaces which can assist during trouble shooting
 | headerName |  | String | Name of header to use as input, instead of the message body
 | threadSafety | false | Boolean | 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 the NODESET concurrently such as from a Camel Splitter EIP in parallel processing mode. This option prevents concurrency issues by doing defensive copies of the nodes. It is recommended to turn this option on i [...]
+| preCompile | true | Boolean | 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 pre-built with graalvm which would then load the xpath factory of the built operating system, and not a JVM runtime.
 | trim | true | Boolean | Whether to trim the value to remove leading and trailing whitespaces and line breaks
 |===
 // language options: END
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 57287f4..e5b94c1 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
@@ -25,6 +25,7 @@
     "logNamespaces": { "kind": "attribute", "displayName": "Log Namespaces", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Whether to log namespaces which can assist during trouble shooting" },
     "headerName": { "kind": "attribute", "displayName": "Header Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": 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, "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 the NODESET concurrent [...]
+    "preCompile": { "kind": "attribute", "displayName": "Pre Compile", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": 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 pre-built with graal [...]
     "trim": { "kind": "attribute", "displayName": "Trim", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" },
     "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "description": "Sets the id of this node" }
   }
diff --git a/components/camel-xpath/src/main/docs/xpath-language.adoc b/components/camel-xpath/src/main/docs/xpath-language.adoc
index 3404897..049480c 100644
--- a/components/camel-xpath/src/main/docs/xpath-language.adoc
+++ b/components/camel-xpath/src/main/docs/xpath-language.adoc
@@ -45,7 +45,7 @@ from("queue:foo").
 == XPath Language options
 
 // language options: START
-The XPath language supports 9 options, which are listed below.
+The XPath language supports 10 options, which are listed below.
 
 
 
@@ -60,6 +60,7 @@ The XPath language supports 9 options, which are listed below.
 | logNamespaces | false | Boolean | Whether to log namespaces which can assist during trouble shooting
 | headerName |  | String | Name of header to use as input, instead of the message body
 | threadSafety | false | Boolean | 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 the NODESET concurrently such as from a Camel Splitter EIP in parallel processing mode. This option prevents concurrency issues by doing defensive copies of the nodes. It is recommended to turn this option on i [...]
+| preCompile | true | Boolean | 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 pre-built with graalvm which would then load the xpath factory of the built operating system, and not a JVM runtime.
 | trim | true | Boolean | Whether to trim the value to remove leading and trailing whitespaces and line breaks
 |===
 // language options: END
diff --git a/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathBuilder.java b/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathBuilder.java
index 42e2ee3..66d7985 100644
--- a/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathBuilder.java
+++ b/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathBuilder.java
@@ -71,11 +71,7 @@ import org.apache.camel.util.StringHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.camel.support.builder.Namespaces.DEFAULT_NAMESPACE;
-import static org.apache.camel.support.builder.Namespaces.FUNCTION_NAMESPACE;
-import static org.apache.camel.support.builder.Namespaces.IN_NAMESPACE;
-import static org.apache.camel.support.builder.Namespaces.OUT_NAMESPACE;
-import static org.apache.camel.support.builder.Namespaces.isMatchingNamespaceOrEmptyNamespace;
+import static org.apache.camel.support.builder.Namespaces.*;
 
 /**
  * Creates an XPath expression builder which creates a nodeset result by default. If you want to evaluate a String
@@ -109,6 +105,7 @@ public class XPathBuilder extends ServiceSupport
     private final ThreadLocal<Exchange> exchange = new ThreadLocal<>();
     private final MessageVariableResolver variableResolver = new MessageVariableResolver(exchange);
     private final Map<String, String> namespaces = new ConcurrentHashMap<>();
+    private boolean preCompile = true;
     private boolean threadSafety;
     private volatile XPathFactory xpathFactory;
     private volatile Class<?> documentType = Document.class;
@@ -166,6 +163,15 @@ public class XPathBuilder extends ServiceSupport
 
     @Override
     public void init(CamelContext context) {
+        if (preCompile) {
+            LOG.trace("PreCompiling new XPathExpression and adding to pool during initialization");
+            try {
+                XPathExpression xpathExpression = createXPathExpression();
+                pool.add(xpathExpression);
+            } catch (XPathExpressionException e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
+        }
     }
 
     @Override
@@ -496,6 +502,21 @@ public class XPathBuilder extends ServiceSupport
         return this;
     }
 
+    /**
+     * 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 pre-built with graalvm which would then load the xpath factory of the built operating
+     * system, and not a JVM runtime.
+     *
+     * @return the current builder.
+     */
+    public XPathBuilder preCompile(boolean preCompile) {
+        setPreCompile(preCompile);
+        return this;
+    }
+
     // Properties
     // -------------------------------------------------------------------------
 
@@ -551,6 +572,14 @@ public class XPathBuilder extends ServiceSupport
         this.threadSafety = threadSafety;
     }
 
+    public boolean isPreCompile() {
+        return preCompile;
+    }
+
+    public void setPreCompile(boolean preCompile) {
+        this.preCompile = preCompile;
+    }
+
     /**
      * Gets the namespace context, can be <tt>null</tt> if no custom context has been assigned.
      * <p/>
@@ -1078,7 +1107,7 @@ public class XPathBuilder extends ServiceSupport
      * started prior to being used.
      */
     protected synchronized XPathExpression createXPathExpression()
-            throws XPathExpressionException, XPathFactoryConfigurationException {
+            throws XPathExpressionException {
         // ensure we are started
         try {
             start();
@@ -1106,7 +1135,7 @@ public class XPathBuilder extends ServiceSupport
     }
 
     protected synchronized XPathExpression createTraceNamespaceExpression()
-            throws XPathFactoryConfigurationException, XPathExpressionException {
+            throws XPathExpressionException {
         // XPathFactory is not thread safe
         XPath xPath = getXPathFactory().newXPath();
         return xPath.compile(OBTAIN_ALL_NS_XPATH);
diff --git a/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java b/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java
index 315a9bf..f896b63 100644
--- a/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java
+++ b/components/camel-xpath/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java
@@ -40,6 +40,7 @@ public class XPathLanguage extends LanguageSupport {
     private Boolean threadSafety;
     private Boolean logNamespaces;
     private String headerName;
+    private Boolean preCompile;
 
     @Override
     public Predicate createPredicate(String expression) {
@@ -81,6 +82,7 @@ public class XPathLanguage extends LanguageSupport {
             setResultQName(qname);
         }
         setUseSaxon(property(Boolean.class, properties, "useSaxon", useSaxon));
+        setPreCompile(property(Boolean.class, properties, "preCompile", preCompile));
         setObjectModelUri(property(String.class, properties, "objectModelUri", objectModelUri));
         setThreadSafety(property(Boolean.class, properties, "threadSafety", threadSafety));
         setLogNamespaces(property(Boolean.class, properties, "logNamespaces", logNamespaces));
@@ -168,7 +170,22 @@ public class XPathLanguage extends LanguageSupport {
         return useSaxon != null && useSaxon;
     }
 
+    public Boolean getPreCompile() {
+        return preCompile;
+    }
+
+    public void setPreCompile(Boolean preCompile) {
+        this.preCompile = preCompile;
+    }
+
+    private boolean isPreCompile() {
+        return preCompile != null && preCompile;
+    }
+
     protected void configureBuilder(XPathBuilder builder) {
+        if (preCompile != null) {
+            builder.setPreCompile(preCompile);
+        }
         if (threadSafety != null) {
             builder.setThreadSafety(threadSafety);
         }
diff --git a/core/camel-core-engine/src/generated/resources/org/apache/camel/model/language/xpath.json b/core/camel-core-engine/src/generated/resources/org/apache/camel/model/language/xpath.json
index 314a15d..0f740d5 100644
--- a/core/camel-core-engine/src/generated/resources/org/apache/camel/model/language/xpath.json
+++ b/core/camel-core-engine/src/generated/resources/org/apache/camel/model/language/xpath.json
@@ -21,6 +21,7 @@
     "logNamespaces": { "kind": "attribute", "displayName": "Log Namespaces", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Whether to log namespaces which can assist during trouble shooting" },
     "headerName": { "kind": "attribute", "displayName": "Header Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": 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, "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 the NODESET concurrent [...]
+    "preCompile": { "kind": "attribute", "displayName": "Pre Compile", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": 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 pre-built with graal [...]
     "trim": { "kind": "attribute", "displayName": "Trim", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" },
     "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "description": "Sets the id of this node" }
   }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/language/XPathExpression.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/language/XPathExpression.java
index d2c8ef4..b7618bb 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/language/XPathExpression.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/language/XPathExpression.java
@@ -64,6 +64,9 @@ public class XPathExpression extends NamespaceAwareExpression {
     @XmlAttribute
     @Metadata(label = "advanced", javaType = "java.lang.Boolean")
     private String threadSafety;
+    @XmlAttribute
+    @Metadata(label = "advanced", javaType = "java.lang.Boolean", defaultValue = "true")
+    private String preCompile;
 
     public XPathExpression() {
     }
@@ -213,6 +216,22 @@ public class XPathExpression extends NamespaceAwareExpression {
         this.threadSafety = threadSafety;
     }
 
+    public String getPreCompile() {
+        return preCompile;
+    }
+
+    /**
+     * 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 pre-built with graalvm which would then load the xpath factory of the built operating
+     * system, and not a JVM runtime.
+     */
+    public void setPreCompile(String preCompile) {
+        this.preCompile = preCompile;
+    }
+
     private void resolveXPathFactory(CamelContext camelContext) {
         // Factory and Object Model can be set simultaneously. The underlying
         // XPathBuilder allows for setting Saxon too, as it is simply a shortcut
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/XPathExpressionReifier.java b/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/XPathExpressionReifier.java
index 6292a83..ead649e 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/XPathExpressionReifier.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/XPathExpressionReifier.java
@@ -66,7 +66,7 @@ public class XPathExpressionReifier extends ExpressionReifier<XPathExpression> {
     }
 
     protected Map<String, Object> createProperties() {
-        Map<String, Object> properties = new HashMap<>(9);
+        Map<String, Object> properties = new HashMap<>(10);
         properties.put("documentType", definition.getDocumentType());
         // resultType can either point to a QName or it can be a regular class that influence the qname
         // so we need this special logic to set resultQName and resultType accordingly
@@ -81,6 +81,7 @@ public class XPathExpressionReifier extends ExpressionReifier<XPathExpression> {
         properties.put("xpathFactory", definition.getXPathFactory());
         properties.put("objectModelUri", parseString(definition.getObjectModel()));
         properties.put("threadSafety", parseBoolean(definition.getThreadSafety()));
+        properties.put("preCompile", parseBoolean(definition.getPreCompile()));
         properties.put("logNamespaces", parseBoolean(definition.getLogNamespaces()));
         properties.put("headerName", parseString(definition.getHeaderName()));
         return properties;
diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java
index 2e4a077..88c52fc 100644
--- a/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java
@@ -41,7 +41,6 @@ import org.apache.camel.ContextTestSupport;
 import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.Predicate;
-import org.apache.camel.language.xpath.InvalidXPathException;
 import org.apache.camel.language.xpath.XPathBuilder;
 import org.apache.camel.support.builder.Namespaces;
 import org.apache.camel.util.StringHelper;
@@ -86,8 +85,7 @@ public class XPathTest extends ContextTestSupport {
         try {
             assertPredicate("/foo/", "<foo><bar xyz='cheese'/></foo>", true);
             fail("Should have thrown exception");
-        } catch (InvalidXPathException e) {
-            assertEquals("/foo/", e.getXpath());
+        } catch (Exception e) {
             assertIsInstanceOf(XPathExpressionException.class, e.getCause());
         }
     }
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 394b9a3..7e99db4 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -2443,6 +2443,7 @@ public class ModelParser extends BaseParser {
                 case "headerName": def.setHeaderName(val); break;
                 case "logNamespaces": def.setLogNamespaces(val); break;
                 case "objectModel": def.setObjectModel(val); break;
+                case "preCompile": def.setPreCompile(val); break;
                 case "resultType": def.setResultTypeName(val); break;
                 case "saxon": def.setSaxon(val); break;
                 case "threadSafety": def.setThreadSafety(val); break;
diff --git a/docs/components/modules/languages/pages/xpath-language.adoc b/docs/components/modules/languages/pages/xpath-language.adoc
index 60dbea7..11b3a9b 100644
--- a/docs/components/modules/languages/pages/xpath-language.adoc
+++ b/docs/components/modules/languages/pages/xpath-language.adoc
@@ -47,7 +47,7 @@ from("queue:foo").
 == XPath Language options
 
 // language options: START
-The XPath language supports 9 options, which are listed below.
+The XPath language supports 10 options, which are listed below.
 
 
 
@@ -62,6 +62,7 @@ The XPath language supports 9 options, which are listed below.
 | logNamespaces | false | Boolean | Whether to log namespaces which can assist during trouble shooting
 | headerName |  | String | Name of header to use as input, instead of the message body
 | threadSafety | false | Boolean | 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 the NODESET concurrently such as from a Camel Splitter EIP in parallel processing mode. This option prevents concurrency issues by doing defensive copies of the nodes. It is recommended to turn this option on i [...]
+| preCompile | true | Boolean | 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 pre-built with graalvm which would then load the xpath factory of the built operating system, and not a JVM runtime.
 | trim | true | Boolean | Whether to trim the value to remove leading and trailing whitespaces and line breaks
 |===
 // language options: END