You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by bv...@apache.org on 2013/09/20 19:49:20 UTC

git commit: CAMEL-6773: The scheduled route policies of camel-quartz2 now support clustered jobs (like as it's done for camel-quartz through CAMEL-6686). Also polished the codebase a bit.

Updated Branches:
  refs/heads/master 0e69a1c0b -> 07bc39c29


CAMEL-6773: The scheduled route policies of camel-quartz2 now support clustered jobs (like as it's done for camel-quartz through CAMEL-6686). Also polished the codebase a bit.

Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/07bc39c2
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/07bc39c2
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/07bc39c2

Branch: refs/heads/master
Commit: 07bc39c29c6649899f8f375ba02c6eabf97a0564
Parents: 0e69a1c
Author: Babak Vahdat <bv...@apache.org>
Authored: Fri Sep 20 19:49:14 2013 +0200
Committer: Babak Vahdat <bv...@apache.org>
Committed: Fri Sep 20 19:49:14 2013 +0200

----------------------------------------------------------------------
 .../component/quartz2/QuartzComponent.java      |  7 ++
 .../quartz2/CronScheduledRoutePolicy.java       |  2 +-
 .../quartz2/ScheduledRoutePolicy.java           | 17 ++++
 .../quartz2/SimpleScheduledRoutePolicy.java     |  2 +-
 ...ringQuartzPersistentStoreRestartAppTest.java |  6 +-
 ...ngQuartzPersistentStoreClusteredAppTest.java | 85 ++++++++++++++++++++
 .../SpringQuartzPersistentStoreRestartTest.xml  |  3 +-
 .../quartz2/SpringQuartzPersistentStoreTest.xml |  3 +-
 .../quartz2/SpringQuartzClusteredAppOneTest.xml | 75 +++++++++++++++++
 .../quartz2/SpringQuartzClusteredAppTwoTest.xml | 75 +++++++++++++++++
 10 files changed, 267 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzComponent.java b/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzComponent.java
index 65d98fc..8215ec2 100644
--- a/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzComponent.java
+++ b/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzComponent.java
@@ -154,6 +154,13 @@ public class QuartzComponent extends DefaultComponent implements StartupListener
         return answer;
     }
 
+    /**
+     * Is the quartz scheduler clustered?
+     */
+    public boolean isClustered() throws SchedulerException {
+        return getScheduler().getMetaData().isJobStoreClustered();
+    }
+
     private Properties loadProperties() throws SchedulerException {
         Properties answer = getProperties();
         if (answer == null && getPropertiesFile() != null) {

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/CronScheduledRoutePolicy.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/CronScheduledRoutePolicy.java b/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/CronScheduledRoutePolicy.java
index 19ecef4..205f113 100644
--- a/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/CronScheduledRoutePolicy.java
+++ b/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/CronScheduledRoutePolicy.java
@@ -57,7 +57,7 @@ public class CronScheduledRoutePolicy extends ScheduledRoutePolicy implements Sc
 
         // validate time options has been configured
         if ((getRouteStartTime() == null) && (getRouteStopTime() == null) && (getRouteSuspendTime() == null) && (getRouteResumeTime() == null)) {
-            throw new IllegalArgumentException("Scheduled Route Policy for route {} has no stop/stop/suspend/resume times specified");
+            throw new IllegalArgumentException("Scheduled Route Policy for route {} has no start/stop/suspend/resume times specified");
         }
 
         registerRouteToScheduledRouteDetails(route);

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/ScheduledRoutePolicy.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/ScheduledRoutePolicy.java b/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/ScheduledRoutePolicy.java
index 45db16e..788b7c1 100644
--- a/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/ScheduledRoutePolicy.java
+++ b/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/ScheduledRoutePolicy.java
@@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.Route;
 import org.apache.camel.ServiceStatus;
+import org.apache.camel.component.quartz2.QuartzComponent;
 import org.apache.camel.impl.RoutePolicySupport;
 import org.apache.camel.util.ServiceHelper;
 import org.quartz.JobBuilder;
@@ -96,6 +97,22 @@ public abstract class ScheduledRoutePolicy extends RoutePolicySupport implements
         updateScheduledRouteDetails(action, jobDetail, trigger, route);
         
         loadCallbackDataIntoSchedulerContext(jobDetail, action, route);
+
+        boolean isClustered = route.getRouteContext().getCamelContext().getComponent("quartz2", QuartzComponent.class).isClustered();
+        if (isClustered) {
+            // check to see if the same job has already been setup through another node of the cluster
+            JobDetail existingJobDetail = getScheduler().getJobDetail(jobDetail.getKey());
+            if (jobDetail.equals(existingJobDetail)) {
+                if (LOG.isInfoEnabled()) {
+                    LOG.info("Skipping to schedule the job: {} for action: {} on route {} as the job: {} already existing!",
+                             new Object[] {jobDetail.getKey(), action, route.getId(), existingJobDetail.getKey()});
+                }
+
+                // skip scheduling the same job as one is already available for the same route and action
+                return;
+            }
+        }
+
         getScheduler().scheduleJob(jobDetail, trigger);
 
         if (LOG.isInfoEnabled()) {

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/SimpleScheduledRoutePolicy.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/SimpleScheduledRoutePolicy.java b/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/SimpleScheduledRoutePolicy.java
index 2e84d4a..95f135e 100644
--- a/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/SimpleScheduledRoutePolicy.java
+++ b/components/camel-quartz2/src/main/java/org/apache/camel/routepolicy/quartz2/SimpleScheduledRoutePolicy.java
@@ -66,7 +66,7 @@ public class SimpleScheduledRoutePolicy extends ScheduledRoutePolicy {
 
         // validate time options has been configured
         if ((getRouteStartDate() == null) && (getRouteStopDate() == null) && (getRouteSuspendDate() == null) && (getRouteResumeDate() == null)) {
-            throw new IllegalArgumentException("Scheduled Route Policy for route {} has no stop/stop/suspend/resume times specified");
+            throw new IllegalArgumentException("Scheduled Route Policy for route {} has no start/stop/suspend/resume times specified");
         }
 
         registerRouteToScheduledRouteDetails(route);

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartAppTest.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartAppTest.java b/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartAppTest.java
index f493b7a..18af3a0 100644
--- a/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartAppTest.java
+++ b/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartAppTest.java
@@ -71,9 +71,11 @@ public class SpringQuartzPersistentStoreRestartAppTest extends TestSupport {
 
         app2.stop();
 
-        // we're done so let's properly close the application contexts
-        app.close();
+        // we're done so let's properly close the application contexts, but stop
+        // the second app before the first one so that the quartz scheduler running
+        // inside it can properly be shutdown
         app2.close();
+        app.close();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/test/java/org/apache/camel/routepolicy/quartz2/SpringQuartzPersistentStoreClusteredAppTest.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/test/java/org/apache/camel/routepolicy/quartz2/SpringQuartzPersistentStoreClusteredAppTest.java b/components/camel-quartz2/src/test/java/org/apache/camel/routepolicy/quartz2/SpringQuartzPersistentStoreClusteredAppTest.java
new file mode 100644
index 0000000..86f9cb5
--- /dev/null
+++ b/components/camel-quartz2/src/test/java/org/apache/camel/routepolicy/quartz2/SpringQuartzPersistentStoreClusteredAppTest.java
@@ -0,0 +1,85 @@
+/**
+ * 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.routepolicy.quartz2;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.direct.DirectConsumerNotAvailableException;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.TestSupport;
+
+import org.junit.Test;
+
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * @version 
+ */
+public class SpringQuartzPersistentStoreClusteredAppTest extends TestSupport {
+
+    @Test
+    public void testQuartzPersistentStoreClusteredApp() throws Exception {
+        // boot up the first clustered app which also launches an embedded database
+        AbstractXmlApplicationContext app = new ClassPathXmlApplicationContext("org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppOneTest.xml");
+        app.start();
+
+        // and now the second one
+        AbstractXmlApplicationContext app2 = new ClassPathXmlApplicationContext("org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppTwoTest.xml");
+        app2.start();
+
+        CamelContext camel = app.getBean("camelContext", CamelContext.class);
+        assertNotNull(camel);
+
+        MockEndpoint mock = camel.getEndpoint("mock:result", MockEndpoint.class);
+        mock.expectedMessageCount(1);
+        mock.expectedBodiesReceived("clustering pings!");
+
+        // wait a bit to make sure the route has been properly started through
+        // the given route policy
+        Thread.sleep(5000);
+
+        app.getBean("template", ProducerTemplate.class).sendBody("direct:start", "clustering");
+
+        mock.assertIsSatisfied();
+
+        CamelContext camel2 = app2.getBean("camelContext", CamelContext.class);
+        assertNotNull(camel2);
+
+        MockEndpoint mock2 = camel2.getEndpoint("mock:result", MockEndpoint.class);
+        mock.expectedMessageCount(0);
+
+        // expect no consumer being started as the seconds app is expected to
+        // run in standby modus
+        try {
+            app2.getBean("template", ProducerTemplate.class).sendBody("direct:start", "clustering");
+            fail("Should have thrown exception");
+        } catch (CamelExecutionException cee) {
+            assertIsInstanceOf(DirectConsumerNotAvailableException.class, cee.getCause());
+        }
+
+        mock2.assertIsSatisfied();
+
+        // we're done so let's properly close the application contexts, but stop
+        // the second app before the first one so that the quartz scheduler running
+        // inside it can properly be shutdown
+        app2.close();
+        app.close();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartTest.xml b/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartTest.xml
index 26f18fd..6f498aa 100644
--- a/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartTest.xml
+++ b/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreRestartTest.xml
@@ -31,10 +31,9 @@
 
   <bean id="quartz" class="org.apache.camel.component.quartz2.QuartzComponent">
     <property name="scheduler" ref="scheduler"/>
-    <property name="autoStartScheduler" value="true"/>
   </bean>
 
-  <!-- jdbc:initialize-database must come before this so the job store exists -->
+  <!-- jdbc:embedded-database must come before this so the job store exists -->
   <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
     <property name="dataSource" ref="camel_quartz"/>
     <property name="autoStartup" value="false"/>

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreTest.xml b/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreTest.xml
index 3b055fd..851f3c5 100644
--- a/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreTest.xml
+++ b/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzPersistentStoreTest.xml
@@ -31,10 +31,9 @@
 
   <bean id="quartz" class="org.apache.camel.component.quartz2.QuartzComponent">
     <property name="scheduler" ref="scheduler"/>
-    <property name="autoStartScheduler" value="true"/>
   </bean>
 
-  <!-- jdbc:initialize-database must come before this so the job store exists -->
+  <!-- jdbc:embedded-database must come before this so the job store exists -->
   <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
     <property name="dataSource" ref="camel_quartz"/>
     <property name="autoStartup" value="false"/>

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/test/resources/org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppOneTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/test/resources/org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppOneTest.xml b/components/camel-quartz2/src/test/resources/org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppOneTest.xml
new file mode 100644
index 0000000..991523d
--- /dev/null
+++ b/components/camel-quartz2/src/test/resources/org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppOneTest.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+    ">
+
+  <!-- the persistent store for quartz -->
+  <jdbc:embedded-database id="camel_quartz" type="DERBY">
+    <jdbc:script location="classpath:tables_derby.sql"/>
+  </jdbc:embedded-database>
+
+  <bean id="quartz2" class="org.apache.camel.component.quartz2.QuartzComponent">
+    <property name="scheduler" ref="scheduler"/>
+  </bean>
+
+  <!-- jdbc:embedded-database must come before this so the job store exists -->
+  <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
+    <property name="dataSource" ref="camel_quartz"/>
+    <property name="autoStartup" value="false"/>
+    <!-- let Camel start -->
+    <property name="schedulerContextAsMap">
+      <!-- hook Camel into Quartz -->
+      <map>
+        <entry key="CamelQuartzCamelContext" value-ref="camelContext"/>
+      </map>
+    </property>
+    <property name="quartzProperties">
+      <props>
+        <prop key="org.quartz.scheduler.instanceName">myscheduler</prop>
+        <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
+        <prop key="org.quartz.scheduler.skipUpdateCheck">true</prop>
+        <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
+        <prop key="org.quartz.jobStore.isClustered">true</prop>
+        <prop key="org.quartz.jobStore.clusterCheckinInterval">1000</prop>
+      </props>
+    </property>
+  </bean>
+
+  <bean id="startPolicy" class="org.apache.camel.routepolicy.quartz2.CronScheduledRoutePolicy">
+    <property name="routeStartTime" value="0/3 * * * * ?" />
+  </bean>
+
+  <camelContext id="camelContext" managementNamePattern="#name#-#counter#" xmlns="http://camel.apache.org/schema/spring">
+    <template id="template" />
+    <route id="myRoute" routePolicyRef="startPolicy" autoStartup="false">
+      <from uri="direct:start" />
+      <to uri="log:triggered" />
+      <transform>
+        <simple>${in.body} pings!</simple>
+      </transform>
+      <to uri="mock:result" />
+    </route>
+  </camelContext>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/camel/blob/07bc39c2/components/camel-quartz2/src/test/resources/org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppTwoTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-quartz2/src/test/resources/org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppTwoTest.xml b/components/camel-quartz2/src/test/resources/org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppTwoTest.xml
new file mode 100644
index 0000000..3ccd7e3
--- /dev/null
+++ b/components/camel-quartz2/src/test/resources/org/apache/camel/routepolicy/quartz2/SpringQuartzClusteredAppTwoTest.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+    ">
+
+  <!-- the persistent store for quartz -->
+  <jdbc:embedded-database id="camel_quartz" type="DERBY">
+    <!-- do not load script as database alreaady exists -->
+  </jdbc:embedded-database>
+
+  <bean id="quartz2" class="org.apache.camel.component.quartz2.QuartzComponent">
+    <property name="scheduler" ref="scheduler"/>
+  </bean>
+
+  <!-- jdbc:embedded-database must come before this so the job store exists -->
+  <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
+    <property name="dataSource" ref="camel_quartz"/>
+    <property name="autoStartup" value="false"/>
+    <!-- let Camel start -->
+    <property name="schedulerContextAsMap">
+      <!-- hook Camel into Quartz -->
+      <map>
+        <entry key="CamelQuartzCamelContext" value-ref="camelContext"/>
+      </map>
+    </property>
+    <property name="quartzProperties">
+      <props>
+        <prop key="org.quartz.scheduler.instanceName">myscheduler</prop>
+        <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
+        <prop key="org.quartz.scheduler.skipUpdateCheck">true</prop>
+        <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
+        <prop key="org.quartz.jobStore.isClustered">true</prop>
+        <prop key="org.quartz.jobStore.clusterCheckinInterval">1000</prop>
+      </props>
+    </property>
+  </bean>
+
+  <bean id="startPolicy" class="org.apache.camel.routepolicy.quartz2.CronScheduledRoutePolicy">
+    <property name="routeStartTime" value="0/3 * * * * ?" />
+  </bean>
+
+  <camelContext id="camelContext" managementNamePattern="#name#-#counter#" xmlns="http://camel.apache.org/schema/spring">
+    <template id="template" />
+    <route id="myRoute" routePolicyRef="startPolicy" autoStartup="false">
+      <from uri="direct:start" />
+      <to uri="log:triggered" />
+      <transform>
+        <simple>${in.body} pongs!</simple>
+      </transform>
+      <to uri="mock:result" />
+    </route>
+  </camelContext>
+
+</beans>