This is an automated email from the ASF dual-hosted git repository. aldettinger pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/master by this push: new a1b0769 Added JSLT native support #1740 a1b0769 is described below commit a1b07697bd99230974de537a817bb5f9b4db8357 Author: aldettinger <aldettin...@gmail.com> AuthorDate: Mon Nov 16 17:56:12 2020 +0100 Added JSLT native support #1740 --- .../ROOT/pages/reference/extensions/jslt.adoc | 54 ++++++- .../ROOT/partials/reference/components/jslt.adoc | 6 +- .../quarkus/component/jslt/it/JsltResource.java | 51 ------- extensions-jvm/pom.xml | 1 - .../jslt/deployment/pom.xml | 0 .../component/jslt/deployment/JsltProcessor.java | 14 -- {extensions-jvm => extensions}/jslt/pom.xml | 1 - .../jslt/runtime/pom.xml | 1 + .../jslt/runtime/src/main/doc/configuration.adoc | 37 +++++ .../main/resources/META-INF/quarkus-extension.yaml | 3 +- extensions/pom.xml | 1 + .../jslt}/pom.xml | 37 ++++- .../component/jslt/it/JsltConfiguration.java | 71 +++++++++ .../quarkus/component/jslt/it/JsltResource.java | 158 +++++++++++++++++++++ .../component/jslt/it/MathFunctionStub.java | 16 +-- .../jslt/src/main/resources/application.properties | 18 +++ .../resources/demoPlayground/transformation.json | 8 ++ .../resources/objectFilter/transformation.json | 7 + .../resources/withVariables/transformation.json | 5 + .../transformationWithProperties.json | 6 + .../camel/quarkus/component/jslt/it/JsltIT.java | 16 +-- .../camel/quarkus/component/jslt/it/JsltTest.java | 94 ++++++++++++ .../src/test/resources/demoPlayground/input.json | 8 ++ .../src/test/resources/demoPlayground/output.json | 1 + .../demoPlayground/outputPrettyPrint.json | 8 ++ .../src/test/resources/objectFilter/input.json | 13 ++ .../src/test/resources/objectFilter/output.json | 1 + .../src/test/resources/withVariables/input.json | 8 ++ .../src/test/resources/withVariables/output.json | 1 + .../withVariables/outputWithProperties.json | 1 + integration-tests/pom.xml | 1 + tooling/scripts/test-categories.yaml | 1 + 32 files changed, 544 insertions(+), 104 deletions(-) diff --git a/docs/modules/ROOT/pages/reference/extensions/jslt.adoc b/docs/modules/ROOT/pages/reference/extensions/jslt.adoc index dbf7aee..f42614c 100644 --- a/docs/modules/ROOT/pages/reference/extensions/jslt.adoc +++ b/docs/modules/ROOT/pages/reference/extensions/jslt.adoc @@ -2,15 +2,15 @@ // This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page = JSLT :cq-artifact-id: camel-quarkus-jslt -:cq-native-supported: false -:cq-status: Preview +:cq-native-supported: true +:cq-status: Stable :cq-description: Query or transform JSON payloads using an JSLT. :cq-deprecated: false :cq-jvm-since: 1.1.0 -:cq-native-since: n/a +:cq-native-since: 1.4.0 [.badges] -[.badge-key]##JVM since##[.badge-supported]##1.1.0## [.badge-key]##Native##[.badge-unsupported]##unsupported## +[.badge-key]##JVM since##[.badge-supported]##1.1.0## [.badge-key]##Native since##[.badge-supported]##1.4.0## Query or transform JSON payloads using an JSLT. @@ -31,3 +31,49 @@ Please refer to the above link for usage and configuration details. ---- Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications. + +== allowContextMapAll option in native mode + +The `allowContextMapAll` option is not supported in native mode as it requires reflective access to security sensitive camel core classes such as +`CamelContext` & `Exchange`. This is considered a security risk and thus access to the feature is not provided by default. + +== Additional Camel Quarkus configuration + +=== Using JSLT templates from classpath resource in native mode +A trick is needed when using JSLT templates from classpath resources in native mode. In such a situation, one needs to explicitly embed the resources in the native executable by specifying the `include-patterns` option. + +For instance, the route below would load the JSLT schema from a classpath resource named _transformation.json_: +[source,java] +---- +from("direct:start").to("jslt:transformation.json"); +---- + +In order to work in native mode the `include-patterns` configuration should be set. For instance, in the `application.properties` file as below : +[source,properties] +---- +quarkus.camel.native.resources.include-patterns = *.json +---- + +More information about selecting resources for inclusion in the native executable could be found at xref:user-guide/native-mode.adoc#embedding-resource-in-native-executable[Embedding resource in native executable]. + +=== Using JSLT functions in native mode +When using JSLT functions from camel-quarkus in native mode, the classes hosting the functions would need to be link:https://quarkus.io/guides/writing-native-applications-tips#registering-for-reflection[registered for reflection]. When registering the target function is not possible, one may end up writing a stub as below. +---- +@RegisterForReflection +public class MathFunctionStub { + public static double pow(double a, double b) { + return java.lang.Math.pow(a, b); + } +} +---- + +The target function `Math.pow(...)` is now accessible through the `MathFunctionStub` class that could be registered in the component as below: +---- +@Named +JsltComponent jsltWithFunction() throws ClassNotFoundException { + JsltComponent component = new JsltComponent(); + component.setFunctions(singleton(wrapStaticMethod("power", "org.apache.cq.example.MathFunctionStub", "pow"))); + return component; +} +---- + diff --git a/docs/modules/ROOT/partials/reference/components/jslt.adoc b/docs/modules/ROOT/partials/reference/components/jslt.adoc index 64f388a..55a3ef5 100644 --- a/docs/modules/ROOT/partials/reference/components/jslt.adoc +++ b/docs/modules/ROOT/partials/reference/components/jslt.adoc @@ -2,11 +2,11 @@ // This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page :cq-artifact-id: camel-quarkus-jslt :cq-artifact-id-base: jslt -:cq-native-supported: false -:cq-status: Preview +:cq-native-supported: true +:cq-status: Stable :cq-deprecated: false :cq-jvm-since: 1.1.0 -:cq-native-since: n/a +:cq-native-since: 1.4.0 :cq-camel-part-name: jslt :cq-camel-part-title: JSLT :cq-camel-part-description: Query or transform JSON payloads using an JSLT. diff --git a/extensions-jvm/jslt/integration-test/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltResource.java b/extensions-jvm/jslt/integration-test/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltResource.java deleted file mode 100644 index bfdb4d9..0000000 --- a/extensions-jvm/jslt/integration-test/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltResource.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.quarkus.component.jslt.it; - -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.apache.camel.CamelContext; -import org.jboss.logging.Logger; - -@Path("/jslt") -@ApplicationScoped -public class JsltResource { - - private static final Logger LOG = Logger.getLogger(JsltResource.class); - - private static final String COMPONENT_JSLT = "jslt"; - @Inject - CamelContext context; - - @Path("/load/component/jslt") - @GET - @Produces(MediaType.TEXT_PLAIN) - public Response loadComponentJslt() throws Exception { - /* This is an autogenerated test */ - if (context.getComponent(COMPONENT_JSLT) != null) { - return Response.ok().build(); - } - LOG.warnf("Could not load [%s] from the Camel context", COMPONENT_JSLT); - return Response.status(500, COMPONENT_JSLT + " could not be loaded from the Camel context").build(); - } -} diff --git a/extensions-jvm/pom.xml b/extensions-jvm/pom.xml index 337ced7..ce43a0b 100644 --- a/extensions-jvm/pom.xml +++ b/extensions-jvm/pom.xml @@ -94,7 +94,6 @@ <module>jgroups-raft</module> <module>jooq</module> <module>jsch</module> - <module>jslt</module> <module>jsonapi</module> <module>jt400</module> <module>language</module> diff --git a/extensions-jvm/jslt/deployment/pom.xml b/extensions/jslt/deployment/pom.xml similarity index 100% rename from extensions-jvm/jslt/deployment/pom.xml rename to extensions/jslt/deployment/pom.xml diff --git a/extensions-jvm/jslt/deployment/src/main/java/org/apache/camel/quarkus/component/jslt/deployment/JsltProcessor.java b/extensions/jslt/deployment/src/main/java/org/apache/camel/quarkus/component/jslt/deployment/JsltProcessor.java similarity index 68% rename from extensions-jvm/jslt/deployment/src/main/java/org/apache/camel/quarkus/component/jslt/deployment/JsltProcessor.java rename to extensions/jslt/deployment/src/main/java/org/apache/camel/quarkus/component/jslt/deployment/JsltProcessor.java index d25bb60..950f195 100644 --- a/extensions-jvm/jslt/deployment/src/main/java/org/apache/camel/quarkus/component/jslt/deployment/JsltProcessor.java +++ b/extensions/jslt/deployment/src/main/java/org/apache/camel/quarkus/component/jslt/deployment/JsltProcessor.java @@ -17,11 +17,7 @@ package org.apache.camel.quarkus.component.jslt.deployment; import io.quarkus.deployment.annotations.BuildStep; -import io.quarkus.deployment.annotations.ExecutionTime; -import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.FeatureBuildItem; -import io.quarkus.deployment.pkg.steps.NativeBuild; -import org.apache.camel.quarkus.core.JvmOnlyRecorder; import org.jboss.logging.Logger; class JsltProcessor { @@ -33,14 +29,4 @@ class JsltProcessor { FeatureBuildItem feature() { return new FeatureBuildItem(FEATURE); } - - /** - * Remove this once this extension starts supporting the native mode. - */ - @BuildStep(onlyIf = NativeBuild.class) - @Record(value = ExecutionTime.RUNTIME_INIT) - void warnJvmInNative(JvmOnlyRecorder recorder) { - JvmOnlyRecorder.warnJvmInNative(LOG, FEATURE); // warn at build time - recorder.warnJvmInNative(FEATURE); // warn at runtime - } } diff --git a/extensions-jvm/jslt/pom.xml b/extensions/jslt/pom.xml similarity index 97% rename from extensions-jvm/jslt/pom.xml rename to extensions/jslt/pom.xml index c915016..bf70efc 100644 --- a/extensions-jvm/jslt/pom.xml +++ b/extensions/jslt/pom.xml @@ -33,6 +33,5 @@ <modules> <module>deployment</module> <module>runtime</module> - <module>integration-test</module> </modules> </project> diff --git a/extensions-jvm/jslt/runtime/pom.xml b/extensions/jslt/runtime/pom.xml similarity index 98% rename from extensions-jvm/jslt/runtime/pom.xml rename to extensions/jslt/runtime/pom.xml index 24cd29b..521d355 100644 --- a/extensions-jvm/jslt/runtime/pom.xml +++ b/extensions/jslt/runtime/pom.xml @@ -32,6 +32,7 @@ <properties> <camel.quarkus.jvmSince>1.1.0</camel.quarkus.jvmSince> + <camel.quarkus.nativeSince>1.4.0</camel.quarkus.nativeSince> </properties> <dependencyManagement> diff --git a/extensions/jslt/runtime/src/main/doc/configuration.adoc b/extensions/jslt/runtime/src/main/doc/configuration.adoc new file mode 100644 index 0000000..431d42c --- /dev/null +++ b/extensions/jslt/runtime/src/main/doc/configuration.adoc @@ -0,0 +1,37 @@ +=== Using JSLT templates from classpath resource in native mode +A trick is needed when using JSLT templates from classpath resources in native mode. In such a situation, one needs to explicitly embed the resources in the native executable by specifying the `include-patterns` option. + +For instance, the route below would load the JSLT schema from a classpath resource named _transformation.json_: +[source,java] +---- +from("direct:start").to("jslt:transformation.json"); +---- + +In order to work in native mode the `include-patterns` configuration should be set. For instance, in the `application.properties` file as below : +[source,properties] +---- +quarkus.camel.native.resources.include-patterns = *.json +---- + +More information about selecting resources for inclusion in the native executable could be found at xref:user-guide/native-mode.adoc#embedding-resource-in-native-executable[Embedding resource in native executable]. + +=== Using JSLT functions in native mode +When using JSLT functions from camel-quarkus in native mode, the classes hosting the functions would need to be link:https://quarkus.io/guides/writing-native-applications-tips#registering-for-reflection[registered for reflection]. When registering the target function is not possible, one may end up writing a stub as below. +---- +@RegisterForReflection +public class MathFunctionStub { + public static double pow(double a, double b) { + return java.lang.Math.pow(a, b); + } +} +---- + +The target function `Math.pow(...)` is now accessible through the `MathFunctionStub` class that could be registered in the component as below: +---- +@Named +JsltComponent jsltWithFunction() throws ClassNotFoundException { + JsltComponent component = new JsltComponent(); + component.setFunctions(singleton(wrapStaticMethod("power", "org.apache.cq.example.MathFunctionStub", "pow"))); + return component; +} +---- diff --git a/extensions-jvm/jslt/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jslt/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 97% rename from extensions-jvm/jslt/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jslt/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b453bf6..c07c711 100644 --- a/extensions-jvm/jslt/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/extensions/jslt/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -24,9 +24,8 @@ name: "Camel JSLT" description: "Query or transform JSON payloads using an JSLT" metadata: - unlisted: true guide: "https://camel.apache.org/camel-quarkus/latest/reference/extensions/jslt.html" categories: - "integration" status: - - "preview" + - "stable" diff --git a/extensions/pom.xml b/extensions/pom.xml index 7ab3743..8e996d3 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -132,6 +132,7 @@ <module>johnzon</module> <module>jolt</module> <module>jpa</module> + <module>jslt</module> <module>json-validator</module> <module>jsonpath</module> <module>jta</module> diff --git a/extensions-jvm/jslt/integration-test/pom.xml b/integration-tests/jslt/pom.xml similarity index 72% rename from extensions-jvm/jslt/integration-test/pom.xml rename to integration-tests/jslt/pom.xml index c358177..8b4a361 100644 --- a/extensions-jvm/jslt/integration-test/pom.xml +++ b/integration-tests/jslt/pom.xml @@ -21,13 +21,12 @@ <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache.camel.quarkus</groupId> - <artifactId>camel-quarkus-build-parent-it</artifactId> + <artifactId>camel-quarkus-integration-tests</artifactId> <version>1.4.0-SNAPSHOT</version> - <relativePath>../../../poms/build-parent-it/pom.xml</relativePath> </parent> - <artifactId>camel-quarkus-jslt-integration-test</artifactId> - <name>Camel Quarkus :: JSLT :: Integration Test</name> + <artifactId>camel-quarkus-integration-test-jslt</artifactId> + <name>Camel Quarkus :: Integration Tests :: JSLT</name> <description>Integration tests for Camel Quarkus JSLT extension</description> <dependencyManagement> @@ -80,4 +79,34 @@ </dependency> </dependencies> + <profiles> + <profile> + <id>native</id> + <activation> + <property> + <name>native</name> + </property> + </activation> + <properties> + <quarkus.package.type>native</quarkus.package.type> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> + </project> diff --git a/integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltConfiguration.java b/integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltConfiguration.java new file mode 100644 index 0000000..b678030 --- /dev/null +++ b/integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltConfiguration.java @@ -0,0 +1,71 @@ +/* + * 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.quarkus.component.jslt.it; + +import javax.inject.Named; + +import com.schibsted.spt.data.jslt.Expression; +import com.schibsted.spt.data.jslt.Parser; +import com.schibsted.spt.data.jslt.filters.JsltJsonFilter; +import org.apache.camel.component.jslt.JsltComponent; + +import static java.util.Collections.singleton; + +import static com.schibsted.spt.data.jslt.FunctionUtils.wrapStaticMethod; + +public class JsltConfiguration { + + @Named + JsltComponent jsltWithFilter() { + Expression filterExpression = Parser.compileString(". != null and . != {}"); + JsltJsonFilter filter = new JsltJsonFilter(filterExpression); + + JsltComponent component = new JsltComponent(); + component.setObjectFilter(filter); + + return component; + } + + @Named + JsltComponent jsltWithFunction() throws ClassNotFoundException { + JsltComponent component = new JsltComponent(); + component.setFunctions( + singleton(wrapStaticMethod("power", "org.apache.camel.quarkus.component.jslt.it.MathFunctionStub", "pow"))); + component.setAllowTemplateFromHeader(true); + + return component; + } + + public static Ping createInfiniteRecursionObject() { + Ping ping = new Ping(); + Pong pong = new Pong(); + ping.pong = pong; + pong.ping = ping; + return ping; + } + + private static class Ping { + @SuppressWarnings("unused") + private Pong pong; + } + + private static class Pong { + @SuppressWarnings("unused") + private Ping ping; + } + +} diff --git a/integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltResource.java b/integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltResource.java new file mode 100644 index 0000000..e213ee1 --- /dev/null +++ b/integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/JsltResource.java @@ -0,0 +1,158 @@ +/* + * 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.quarkus.component.jslt.it; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.apache.camel.CamelExecutionException; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.jslt.JsltConstants; +import org.jboss.logging.Logger; + +import static java.util.Collections.singletonMap; + +@Path("/jslt") +@ApplicationScoped +public class JsltResource { + + private static final Logger LOG = Logger.getLogger(JsltResource.class); + + @Inject + ProducerTemplate template; + + @Path("/transformInputStream") + @GET + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public String transformInputStream(String input) throws IOException { + LOG.debugf("Invoking transformInputStream(%s)", input); + try (InputStream is = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8))) { + return template.requestBody("jslt:demoPlayground/transformation.json", is, String.class); + } + } + + @Path("/transformInvalidBody") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String transformInvalidBody() { + LOG.debugf("Invoking transformInvalidBody()"); + try { + template.requestBody("jslt:demoPlayground/transformation.json", 4, String.class); + } catch (CamelExecutionException vex) { + return vex.getCause().getMessage(); + } + return null; + } + + @Path("/transformString") + @GET + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public String transformString(String input) { + LOG.debugf("Invoking transformString(%s)", input); + return template.requestBody("jslt:demoPlayground/transformation.json", input, String.class); + } + + @Path("/transformFromHeaderWithPrettyPrint") + @GET + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public String transformFromHeaderWithPrettyPrint(String input) throws IOException { + LOG.debugf("Invoking transformFromHeaderWithPrettyPrint(%s)", input); + Map<String, Object> headers = singletonMap(JsltConstants.HEADER_JSLT_RESOURCE_URI, + "demoPlayground/transformation.json"); + try (InputStream is = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8))) { + String uri = "jslt:demoPlayground/transformation.json?prettyPrint=true&allowTemplateFromHeader=true"; + return template.requestBodyAndHeaders(uri, is, headers, String.class); + } + } + + @Path("/transformInputStreamWithFilter") + @GET + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public String transformInputStreamWithFilter(String input) throws IOException { + LOG.debugf("Invoking transformInputStreamWithFilter(%s)", input); + try (InputStream is = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8))) { + String uri = "jsltWithFilter:objectFilter/transformation.json"; + return template.requestBody(uri, is, String.class); + } + } + + @Path("/transformInputStreamWithVariables") + @GET + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public String transformInputStreamWithVariables(String input) throws IOException { + LOG.debugf("Invoking transformInputStreamWithVariables(%s)", input); + + Map<String, Object> headers = new HashMap<>(); + headers.put("published", "2020-05-26T16:00:00+02:00"); + headers.put("type", "Controller"); + // infinite recursion value that cannot be serialized by camel-jslt + headers.put("infinite", JsltConfiguration.createInfiniteRecursionObject()); + + try (InputStream is = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8))) { + String uri = "jslt:withVariables/transformation.json"; + return template.requestBodyAndHeaders(uri, is, headers, String.class); + } + } + + @Path("/transformInputStreamWithVariablesAndProperties") + @GET + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public String transformInputStreamWithVariablesAndProperties(String input) throws IOException { + LOG.debugf("Invoking transformInputStreamWithVariablesAndProperties(%s)", input); + + try (InputStream is = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8))) { + String uri = "jslt:withVariables/transformationWithProperties.json?allowContextMapAll=true"; + + Exchange ex = template.request(uri, e -> { + e.getMessage().setBody(is); + e.getMessage().setHeader("published", "2020-05-26T16:00:00+02:00"); + e.getMessage().setHeader("type", "Controller"); + e.setProperty("infinite", JsltConfiguration.createInfiniteRecursionObject()); + e.setProperty("instance", "559e934f-b32b-47ab-8327-bd50e2bdc029"); + }); + return ex.getMessage().getBody(String.class); + } + } + + @Path("/transformWithFunction") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String transformWithFunction() { + LOG.debugf("Invoking transformWithFunction()"); + Map<String, Object> headers = singletonMap(JsltConstants.HEADER_JSLT_STRING, "power(2, 10)"); + return template.requestBodyAndHeaders("jsltWithFunction:dummy", "{}", headers, String.class); + } +} diff --git a/extensions-jvm/jslt/integration-test/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java b/integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/MathFunctionStub.java similarity index 71% copy from extensions-jvm/jslt/integration-test/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java copy to integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/MathFunctionStub.java index 2c7cdff..eb27897 100644 --- a/extensions-jvm/jslt/integration-test/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java +++ b/integration-tests/jslt/src/main/java/org/apache/camel/quarkus/component/jslt/it/MathFunctionStub.java @@ -16,19 +16,13 @@ */ package org.apache.camel.quarkus.component.jslt.it; -import io.quarkus.test.junit.QuarkusTest; -import io.restassured.RestAssured; -import org.junit.jupiter.api.Test; +import io.quarkus.runtime.annotations.RegisterForReflection; -@QuarkusTest -class JsltTest { +@RegisterForReflection +public class MathFunctionStub { - @Test - public void loadComponentJslt() { - /* A simple autogenerated test */ - RestAssured.get("/jslt/load/component/jslt") - .then() - .statusCode(200); + public static double pow(double a, double b) { + return java.lang.Math.pow(a, b); } } diff --git a/integration-tests/jslt/src/main/resources/application.properties b/integration-tests/jslt/src/main/resources/application.properties new file mode 100644 index 0000000..b8f2b9b --- /dev/null +++ b/integration-tests/jslt/src/main/resources/application.properties @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +quarkus.camel.native.resources.include-patterns = demoPlayground/*.json,objectFilter/*.json,withVariables/*.json diff --git a/integration-tests/jslt/src/main/resources/demoPlayground/transformation.json b/integration-tests/jslt/src/main/resources/demoPlayground/transformation.json new file mode 100644 index 0000000..6f23215 --- /dev/null +++ b/integration-tests/jslt/src/main/resources/demoPlayground/transformation.json @@ -0,0 +1,8 @@ +let idparts = split(.id, "-") +let xxx = [for ($idparts) "x" * size(.)] + +{ +"id" : join($xxx, "-"), +"type" : "Anonymized-View", +* : . +} diff --git a/integration-tests/jslt/src/main/resources/objectFilter/transformation.json b/integration-tests/jslt/src/main/resources/objectFilter/transformation.json new file mode 100644 index 0000000..a780b7f --- /dev/null +++ b/integration-tests/jslt/src/main/resources/objectFilter/transformation.json @@ -0,0 +1,7 @@ +{ + "name": { + * - firstname: . + }, + "list": [for(.list) . if(.value > 2)], + "shoudBeRemoved": .name.lastname +} \ No newline at end of file diff --git a/integration-tests/jslt/src/main/resources/withVariables/transformation.json b/integration-tests/jslt/src/main/resources/withVariables/transformation.json new file mode 100644 index 0000000..26e101f --- /dev/null +++ b/integration-tests/jslt/src/main/resources/withVariables/transformation.json @@ -0,0 +1,5 @@ +{ + "published": $headers.published, + "type": $headers.type, + * : . +} \ No newline at end of file diff --git a/integration-tests/jslt/src/main/resources/withVariables/transformationWithProperties.json b/integration-tests/jslt/src/main/resources/withVariables/transformationWithProperties.json new file mode 100644 index 0000000..f3c65fb --- /dev/null +++ b/integration-tests/jslt/src/main/resources/withVariables/transformationWithProperties.json @@ -0,0 +1,6 @@ +{ + "published": $headers.published, + "type": $headers.type, + "id": $exchange.properties.instance, + * : . +} \ No newline at end of file diff --git a/extensions-jvm/jslt/integration-test/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java b/integration-tests/jslt/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltIT.java similarity index 71% rename from extensions-jvm/jslt/integration-test/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java rename to integration-tests/jslt/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltIT.java index 2c7cdff..131473f 100644 --- a/extensions-jvm/jslt/integration-test/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java +++ b/integration-tests/jslt/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltIT.java @@ -16,19 +16,9 @@ */ package org.apache.camel.quarkus.component.jslt.it; -import io.quarkus.test.junit.QuarkusTest; -import io.restassured.RestAssured; -import org.junit.jupiter.api.Test; +import io.quarkus.test.junit.NativeImageTest; -@QuarkusTest -class JsltTest { - - @Test - public void loadComponentJslt() { - /* A simple autogenerated test */ - RestAssured.get("/jslt/load/component/jslt") - .then() - .statusCode(200); - } +@NativeImageTest +class JsltIT extends JsltTest { } diff --git a/integration-tests/jslt/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java b/integration-tests/jslt/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java new file mode 100644 index 0000000..e6ac493 --- /dev/null +++ b/integration-tests/jslt/src/test/java/org/apache/camel/quarkus/component/jslt/it/JsltTest.java @@ -0,0 +1,94 @@ +/* + * 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.quarkus.component.jslt.it; + +import java.io.IOException; + +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Test; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import static io.restassured.RestAssured.given; +import static org.apache.commons.io.IOUtils.resourceToString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; + +@QuarkusTest +class JsltTest { + + @Test + public void transformInputStreamShouldSucceed() throws IOException { + String expected = resourceToString("/demoPlayground/output.json", UTF_8); + String input = resourceToString("/demoPlayground/input.json", UTF_8); + + given().when().body(input).get("/jslt/transformInputStream").then().statusCode(200).body(is(expected)); + } + + @Test + public void transformInvalidBodyShouldIssueValidationErrorMessage() { + given().when().get("/jslt/transformInvalidBody").then().statusCode(200) + .body(startsWith("Allowed body types are String or InputStream.")); + } + + @Test + public void transformStringShouldSucceed() throws IOException { + String expected = resourceToString("/demoPlayground/output.json", UTF_8); + String input = resourceToString("/demoPlayground/input.json", UTF_8); + + given().when().body(input).get("/jslt/transformString").then().statusCode(200).body(is(expected)); + } + + @Test + public void transformFromHeaderWithPrettyPrintShouldSucceed() throws IOException { + String expected = resourceToString("/demoPlayground/outputPrettyPrint.json", UTF_8); + String input = resourceToString("/demoPlayground/input.json", UTF_8); + + given().when().body(input).get("/jslt/transformFromHeaderWithPrettyPrint").then().statusCode(200).body(is(expected)); + } + + @Test + public void transformInputStreamWithFilterShouldSucceed() throws IOException { + String expected = resourceToString("/objectFilter/output.json", UTF_8); + String input = resourceToString("/objectFilter/input.json", UTF_8); + + given().when().body(input).get("/jslt/transformInputStreamWithFilter").then().statusCode(200).body(is(expected)); + } + + @Test + public void transformInputStreamWithVariablesShouldSucceed() throws IOException { + String expected = resourceToString("/withVariables/output.json", UTF_8); + String input = resourceToString("/withVariables/input.json", UTF_8); + + given().when().body(input).get("/jslt/transformInputStreamWithVariables").then().statusCode(200).body(is(expected)); + } + + @Test + public void transformInputStreamWithVariablesAndPropertiesShouldSucceed() throws IOException { + String expected = resourceToString("/withVariables/outputWithProperties.json", UTF_8); + String input = resourceToString("/withVariables/input.json", UTF_8); + + given().when().body(input).get("/jslt/transformInputStreamWithVariablesAndProperties").then().statusCode(200) + .body(is(expected)); + } + + @Test + public void transformWithFunctionShouldSucceed() { + given().get("/jslt/transformWithFunction").then().statusCode(200).body(is("1024.0")); + } + +} diff --git a/integration-tests/jslt/src/test/resources/demoPlayground/input.json b/integration-tests/jslt/src/test/resources/demoPlayground/input.json new file mode 100644 index 0000000..361d47a --- /dev/null +++ b/integration-tests/jslt/src/test/resources/demoPlayground/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/integration-tests/jslt/src/test/resources/demoPlayground/output.json b/integration-tests/jslt/src/test/resources/demoPlayground/output.json new file mode 100644 index 0000000..3a4e267 --- /dev/null +++ b/integration-tests/jslt/src/test/resources/demoPlayground/output.json @@ -0,0 +1 @@ +{"id":"xxxxxxxx-xxxx-xxxxx-xxxx-xxxxxxxxxxxxx","type":"Anonymized-View","schema":"http://schemas.schibsted.io/thing/pulse-simple.json#1.json","published":"2017-05-04T09:13:29+02:00","environmentId":"urn:schibsted.com:environment:uuid","url":"http://www.aftenposten.no/"} \ No newline at end of file diff --git a/integration-tests/jslt/src/test/resources/demoPlayground/outputPrettyPrint.json b/integration-tests/jslt/src/test/resources/demoPlayground/outputPrettyPrint.json new file mode 100644 index 0000000..6d6bfd1 --- /dev/null +++ b/integration-tests/jslt/src/test/resources/demoPlayground/outputPrettyPrint.json @@ -0,0 +1,8 @@ +{ + "id" : "xxxxxxxx-xxxx-xxxxx-xxxx-xxxxxxxxxxxxx", + "type" : "Anonymized-View", + "schema" : "http://schemas.schibsted.io/thing/pulse-simple.json#1.json", + "published" : "2017-05-04T09:13:29+02:00", + "environmentId" : "urn:schibsted.com:environment:uuid", + "url" : "http://www.aftenposten.no/" +} \ No newline at end of file diff --git a/integration-tests/jslt/src/test/resources/objectFilter/input.json b/integration-tests/jslt/src/test/resources/objectFilter/input.json new file mode 100644 index 0000000..d6d7fe7 --- /dev/null +++ b/integration-tests/jslt/src/test/resources/objectFilter/input.json @@ -0,0 +1,13 @@ +{ + "name": { + "firstname": "foo" + }, + "list": [ + { + "value": 1 + }, + { + "value": 2 + } + ] +} diff --git a/integration-tests/jslt/src/test/resources/objectFilter/output.json b/integration-tests/jslt/src/test/resources/objectFilter/output.json new file mode 100644 index 0000000..d307513 --- /dev/null +++ b/integration-tests/jslt/src/test/resources/objectFilter/output.json @@ -0,0 +1 @@ +{"list":[]} \ No newline at end of file diff --git a/integration-tests/jslt/src/test/resources/withVariables/input.json b/integration-tests/jslt/src/test/resources/withVariables/input.json new file mode 100644 index 0000000..e332d40 --- /dev/null +++ b/integration-tests/jslt/src/test/resources/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/integration-tests/jslt/src/test/resources/withVariables/output.json b/integration-tests/jslt/src/test/resources/withVariables/output.json new file mode 100644 index 0000000..46b8e27 --- /dev/null +++ b/integration-tests/jslt/src/test/resources/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/integration-tests/jslt/src/test/resources/withVariables/outputWithProperties.json b/integration-tests/jslt/src/test/resources/withVariables/outputWithProperties.json new file mode 100644 index 0000000..45418ed --- /dev/null +++ b/integration-tests/jslt/src/test/resources/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/integration-tests/pom.xml b/integration-tests/pom.xml index b1c8f81..eab78ea 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -112,6 +112,7 @@ <module>jira</module> <module>jolt</module> <module>jpa</module> + <module>jslt</module> <module>json-validator</module> <module>jsonpath</module> <module>jta</module> diff --git a/tooling/scripts/test-categories.yaml b/tooling/scripts/test-categories.yaml index 6831550..3355be6 100644 --- a/tooling/scripts/test-categories.yaml +++ b/tooling/scripts/test-categories.yaml @@ -80,6 +80,7 @@ xml-json-olingo4: - dataformats-json - dropbox - jing + - jslt - msv - olingo4 - weather