Skip to content

Commit

Permalink
CAMEL-20333 camel-kotlin-api: add docs for all except bean instantiation
Browse files Browse the repository at this point in the history
  • Loading branch information
iMashtak committed Jan 18, 2024
1 parent e10fa3e commit d15ae0b
Show file tree
Hide file tree
Showing 20 changed files with 278 additions and 19 deletions.
260 changes: 259 additions & 1 deletion dsl/camel-kotlin-api/src/main/docs/kotlin-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,262 @@

IMPORTANT: This API is experimental support level and is not recommended being used for production

Kotlin API provides alternative approach to define routes in addition to Java API.
Kotlin API provides alternative approach to define routes.

== Defining a route

To define route using Kotlin API you need to retrieve `CamelContext` and pass it to function `camel`:

[source,kotlin]
----
import org.apache.camel.kotlin.camel
val ctx: CamelContext = ...
camel(ctx) { ... }
----

Then you can define route in `route` block:

[source,kotlin]
----
camel(ctx) {
route { <1>
from { <2>
component("direct")
url("input")
}
steps { <3>
to {
component("mock")
url("output")
}
}
}
}
----
<1> Definition of route
<2> Definition of consuming endpoint
<3> Definition of processing steps

You can find a number of handful methods in `route` block, for example, setting route id:

[source,kotlin]
----
camel(ctx) {
route {
id("my-route")
}
}
----

== Defining endpoints

Here and further `camel(ctx)` block will be omitted to make code less annoying.

=== Raw endpoints

Raw endpoint constructs from three components: `component`, `url` and a number of `property`-es. They all connected with each other and form resulting uri by the following rule:

[source,kotlin]
----
"$component:$url?${property1.key}=${property1.value}&..."
----

So to define consumer from `netty-http` you can write the following:

[source,kotlin]
----
route {
from {
component("netty-http")
url("http://localhost:8080")
property("keepAlive", "false")
property("reuseAddress", "false")
}
}
----

Also you can omit `component` and write only `url` by the following schema:

[source,kotlin]
----
route {
from {
url("netty-http:http://localhost:8080")
property("keepAlive", "false")
property("reuseAddress", "false")
}
}
----

Moreover, you can omit `property` at all and write full uri in `url` function:

[source,kotlin]
----
route {
from {
url("netty-http:http://localhost:8080?keepAlive=false&reuseAddress=false")
}
}
----

This three definitions are equivalent.

`property` method accepts only `String` value type. This is because it builds raw uri, not `Endpoint`. That means that if you need to define property of complex type, you must define bean in registry. Also that behaviour may be very useful in the following situations:

- usage of property placeholders
- `toD` and `enrich` EIPs accepts simple language in uri, so it will be handful to use simple in property values

=== Endpoint DSL

Defining string-based uris may not be very handy. So there is Endpoint DSL for building uris. For each Camel component exists an extension function with the name of that component. An example:

[source,kotlin]
----
import org.apache.camel.kotlin.components.`netty-http`
import org.apache.camel.kotlin.components.mock
route {
from {
`netty-http` {
protocol("http")
host("localhost")
port(8080)
keepAlive(false)
reuseAddress(false)
}
}
steps {
to { mock { name("output") } }
}
}
----

Rules remain the same: all non-primitive types must be defined as beans in registry and referenced in properties by `#name`.

== Defining EIPs

In that section we will take a look at several important EIPs to demonstrate logic of their definition.

=== Marshal, Unmarshal and DataFormat DSL

Marshal and Unmarshal EIPs come with DataFormat DSL. This DSL is the only way to define both EIPs. Example:

[source,kotlin]
----
import org.apache.camel.kotlin.dataformats.csv
route {
from { direct { name("input") } }
steps {
unmarshal {
csv {
delimiter(";")
}
}
}
}
----

=== LoadBalance and nested DSLs

Some of EIPs provide additional complex configuration for their fields. For example, Load Balance EIP: there we can define various variants of which algorithm to use. So all that options are wrapped into their own DSL. Example:

[source,kotlin]
----
route {
from { direct { name("input") } }
steps {
loadBalance {
failover {
maximumFailoverAttempts(1)
}
}
}
}
----

=== Filter, Multicast, Pipeline and outputs

Some of EIPs defines their own subroutes, for example, Filter and Multicast. In that cases use `outputs` property of EIP's block. Filter example:

[source,kotlin]
----
route {
from { direct { name("input") } }
steps {
filter(constant("true")) {
outputs {
log("only calls in filter block")
}
}
log("calls after filter block executed")
}
}
----

Multicast example:

[source,kotlin]
----
route {
from { direct { name("input") } }
steps {
multicast {
outputs {
to { direct { name("first") } }
to { direct { name("second") } }
}
}
}
}
----

