nicolaferraro closed pull request #133: runtime: support for kotlin runtime URL: https://github.com/apache/camel-k/pull/133
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/README.adoc b/README.adoc index 24d0779..fadd6d1 100644 --- a/README.adoc +++ b/README.adoc @@ -114,6 +114,7 @@ Camel K supports multiple languages for writing integrations: | XML | Integrations written in plain XML DSL are supported (Spring XML or Blueprint not supported). | Groovy | Groovy `.groovy` files are supported (experimental). | JavaScript | JavaScript `.js` files are supported (experimental). +| Kotlin | Kotlin Script `.kts` files are supported (experimental). |======================= Integrations written in different languages are provided in the link:/runtime/examples[examples] directory. diff --git a/deploy/platform-integration-context-groovy.yaml b/deploy/platform-integration-context-groovy.yaml index cabe24a..31aaeff 100644 --- a/deploy/platform-integration-context-groovy.yaml +++ b/deploy/platform-integration-context-groovy.yaml @@ -9,5 +9,6 @@ metadata: camel.apache.org/context.type: platform spec: dependencies: - - camel:core - - camel:groovy \ No newline at end of file + - runtime:jvm + - runtime:groovy + - camel:core \ No newline at end of file diff --git a/deploy/platform-integration-context-core.yaml b/deploy/platform-integration-context-jvm.yaml similarity index 69% rename from deploy/platform-integration-context-core.yaml rename to deploy/platform-integration-context-jvm.yaml index d0d3289..28e8ff5 100644 --- a/deploy/platform-integration-context-core.yaml +++ b/deploy/platform-integration-context-jvm.yaml @@ -1,12 +1,13 @@ apiVersion: camel.apache.org/v1alpha1 kind: IntegrationContext metadata: - name: core + name: jvm labels: app: "camel-k" camel.apache.org/context.created.by.kind: Operator - camel.apache.org/context.created.by.name: core + camel.apache.org/context.created.by.name: jvm camel.apache.org/context.type: platform spec: dependencies: + - runtime:jvm - camel:core \ No newline at end of file diff --git a/deploy/platform-integration-context-kotlin.yaml b/deploy/platform-integration-context-kotlin.yaml new file mode 100644 index 0000000..822b4a4 --- /dev/null +++ b/deploy/platform-integration-context-kotlin.yaml @@ -0,0 +1,14 @@ +apiVersion: camel.apache.org/v1alpha1 +kind: IntegrationContext +metadata: + name: kotlin + labels: + app: "camel-k" + camel.apache.org/context.created.by.kind: Operator + camel.apache.org/context.created.by.name: jvm + camel.apache.org/context.type: platform +spec: + dependencies: + - runtime:jvm + - runtime:kotlin + - camel:core \ No newline at end of file diff --git a/deploy/resources.go b/deploy/resources.go index 7749be3..a3274cb 100644 --- a/deploy/resources.go +++ b/deploy/resources.go @@ -2467,12 +2467,12 @@ metadata: app: "camel-k" ` - Resources["platform-integration-context-core.yaml"] = + Resources["platform-integration-context-groovy.yaml"] = ` apiVersion: camel.apache.org/v1alpha1 kind: IntegrationContext metadata: - name: core + name: groovy labels: app: "camel-k" camel.apache.org/context.created.by.kind: Operator @@ -2480,23 +2480,42 @@ metadata: camel.apache.org/context.type: platform spec: dependencies: + - runtime:jvm + - runtime:groovy - camel:core ` - Resources["platform-integration-context-groovy.yaml"] = + Resources["platform-integration-context-jvm.yaml"] = ` apiVersion: camel.apache.org/v1alpha1 kind: IntegrationContext metadata: - name: groovy + name: jvm labels: app: "camel-k" camel.apache.org/context.created.by.kind: Operator - camel.apache.org/context.created.by.name: core + camel.apache.org/context.created.by.name: jvm camel.apache.org/context.type: platform spec: dependencies: + - runtime:jvm + - camel:core +` + Resources["platform-integration-context-kotlin.yaml"] = + ` +apiVersion: camel.apache.org/v1alpha1 +kind: IntegrationContext +metadata: + name: kotlin + labels: + app: "camel-k" + camel.apache.org/context.created.by.kind: Operator + camel.apache.org/context.created.by.name: jvm + camel.apache.org/context.type: platform +spec: + dependencies: + - runtime:jvm + - runtime:kotlin - camel:core - - camel:groovy ` Resources["user-cluster-role.yaml"] = ` diff --git a/pkg/apis/camel/v1alpha1/types.go b/pkg/apis/camel/v1alpha1/types.go index fa27617..114942f 100644 --- a/pkg/apis/camel/v1alpha1/types.go +++ b/pkg/apis/camel/v1alpha1/types.go @@ -77,6 +77,8 @@ const ( LanguageJavaScript Language = "js" // LanguageXML -- LanguageXML Language = "xml" + // LanguageKotlin -- + LanguageKotlin Language = "kts" ) // IntegrationStatus -- diff --git a/pkg/build/assemble/maven_assembler.go b/pkg/build/assemble/maven_assembler.go index 9094181..9b2674e 100644 --- a/pkg/build/assemble/maven_assembler.go +++ b/pkg/build/assemble/maven_assembler.go @@ -162,6 +162,10 @@ func generateProject(source *build.Request) (maven.Project, error) { gav := strings.Replace(mid, "/", ":", -1) deps.AddEncodedGAV(gav) + } else if strings.HasPrefix(d, "runtime:") { + artifactID := strings.Replace(d, "runtime:", "camel-k-runtime-", 1) + + deps.AddGAV("org.apache.camel.k", artifactID, version.Version) } else { return maven.Project{}, fmt.Errorf("unknown dependency type: %s", d) } diff --git a/pkg/client/cmd/completion_bash.go b/pkg/client/cmd/completion_bash.go index c689f8e..513a821 100644 --- a/pkg/client/cmd/completion_bash.go +++ b/pkg/client/cmd/completion_bash.go @@ -50,24 +50,29 @@ __kamel_dependency_type() { COMPREPLY=( $( compgen -W "${type_list}" -- "$cur") ) ;; m*) - local type_list="mvn:"" + local type_list="mvn:" COMPREPLY=( $( compgen -W "${type_list}" -- "$cur") ) compopt -o nospace ;; f*) - local type_list="file:"" + local type_list="file:" COMPREPLY=( $( compgen -W "${type_list}" -- "$cur") ) compopt -o nospace ;; *) - local type_list="camel: mvn: file:" - COMPREPLY=( $( compgen -W "camel mvn: file:" -- "$cur") ) + local type_list="camel mvn: file:" + COMPREPLY=( $( compgen -W "${type_list}" -- "$cur") ) compopt -o nospace esac } __kamel_languages() { - local type_list="js groovy java xml" + local type_list="js groovy kotlin java xml" + COMPREPLY=( $( compgen -W "${type_list}" -- "$cur") ) +} + +__kamel_runtimes() { + local type_list="jvm groovy kotlin" COMPREPLY=( $( compgen -W "${type_list}" -- "$cur") ) } @@ -195,6 +200,13 @@ func configureKnownBashCompletions(command *cobra.Command) { cobra.BashCompCustom: {"__kamel_languages"}, }, ) + configureBashAnnotationForFlag( + command, + "runtime", + map[string][]string{ + cobra.BashCompCustom: {"__kamel_runtimes"}, + }, + ) } func configureBashAnnotationForFlag(command *cobra.Command, flagName string, annotations map[string][]string) { diff --git a/pkg/client/cmd/context_create.go b/pkg/client/cmd/context_create.go index e95ae73..739fc8d 100644 --- a/pkg/client/cmd/context_create.go +++ b/pkg/client/cmd/context_create.go @@ -23,6 +23,8 @@ import ( "strconv" "strings" + "github.com/apache/camel-k/pkg/util" + "github.com/operator-framework/operator-sdk/pkg/sdk" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" @@ -46,6 +48,7 @@ func newContextCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command { RunE: impl.run, } + cmd.Flags().StringVarP(&impl.runtime, "runtime", "r", "jvm", "Runtime provided by the context") cmd.Flags().StringSliceVarP(&impl.dependencies, "dependency", "d", nil, "Add a dependency") cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, "Add a camel property") cmd.Flags().StringSliceVar(&impl.configmaps, "configmap", nil, "Add a ConfigMap") @@ -60,6 +63,7 @@ func newContextCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command { type contextCreateCommand struct { *RootCmdOptions + runtime string dependencies []string properties []string configmaps []string @@ -105,6 +109,13 @@ func (command *contextCreateCommand) run(cmd *cobra.Command, args []string) erro } } + // jvm runtime required by default + util.StringSliceUniqueAdd(&ctx.Spec.Dependencies, "runtime:jvm") + + if command.runtime != "" { + util.StringSliceUniqueAdd(&ctx.Spec.Dependencies, "runtime:"+command.runtime) + } + for _, item := range command.properties { ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{ Type: "property", diff --git a/pkg/client/cmd/run.go b/pkg/client/cmd/run.go index ca4e52f..b9f40eb 100644 --- a/pkg/client/cmd/run.go +++ b/pkg/client/cmd/run.go @@ -56,6 +56,7 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command { } cmd.Flags().StringVarP(&options.Language, "language", "l", "", "Programming Language used to write the file") + cmd.Flags().StringVarP(&options.Runtime, "runtime", "r", "jvm", "Runtime used by the integration") cmd.Flags().StringVar(&options.IntegrationName, "name", "", "The integration name") cmd.Flags().StringSliceVarP(&options.Dependencies, "dependency", "d", nil, "The integration dependency") cmd.Flags().BoolVarP(&options.Wait, "wait", "w", false, "Waits for the integration to be running") @@ -78,6 +79,7 @@ type runCmdOptions struct { *RootCmdOptions IntegrationContext string Language string + Runtime string IntegrationName string Dependencies []string Properties []string @@ -269,13 +271,22 @@ func (o *runCmdOptions) updateIntegrationCode(filename string) (*v1alpha1.Integr } } - // special handling for groovy - // TODO: we should define handlers for languages and/or file extensions - if o.Language == "groovy" && !util.StringSliceExists(o.Dependencies, "camel:groovy") { - integration.Spec.Dependencies = append(integration.Spec.Dependencies, "camel:groovy") + if o.Language == "groovy" || strings.HasSuffix(filename, ".groovy") { + util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:groovy") } - if o.Language == "" && strings.HasSuffix(filename, ".groovy") { - integration.Spec.Dependencies = append(integration.Spec.Dependencies, "camel:groovy") + if o.Language == "kotlin" || strings.HasSuffix(filename, ".kts") { + util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:kotlin") + } + + // jvm runtime required by default + util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:jvm") + + if o.Runtime != "" { + util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:"+o.Runtime) + } + + switch o.Runtime { + } for _, item := range o.Properties { diff --git a/pkg/discover/dependencies.go b/pkg/discover/dependencies.go index 82ef757..b6daa63 100644 --- a/pkg/discover/dependencies.go +++ b/pkg/discover/dependencies.go @@ -18,11 +18,12 @@ limitations under the License. package discover import ( - "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" - "github.com/apache/camel-k/pkg/util/camel" "regexp" "sort" "strings" + + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/util/camel" ) var ( @@ -65,6 +66,8 @@ func getRegexpsForLanguage(language v1alpha1.Language) []*regexp.Regexp { return []*regexp.Regexp{singleQuotedURI, doubleQuotedURI} case v1alpha1.LanguageJavaScript: return []*regexp.Regexp{singleQuotedURI, doubleQuotedURI} + case v1alpha1.LanguageKotlin: + return []*regexp.Regexp{doubleQuotedURI} } return []*regexp.Regexp{} } diff --git a/pkg/discover/language.go b/pkg/discover/language.go index e38d583..cafb6c3 100644 --- a/pkg/discover/language.go +++ b/pkg/discover/language.go @@ -19,8 +19,9 @@ limitations under the License. package discover import ( - "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" "strings" + + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" ) // Language discovers the code language from file extension if not set @@ -33,7 +34,8 @@ func Language(source v1alpha1.SourceSpec) v1alpha1.Language { v1alpha1.LanguageJavaClass, v1alpha1.LanguageJavaScript, v1alpha1.LanguageGroovy, - v1alpha1.LanguageJavaScript} { + v1alpha1.LanguageJavaScript, + v1alpha1.LanguageKotlin} { if strings.HasSuffix(source.Name, "."+string(l)) { return l diff --git a/pkg/install/operator.go b/pkg/install/operator.go index 0f6039c..eb3ac4c 100644 --- a/pkg/install/operator.go +++ b/pkg/install/operator.go @@ -30,7 +30,7 @@ func Operator(namespace string) error { // Platform installs the platform custom resource func Platform(namespace string) error { - return Resource(namespace,"platform-cr.yaml") + return Resource(namespace, "platform-cr.yaml") } // Example -- diff --git a/pkg/stub/action/integration/initialize.go b/pkg/stub/action/integration/initialize.go index d9ab6c0..f0b5e7f 100644 --- a/pkg/stub/action/integration/initialize.go +++ b/pkg/stub/action/integration/initialize.go @@ -22,6 +22,8 @@ import ( "github.com/sirupsen/logrus" "sort" + "github.com/apache/camel-k/pkg/util" + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" "github.com/apache/camel-k/pkg/discover" "github.com/apache/camel-k/pkg/util/digest" @@ -46,7 +48,7 @@ func (action *initializeAction) CanHandle(integration *v1alpha1.Integration) boo return integration.Status.Phase == "" } -// Handle handles the integratios +// Handle handles the integrations func (action *initializeAction) Handle(integration *v1alpha1.Integration) error { // The integration platform needs to be ready before starting to create integrations if pl, err := platform.GetCurrentPlatform(integration.Namespace); err != nil || pl.Status.Phase != v1alpha1.IntegrationPlatformPhaseReady { @@ -63,6 +65,11 @@ func (action *initializeAction) Handle(integration *v1alpha1.Integration) error // set the correct language language := discover.Language(target.Spec.Source) target.Spec.Source.Language = language + + if !util.StringSliceExists(target.Spec.Dependencies, "camel:core") { + target.Spec.Dependencies = append(target.Spec.Dependencies, "camel:core") + } + // discover dependencies if target.Spec.DependenciesAutoDiscovery == nil { var autoDiscoveryDependencies = true diff --git a/pkg/stub/action/platform/create.go b/pkg/stub/action/platform/create.go index c313ccf..0933e2f 100644 --- a/pkg/stub/action/platform/create.go +++ b/pkg/stub/action/platform/create.go @@ -24,6 +24,12 @@ import ( "github.com/sirupsen/logrus" ) +var resources = []string{ + "platform-integration-context-jvm.yaml", + "platform-integration-context-groovy.yaml", + "platform-integration-context-kotlin.yaml", +} + // NewCreateAction returns a action that creates resources needed by the platform func NewCreateAction() Action { return &createAction{} @@ -41,7 +47,7 @@ func (action *createAction) CanHandle(platform *v1alpha1.IntegrationPlatform) bo } func (action *createAction) Handle(platform *v1alpha1.IntegrationPlatform) error { - err := install.Resources(platform.Namespace, "platform-integration-context-core.yaml", "platform-integration-context-groovy.yaml") + err := install.Resources(platform.Namespace, resources...) if err != nil { return err } diff --git a/pkg/util/util.go b/pkg/util/util.go index c2a2631..7792210 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -38,3 +38,16 @@ func StringSliceExists(slice []string, item string) bool { return false } + +// StringSliceUniqueAdd append the given item if not already present in the slice +func StringSliceUniqueAdd(slice *[]string, item string) bool { + for _, i := range *slice { + if i == item { + return false + } + } + + *slice = append(*slice, item) + + return true +} diff --git a/runtime/examples/kotlin-routes.kts b/runtime/examples/kotlin-routes.kts new file mode 100644 index 0000000..8c49d44 --- /dev/null +++ b/runtime/examples/kotlin-routes.kts @@ -0,0 +1,20 @@ +// +// To run this integrations use: +// +// kamel run --runtime kotlin runtime/examples/kotlin-routes.kts +// +// Or leveraging runtime detection +// +// kamel run runtime/examples/kotlin-routes.kts +// + +val rnd = java.util.Random() + +from("timer:kotlin?period=1s") + .routeId("kotlin") + .setBody() + .constant("Hello Camel K!") + .process().message { + m -> m.headers["RandomValue"] = rnd.nextInt() + } + .to("log:info?showHeaders=true") \ No newline at end of file diff --git a/runtime/groovy/.gitignore b/runtime/groovy/.gitignore new file mode 100644 index 0000000..ed92983 --- /dev/null +++ b/runtime/groovy/.gitignore @@ -0,0 +1,10 @@ +target + +*.iml + +.idea +.project +.metadata +.settings +.factorypath +.classpath diff --git a/runtime/groovy/pom.xml b/runtime/groovy/pom.xml new file mode 100644 index 0000000..a3fb478 --- /dev/null +++ b/runtime/groovy/pom.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.apache.camel.k</groupId> + <artifactId>camel-k-runtime-parent</artifactId> + <version>0.0.3-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>camel-k-runtime-groovy</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.camel.k</groupId> + <artifactId>camel-k-runtime-jvm</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-groovy</artifactId> + </dependency> + + <!-- ****************************** --> + <!-- --> + <!-- TESTS --> + <!-- --> + <!-- ****************************** --> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>${assertj.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + +</project> diff --git a/runtime/groovy/src/main/java/org/apache/camel/k/groovy/GroovyRoutesLoader.java b/runtime/groovy/src/main/java/org/apache/camel/k/groovy/GroovyRoutesLoader.java new file mode 100644 index 0000000..ee8a512 --- /dev/null +++ b/runtime/groovy/src/main/java/org/apache/camel/k/groovy/GroovyRoutesLoader.java @@ -0,0 +1,63 @@ +/** + * 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.k.groovy; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Collections; +import java.util.List; + +import groovy.lang.Binding; +import groovy.lang.GroovyShell; +import groovy.util.DelegatingScript; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.k.jvm.Language; +import org.apache.camel.k.jvm.RoutesLoader; +import org.apache.camel.k.jvm.dsl.Scripting; +import org.apache.camel.util.ResourceHelper; +import org.codehaus.groovy.control.CompilerConfiguration; + +public class GroovyRoutesLoader implements RoutesLoader { + @Override + public List<Language> getSupportedLanguages() { + return Collections.singletonList(Language.Groovy); + } + + @Override + public RouteBuilder load(String resource) throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + CompilerConfiguration cc = new CompilerConfiguration(); + cc.setScriptBaseClass(DelegatingScript.class.getName()); + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + GroovyShell sh = new GroovyShell(cl, new Binding(), cc); + + try (InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(getContext(), resource)) { + Reader reader = new InputStreamReader(is); + DelegatingScript script = (DelegatingScript) sh.parse(reader); + + // set the delegate target + script.setDelegate(new Scripting(this)); + script.run(); + } + } + }; + } +} diff --git a/runtime/groovy/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader b/runtime/groovy/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader new file mode 100644 index 0000000..db214e0 --- /dev/null +++ b/runtime/groovy/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader @@ -0,0 +1 @@ +org.apache.camel.k.groovy.GroovyRoutesLoader \ No newline at end of file diff --git a/runtime/groovy/src/test/java/org/apache/camel/k/groovy/RoutesLoadersTest.java b/runtime/groovy/src/test/java/org/apache/camel/k/groovy/RoutesLoadersTest.java new file mode 100644 index 0000000..8a64faa --- /dev/null +++ b/runtime/groovy/src/test/java/org/apache/camel/k/groovy/RoutesLoadersTest.java @@ -0,0 +1,47 @@ +/** + * 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.k.groovy; + +import java.util.List; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.k.jvm.RoutesLoader; +import org.apache.camel.k.jvm.RoutesLoaders; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.model.ToDefinition; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RoutesLoadersTest { + @Test + public void testLoadGroovy() throws Exception { + String resource = "classpath:routes.groovy"; + RoutesLoader loader = RoutesLoaders.loaderFor(resource, null); + RouteBuilder builder = loader.load(resource); + + assertThat(loader).isInstanceOf(GroovyRoutesLoader.class); + assertThat(builder).isNotNull(); + + builder.configure(); + + List<RouteDefinition> routes = builder.getRouteCollection().getRoutes(); + assertThat(routes).hasSize(1); + assertThat(routes.get(0).getInputs().get(0).getEndpointUri()).isEqualTo("timer:tick"); + assertThat(routes.get(0).getOutputs().get(0)).isInstanceOf(ToDefinition.class); + } +} diff --git a/runtime/jvm/src/test/resources/routes.groovy b/runtime/groovy/src/test/resources/routes.groovy similarity index 100% rename from runtime/jvm/src/test/resources/routes.groovy rename to runtime/groovy/src/test/resources/routes.groovy diff --git a/runtime/jvm/pom.xml b/runtime/jvm/pom.xml index 2ea58ff..9dc3918 100644 --- a/runtime/jvm/pom.xml +++ b/runtime/jvm/pom.xml @@ -11,7 +11,18 @@ <artifactId>camel-k-runtime-jvm</artifactId> + <properties> + <kotlin.version>1.2.71</kotlin.version> + </properties> + <dependencies> + + <!-- ****************************** --> + <!-- --> + <!-- RUNTIME --> + <!-- --> + <!-- ****************************** --> + <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-core</artifactId> @@ -25,6 +36,7 @@ <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j2.version}</version> + <scope>runtime</scope> </dependency> <dependency> <groupId>org.jooq</groupId> @@ -41,12 +53,12 @@ <artifactId>commons-lang3</artifactId> <version>${commons-lang.version}</version> </dependency> - <dependency> - <groupId>org.codehaus.groovy</groupId> - <artifactId>groovy</artifactId> - <version>${groovy.version}</version> - <optional>true</optional> - </dependency> + + <!-- ****************************** --> + <!-- --> + <!-- TESTS --> + <!-- --> + <!-- ****************************** --> <dependency> <groupId>junit</groupId> diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java index a2a8377..d041faa 100644 --- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java +++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java @@ -16,29 +16,45 @@ */ package org.apache.camel.k.jvm; +import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.commons.lang3.StringUtils; public enum Language { - Unknow("", Collections.emptyList()), - JavaClass("class", Collections.singletonList("class")), - JavaSource("java", Collections.singletonList("java")), - JavaScript("js", Collections.singletonList("js")), - Groovy("groovy", Collections.singletonList("groovy")), - Xml("xml", Collections.singletonList("xml")); + Unknown( + Collections.emptyList(), + Collections.emptyList()), + JavaClass( + Collections.singletonList("class"), + Collections.singletonList("class")), + JavaSource( + Collections.singletonList("java"), + Collections.singletonList("java")), + JavaScript( + Arrays.asList("js", "javascript"), + Collections.singletonList("js")), + Groovy( + Collections.singletonList("groovy"), + Collections.singletonList("groovy")), + Xml( + Collections.singletonList("xml"), + Collections.singletonList("xml")), + Kotlin( + Arrays.asList("kotlin", "kts"), + Collections.singletonList("kts")); - private final String name; + private final List<String> names; private final List<String> extensions; - Language(String name, List<String> extensions) { - this.name = name; + Language(List<String> names, List<String> extensions) { + this.names = names; this.extensions = extensions; } - public String getName() { - return name; + public List<String> getNames() { + return names; } public List<String> getExtensions() { @@ -47,12 +63,12 @@ public String getName() { public static Language fromLanguageName(String name) { for (Language language: values()) { - if (language.getName().equals(name)) { + if (language.getNames().contains(name)) { return language; } } - return Unknow; + return Unknown; } public static Language fromResource(String resource) { @@ -66,6 +82,6 @@ public static Language fromResource(String resource) { } } - return Unknow; + return Unknown; } } diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java index 448c2bb..2581d48 100644 --- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java +++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java @@ -18,10 +18,10 @@ import java.io.InputStream; import java.io.InputStreamReader; -import java.io.Reader; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; +import java.util.ServiceLoader; import java.util.function.Function; import java.util.function.Supplier; import javax.script.Bindings; @@ -30,12 +30,9 @@ import javax.script.SimpleBindings; import javax.xml.bind.UnmarshalException; -import groovy.lang.Binding; -import groovy.lang.GroovyShell; -import groovy.util.DelegatingScript; import org.apache.camel.CamelContext; -import org.apache.camel.Component; import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.k.jvm.dsl.Components; import org.apache.camel.model.RouteDefinition; import org.apache.camel.model.rest.RestConfigurationDefinition; import org.apache.camel.model.rest.RestDefinition; @@ -43,7 +40,6 @@ import org.apache.camel.util.ResourceHelper; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.codehaus.groovy.control.CompilerConfiguration; import org.joor.Reflect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +47,13 @@ import static org.apache.camel.k.jvm.Constants.SCHEME_CLASSPATH; import static org.apache.camel.k.jvm.Constants.SCHEME_FILE; -public enum RoutesLoaders implements RoutesLoader { - JavaClass { +public final class RoutesLoaders { + private static final Logger LOGGER = LoggerFactory.getLogger(RoutesLoaders.class); + + private RoutesLoaders() { + } + + public static class JavaClass implements RoutesLoader { @Override public List<Language> getSupportedLanguages() { return Collections.singletonList(Language.JavaClass); @@ -72,8 +73,9 @@ public RouteBuilder load(String resource) throws Exception { return (RouteBuilder)type.newInstance(); } - }, - JavaSource { + } + + public static class JavaSource implements RoutesLoader { @Override public List<Language> getSupportedLanguages() { return Collections.singletonList(Language.JavaSource); @@ -93,15 +95,16 @@ public void configure() throws Exception { } // Wrap routes builder - includeRoutes( + addRoutes( Reflect.compile(name, IOUtils.toString(is, StandardCharsets.UTF_8)).create().get() ); } } }; } - }, - JavaScript { + } + + public static class JavaScript implements RoutesLoader { @Override public List<Language> getSupportedLanguages() { return Collections.singletonList(Language.JavaScript); @@ -119,6 +122,7 @@ public void configure() throws Exception { // Exposed to the underlying script, but maybe better to have // a nice dsl + bindings.put("builder", this); bindings.put("context", context); bindings.put("components", new Components(context)); bindings.put("from", (Function<String, RouteDefinition>) uri -> from(uri)); @@ -131,37 +135,9 @@ public void configure() throws Exception { } }; } - }, - Groovy { - @Override - public List<Language> getSupportedLanguages() { - return Collections.singletonList(Language.Groovy); - } - - @Override - public RouteBuilder load(String resource) throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - CompilerConfiguration cc = new CompilerConfiguration(); - cc.setScriptBaseClass(DelegatingScript.class.getName()); - - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - GroovyShell sh = new GroovyShell(cl, new Binding(), cc); - - try (InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(getContext(), resource)) { - Reader reader = new InputStreamReader(is); - DelegatingScript script = (DelegatingScript) sh.parse(reader); + } - // set the delegate target - script.setDelegate(new ScriptingDsl(this)); - script.run(); - } - } - }; - } - }, - Xml { + public static class Xml implements RoutesLoader { @Override public List<Language> getSupportedLanguages() { return Collections.singletonList(Language.Xml); @@ -192,9 +168,8 @@ public void configure() throws Exception { } }; } - }; + } - private static final Logger LOGGER = LoggerFactory.getLogger(RoutesLoaders.class); public static RoutesLoader loaderFor(String resource, String languageName) { if (!resource.startsWith(SCHEME_CLASSPATH) && !resource.startsWith(SCHEME_FILE)) { @@ -205,7 +180,7 @@ public static RoutesLoader loaderFor(String resource, String languageName) { ? Language.fromLanguageName(languageName) : Language.fromResource(resource); - for (RoutesLoader loader: RoutesLoaders.values()) { + for (RoutesLoader loader: ServiceLoader.load(RoutesLoader.class)) { if (loader.getSupportedLanguages().contains(language)) { return loader; } @@ -213,64 +188,4 @@ public static RoutesLoader loaderFor(String resource, String languageName) { throw new IllegalArgumentException("Unable to find loader for: resource=" + resource + " language=" + languageName); } - - // ******************************** - // - // Helpers - // - // TODO: move to a dedicate class - // ******************************** - - - public static class Components { - private CamelContext context; - - public Components(CamelContext context) { - this.context = context; - } - - public Component get(String scheme) { - return context.getComponent(scheme, true); - } - - public Component put(String scheme, Component instance) { - context.addComponent(scheme, instance); - - return instance; - } - - public Component make(String scheme, String type) { - final Class<?> clazz = context.getClassResolver().resolveClass(type); - final Component instance = (Component)context.getInjector().newInstance(clazz); - - context.addComponent(scheme, instance); - - return instance; - } - } - - private static class ScriptingDsl { - private final RouteBuilder builder; - - public final CamelContext context; - public final Components components; - - public ScriptingDsl(RouteBuilder builder) { - this.builder = builder; - this.context = builder.getContext(); - this.components = new Components(builder.getContext()); - } - - public RouteDefinition from(String endpoint) { - return builder.from(endpoint); - } - - public RestDefinition rest() { - return builder.rest(); - } - - public RestConfigurationDefinition restConfiguration() { - return builder.restConfiguration(); - } - } } diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/dsl/Components.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/dsl/Components.java new file mode 100644 index 0000000..bac1390 --- /dev/null +++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/dsl/Components.java @@ -0,0 +1,47 @@ +/** + * 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.k.jvm.dsl; + +import org.apache.camel.CamelContext; +import org.apache.camel.Component; + +public class Components { + private CamelContext context; + + public Components(CamelContext context) { + this.context = context; + } + + public Component get(String scheme) { + return context.getComponent(scheme, true); + } + + public Component put(String scheme, Component instance) { + context.addComponent(scheme, instance); + + return instance; + } + + public Component make(String scheme, String type) { + final Class<?> clazz = context.getClassResolver().resolveClass(type); + final Component instance = (Component)context.getInjector().newInstance(clazz); + + context.addComponent(scheme, instance); + + return instance; + } +} diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/dsl/Scripting.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/dsl/Scripting.java new file mode 100644 index 0000000..3988290 --- /dev/null +++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/dsl/Scripting.java @@ -0,0 +1,47 @@ +/** + * 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.k.jvm.dsl; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.model.rest.RestConfigurationDefinition; +import org.apache.camel.model.rest.RestDefinition; + +public class Scripting { + public final RouteBuilder builder; + public final CamelContext context; + public final Components components; + + public Scripting(RouteBuilder builder) { + this.builder = builder; + this.context = builder.getContext(); + this.components = new Components(builder.getContext()); + } + + public RouteDefinition from(String endpoint) { + return builder.from(endpoint); + } + + public RestDefinition rest() { + return builder.rest(); + } + + public RestConfigurationDefinition restConfiguration() { + return builder.restConfiguration(); + } +} diff --git a/runtime/jvm/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader b/runtime/jvm/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader new file mode 100644 index 0000000..5a57927 --- /dev/null +++ b/runtime/jvm/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader @@ -0,0 +1,4 @@ +org.apache.camel.k.jvm.RoutesLoaders$JavaClass +org.apache.camel.k.jvm.RoutesLoaders$JavaSource +org.apache.camel.k.jvm.RoutesLoaders$JavaScript +org.apache.camel.k.jvm.RoutesLoaders$Xml diff --git a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java index 4b2090f..54b492b 100644 --- a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java +++ b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java @@ -33,7 +33,7 @@ public void testLoadClass() throws Exception { RoutesLoader loader = RoutesLoaders.loaderFor(resource, null); RouteBuilder builder = loader.load(resource); - assertThat(loader).isSameAs(RoutesLoaders.JavaClass); + assertThat(loader).isInstanceOf(RoutesLoaders.JavaClass.class); assertThat(builder).isNotNull(); builder.configure(); @@ -50,7 +50,7 @@ public void testLoadJava() throws Exception { RoutesLoader loader = RoutesLoaders.loaderFor(resource, null); RouteBuilder builder = loader.load(resource); - assertThat(loader).isSameAs(RoutesLoaders.JavaSource); + assertThat(loader).isInstanceOf(RoutesLoaders.JavaSource.class); assertThat(builder).isNotNull(); builder.configure(); @@ -67,7 +67,7 @@ public void testLoadJavaScript() throws Exception { RoutesLoader loader = RoutesLoaders.loaderFor(resource, null); RouteBuilder builder = loader.load(resource); - assertThat(loader).isSameAs(RoutesLoaders.JavaScript); + assertThat(loader).isInstanceOf(RoutesLoaders.JavaScript.class); assertThat(builder).isNotNull(); builder.configure(); @@ -84,24 +84,7 @@ public void testLoadJavaScriptWithCustomExtension() throws Exception { RoutesLoader loader = RoutesLoaders.loaderFor(resource, "js"); RouteBuilder builder = loader.load(resource); - assertThat(loader).isSameAs(RoutesLoaders.JavaScript); - assertThat(builder).isNotNull(); - - builder.configure(); - - List<RouteDefinition> routes = builder.getRouteCollection().getRoutes(); - assertThat(routes).hasSize(1); - assertThat(routes.get(0).getInputs().get(0).getEndpointUri()).isEqualTo("timer:tick"); - assertThat(routes.get(0).getOutputs().get(0)).isInstanceOf(ToDefinition.class); - } - - @Test - public void testLoadGroovy() throws Exception { - String resource = "classpath:routes.groovy"; - RoutesLoader loader = RoutesLoaders.loaderFor(resource, null); - RouteBuilder builder = loader.load(resource); - - assertThat(loader).isSameAs(RoutesLoaders.Groovy); + assertThat(loader).isInstanceOf(RoutesLoaders.JavaScript.class); assertThat(builder).isNotNull(); builder.configure(); @@ -118,7 +101,7 @@ public void testLoadXml() throws Exception { RoutesLoader loader = RoutesLoaders.loaderFor(resource, null); RouteBuilder builder = loader.load(resource); - assertThat(loader).isSameAs(RoutesLoaders.Xml); + assertThat(loader).isInstanceOf(RoutesLoaders.Xml.class); assertThat(builder).isNotNull(); builder.configure(); diff --git a/runtime/kotlin/.gitignore b/runtime/kotlin/.gitignore new file mode 100644 index 0000000..ed92983 --- /dev/null +++ b/runtime/kotlin/.gitignore @@ -0,0 +1,10 @@ +target + +*.iml + +.idea +.project +.metadata +.settings +.factorypath +.classpath diff --git a/runtime/kotlin/pom.xml b/runtime/kotlin/pom.xml new file mode 100644 index 0000000..9036f76 --- /dev/null +++ b/runtime/kotlin/pom.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.apache.camel.k</groupId> + <artifactId>camel-k-runtime-parent</artifactId> + <version>0.0.3-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>camel-k-runtime-kotlin</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.camel.k</groupId> + <artifactId>camel-k-runtime-jvm</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-stdlib-jdk8</artifactId> + <version>${kotlin.version}</version> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-script-util</artifactId> + <version>${kotlin.version}</version> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-compiler-embeddable</artifactId> + <version>${kotlin.version}</version> + </dependency> + + <!-- ****************************** --> + <!-- --> + <!-- TESTS --> + <!-- --> + <!-- ****************************** --> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>${assertj.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + +</project> diff --git a/runtime/kotlin/src/main/java/org/apache/camel/k/kotlin/KotlinRoutesLoader.java b/runtime/kotlin/src/main/java/org/apache/camel/k/kotlin/KotlinRoutesLoader.java new file mode 100644 index 0000000..0b887ef --- /dev/null +++ b/runtime/kotlin/src/main/java/org/apache/camel/k/kotlin/KotlinRoutesLoader.java @@ -0,0 +1,77 @@ +/** + * 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.k.kotlin; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Collections; +import java.util.List; +import javax.script.Bindings; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.SimpleBindings; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.k.jvm.dsl.Components; +import org.apache.camel.k.jvm.Language; +import org.apache.camel.k.jvm.RoutesLoader; +import org.apache.camel.util.ResourceHelper; + +public class KotlinRoutesLoader implements RoutesLoader { + + @Override + public List<Language> getSupportedLanguages() { + return Collections.singletonList(Language.Kotlin); + } + + @Override + public RouteBuilder load(String resource) throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + final CamelContext context = getContext(); + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByExtension("kts"); + final Bindings bindings = new SimpleBindings(); + + // Exposed to the underlying script, but maybe better to have + // a nice dsl + bindings.put("builder", this); + bindings.put("context", context); + bindings.put("components", new Components(context)); + + try (InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(context, resource)) { + StringBuilder builder = new StringBuilder(); + + // extract global objects from 'bindings' + builder.append("val builder = bindings[\"builder\"] as org.apache.camel.builder.RouteBuilder").append('\n'); + builder.append("val context = bindings[\"context\"] as org.apache.camel.CamelContext").append('\n'); + builder.append("val components = bindings[\"components\"] as org.apache.camel.k.jvm.dsl.Components").append('\n'); + + // create aliases for common functions + builder.append("fun from(uri: String): org.apache.camel.model.RouteDefinition = builder.from(uri)").append('\n'); + builder.append("fun rest(): org.apache.camel.model.rest.RestDefinition = builder.rest()").append('\n'); + builder.append("fun restConfiguration(): org.apache.camel.model.rest.RestConfigurationDefinition = builder.restConfiguration()").append('\n'); + + engine.eval(builder.toString(), bindings); + engine.eval(new InputStreamReader(is), bindings); + } + } + }; + } +} diff --git a/runtime/kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory b/runtime/kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 0000000..f8f5900 --- /dev/null +++ b/runtime/kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1 @@ +org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory \ No newline at end of file diff --git a/runtime/kotlin/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader b/runtime/kotlin/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader new file mode 100644 index 0000000..83c3f09 --- /dev/null +++ b/runtime/kotlin/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader @@ -0,0 +1 @@ +org.apache.camel.k.kotlin.KotlinRoutesLoader \ No newline at end of file diff --git a/runtime/kotlin/src/test/java/org/apache/camel/k/kotlin/RoutesLoadersTest.java b/runtime/kotlin/src/test/java/org/apache/camel/k/kotlin/RoutesLoadersTest.java new file mode 100644 index 0000000..5c23d67 --- /dev/null +++ b/runtime/kotlin/src/test/java/org/apache/camel/k/kotlin/RoutesLoadersTest.java @@ -0,0 +1,50 @@ +/** + * 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.k.kotlin; + +import java.util.List; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.k.jvm.RoutesLoader; +import org.apache.camel.k.jvm.RoutesLoaders; +import org.apache.camel.model.ProcessDefinition; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.model.ToDefinition; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RoutesLoadersTest { + + @Test + public void testLoadKotlin() throws Exception { + String resource = "classpath:routes.kts"; + RoutesLoader loader = RoutesLoaders.loaderFor(resource, null); + RouteBuilder builder = loader.load(resource); + + assertThat(loader).isInstanceOf(KotlinRoutesLoader.class); + assertThat(builder).isNotNull(); + + builder.configure(); + + List<RouteDefinition> routes = builder.getRouteCollection().getRoutes(); + assertThat(routes).hasSize(1); + assertThat(routes.get(0).getInputs().get(0).getEndpointUri()).isEqualTo("timer:tick"); + assertThat(routes.get(0).getOutputs().get(0)).isInstanceOf(ProcessDefinition.class); + assertThat(routes.get(0).getOutputs().get(1)).isInstanceOf(ToDefinition.class); + } +} diff --git a/runtime/kotlin/src/test/resources/routes.kts b/runtime/kotlin/src/test/resources/routes.kts new file mode 100644 index 0000000..22b0e14 --- /dev/null +++ b/runtime/kotlin/src/test/resources/routes.kts @@ -0,0 +1,21 @@ + +// ******************** +// +// setup +// +// ******************** + +//val builder = bindings["builder"] as org.apache.camel.builder.RouteBuilder +//fun from(uri: String): org.apache.camel.model.RouteDefinition = builder.from(uri) + +// ******************** +// +// routes +// +// ******************** + +from("timer:tick") + .process().message { + m -> m.headers["MyHeader"] = "MyHeaderValue" + } + .to("log:info") \ No newline at end of file diff --git a/runtime/pom.xml b/runtime/pom.xml index 0948ca3..8278b4f 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -24,6 +24,7 @@ <log4j2.version>2.11.0</log4j2.version> <slf4j.version>1.7.25</slf4j.version> <groovy.version>2.5.2</groovy.version> + <kotlin.version>1.2.71</kotlin.version> <snakeyaml.version>1.23</snakeyaml.version> <fabric8-maven-plugin.version>3.5.40</fabric8-maven-plugin.version> @@ -55,6 +56,8 @@ <modules> <module>jvm</module> + <module>groovy</module> + <module>kotlin</module> <module>catalog-builder</module> <module>dependency-lister</module> </modules> ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services