This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 6913feb9a1c88e8d4f869cb089f5eabf15ef7daf Author: Claus Ibsen <[email protected]> AuthorDate: Wed Feb 25 10:49:16 2026 +0100 CAMEL-16861: Update docs --- docs/user-manual/modules/ROOT/pages/testing.adoc | 39 ++--- .../modules/ROOT/pages/threading-model.adoc | 193 ++++++++++++++------- .../apache/camel/main/stub/StubBeanRepository.java | 6 + 3 files changed, 155 insertions(+), 83 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/testing.adoc b/docs/user-manual/modules/ROOT/pages/testing.adoc index 8996181acc68..a44deb321a64 100644 --- a/docs/user-manual/modules/ROOT/pages/testing.adoc +++ b/docs/user-manual/modules/ROOT/pages/testing.adoc @@ -16,28 +16,25 @@ and powerful as possible, so we have introduced the following features. The following modules are supported: [width="100%",cols="1m,4",options="header",] -|======================================================================= +|=== |Component |Description -|xref:components:others:test-junit5.adoc[camel-test-junit5] |*JUnit 5*: Is an older standalone Java -library letting you easily create Camel test cases using a single Java -class for all your configuration and routing without. +|xref:components:others:test-junit5.adoc[camel-test-junit5] |*JUnit 5*: Used for testing Camel in standalone mode (or without Spring) |xref:components:others:test-main-junit5.adoc[camel-test-main-junit5] | *JUnit 5*: Used for testing Camel in Camel Main mode - |xref:components:others:test-spring-junit5.adoc[camel-test-spring-junit5] | *JUnit 5*: Used for testing Camel with Spring / Spring Boot -|xref:test-infra.adoc[camel-test-infra] | *Camel Test Infra*: Camel Test Infra is a set of modules that leverage modern JUnit 5 features to abstract the provisioning and execution of test infrastructure. Among other things, it provides abstraction of the infrastructure (based on Test Containers - being the de-facto successor of the camel-testcontainers components) as well as JUnit 5 extensions for the Camel Context itself. +|xref:components:others:test-junit6.adoc[camel-test-junit5] |*JUnit 6*: Used for testing Camel in standalone mode (or without Spring) +|xref:components:others:test-main-junit6.adoc[camel-test-main-junit5] | *JUnit 6*: Used for testing Camel in Camel Main mode +|xref:components:others:test-spring-junit6.adoc[camel-test-spring-junit5] | *JUnit 6*: Used for testing Camel with Spring / Spring Boot +|xref:test-infra.adoc[camel-test-infra] | *Camel Test Infra*: Camel Test Infra is a set of modules that leverage modern JUnit 5 features to abstract the provisioning and execution of test infrastructure. Among other things, it provides abstraction of the infrastructure (based on Test Containers - being the de-facto successor of the camel-testcontainers components) as well as JUnit 5 extensions for the Camel Context itself. |xref:camel-jbang-test.adoc[camel-jbang-test] | *Camel JBang Test Plugin*: A Camel JBang plugin to help writing automated tests during prototyping with JBang. The tests are able to start the Camel integration and verify its logic from the very beginning. The test plugin does not require any project setup so you can just start writing and executing automated tests. +|=== -|======================================================================= - -NOTE: If you are using Camel Quarkus, then you can find information in -its documentation how to do testing with Quarkus and Camel. +NOTE: If you are using Camel Quarkus, then you can find information in the Camel Quarkus documentation how to do testing with Quarkus and Camel. In all approaches, the test classes look pretty much the same in that -they all reuse the xref:bean-integration.adoc[Camel binding and -injection annotations]. +they all reuse the xref:bean-integration.adoc[Camel binding and injection annotations]. TIP: For more details on the different testing modules, then see their respective documentation from the links in the table above. @@ -51,7 +48,7 @@ Camel provides a set of features that are common to use when writing unit or int Camel provides a number of xref:endpoint.adoc[endpoints] which can make testing easier. [width="100%",cols="1,3",options="header",] -|======================================================================= +|=== |Name |Description |xref:components::mock-component.adoc[Mock] |For testing routes and mediation rules using mocks and allowing assertions to be added to an endpoint. @@ -63,8 +60,7 @@ components and asserting that they are consumed correctly. |xref:components::dataset-test-component.adoc[DataSet Test] |Used to automatically load a set of expected messages from another endpoint which is then compared to the messages that arrive at this endpoint. - -|======================================================================= +|=== The main endpoint is the xref:components::mock-component.adoc[Mock] endpoint, which allows expectations to be added to different endpoints; you can then run your @@ -78,7 +74,7 @@ endpoints can be useful: NOTE: For example, to unit test a transformation route rather than performing a full integration test [width="100%",cols="1,3",options="header",] -|======================================================================= +|=== |Name |Description |xref:components::direct-component.adoc[Direct] |Direct invocation of the consumer from the producer so that single threaded (non-SEDA) in VM invocation is @@ -89,17 +85,18 @@ a `BlockingQueue` which is good for testing asynchronous transports |xref:components::stub-component.adoc[Stub] |Works like xref:components::stub-component.adoc[SEDA] but does not validate the endpoint URI, which makes stubbing straightforward. -|======================================================================= +|=== === Testing existing routes Camel provides some features to aid during testing of existing routes where you cannot or will not use xref:components::mock-component.adoc[Mock] etc. + For example, you may have a production ready route which you want to test with some third party API that sends messages into this route. [width="100%",cols="1,3",options="header",] -|======================================================================= +|=== |Name |Description |xref:notify-builder.adoc[NotifyBuilder] |Allows you to be notified when a certain condition has occurred. For example, when the route has @@ -110,7 +107,7 @@ criteria when to be notified. an existing route using a xref:route-builder.adoc[RouteBuilder] style. For example, you can send (or send and skip) a message to a xref:components::mock-component.adoc[Mock] endpoint for validating the message send by Camel is as expected. -|======================================================================= +|=== == Integration testing @@ -142,13 +139,13 @@ Please refer to the https://citrusframework.org/citrus/reference/html/[Citrus do The following sections might be interesting to explore for Camel developers and testers: [width="100%",cols="1,3",options="header",] -|======================================================================= +|=== |Name |Description | https://citrusframework.org/citrus/reference/html/#apache-camel[Citrus & Camel routes] | Start and stop Camel routes as part of the test. | https://citrusframework.org/citrus/reference/html/#camel-infra[Citrus & Camel test infra] | Start and stop Camel test infrastructure services as part of the Citrus test. | https://citrusframework.org/citrus/reference/html/#camel-processor-support[Citrus & Camel processors] | Use Camel processor, transformer and data format EIPs in Citrus tests. | https://citrusframework.org/citrus/reference/html/#apache-camel[Citrus & Camel JBang] | Run Camel integrations with JBang as part of a test. -|======================================================================= +|=== TIP: Citrus provides a good integration with https://www.jbang.dev[JBang] and Camel JBang. This means you can use Citrus from the very beginning for writing automated tests also in the prototyping phase with Camel JBang. diff --git a/docs/user-manual/modules/ROOT/pages/threading-model.adoc b/docs/user-manual/modules/ROOT/pages/threading-model.adoc index 8368e2a56cd6..fb2afc1ed5b5 100644 --- a/docs/user-manual/modules/ROOT/pages/threading-model.adoc +++ b/docs/user-manual/modules/ROOT/pages/threading-model.adoc @@ -10,8 +10,8 @@ Camel leverages thread pools in several places such as: concurrency * xref:components::seda-component.adoc[SEDA] component for asynchronous connectivity * xref:components:eips:threads-eip.adoc[Threads] EIP in Camel routes -* Some components use thread pools out of the box, such as -xref:components::jms-component.adoc[JMS] or xref:components::jetty-component.adoc[Jetty] +* Several components use thread pools out of the box, such as +xref:components::jms-component.adoc[JMS], xref:components::kafka-component.adoc[Kafka], xref:components::netty-component.adoc[Netty] or xref:components::jetty-component.adoc[Jetty] == Thread pool profiles @@ -46,16 +46,11 @@ profile. In Spring XML you can configure thread pool profile with `threadPoolProfile` as shown: -[source,xml] ----- -<threadPoolProfile id="defaultThreadPoolProfile" - defaultProfile="true" - poolSize="5" - maxPoolSize="10"/> ----- - -And in Java DSL +[tabs] +==== +Java:: ++ [source,java] ---- ThreadPoolProfile profile = camelContext.getExecutorServiceManager().getDefaultThreadPoolProfile(); @@ -63,15 +58,27 @@ profile.setPoolSize(5); profile.setMaxPoolSize(10); ---- -And with camel-main, Spring Boot or Quarkus you can configure this in the `application.properties|yaml` file: +Spring XML:: ++ +[source,xml] +---- +<threadPoolProfile id="defaultThreadPoolProfile" + defaultProfile="true" + poolSize="5" + maxPoolSize="10"/> +---- +Application Properties:: ++ +You can also configure the thread pools in `application.properties`. The default pool can easily be configured as follows: ++ [source,properties] ---- ## configure default thread pool profile camel.threadpool.pool-size = 5 camel.threadpool.max-pool-size = 5 ---- - +==== === Using thread pool profiles @@ -79,8 +86,31 @@ Suppose you want to use a custom thread pool profile for a Multicast EIP pattern in a Camel route you can do it using the `executorServiceRef` attribute as shown in Spring XML: +[tabs] +==== + +Java:: ++ +In Java DSL you can use `ThreadPoolProfileBuilder` to create a profile and then register the profile: ++ +[source,java] +---- +// setup thread pool profile +ThreadPoolProfileBuilder builder = new ThreadPoolProfileBuilder("fooProfile"); +builder.poolSize(20).maxPoolSize(50).maxQueueSize(-1); + +// add profile to camel +camelContext.getExecutorServiceManager().registerThreadPoolProfile(builder.build()); + +// camel routes can now refer to the thread pool via its id +from("direct:start") + .multicast().aggregationStrategy("myStrategy").executorService("fooProfile").to("xxx"); +---- + +Spring XML:: ++ [source,xml] ---------------------------------------------------------------------------- +---- <camelContext> <threadPoolProfile id="fooProfile" @@ -92,7 +122,36 @@ attribute as shown in Spring XML: </multicast> </route> </camelContext> ---------------------------------------------------------------------------- +---- + +YAML:: ++ +To create a new profile, then use `camel.threadpool.config[profileId]` syntax as shown below: ++ +[source,properties] +---- +camel.threadpool.config[fooProfile].id = fooProfile +camel.threadpool.config[fooProfile].pool-size = 20 +camel.threadpool.config[fooProfile].max-pool-size = 50 +camel.threadpool.config[fooProfile].max-queue-size = -1 +---- ++ +And then you can refer to the thread pool in the Camel route: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - multicast: + aggregationStrategy: myStrategy + executorService: fooProfile + steps: + - to: + uri: log:hello +---- +==== What Camel will do at runtime is to lookup in the xref:registry.adoc[Registry] for a `ExecutorService` with the id `fooProfile`. @@ -102,25 +161,38 @@ so the profile is used as base settings for creating a new `ExecutorService` whi handed back to the xref:components:eips:multicast-eip.adoc[Multicast] EIP to use in the Camel route. -In Java DSL you can use `ThreadPoolProfileBuilder` to create a profile and then register the profile: - -[source,java] ----- -ThreadPoolProfileBuilder builder = new ThreadPoolProfileBuilder("fooProfile"); -builder.poolSize(20).maxPoolSize(50).maxQueueSize(-1); - -camelContext.getExecutorServiceManager().registerThreadPoolProfile(builder.build()); ----- - == Creating custom thread pools You can also use the `<threadPool>` tag in Spring XML to create a -specific thread pool (`ExecutorService`). Notice that any options you +Java thread pool (`ExecutorService`). Notice that any options you do not explicit define, will have Camel to use the default thread pool profile as fallback. For example if you omit setting the `maxQueueSize` then Camel will fallback and use the value from the default thread pool profiles, which by default is `1000`. +Spring XML:: ++ +[source,xml] +---- +<camelContext> + + <threadPool id="nyPool" poolSize="20" maxPoolSize="50"/> + + <route> + <multicast aggregationStrategy="myStrategy" executorServiceRef="myPool"> + ... + </multicast> + </route> +</camelContext> +---- + +== What is the difference between thread-pool and thread-pool-profile? + +A thread pool profile is a recipe for creating 1 or more actual thread pools (ie `ExecutorService`). +A thread pool is a concrete `ExecutorService` object. + +The purpose is to use profiles to make it easy to create many thread pools using the same settings. + == Customizing thread names On the `ExecutorServiceManager` you can @@ -142,8 +214,23 @@ In the pattern you can use the following placeholders * `\#name#` - The thread name * `\#longName#` - The long thread name which can include endpoint parameters etc. -In Spring XML the pattern can be set with `threadNamePattern` attribute as shown: +[tabs] +==== + +Java:: ++ +In Javayou set the pattern on the `ExecutorServiceMananger` as shown: ++ +[source,java] +---- +CamelContext camel = ... +camel.getExecutorServiceManager().setThreadNamePattern("Riding the thread #counter#") +---- +Spring XML:: ++ +In Spring XML the pattern can be set with `threadNamePattern` attribute as shown: ++ [source,xml] ---- <camelContext threadNamePattern="Riding the thread #counter#"> @@ -155,24 +242,16 @@ In Spring XML the pattern can be set with `threadNamePattern` attribute as shown </camelContext> ---- -In Java DSL you can set the pattern as follows: - -[source,java] ----- -CamelContext camel = ... -camel.getExecutorServiceManager().setThreadNamePattern("Riding the thread #counter#") ----- - +Application Properties:: ++ And with camel-main, Spring Boot or Quarkus you can configure this in the `application.properties|yaml` file: - ++ [source,properties] ---- -## camel-main or quarkus camel.main.thread-name-pattern = Riding the thread #counter# - -## spring boot -camel.springboot.thread-name-pattern = Riding the thread #counter# ---- +==== + == Shutting down thread pools @@ -202,43 +281,32 @@ thread pool is as follows: [width="100%",cols="25%,75%",options="header"] |=== |Method |Description -|shutdown |Marks the thread pool as shutdown -(like calling the `ExecutorService.shutdown()` method). -|shutdownNow |Forces the thread pool to shut down now -(like calling the `ExecutorService.shutdownNow()` method). -|shutdownGraceful |Marks the thread pool as shutdown, and graceful shutdown -the pool, by waiting for tasks to complete. A default timeout value of -10 sec is used, before shutdown becomes aggressive using `shutdownNow`, -forcing threads to shut down quicker. +|shutdown |Marks the thread pool as shutdown(like calling the `ExecutorService.shutdown()` method). +|shutdownNow |Forces the thread pool to shut down now(like calling the `ExecutorService.shutdownNow()` method). +|shutdownGraceful |Marks the thread pool as shutdown, and graceful shutdown the pool, by waiting for tasks to complete. A default timeout value of 10 sec is used, before shutdown becomes aggressive using `shutdownNow`, forcing threads to shut down quicker. |shutdownGraceful(timeout) |As shutdownGraceful but with custom timeout value -|awaitTermination |To wait graceful for the termination of a thread pool (eg -to wait for its tasks to complete). Will wait until all tasks are completed or timed out. +|awaitTermination |To wait graceful for the termination of a thread pool (e.g. to wait for its tasks to complete). Will wait until all tasks are completed or timed out. |=== == JMX Management -All the thread pools that Camel creates are managed and thus you can see -them in JMX under the `threadpools` tree. +All the thread pools that Camel creates are managed, and thus you can see them in JMX under the `threadpools` tree. NOTE: This requires to enabled JMX by including `camel-management` JAR in the classpath. == Component developers -If you develop your own Camel component and are in need of a thread -pool, then it is advised to use the -`ExecutorServiceStrategy`/`ExecutorServiceManager` to create the thread -pool you need. +If you develop your own Camel component and are in need of a thread pool, +then it is advised to use the `ExecutorServiceStrategy`/`ExecutorServiceManager` +to create the thread pool you need. -=== ExecutorServiceStrategy +=== ExecutorServiceStrategy and ExecutorServiceManager Camel provides a pluggable strategy to hook in your own thread pool -provider, for example from a WorkManager in a J2EE server etc. + -See the `org.apache.camel.spi.ExecutorServiceStrategy` interface which +provider.See the `org.apache.camel.spi.ExecutorServiceStrategy` interface which you should implement and hook into the WorkManager. -=== ExecutorServiceManager - -To hook in custom thread pool providers (e.g. for J2EE servers) a +To hook in custom thread pool providers a `ThreadPoolFactory` interface can be implemented. The implementation can be set in the `ExecutorServiceManager`. @@ -246,6 +314,7 @@ be set in the `ExecutorServiceManager`. Starting from Java 21, the default `ThreadPoolFactory` can build `ExecutorService` and `ScheduledExecutorService` that use https://openjdk.org/jeps/425[virtual threads] instead of platform threads. + But as it is an experimental feature, it is not enabled by default, you need to set the System property `camel.threads.virtual.enabled` to `true` and run Camel using Java 21 or above to enable it. diff --git a/dsl/camel-kamelet-main-support/src/main/java/org/apache/camel/main/stub/StubBeanRepository.java b/dsl/camel-kamelet-main-support/src/main/java/org/apache/camel/main/stub/StubBeanRepository.java index 427ac9938527..a6a6f44cd370 100644 --- a/dsl/camel-kamelet-main-support/src/main/java/org/apache/camel/main/stub/StubBeanRepository.java +++ b/dsl/camel-kamelet-main-support/src/main/java/org/apache/camel/main/stub/StubBeanRepository.java @@ -21,6 +21,8 @@ import java.util.Comparator; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import org.apache.camel.AggregationStrategy; import org.apache.camel.Processor; @@ -59,6 +61,7 @@ public class StubBeanRepository implements BeanRepository { private final Comparator<?> service8 = (o1, o2) -> 0; private final RoutePolicy service9 = new RoutePolicySupport() { }; + private final ExecutorService service10 = Executors.newCachedThreadPool(); private final String stubPattern; @@ -133,6 +136,9 @@ public class StubBeanRepository implements BeanRepository { if (RoutePolicy.class.isAssignableFrom(type)) { return (T) service9; } + if (ExecutorService.class.isAssignableFrom(type)) { + return (T) service10; + } if (Logger.class.isAssignableFrom(type)) { return (T) LOG; }
