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 3c11d29 CAMEL-15645: camel-saxon - Eager initialize and pre-compiled expression/builder. 3c11d29 is described below commit 3c11d296047ec21136172895bbe09ac8a430dea6 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Oct 6 14:14:58 2020 +0200 CAMEL-15645: camel-saxon - Eager initialize and pre-compiled expression/builder. --- .../camel/component/xquery/XQueryBuilder.java | 126 ++++++++++----------- .../camel/component/xquery/XQueryEndpoint.java | 17 ++- .../camel/language/xquery/XQueryLanguage.java | 1 - .../camel/builder/saxon/ParameterDynamicTest.java | 16 ++- .../org/apache/camel/builder/saxon/XQueryTest.java | 14 ++- .../xquery/XQueryStripWhitespaceTest.java | 4 + .../apache/camel/language/xpath/XPathLanguage.java | 1 - 7 files changed, 102 insertions(+), 77 deletions(-) diff --git a/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java b/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java index e18aa66..fd7f38a 100644 --- a/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java +++ b/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; import javax.xml.transform.Result; import javax.xml.transform.Source; @@ -68,6 +67,7 @@ import org.apache.camel.Message; import org.apache.camel.NoTypeConversionAvailableException; import org.apache.camel.Predicate; import org.apache.camel.Processor; +import org.apache.camel.RuntimeCamelException; import org.apache.camel.RuntimeExpressionException; import org.apache.camel.spi.NamespaceAware; import org.apache.camel.support.MessageHelper; @@ -95,7 +95,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA private ResultFormat resultsFormat = ResultFormat.DOM; private Properties properties = new Properties(); private Class<?> resultType; - private final AtomicBoolean initialized = new AtomicBoolean(); private boolean stripsAllWhiteSpace = true; private ModuleURIResolver moduleURIResolver; private boolean allowStAX; @@ -117,6 +116,44 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA @Override public void init(CamelContext context) { + // must use synchronized for concurrency issues and only let it initialize once + LOG.debug("Initializing XQueryBuilder {}", this); + if (configuration == null) { + configuration = new Configuration(); + configuration.getParseOptions().setSpaceStrippingRule(isStripsAllWhiteSpace() + ? AllElementsSpaceStrippingRule.getInstance() : IgnorableSpaceStrippingRule.getInstance()); + LOG.debug("Created new Configuration {}", configuration); + } else { + LOG.debug("Using existing Configuration {}", configuration); + } + + if (configurationProperties != null && !configurationProperties.isEmpty()) { + for (Map.Entry<String, Object> entry : configurationProperties.entrySet()) { + configuration.setConfigurationProperty(entry.getKey(), entry.getValue()); + } + } + staticQueryContext = getConfiguration().newStaticQueryContext(); + if (moduleURIResolver != null) { + staticQueryContext.setModuleURIResolver(moduleURIResolver); + } + + Set<Map.Entry<String, String>> entries = namespacePrefixes.entrySet(); + for (Map.Entry<String, String> entry : entries) { + String prefix = entry.getKey(); + String uri = entry.getValue(); + // skip invalid prefix or uri according to XQuery spec + boolean invalid = "xml".equals(prefix) || "xmlns".equals(prefix); + if (!invalid) { + LOG.debug("Declaring namespace [prefix: {}, uri: {}]", prefix, uri); + staticQueryContext.declareNamespace(prefix, uri); + staticQueryContext.setInheritNamespaces(true); + } + } + try { + expression = createQueryExpression(staticQueryContext); + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeException(e); + } } @Override @@ -162,14 +199,12 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public List<?> evaluateAsList(Exchange exchange) throws Exception { LOG.debug("evaluateAsList: {} for exchange: {}", expression, exchange); - initialize(exchange); return getExpression().evaluate(createDynamicContext(exchange)); } public Object evaluateAsStringSource(Exchange exchange) throws Exception { LOG.debug("evaluateAsString: {} for exchange: {}", expression, exchange); - initialize(exchange); String text = evaluateAsString(exchange); return new StringSource(text); @@ -177,7 +212,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public Object evaluateAsBytesSource(Exchange exchange) throws Exception { LOG.debug("evaluateAsBytesSource: {} for exchange: {}", expression, exchange); - initialize(exchange); byte[] bytes = evaluateAsBytes(exchange); return new BytesSource(bytes); @@ -185,7 +219,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public Node evaluateAsDOM(Exchange exchange) throws Exception { LOG.debug("evaluateAsDOM: {} for exchange: {}", expression, exchange); - initialize(exchange); DOMResult result = new DOMResult(); DynamicQueryContext context = createDynamicContext(exchange); @@ -196,7 +229,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public byte[] evaluateAsBytes(Exchange exchange) throws Exception { LOG.debug("evaluateAsBytes: {} for exchange: {}", expression, exchange); - initialize(exchange); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); Result result = new StreamResult(buffer); @@ -209,7 +241,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public String evaluateAsString(Exchange exchange) throws Exception { LOG.debug("evaluateAsString: {} for exchange: {}", expression, exchange); - initialize(exchange); StringWriter buffer = new StringWriter(); SequenceIterator iter = getExpression().iterator(createDynamicContext(exchange)); @@ -250,6 +281,12 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA // Static helper methods //------------------------------------------------------------------------- + + /** + * Creates a new {@link XQueryBuilder} to evaluate against the expression from the string. + * + * Important: The builder must be initialized before use. + */ public static XQueryBuilder xquery(final String queryText) { return new XQueryBuilder() { protected XQueryExpression createQueryExpression(StaticQueryContext staticQueryContext) @@ -259,6 +296,11 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA }; } + /** + * Creates a new {@link XQueryBuilder} to evaluate against the expression loaded from the reader. + * + * Important: The builder must be initialized before use. + */ public static XQueryBuilder xquery(final Reader reader) { return new XQueryBuilder() { protected XQueryExpression createQueryExpression(StaticQueryContext staticQueryContext) @@ -272,6 +314,11 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA }; } + /** + * Creates a new {@link XQueryBuilder} to evaluate against the expression loaded from the input stream. + * + * Important: The builder must be initialized before use. + */ public static XQueryBuilder xquery(final InputStream in, final String characterSet) { return new XQueryBuilder() { protected XQueryExpression createQueryExpression(StaticQueryContext staticQueryContext) @@ -285,6 +332,11 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA }; } + /** + * Creates a new {@link XQueryBuilder} to evaluate against the expression loaded from the input stream. + * + * Important: The builder must be initialized before use. + */ public static XQueryBuilder xquery(final InputStream in) { return new XQueryBuilder() { protected XQueryExpression createQueryExpression(StaticQueryContext staticQueryContext) @@ -307,8 +359,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public XQueryBuilder namespace(String prefix, String uri) { namespacePrefixes.put(prefix, uri); - // more namespace, we must re initialize - initialized.set(false); return this; } @@ -381,8 +431,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA @Override public void setNamespaces(Map<String, String> namespaces) { namespacePrefixes.putAll(namespaces); - // more namespace, we must re initialize - initialized.set(false); } @Override @@ -400,8 +448,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public void setConfiguration(Configuration configuration) { this.configuration = configuration; - // change configuration, we must re initialize - initialized.set(false); } public Map<String, Object> getConfigurationProperties() { @@ -410,8 +456,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public void setConfigurationProperties(Map<String, Object> configurationProperties) { this.configurationProperties = Collections.unmodifiableMap(new HashMap<>(configurationProperties)); - // change configuration, we must re initialize - initialized.set(false); } public StaticQueryContext getStaticQueryContext() { @@ -420,8 +464,6 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA public void setStaticQueryContext(StaticQueryContext staticQueryContext) { this.staticQueryContext = staticQueryContext; - // change context, we must re initialize - initialized.set(false); } public Map<String, Object> getParameters() { @@ -685,52 +727,4 @@ public abstract class XQueryBuilder implements Expression, Predicate, NamespaceA return ObjectHelper.matches(results); } - /** - * Initializes this builder - <b>Must be invoked before evaluation</b>. - */ - protected synchronized void initialize(Exchange exchange) throws XPathException, IOException { - // must use synchronized for concurrency issues and only let it initialize once - if (!initialized.get()) { - LOG.debug("Initializing XQueryBuilder {}", this); - if (configuration == null) { - configuration = new Configuration(); - configuration.getParseOptions().setSpaceStrippingRule(isStripsAllWhiteSpace() - ? AllElementsSpaceStrippingRule.getInstance() : IgnorableSpaceStrippingRule.getInstance()); - LOG.debug("Created new Configuration {}", configuration); - } else { - LOG.debug("Using existing Configuration {}", configuration); - } - - if (configurationProperties != null && !configurationProperties.isEmpty()) { - for (Map.Entry<String, Object> entry : configurationProperties.entrySet()) { - configuration.setConfigurationProperty(entry.getKey(), entry.getValue()); - } - } - staticQueryContext = getConfiguration().newStaticQueryContext(); - if (moduleURIResolver != null) { - staticQueryContext.setModuleURIResolver(moduleURIResolver); - } - - Set<Map.Entry<String, String>> entries = namespacePrefixes.entrySet(); - for (Map.Entry<String, String> entry : entries) { - String prefix = entry.getKey(); - String uri = entry.getValue(); - // skip invalid prefix or uri according to XQuery spec - boolean invalid = "xml".equals(prefix) || "xmlns".equals(prefix); - if (!invalid) { - LOG.debug("Declaring namespace [prefix: {}, uri: {}]", prefix, uri); - staticQueryContext.declareNamespace(prefix, uri); - staticQueryContext.setInheritNamespaces(true); - } - } - expression = createQueryExpression(staticQueryContext); - - initialized.set(true); - } - - // let the configuration be accessible on the exchange as its shared for this evaluation - // and can be needed by 3rd party type converters or other situations (camel-artixds) - exchange.setProperty("CamelSaxonConfiguration", configuration); - } - } diff --git a/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryEndpoint.java b/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryEndpoint.java index c7bfc49..dcc2a18 100644 --- a/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryEndpoint.java +++ b/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryEndpoint.java @@ -223,9 +223,23 @@ public class XQueryEndpoint extends ProcessorEndpoint { } @Override + protected void doInit() throws Exception { + super.doInit(); + if (ResourceHelper.isClasspathUri(resourceUri)) { + doInitXQuery(); + } + } + + @Override protected void doStart() throws Exception { super.doStart(); + if (!ResourceHelper.isClasspathUri(resourceUri)) { + doInitXQuery(); + } + ServiceHelper.startService(xquery); + } + protected void doInitXQuery() throws Exception { LOG.debug("{} using schema resource: {}", this, resourceUri); InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(getCamelContext(), resourceUri); @@ -242,10 +256,9 @@ public class XQueryEndpoint extends ProcessorEndpoint { this.xquery.setAllowStAX(isAllowStAX()); this.xquery.setHeaderName(getHeaderName()); this.xquery.setModuleURIResolver(getModuleURIResolver()); + this.xquery.init(getCamelContext()); setProcessor(xquery); - - ServiceHelper.startService(xquery); } @Override diff --git a/components/camel-saxon/src/main/java/org/apache/camel/language/xquery/XQueryLanguage.java b/components/camel-saxon/src/main/java/org/apache/camel/language/xquery/XQueryLanguage.java index 30e6814..8b9b017 100644 --- a/components/camel-saxon/src/main/java/org/apache/camel/language/xquery/XQueryLanguage.java +++ b/components/camel-saxon/src/main/java/org/apache/camel/language/xquery/XQueryLanguage.java @@ -91,7 +91,6 @@ public class XQueryLanguage extends LanguageSupport { if (headerName != null) { builder.setHeaderName(headerName); } - builder.init(getCamelContext()); } } diff --git a/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/ParameterDynamicTest.java b/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/ParameterDynamicTest.java index 9788114..7e6957c 100644 --- a/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/ParameterDynamicTest.java +++ b/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/ParameterDynamicTest.java @@ -23,7 +23,9 @@ import net.sf.saxon.query.DynamicQueryContext; import net.sf.saxon.query.XQueryExpression; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.ObjectValue; +import org.apache.camel.CamelContext; import org.apache.camel.Exchange; +import org.apache.camel.component.xquery.XQueryBuilder; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.support.DefaultExchange; import org.junit.jupiter.api.BeforeEach; @@ -82,15 +84,23 @@ public class ParameterDynamicTest { @Test public void testXQueryBuilder() throws Exception { - Exchange exchange = new DefaultExchange(new DefaultCamelContext()); + CamelContext context = new DefaultCamelContext(); + context.start(); + + Exchange exchange = new DefaultExchange(context); exchange.getIn().setBody("<foo><bar>abc_def_ghi</bar></foo>"); exchange.setProperty("extParam", true); - Object result = xquery(TEST_QUERY).asString().evaluate(exchange, boolean.class); + XQueryBuilder xquery = xquery(TEST_QUERY); + xquery.init(context); + + Object result = xquery.asString().evaluate(exchange, boolean.class); assertEquals(true, result); exchange.setProperty("extParam", false); - result = xquery(TEST_QUERY).asString().evaluate(exchange, boolean.class); + result = xquery.evaluate(exchange, boolean.class); assertEquals(false, result); + + context.stop(); } } diff --git a/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XQueryTest.java b/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XQueryTest.java index bfdd778..7592d59 100644 --- a/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XQueryTest.java +++ b/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XQueryTest.java @@ -18,7 +18,9 @@ package org.apache.camel.builder.saxon; import org.w3c.dom.Document; +import org.apache.camel.CamelContext; import org.apache.camel.Exchange; +import org.apache.camel.component.xquery.XQueryBuilder; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.support.DefaultExchange; import org.junit.jupiter.api.Test; @@ -31,18 +33,22 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class XQueryTest { @Test public void testXQuery() throws Exception { - Exchange exchange = new DefaultExchange(new DefaultCamelContext()); + CamelContext context = new DefaultCamelContext(); + context.start(); + + Exchange exchange = new DefaultExchange(context); exchange.getIn().setBody( "<products><product type='food'><pizza/></product><product type='beer'><stella/></product></products>"); - Object result = xquery(".//product[@type = 'beer']/*").evaluate(exchange, Object.class); + XQueryBuilder xquery = xquery(".//product[@type = 'beer']/*"); + xquery.init(context); + Object result = xquery.evaluate(exchange, Object.class); assertTrue(result instanceof Document, "Should be a document but was: " + className(result)); - Document doc = (Document) result; assertEquals("stella", doc.getDocumentElement().getLocalName(), "Root document element name"); - result = xquery(".//product[@type = 'beer']/*").evaluate(exchange, String.class); + result = xquery.evaluate(exchange, String.class); assertEquals("<stella/>", result, "Get a wrong result"); } } diff --git a/components/camel-saxon/src/test/java/org/apache/camel/component/xquery/XQueryStripWhitespaceTest.java b/components/camel-saxon/src/test/java/org/apache/camel/component/xquery/XQueryStripWhitespaceTest.java index 970559a..c9cd016 100644 --- a/components/camel-saxon/src/test/java/org/apache/camel/component/xquery/XQueryStripWhitespaceTest.java +++ b/components/camel-saxon/src/test/java/org/apache/camel/component/xquery/XQueryStripWhitespaceTest.java @@ -39,6 +39,8 @@ public class XQueryStripWhitespaceTest extends CamelTestSupport { exchange.getIn().setBody(new File("src/test/resources/payload.xml")); XQueryBuilder xquery = XQueryBuilder.xquery("//payload").asString().stripsAllWhiteSpace(); + xquery.init(context); + Object result = xquery.evaluate(exchange); assertNotNull(result); assertEquals("012010-10-04JohnDoeThis is a test reportserver is downsomeone@somewhere.com12345678", result); @@ -50,6 +52,8 @@ public class XQueryStripWhitespaceTest extends CamelTestSupport { exchange.getIn().setBody(new File("src/test/resources/payload.xml")); XQueryBuilder xquery = XQueryBuilder.xquery("//payload").asString().stripsIgnorableWhiteSpace(); + xquery.init(context); + String result = xquery.evaluate(exchange, String.class); assertNotNull(result); 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 3b9deb0..315a9bf 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 @@ -198,7 +198,6 @@ public class XPathLanguage extends LanguageSupport { builder.setObjectModelUri(objectModelUri); } } - builder.init(getCamelContext()); } }