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 cbe77ef CAMEL-15120: camel-jslt - Use headers as variables in the jslt component (#3861) cbe77ef is described below commit cbe77efd081aa0775aa2985a0d5c7ef8427f3e95 Author: jflabatBCSS <65955832+jflabatb...@users.noreply.github.com> AuthorDate: Thu May 28 16:24:33 2020 +0200 CAMEL-15120: camel-jslt - Use headers as variables in the jslt component (#3861) --- .../apache/camel/component/jslt/JsltEndpoint.java | 46 ++++++++- .../camel/component/jslt/JsltVariablesTest.java | 112 +++++++++++++++++++++ .../camel/component/jslt/withVariables/input.json | 8 ++ .../camel/component/jslt/withVariables/output.json | 1 + .../jslt/withVariables/outputWithProperties.json | 1 + .../jslt/withVariables/transformation.json | 5 + .../transformationWithProperties.json | 6 ++ 7 files changed, 178 insertions(+), 1 deletion(-) 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 a64bfae..536ad91 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 @@ -22,9 +22,12 @@ import java.io.Reader; import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.schibsted.spt.data.jslt.Expression; import com.schibsted.spt.data.jslt.Function; import com.schibsted.spt.data.jslt.JsltException; @@ -38,6 +41,7 @@ import org.apache.camel.ValidationException; import org.apache.camel.component.ResourceEndpoint; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; +import org.apache.camel.support.ExchangeHelper; import org.apache.camel.util.IOHelper; import org.apache.camel.util.ObjectHelper; @@ -47,6 +51,7 @@ import org.apache.camel.util.ObjectHelper; @UriEndpoint(firstVersion = "3.1.0", scheme = "jslt", title = "JSLT", syntax = "jslt:resourceUri", producerOnly = true, category = {Category.TRANSFORMATION}) public class JsltEndpoint extends ResourceEndpoint { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private Expression transform; @UriParam(defaultValue = "false") @@ -146,13 +151,52 @@ public class JsltEndpoint extends ResourceEndpoint { throw new ValidationException(exchange, "Allowed body types are String or InputStream."); } - JsonNode output = getTransform(exchange.getMessage()).apply(input); + Map<String, JsonNode> variables = extractVariables(exchange); + + JsonNode output = getTransform(exchange.getMessage()).apply(variables, input); + Message out = exchange.getMessage(); out.setBody(isPrettyPrint() ? output.toPrettyString() : output.toString()); out.setHeaders(exchange.getIn().getHeaders()); } /** + * Extract the variables from the headers in the message. + */ + private Map<String, JsonNode> extractVariables(Exchange exchange) { + Map<String, Object> variableMap = ExchangeHelper.createVariableMap(exchange, isAllowContextMapAll()); + Map<String, JsonNode> serializedVariableMap = new HashMap<>(); + if (variableMap.containsKey("headers")) { + serializedVariableMap.put("headers", serializeMapToJsonNode((Map<String, Object>) variableMap.get("headers"))); + } + if (variableMap.containsKey("exchange")) { + Exchange ex = (Exchange) variableMap.get("exchange"); + ObjectNode exchangeNode = OBJECT_MAPPER.createObjectNode(); + if (ex.getProperties() != null) { + exchangeNode.set("properties", serializeMapToJsonNode(ex.getProperties())); + } + serializedVariableMap.put("exchange", exchangeNode); + } + return serializedVariableMap; + } + + private ObjectNode serializeMapToJsonNode(Map<String, Object> map) { + ObjectNode mapNode = OBJECT_MAPPER.createObjectNode(); + for (Map.Entry<String, Object> entry : map.entrySet()) { + if (entry.getValue() != null) { + try { + // Use Jackson to convert value to JsonNode + mapNode.set(entry.getKey(), OBJECT_MAPPER.valueToTree(entry.getValue())); + } catch (IllegalArgumentException e) { + //If Jackson cannot convert the value to json (e.g. infinite recursion in the value to serialize) + log.debug("Value could not be converted to JsonNode", e); + } + } + } + return mapNode; + } + + /** * If true, JSON in output message is pretty printed. */ public boolean isPrettyPrint() { diff --git a/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltVariablesTest.java b/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltVariablesTest.java new file mode 100644 index 0000000..bf51bce --- /dev/null +++ b/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltVariablesTest.java @@ -0,0 +1,112 @@ +/* + * 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 java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.support.ResourceHelper; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.camel.util.IOHelper; +import org.junit.Test; + +/** + * Tests using variables used in headers + */ +public class JsltVariablesTest extends CamelTestSupport { + + @Test + public void testWithVariables() throws Exception { + getMockEndpoint("mock:result").expectedMinimumMessageCount(1); + getMockEndpoint("mock:result").expectedBodiesReceived( + IOHelper.loadText( + ResourceHelper.resolveMandatoryResourceAsInputStream( + context, "org/apache/camel/component/jslt/withVariables/output.json")) + .trim() // Remove the last newline added by IOHelper.loadText() + ); + + Map<String, Object> headers = new HashMap<>(); + headers.put("published", "2020-05-26T16:00:00+02:00"); + headers.put("type", "Controller"); + //add an infinite recursion value, cannot be serialized with Jackson + headers.put("infinite", createInfiniteRecursionObject()); + sendBody("direct://start", + ResourceHelper.resolveMandatoryResourceAsInputStream( + context, "org/apache/camel/component/jslt/withVariables/input.json"), + headers); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testWithVariablesAndProperties() throws Exception { + getMockEndpoint("mock:result").expectedMinimumMessageCount(1); + getMockEndpoint("mock:result").expectedBodiesReceived( + IOHelper.loadText( + ResourceHelper.resolveMandatoryResourceAsInputStream( + context, "org/apache/camel/component/jslt/withVariables/outputWithProperties.json")) + .trim() // Remove the last newline added by IOHelper.loadText() + ); + + InputStream body = ResourceHelper.resolveMandatoryResourceAsInputStream( + context, "org/apache/camel/component/jslt/withVariables/input.json"); + + template.send("direct://startWithProperties", exchange -> { + exchange.getIn().setBody(body); + exchange.getIn().setHeader("published", "2020-05-26T16:00:00+02:00"); + exchange.getIn().setHeader("type", "Controller"); + // add an infinite recursion value, cannot be serialized with Jackson + exchange.setProperty("infinite", createInfiniteRecursionObject()); + exchange.setProperty("instance", "559e934f-b32b-47ab-8327-bd50e2bdc029"); + }); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct://start") + .to("jslt:org/apache/camel/component/jslt/withVariables/transformation.json") + .to("mock:result"); + + from("direct://startWithProperties") + .to("jslt:org/apache/camel/component/jslt/withVariables/transformationWithProperties.json?allowContextMapAll=true") + .to("mock:result"); + } + }; + } + + private static Master createInfiniteRecursionObject() { + Master master = new Master(); + Slave slave = new Slave(); + master.slave = slave; + slave.master = master; + return master; + } + + private static class Master { + private Slave slave; + } + + private static class Slave { + private Master master; + } +} diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/input.json b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/input.json new file mode 100644 index 0000000..e332d40e --- /dev/null +++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/input.json @@ -0,0 +1,8 @@ +{ + "schema": "http://schemas.schibsted.io/thing/pulse-simple.json#1.json", + "id": "w23q7ca1-8729-24923-922b-1c0517ddffjf1", + "published": "2017-05-04T09:13:29+02:00", + "type": "View", + "environmentId": "urn:schibsted.com:environment:uuid", + "url": "http://www.aftenposten.no/" +} diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/output.json b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/output.json new file mode 100644 index 0000000..46b8e27 --- /dev/null +++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/output.json @@ -0,0 +1 @@ +{"published":"2020-05-26T16:00:00+02:00","type":"Controller","schema":"http://schemas.schibsted.io/thing/pulse-simple.json#1.json","id":"w23q7ca1-8729-24923-922b-1c0517ddffjf1","environmentId":"urn:schibsted.com:environment:uuid","url":"http://www.aftenposten.no/"} \ No newline at end of file diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/outputWithProperties.json b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/outputWithProperties.json new file mode 100644 index 0000000..45418ed --- /dev/null +++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/outputWithProperties.json @@ -0,0 +1 @@ +{"published":"2020-05-26T16:00:00+02:00","type":"Controller","id":"559e934f-b32b-47ab-8327-bd50e2bdc029","schema":"http://schemas.schibsted.io/thing/pulse-simple.json#1.json","environmentId":"urn:schibsted.com:environment:uuid","url":"http://www.aftenposten.no/"} \ No newline at end of file diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/transformation.json b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/transformation.json new file mode 100644 index 0000000..26e101f --- /dev/null +++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/transformation.json @@ -0,0 +1,5 @@ +{ + "published": $headers.published, + "type": $headers.type, + * : . +} \ No newline at end of file diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/transformationWithProperties.json b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/transformationWithProperties.json new file mode 100644 index 0000000..f3c65fb --- /dev/null +++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/withVariables/transformationWithProperties.json @@ -0,0 +1,6 @@ +{ + "published": $headers.published, + "type": $headers.type, + "id": $exchange.properties.instance, + * : . +} \ No newline at end of file