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 2023/05/24 04:25:18 UTC

[camel] branch camel-3.x updated: CAMEL-19383: camel-jslt allowTemplateFromHeader bug (#10194)

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

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


The following commit(s) were added to refs/heads/camel-3.x by this push:
     new 04a1e5b57c0 CAMEL-19383: camel-jslt allowTemplateFromHeader bug (#10194)
04a1e5b57c0 is described below

commit 04a1e5b57c006831f8a496c65685a7ade6e516b7
Author: jacekszymanski <ja...@gmail.com>
AuthorDate: Wed May 24 06:25:11 2023 +0200

    CAMEL-19383: camel-jslt allowTemplateFromHeader bug (#10194)
    
    * test case for CAMEL-19383
    
    * two more test cases for the bug
    
    * fix JsltEndpoint
---
 .../apache/camel/component/jslt/JsltEndpoint.java  | 84 ++++++++++++--------
 .../component/jslt/JsltTemplateFromHeaderTest.java | 89 ++++++++++++++++++++++
 .../component/jslt/simple/transformation.jslt      |  1 +
 3 files changed, 143 insertions(+), 31 deletions(-)

diff --git a/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltEndpoint.java b/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltEndpoint.java
index f95d1d6ca1c..11e3cbb4246 100644
--- a/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltEndpoint.java
+++ b/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltEndpoint.java
@@ -16,16 +16,18 @@
  */
 package org.apache.camel.component.jslt;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.Serializable;
-import java.io.StringReader;
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 import com.fasterxml.jackson.databind.BeanDescription;
 import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -40,6 +42,7 @@ import com.schibsted.spt.data.jslt.Expression;
 import com.schibsted.spt.data.jslt.Function;
 import com.schibsted.spt.data.jslt.JsltException;
 import com.schibsted.spt.data.jslt.Parser;
+import com.schibsted.spt.data.jslt.filters.DefaultJsonFilter;
 import com.schibsted.spt.data.jslt.filters.JsonFilter;
 import org.apache.camel.Category;
 import org.apache.camel.Exchange;
@@ -63,6 +66,7 @@ import org.apache.camel.util.ObjectHelper;
 public class JsltEndpoint extends ResourceEndpoint {
 
     private static final ObjectMapper OBJECT_MAPPER;
+    private static final JsonFilter DEFAULT_JSON_FILTER = new DefaultJsonFilter();
 
     static {
         OBJECT_MAPPER = new ObjectMapper();
@@ -99,41 +103,59 @@ public class JsltEndpoint extends ResourceEndpoint {
     }
 
     private synchronized Expression getTransform(Message msg) throws Exception {
-        if (transform == null) {
+        final String jsltStringFromHeader
+                = allowTemplateFromHeader ? msg.getHeader(JsltConstants.HEADER_JSLT_STRING, String.class) : null;
+
+        final boolean useTemplateFromUri = jsltStringFromHeader == null;
+
+        if (useTemplateFromUri && transform != null) {
+            return transform;
+        }
+
+        final Collection<Function> functions = Objects.requireNonNullElse(
+                ((JsltComponent) getComponent()).getFunctions(),
+                Collections.emptyList());
+
+        final JsonFilter objectFilter = Objects.requireNonNullElse(
+                ((JsltComponent) getComponent()).getObjectFilter(),
+                DEFAULT_JSON_FILTER);
+
+        final String transformSource;
+        final InputStream stream;
+
+        if (useTemplateFromUri) {
+            transformSource = getResourceUri();
+
             if (log.isDebugEnabled()) {
-                String path = getResourceUri();
-                log.debug("Jslt content read from resource {} with resourceUri: {} for endpoint {}", getResourceUri(), path,
+                log.debug("Jslt content read from resource {} with resourceUri: {} for endpoint {}",
+                        transformSource,
+                        transformSource,
                         getEndpointUri());
             }
 
-            String jsltStringFromHeader
-                    = allowTemplateFromHeader ? msg.getHeader(JsltConstants.HEADER_JSLT_STRING, String.class) : null;
-            Collection<Function> functions = ((JsltComponent) getComponent()).getFunctions();
-            JsonFilter objectFilter = ((JsltComponent) getComponent()).getObjectFilter();
-
-            Parser parser;
-            InputStream stream = null;
-            try {
-                if (jsltStringFromHeader != null) {
-                    parser = new Parser(new StringReader(jsltStringFromHeader)).withSource("<inline>");
-                } else {
-                    stream = ResourceHelper.resolveMandatoryResourceAsInputStream(getCamelContext(), getResourceUri());
-                    if (stream == null) {
-                        throw new JsltException("Cannot load resource '" + getResourceUri() + "': not found");
-                    }
-                    Reader reader = new InputStreamReader(stream, StandardCharsets.UTF_8);
-                    parser = new Parser(reader).withSource(getResourceUri());
-                }
-                if (functions != null) {
-                    parser = parser.withFunctions(functions);
-                }
-                if (objectFilter != null) {
-                    parser = parser.withObjectFilter(objectFilter);
-                }
-                this.transform = parser.compile();
-            } finally {
-                IOHelper.close(stream);
+            stream = ResourceHelper.resolveMandatoryResourceAsInputStream(getCamelContext(), transformSource);
+            if (stream == null) {
+                throw new JsltException("Cannot load resource '" + transformSource + "': not found");
             }
+        } else { // use template from header
+            stream = new ByteArrayInputStream(jsltStringFromHeader.getBytes(StandardCharsets.UTF_8));
+            transformSource = "<inline>";
+        }
+
+        final Expression transform;
+        try {
+            transform = new Parser(new InputStreamReader(stream))
+                    .withFunctions(functions)
+                    .withObjectFilter(objectFilter)
+                    .withSource(transformSource)
+                    .compile();
+        } finally {
+            // the stream is consumed only on .compile(), cannot be closed before
+            IOHelper.close(stream);
+        }
+
+        if (useTemplateFromUri) {
+            this.transform = transform;
         }
         return transform;
     }
diff --git a/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltTemplateFromHeaderTest.java b/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltTemplateFromHeaderTest.java
new file mode 100644
index 00000000000..80dc4ab2e56
--- /dev/null
+++ b/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltTemplateFromHeaderTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.component.jslt;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+public class JsltTemplateFromHeaderTest extends CamelTestSupport {
+
+    private static final String TEST_BODY = "{ \"foo\": \"foo\", \"bar\": \"bar\" }";
+
+    @Test
+    public void testTemplateInHeaderOnMoreExchanges() throws Exception {
+        getMockEndpoint("mock:result").expectedMinimumMessageCount(2);
+        getMockEndpoint("mock:result").expectedBodiesReceived(
+                "\"foo\"",
+                "\"bar\"");
+
+        template.sendBodyAndHeader("direct:start", TEST_BODY,
+                JsltConstants.HEADER_JSLT_STRING, ".foo");
+
+        template.sendBodyAndHeader("direct:start", TEST_BODY,
+                JsltConstants.HEADER_JSLT_STRING, ".bar");
+
+        MockEndpoint.assertIsSatisfied(context);
+
+    }
+
+    @Test
+    public void testTemplateInHeaderOverrideUri() throws Exception {
+        getMockEndpoint("mock:result").expectedMinimumMessageCount(2);
+        getMockEndpoint("mock:result").expectedBodiesReceived(
+                "\"foo\"",
+                "\"bar\"");
+
+        template.sendBody("direct:start", TEST_BODY);
+
+        template.sendBodyAndHeader("direct:start", TEST_BODY,
+                JsltConstants.HEADER_JSLT_STRING, ".bar");
+
+        MockEndpoint.assertIsSatisfied(context);
+
+    }
+
+    @Test
+    public void testTemplateInHeaderOverrideUriOnlyWhenSet() throws Exception {
+        getMockEndpoint("mock:result").expectedMinimumMessageCount(2);
+        getMockEndpoint("mock:result").expectedBodiesReceived(
+                "\"bar\"",
+                "\"foo\"");
+
+        template.sendBodyAndHeader("direct:start", TEST_BODY,
+                JsltConstants.HEADER_JSLT_STRING, ".bar");
+
+        template.sendBody("direct:start", TEST_BODY);
+
+        MockEndpoint.assertIsSatisfied(context);
+
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct://start")
+                        .to("jslt:org/apache/camel/component/jslt/simple/transformation.jslt?allowTemplateFromHeader=true")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/simple/transformation.jslt b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/simple/transformation.jslt
new file mode 100644
index 00000000000..1e8ea91de53
--- /dev/null
+++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/simple/transformation.jslt
@@ -0,0 +1 @@
+.foo