nicolaferraro closed pull request #155: doc: add initial documentation about integration DSLs URL: https://github.com/apache/camel-k/pull/155
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 20ad1996..ff411882 100644 --- a/README.adoc +++ b/README.adoc @@ -144,10 +144,12 @@ Camel K supports multiple languages for writing integrations: | Java | Both integrations in source `.java` files or compiled `.class` file can be run. | 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). +| JavaScript | JavaScript `.js` files are supported (experimental). | Kotlin | Kotlin Script `.kts` files are supported (experimental). |======================= +More information about supported languages is provided in the link:docs/languages.adoc[lanuguages guide] + Integrations written in different languages are provided in the link:/runtime/examples[examples] directory. An example of integration written in JavaScript is the link:/runtime/examples/dns.js[/runtime/examples/dns.js] integration. @@ -198,4 +200,4 @@ oc delete all,pvc,configmap,rolebindings,clusterrolebindings,secrets,sa,roles,cl [[licensing]] == Licensing -This software is licensed under the terms you may find in the file named LICENSE in this directory. \ No newline at end of file +This software is licensed under the terms you may find in the file named LICENSE in this directory. diff --git a/docs/languages.adoc b/docs/languages.adoc new file mode 100644 index 00000000..1bef183c --- /dev/null +++ b/docs/languages.adoc @@ -0,0 +1,296 @@ +[[languages]] += Languages + +Camel K supports integration written in the following languages:name: value + +[options="header"] +|======================= +| Language | Description +| Java | Both integrations in source `.java` files or compiled `.class` file can be run. +| 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). +|======================= + +[WARNING] +==== +Work In Progress +==== + +=== Java + +Using java to write an integration to be deployed using camel-k is not different from defining your routing rules in Camel with the only difference that you do not need to build and package it as a jar. + +[source,java] +.Example +---- +import org.apache.camel.builder.RouteBuilder; + +public class Sample extends RouteBuilder { + @Override + public void configure() throws Exception { + from("timer:tick") + .setBody() + .constant("Hello Camel K!") + .to("log:info"); + } +} +---- + +=== XML + +Camel K support the standard Camel Routes XML DSL: + +[source,xml] +.Example +---- +<routes xmlns="http://camel.apache.org/schema/spring"> + <route> + <from uri="timer:tick"/> + <setBody> + <constant>Hello Camel K!</constant> + </setBody> + <to uri="log:info"/> + </route> +</routes> +---- + +=== Groovy + +An integration written in Groovy looks very similar to a Java one except it can leverages Groovy's language enhancements over Java: + +[source,java] +---- +from('timer:tick') + .process { it.in.body = 'Hello Camel K!' } + .to('log:info') +---- + +Camel K extends the Camel Java DSL making it easier to configure the context in which the integration runs using the top level _context_ block + +[source,java] +---- +context { + // configure the context here +} +---- + +At the moment the enhanced DSL provides a way to bind items to the registry, to configure the components the context creates and some improvements over the REST DSL. + +- *Registry* ++ +The registry is accessible using the _registry_ block inside the _context_ one: ++ +[source,java] +---- +context { + registry { + bind "my-cache", Caffeine.newBuilder().build() // <1> + bind "my-processor", processor { // <2> + it.in.body = 'Hello Camel K!' + } + bind "my-predicate", predicate { // <3> + it.in.body != null + } + } +} +---- +<1> bind a bean to the context +<2> define a custom processor to be used later in the routes by ref +<2> define a custom predicate to be used later in the routes by ref + + +- *Components* ++ +Components can be configured within the _components_ block inside the _context_ one: ++ +[source,java] +---- +context { + components { + 'seda' { // <1> + queueSize = 1234 + concurrentConsumers = 12 + } + + 'log' { // <2> + exchangeFormatter = { + 'body ==> ' + it.in.body + } as org.apache.camel.spi.ExchangeFormatter + } + } +} +---- +<1> configure the properties of the component whit name _seda_ +<2> configure the properties of the component whit name _log_ ++ +Setting the property _exchangeFormatter_ looks a little ugly as you have to declare the type of your closure. For demonstration purpose we have created a Groovy extension module that simplify configuring the _exchangeFormatter_ so you can rewrite your DSL as ++ +[source,java] +---- +context { + components { + ... + + 'log' { + formatter { + 'body ==> ' + it.in.body + } + } + } +} +---- ++ +which is much better. ++ +[TIP] +==== +You can provide your custom extensions by packaging them in a dependency you declare for your integration. +==== + +- *Rest* ++ +Integrations's REST endpoints can be configured using the top level _rest_ block: ++ +[source,java] +---- +rest { + configuration { // <1> + host = 'my-host' + port '9192' + } + + path('/my/path') { // <2> + // standard Rest DSL + } +} +---- +<1> Configure the rest engine +<2> Configure the rest endpoint for the base path '/my/path' + +=== Kotlin + +An integration written in Kotlin looks very similar to a Java one except it can leverages Kotlin's language enhancements over Java: + +[source,java] +---- +from('timer:tick') + .process { e -> e.getIn().body = 'Hello Camel K!' } + .to('log:info'); +---- + +Camel K extends the Camel Java DSL making it easier to configure the context in which the integration runs using the top level _context_ block + +[source,java] +---- +context { + // configure the context here +} +---- + +At the moment the enhanced DSL provides a way to bind items to the registry, to configure the components the context creates and some improvements over the REST DSL. + +- *Registry* ++ +The registry is accessible using the _registry_ block inside the _context_ one: ++ +[source,java] +---- +context { + registry { + bind("my-cache", Caffeine.newBuilder().build()) // <1> + bind("my-processor", processor { // <2> + e -> e.getIn().body = "Hello" + }) + bind("my-predicate", predicate { // <2> + e -> e.getIn().body != null + }) + } +} +---- +<1> bind a simple bean to the context +<2> define a custom processor to be used later in the routes by ref +<2> define a custom predicate to be used later in the routes by ref + + +- *Components* ++ +Components can be configured within the _components_ block inside the _context_ one: ++ +[source,java] +---- +context { + components { + component<SedaComponent>("seda") { //<1> + queueSize = 1234 + concurrentConsumers = 12 + } + + component<SedaComponent>("mySeda") { // <2> + queueSize = 4321 + concurrentConsumers = 21 + } + + component<LogComponent>("log") { // <3> + setExchangeFormatter { + e: Exchange -> "" + e.getIn().body + } + } + } +} +---- +<1> configure the properties of a component whit type _SedaComponent_ and name _seda_ +<2> configure the properties of a component with type SedaComponent and name _mySeda_, note that as _mySeda_ does not represent a valid component scheme, a new component of the required type will be instantiated. +<3> configure the properties of the component whit name _log_ ++ +[NOTE] +==== +As for Groovy, you can provide your custom extension to the DSL +==== + +- *Rest* ++ +Integrations's REST endpoints can be configured using the top level _rest_ block: ++ +[source,java] +---- +rest { + configuration { + host = "my-host" + port = "9192" + } + + path("/my/path") { // <2> + // standard Rest DSL + } +} +---- +<1> Configure the rest engine +<2> Configure the rest endpoint for the base path '/my/path' + +=== JavaScript + +integration written in Kotlin looks very similar to a Java one: + +[source,js] +---- +function proc(e) { + e.getIn().setBody('Hello Camel K!') +} + +from('timer:tick') + .process(proc) + .to('log:info') +---- + +For JavaScript integrations, Camel K does not yet provide an enhanced DSL but you can access to some global bounded objects such as a writable registry and the camel context so to set the property _exchangeFormatter_ of the _LogComponent_ as done in previous example, you can do something like: + +[source,js] +---- + +l = context.getComponent('log', true, false) +l.exchangeFormatter = function(e) { + return "log - body=" + e.in.body + ", headers=" + e.in.headers +} +---- diff --git a/runtime/groovy/src/test/resources/routes-with-component-configuration.groovy b/runtime/groovy/src/test/resources/routes-with-component-configuration.groovy index b4ed14da..1d7b5a4e 100644 --- a/runtime/groovy/src/test/resources/routes-with-component-configuration.groovy +++ b/runtime/groovy/src/test/resources/routes-with-component-configuration.groovy @@ -10,9 +10,9 @@ context { } 'log' { - formatter { + exchangeFormatter = { 'body ==> ' + it.in.body - } + } as org.apache.camel.spi.ExchangeFormatter } } } diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt index 62e8369a..609f9c55 100644 --- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt +++ b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt @@ -64,6 +64,17 @@ class KotlinRoutesLoader : RoutesLoader { } fun from(uri: String): org.apache.camel.model.RouteDefinition = builder.from(uri) + + fun processor(fn: (org.apache.camel.Exchange) -> Unit) : org.apache.camel.Processor { + return object: org.apache.camel.Processor { + override fun process(exchange: org.apache.camel.Exchange) = fn(exchange) + } + } + fun predicate(fn: (org.apache.camel.Exchange) -> Boolean) : org.apache.camel.Predicate { + return object: org.apache.camel.Predicate { + override fun matches(exchange: org.apache.camel.Exchange) : Boolean = fn(exchange) + } + } """.trimIndent() engine.eval(pre, bindings) diff --git a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt b/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt index 12cb096a..7d38bb30 100644 --- a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt +++ b/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt @@ -27,7 +27,7 @@ class LoaderTest { @Test @Throws(Exception::class) - fun `load integration with bindings`() { + fun `load route from classpath`() { val resource = "classpath:routes.kts" val loader = RoutesLoaders.loaderFor(resource, null) val builder = loader.load(RuntimeRegistry(), resource) diff --git a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationTest.kt b/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationTest.kt index d35bc61b..62f485f1 100644 --- a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationTest.kt +++ b/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationTest.kt @@ -1,5 +1,6 @@ package org.apache.camel.k.kotlin.dsl +import org.apache.camel.Processor import org.apache.camel.component.log.LogComponent import org.apache.camel.component.seda.SedaComponent import org.apache.camel.main.MainListenerSupport @@ -47,8 +48,8 @@ class IntegrationTest { runtime.run() - assertThat(runtime.camelContext.registry.lookup("myEntry1")).isEqualTo("myRegistryEntry1") - assertThat(runtime.camelContext.registry.lookup("myEntry2")).isEqualTo("myRegistryEntry2") + assertThat(runtime.camelContext.registry.lookup("my-entry")).isEqualTo("myRegistryEntry1") + assertThat(runtime.camelContext.registry.lookup("my-proc")).isInstanceOf(Processor::class.java) } @Test diff --git a/runtime/kotlin/src/test/resources/routes-with-bindings.kts b/runtime/kotlin/src/test/resources/routes-with-bindings.kts index 530ea98d..b4feaeb2 100644 --- a/runtime/kotlin/src/test/resources/routes-with-bindings.kts +++ b/runtime/kotlin/src/test/resources/routes-with-bindings.kts @@ -1,8 +1,10 @@ context { registry { - bind("myEntry1", "myRegistryEntry1") - bind("myEntry2", "myRegistryEntry2") + bind("my-entry", "myRegistryEntry1") + bind("my-proc", processor { + e -> e.getIn().body = "Hello" + }) } } ---------------------------------------------------------------- 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