This is an automated email from the ASF dual-hosted git repository.
nferraro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/master by this push:
new 6d9d529 runtime: support for kotlin runtime
6d9d529 is described below
commit 6d9d529bb4257036bad924be72f9e7f43e7cf218
Author: lburgazzoli <[email protected]>
AuthorDate: Tue Sep 25 10:32:40 2018 +0200
runtime: support for kotlin runtime
---
README.adoc | 1 +
deploy/platform-integration-context-groovy.yaml | 5 +-
....yaml => platform-integration-context-jvm.yaml} | 5 +-
...ml => platform-integration-context-kotlin.yaml} | 6 +-
deploy/resources.go | 31 ++++-
pkg/apis/camel/v1alpha1/types.go | 2 +
pkg/build/assemble/maven_assembler.go | 4 +
pkg/client/cmd/completion_bash.go | 22 +++-
pkg/client/cmd/context_create.go | 11 ++
pkg/client/cmd/run.go | 23 +++-
pkg/discover/dependencies.go | 7 +-
pkg/discover/language.go | 6 +-
pkg/install/operator.go | 2 +-
pkg/stub/action/integration/initialize.go | 9 +-
pkg/stub/action/platform/create.go | 8 +-
pkg/util/util.go | 13 +++
runtime/examples/kotlin-routes.kts | 20 ++++
runtime/groovy/.gitignore | 10 ++
runtime/groovy/pom.xml | 45 ++++++++
.../apache/camel/k/groovy/GroovyRoutesLoader.java | 63 ++++++++++
.../services/org.apache.camel.k.jvm.RoutesLoader | 1 +
.../apache/camel/k/groovy/RoutesLoadersTest.java | 47 ++++++++
.../src/test/resources/routes.groovy | 0
runtime/jvm/pom.xml | 24 +++-
.../main/java/org/apache/camel/k/jvm/Language.java | 44 ++++---
.../java/org/apache/camel/k/jvm/RoutesLoaders.java | 127 ++++-----------------
.../org/apache/camel/k/jvm/dsl/Components.java | 47 ++++++++
.../java/org/apache/camel/k/jvm/dsl/Scripting.java | 47 ++++++++
.../services/org.apache.camel.k.jvm.RoutesLoader | 4 +
.../org/apache/camel/k/jvm/RoutesLoadersTest.java | 27 +----
runtime/kotlin/.gitignore | 10 ++
runtime/kotlin/pom.xml | 56 +++++++++
.../apache/camel/k/kotlin/KotlinRoutesLoader.java | 77 +++++++++++++
.../services/javax.script.ScriptEngineFactory | 1 +
.../services/org.apache.camel.k.jvm.RoutesLoader | 1 +
.../apache/camel/k/kotlin/RoutesLoadersTest.java | 50 ++++++++
runtime/kotlin/src/test/resources/routes.kts | 21 ++++
runtime/pom.xml | 3 +
38 files changed, 702 insertions(+), 178 deletions(-)
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%
copy from deploy/platform-integration-context-core.yaml
copy 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-core.yaml
b/deploy/platform-integration-context-kotlin.yaml
similarity index 65%
rename from deploy/platform-integration-context-core.yaml
rename to deploy/platform-integration-context-kotlin.yaml
index d0d3289..822b4a4 100644
--- a/deploy/platform-integration-context-core.yaml
+++ b/deploy/platform-integration-context-kotlin.yaml
@@ -1,12 +1,14 @@
apiVersion: camel.apache.org/v1alpha1
kind: IntegrationContext
metadata:
- name: core
+ name: kotlin
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
+ - 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 enum Language {
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 enum Language {
}
}
- 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 @@ package org.apache.camel.k.jvm;
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.ScriptEngineManager;
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.ObjectHelper;
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 org.slf4j.LoggerFactory;
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 enum RoutesLoaders implements RoutesLoader {
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 enum RoutesLoaders implements RoutesLoader {
}
// 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 enum RoutesLoaders implements RoutesLoader {
// 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 enum RoutesLoaders implements RoutesLoader {
}
};
}
- },
- 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 enum RoutesLoaders implements RoutesLoader {
}
};
}
- };
+ }
- 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 enum RoutesLoaders implements RoutesLoader {
? 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 enum RoutesLoaders implements RoutesLoader {
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 class RoutesLoadersTest {
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 class RoutesLoadersTest {
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 class RoutesLoadersTest {
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 class RoutesLoadersTest {
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 class RoutesLoadersTest {
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>