That behaviour differs for Pipeline EIP, which has not any properties and so all nested steps defines in `pipeline` block:

[source,kotlin]
----
route {
from { direct { name("input") } }
steps {
pipeline {
log("first pipeline")
}
pipeline {
log("second pipeline")
}
}
}
----

== Defining beans

== Using languages, expressions and predicates

There are a number of functions that provides Camel languages like `constant` or `simple` and a number of helper functions for building predicates/expressions like `body` or `header`. All of them are in the package `org.apache.camel.kotlin`.

There are two useful extension functions:

- `Expression.toPredicate(): Predicate` converts any expression to predicate type
- `Expression.which(): ValueBuilder` converts any expression to `ValueBuiler`, makes possible to write expressions like:
+
[source,kotlin]
----
body().which().isInstanceOf(String::class)
----

== Fallback to Java API

For each block except `camel` there is `def` field which provides common Java API. It can be used if some functionality is missing. Example:

[source,kotlin]
----
route {
from { direct { name("input") } }
steps {
def.pipeline().log("Java API").end()
}
}
----
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import java.util.concurrent.ScheduledExecutorService
@CamelDslMarker
class AggregateDsl(
val def: AggregateDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun eagerCheckCompletion(eagerCheckCompletion: Boolean) {
def.eagerCheckCompletion = eagerCheckCompletion.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.apache.camel.model.CatchDefinition
@CamelDslMarker
class CatchDsl(
val def: CatchDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun onWhen(onWhen: Predicate) {
def.onWhen(onWhen)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import org.apache.camel.model.Resilience4jConfigurationDefinition
@CamelDslMarker
class CircuitBreakerDsl(
val def: CircuitBreakerDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun resilience4jConfiguration(i: Resilience4jConfigurationDsl.() -> Unit) {
val resilience4jDef = def.resilience4jConfiguration()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.apache.camel.model.ClaimCheckOperation
@CamelDslMarker
class ClaimCheckDsl(
val def: ClaimCheckDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun operation(operation: ClaimCheckOperation) {
def.operation(operation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.apache.camel.model.ConvertBodyDefinition
@CamelDslMarker
class ConvertBodyDsl(
val def: ConvertBodyDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun mandatory(mandatory: Boolean) {
def.mandatory = mandatory.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.apache.camel.model.ConvertHeaderDefinition
@CamelDslMarker
class ConvertHeaderDsl(
val def: ConvertHeaderDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun mandatory(mandatory: Boolean) {
def.mandatory = mandatory.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import java.util.concurrent.ExecutorService
@CamelDslMarker
class DelayDsl(
val def: DelayDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun asyncDelayed(asyncDelayed: Boolean) {
def.asyncDelayed = asyncDelayed.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.apache.camel.model.DynamicRouterDefinition
@CamelDslMarker
class DynamicRouterDsl(
val def: DynamicRouterDefinition<*>
) {
) : OptionalIdentifiedDsl(def) {

fun uriDelimiter(uriDelimiter: String) {
def.uriDelimiter(uriDelimiter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import org.apache.camel.model.FilterDefinition
@CamelDslMarker
class FilterDsl(
val def: FilterDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun statusPropertyName(statusPropertyName: String) {
def.statusPropertyName = statusPropertyName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import org.apache.camel.spi.IdempotentRepository
@CamelDslMarker
class IdempotentConsumerDsl(
val def: IdempotentConsumerDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun idempotentRepository(idempotentRepository: String) {
def.idempotentRepository(idempotentRepository)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class LoadBalanceDsl(
}
}

@CamelDslMarker
class FailoverLoadBalancerDsl(
val def: FailoverLoadBalancerDefinition
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.slf4j.Logger
@CamelDslMarker
class LogDsl(
val def: LogDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun message(message: String) {
def.message = message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.apache.camel.model.LoopDefinition
@CamelDslMarker
class LoopDsl(
val def: LoopDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun copy(copy: Boolean) {
def.copy = copy.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import java.util.concurrent.ExecutorService
@CamelDslMarker
class RecipientListDsl(
val def: RecipientListDefinition<*>
) {
) : OptionalIdentifiedDsl(def) {

fun delimiter(delimiter: String) {
def.delimiter(delimiter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import java.time.Duration
@CamelDslMarker
class ResequenceDsl(
val def: ResequenceDefinition
) {
) : OptionalIdentifiedDsl(def) {

fun batch(i: BatchResequenceDsl.() -> Unit = {}) {
val config = BatchResequencerConfig.getDefault()
Expand Down
Loading

0 comments on commit d15ae0b

Please sign in to comment.