diff --git a/README.adoc b/README.adoc
index 0f59ad8e4..7227e5512 100644
--- a/README.adoc
+++ b/README.adoc
@@ -28,7 +28,7 @@ readme's instructions.
== Examples
// examples: START
-Number of Examples: 72 (0 deprecated)
+Number of Examples: 73 (0 deprecated)
[width="100%",cols="4,2,4",options="header"]
|===
@@ -66,6 +66,8 @@ Number of Examples: 72 (0 deprecated)
| link:spring/README.adoc[Spring] (spring) | Beginner | An example showing how to work with Camel and Spring
+| link:timer/README.adoc[Timer] (timer) | Beginner | An example showing how to work with Camel Timer component
+
| link:main/README.adoc[Main] (main) | Camel Standalone | An example for showing standalone Camel
| link:main-endpointdsl/README.adoc[Main Endpointdsl] (main-endpointdsl) | Camel Standalone | An example for showing standalone Camel with Endpoint DSL
diff --git a/pom.xml b/pom.xml
index c9824d6e0..81fb857e7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -134,6 +134,7 @@
+ * The timer component is used to generate message exchanges at regular intervals. + * This is useful for polling, scheduling, and triggering periodic tasks. + */ +public final class TimerExample { + + public static void main(String[] args) throws Exception { + // create a CamelContext + try (CamelContext camel = new DefaultCamelContext()) { + + // add routes demonstrating different timer patterns + camel.addRoutes(createTimerRoutes()); + + // start is not blocking + camel.start(); + + // run for 5 seconds to demonstrate the timers + Thread.sleep(5_000); + + System.out.println("\nShutting down..."); + } + } + + static RouteBuilder createTimerRoutes() { + return new RouteBuilder() { + @Override + public void configure() { + + // Simple timer - fires every 300ms + from("timer:simple?period=300") + .routeId("simple-timer") + .setBody(simple("Simple timer fired at ${date:now:yyyy-MM-dd HH:mm:ss}")) + .log("${body}"); + + // Timer with initial delay - waits 500ms before first fire, then every 300ms + from("timer:withDelay?delay=500&period=300") + .routeId("delayed-timer") + .setBody(simple("Delayed timer fired at ${date:now:yyyy-MM-dd HH:mm:ss}")) + .log("${body}"); + + // Timer with repeat count - fires only 3 times + from("timer:limited?period=100&repeatCount=3") + .routeId("limited-timer") + .setBody(simple("Limited timer fired (${header.CamelTimerCounter} of 3) at ${date:now:yyyy-MM-dd HH:mm:ss}")) + .log("${body}"); + + // Fixed rate timer - uses scheduleAtFixedRate (start-to-start timing) + // Attempts to maintain fixed intervals. If processing time < period, fires at regular intervals. + // vs fixedRate=false (default) - uses scheduleWithFixedDelay (end-to-start timing) + // Waits for completion + full period before next execution. + from("timer:fixedRate?period=500&fixedRate=true") + .routeId("fixed-rate-timer") + .setBody(simple("Fixed-rate timer fired at ${date:now:yyyy-MM-dd HH:mm:ss}")) + .log("${body}") + // simulate some processing time + .process(exchange -> { + // This 50ms delay is less than the 500ms period, demonstrating fixed-rate timing + Thread.sleep(50); + }); + } + }; + } +} \ No newline at end of file diff --git a/timer/src/main/resources/log4j2.properties b/timer/src/main/resources/log4j2.properties new file mode 100644 index 000000000..dde96bbd3 --- /dev/null +++ b/timer/src/main/resources/log4j2.properties @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n +rootLogger.level = INFO +rootLogger.appenderRef.out.ref = out \ No newline at end of file diff --git a/timer/src/test/java/org/apache/camel/example/timer/TimerExampleTest.java b/timer/src/test/java/org/apache/camel/example/timer/TimerExampleTest.java new file mode 100644 index 000000000..80689cba5 --- /dev/null +++ b/timer/src/test/java/org/apache/camel/example/timer/TimerExampleTest.java @@ -0,0 +1,64 @@ +/* + * 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.example.timer; + +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.NotifyBuilder; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.TimeUnit; + +import static org.apache.camel.example.timer.TimerExample.createTimerRoutes; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * A unit test verifying that timer routes work correctly. + */ +class TimerExampleTest extends CamelTestSupport { + + @Test + void should_fire_simple_timer() { + // Wait for at least 2 messages from the simple timer (fires every 300ms) + NotifyBuilder notify = new NotifyBuilder(context) + .from("timer:simple*") + .whenCompleted(2) + .create(); + + assertTrue( + notify.matches(20, TimeUnit.SECONDS), "Simple timer should fire at least twice" + ); + } + + @Test + void should_respect_repeat_count() { + // The limited timer should fire exactly 3 times + NotifyBuilder notify = new NotifyBuilder(context) + .from("timer:limited*") + .whenExactlyCompleted(3) + .create(); + + assertTrue( + notify.matches(20, TimeUnit.SECONDS), "Limited timer should fire exactly 3 times" + ); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return createTimerRoutes(); + } +} \ No newline at end of file