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 4b327ed CAMEL-15122: camel-jslt - providing custom object filtering (#3863) 4b327ed is described below commit 4b327ed8726251bf91c8c71871ca7cdc01d33b38 Author: jflabatBCSS <65955832+jflabatb...@users.noreply.github.com> AuthorDate: Thu May 28 06:00:35 2020 +0200 CAMEL-15122: camel-jslt - providing custom object filtering (#3863) --- .../component/jslt/JsltComponentConfigurer.java | 5 ++ .../org/apache/camel/component/jslt/jslt.json | 3 +- .../camel-jslt/src/main/docs/jslt-component.adoc | 3 +- .../apache/camel/component/jslt/JsltComponent.java | 16 ++++- .../apache/camel/component/jslt/JsltEndpoint.java | 42 ++++++++---- .../camel/component/jslt/JsltObjectFilterTest.java | 76 ++++++++++++++++++++++ .../camel/component/jslt/objectFilter/input.json | 13 ++++ .../camel/component/jslt/objectFilter/output.json | 1 + .../jslt/objectFilter/transformation.json | 7 ++ 9 files changed, 152 insertions(+), 14 deletions(-) diff --git a/components/camel-jslt/src/generated/java/org/apache/camel/component/jslt/JsltComponentConfigurer.java b/components/camel-jslt/src/generated/java/org/apache/camel/component/jslt/JsltComponentConfigurer.java index 05cc16a..71f49a2 100644 --- a/components/camel-jslt/src/generated/java/org/apache/camel/component/jslt/JsltComponentConfigurer.java +++ b/components/camel-jslt/src/generated/java/org/apache/camel/component/jslt/JsltComponentConfigurer.java @@ -26,6 +26,8 @@ public class JsltComponentConfigurer extends PropertyConfigurerSupport implement case "functions": target.setFunctions(property(camelContext, java.util.Collection.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "objectfilter": + case "objectFilter": target.setObjectFilter(property(camelContext, com.schibsted.spt.data.jslt.filters.JsonFilter.class, value)); return true; default: return false; } } @@ -37,6 +39,7 @@ public class JsltComponentConfigurer extends PropertyConfigurerSupport implement answer.put("basicPropertyBinding", boolean.class); answer.put("functions", java.util.Collection.class); answer.put("lazyStartProducer", boolean.class); + answer.put("objectFilter", com.schibsted.spt.data.jslt.filters.JsonFilter.class); return answer; } @@ -51,6 +54,8 @@ public class JsltComponentConfigurer extends PropertyConfigurerSupport implement case "functions": return target.getFunctions(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); + case "objectfilter": + case "objectFilter": return target.getObjectFilter(); default: return null; } } diff --git a/components/camel-jslt/src/generated/resources/org/apache/camel/component/jslt/jslt.json b/components/camel-jslt/src/generated/resources/org/apache/camel/component/jslt/jslt.json index 7f39648..7e90455 100644 --- a/components/camel-jslt/src/generated/resources/org/apache/camel/component/jslt/jslt.json +++ b/components/camel-jslt/src/generated/resources/org/apache/camel/component/jslt/jslt.json @@ -24,7 +24,8 @@ "allowTemplateFromHeader": { "kind": "property", "displayName": "Allow Template From Header", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": "false", "description": "Whether to allow to use resource template from header or not (default false). Enabling this allows to specify dynamic templates via message header. However this can be seen as a potential security vulnerability if the he [...] "lazyStartProducer": { "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the r [...] "basicPropertyBinding": { "kind": "property", "displayName": "Basic Property Binding", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities" }, - "functions": { "kind": "property", "displayName": "Functions", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.Collection<com.schibsted.spt.data.jslt.Function>", "deprecated": false, "secret": false, "description": "JSLT can be extended by plugging in functions written in Java." } + "functions": { "kind": "property", "displayName": "Functions", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.Collection<com.schibsted.spt.data.jslt.Function>", "deprecated": false, "secret": false, "description": "JSLT can be extended by plugging in functions written in Java." }, + "objectFilter": { "kind": "property", "displayName": "Object Filter", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "com.schibsted.spt.data.jslt.filters.JsonFilter", "deprecated": false, "secret": false, "description": "JSLT can be extended by plugging in a custom jslt object filter" } }, "properties": { "resourceUri": { "kind": "path", "displayName": "Resource Uri", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "secret": false, "description": "Path to the resource. You can prefix with: classpath, file, http, ref, or bean. classpath, file and http loads the resource using these protocols (classpath is default). ref will lookup the resource in the registry. bean will call a method on a [...] diff --git a/components/camel-jslt/src/main/docs/jslt-component.adoc b/components/camel-jslt/src/main/docs/jslt-component.adoc index 85e2d8e..52a6721 100644 --- a/components/camel-jslt/src/main/docs/jslt-component.adoc +++ b/components/camel-jslt/src/main/docs/jslt-component.adoc @@ -50,7 +50,7 @@ format, `?option=value&option=value&...` // component options: START -The JSLT component supports 4 options, which are listed below. +The JSLT component supports 5 options, which are listed below. @@ -61,6 +61,7 @@ The JSLT component supports 4 options, which are listed below. | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...] | *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean | *functions* (advanced) | JSLT can be extended by plugging in functions written in Java. | | Collection +| *objectFilter* (advanced) | JSLT can be extended by plugging in a custom jslt object filter | | JsonFilter |=== // component options: END diff --git a/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltComponent.java b/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltComponent.java index d79c8a7..3a42457 100644 --- a/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltComponent.java +++ b/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltComponent.java @@ -19,18 +19,22 @@ package org.apache.camel.component.jslt; import java.util.Collection; import java.util.Map; -import com.schibsted.spt.data.jslt.Function; import org.apache.camel.Endpoint; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.annotations.Component; import org.apache.camel.support.DefaultComponent; import org.apache.camel.support.ResourceHelper; +import com.schibsted.spt.data.jslt.Function; +import com.schibsted.spt.data.jslt.filters.JsonFilter; + @Component("jslt") public class JsltComponent extends DefaultComponent { @Metadata(label = "advanced") private Collection<Function> functions; + @Metadata(label = "advanced") + private JsonFilter objectFilter; @Metadata(defaultValue = "false") private boolean allowTemplateFromHeader; @@ -80,4 +84,14 @@ public class JsltComponent extends DefaultComponent { this.allowTemplateFromHeader = allowTemplateFromHeader; } + /** + * JSLT can be extended by plugging in a custom jslt object filter + */ + public JsonFilter getObjectFilter() { + return objectFilter; + } + + public void setObjectFilter(JsonFilter objectFilter) { + this.objectFilter = objectFilter; + } } 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 53370ea..15cecdb 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,14 +16,21 @@ */ package org.apache.camel.component.jslt; +import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; import java.util.Collection; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; 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.JsonFilter; import org.apache.camel.Category; import org.apache.camel.Exchange; import org.apache.camel.ExchangePattern; @@ -72,19 +79,32 @@ public class JsltEndpoint extends ResourceEndpoint { } String jsltStringFromHeader = allowTemplateFromHeader ? msg.getHeader(JsltConstants.HEADER_JSLT_STRING, String.class) : null; - Collection<Function> functions = ((JsltComponent)getComponent()).getFunctions(); - - if (jsltStringFromHeader != null) { - if (functions == null) { - this.transform = Parser.compileString(jsltStringFromHeader); + 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 { - this.transform = Parser.compileString(jsltStringFromHeader, functions); + stream = JsltEndpoint.class.getClassLoader().getResourceAsStream(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()); } - } else { - if (functions == null) { - this.transform = Parser.compileResource(getResourceUri()); - } else { - this.transform = Parser.compileResource(getResourceUri(), functions); + if (functions != null) { + parser = parser.withFunctions(functions); + } + if (objectFilter != null) { + parser = parser.withObjectFilter(objectFilter); + } + this.transform = parser.compile(); + } finally { + if(stream != null){ + stream.close(); } } } diff --git a/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltObjectFilterTest.java b/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltObjectFilterTest.java new file mode 100644 index 0000000..46b1275 --- /dev/null +++ b/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltObjectFilterTest.java @@ -0,0 +1,76 @@ +/* + * 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.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.support.ResourceHelper; +import org.apache.camel.test.junit4.CamelTestSupport; + +import com.schibsted.spt.data.jslt.Expression; +import com.schibsted.spt.data.jslt.Parser; +import com.schibsted.spt.data.jslt.filters.JsltJsonFilter; +import com.schibsted.spt.data.jslt.filters.JsonFilter; +import org.apache.camel.util.IOHelper; +import org.junit.Test; + +public class JsltObjectFilterTest extends CamelTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + context.getPropertiesComponent().setLocation("ref:prop"); + + context.getComponent("jslt", JsltComponent.class).setObjectFilter(createObjectFilter()); + + return context; + } + + @Test + public void testJsltAsInputStream() throws Exception { + getMockEndpoint("mock:result").expectedMinimumMessageCount(1); + getMockEndpoint("mock:result").expectedBodiesReceived( + IOHelper.loadText( + ResourceHelper.resolveMandatoryResourceAsInputStream( + context, "org/apache/camel/component/jslt/objectFilter/output.json") + ).trim() // Remove the last newline added by IOHelper.loadText() + ); + + sendBody("direct://start", + ResourceHelper.resolveMandatoryResourceAsInputStream( + context, "org/apache/camel/component/jslt/objectFilter/input.json")); + + assertMockEndpointsSatisfied(); + } + + private JsonFilter createObjectFilter() { + Expression filterExpression = Parser.compileString(". != null and . != {}"); + return new JsltJsonFilter(filterExpression); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() { + from("direct://start") + .to("jslt:org/apache/camel/component/jslt/objectFilter/transformation.json") + .to("mock:result"); + } + }; + } +} diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/input.json b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/input.json new file mode 100644 index 0000000..d6d7fe7 --- /dev/null +++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/input.json @@ -0,0 +1,13 @@ +{ + "name": { + "firstname": "foo" + }, + "list": [ + { + "value": 1 + }, + { + "value": 2 + } + ] +} diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/output.json b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/output.json new file mode 100644 index 0000000..d307513 --- /dev/null +++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/output.json @@ -0,0 +1 @@ +{"list":[]} \ No newline at end of file diff --git a/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/transformation.json b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/transformation.json new file mode 100644 index 0000000..a780b7f --- /dev/null +++ b/components/camel-jslt/src/test/resources/org/apache/camel/component/jslt/objectFilter/transformation.json @@ -0,0 +1,7 @@ +{ + "name": { + * - firstname: . + }, + "list": [for(.list) . if(.value > 2)], + "shoudBeRemoved": .name.lastname +} \ No newline at end of file