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 67d2afd0c6485d8e0bc1a25fe21b64f7343f9111 Author: Claus Ibsen <[email protected]> AuthorDate: Thu Nov 18 09:20:18 2021 +0100 CAMEL-16656: camel-core - ResourceReloader SPI - Allow to reload on changes --- .../camel/support/RouteWatcherReloadStrategy.java | 3 + dsl/camel-xml-io-dsl/pom.xml | 5 + .../org/apache/camel/dsl/xml/io/XmlMainTest.java | 2 +- .../io/reload/RouteWatcherReloadStrategyTest.java | 205 +++++++++++++++++++++ .../resources/org/apache/camel/reload/barRoute.xml | 29 +++ .../org/apache/camel/reload/barUpdatedRoute.xml | 34 ++++ 6 files changed, 277 insertions(+), 1 deletion(-) diff --git a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java index 15cb62e..f8a0748 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java @@ -33,6 +33,9 @@ public class RouteWatcherReloadStrategy extends FileWatcherResourceReloadStrateg private String pattern = "*.yaml,*.xml"; + public RouteWatcherReloadStrategy() { + } + public RouteWatcherReloadStrategy(String directory) { super(directory, true); } diff --git a/dsl/camel-xml-io-dsl/pom.xml b/dsl/camel-xml-io-dsl/pom.xml index 187f5ec..896f4c0 100644 --- a/dsl/camel-xml-io-dsl/pom.xml +++ b/dsl/camel-xml-io-dsl/pom.xml @@ -123,6 +123,11 @@ <artifactId>camel-test-junit5</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> diff --git a/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlMainTest.java b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlMainTest.java index 60ebf97..67715ed 100644 --- a/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlMainTest.java +++ b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlMainTest.java @@ -78,7 +78,7 @@ public class XmlMainTest { public void testMainRoutesCollectorScanWildcardDirFilePath() throws Exception { doTestMain( "file:src/test/resources/**/*.xml", - "**/org/apache/camel/dsl/**,**/camel-rests.xml,**/camel-template.xml"); + "**/org/apache/camel/dsl/**,**/camel-rests.xml,**/camel-template.xml,**/reload/*"); } @Test diff --git a/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/reload/RouteWatcherReloadStrategyTest.java b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/reload/RouteWatcherReloadStrategyTest.java new file mode 100644 index 0000000..58b4f5f --- /dev/null +++ b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/reload/RouteWatcherReloadStrategyTest.java @@ -0,0 +1,205 @@ +/* + * 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.dsl.xml.io.reload; + +import java.io.File; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spi.CamelEvent; +import org.apache.camel.support.EventNotifierSupport; +import org.apache.camel.support.RouteWatcherReloadStrategy; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.util.FileUtil; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.camel.test.junit5.TestSupport.createDirectory; +import static org.apache.camel.test.junit5.TestSupport.deleteDirectory; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class RouteWatcherReloadStrategyTest extends CamelTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(RouteWatcherReloadStrategyTest.class); + + private RouteWatcherReloadStrategy reloadStrategy; + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + reloadStrategy = new RouteWatcherReloadStrategy(); + reloadStrategy.setFolder("target/dummy"); + reloadStrategy.setPattern("*.xml"); + // to make unit test faster + reloadStrategy.setPollTimeout(100); + context.addService(reloadStrategy); + return context; + } + + @Test + public void testAddNewRoute() throws Exception { + deleteDirectory("target/dummy"); + createDirectory("target/dummy"); + + context.start(); + + // there are 0 routes to begin with + assertEquals(0, context.getRoutes().size()); + + LOG.info("Copying file to target/dummy"); + + // create an xml file with some routes + FileUtil.copyFile(new File("src/test/resources/org/apache/camel/reload/barRoute.xml"), + new File("target/dummy/barRoute.xml")); + + // wait for that file to be processed + // (is slow on osx, so wait up till 20 seconds) + await().atMost(20, TimeUnit.SECONDS).untilAsserted(() -> assertEquals(1, context.getRoutes().size())); + + // and the route should work + getMockEndpoint("mock:bar").expectedMessageCount(1); + template.sendBody("direct:bar", "Hello World"); + assertMockEndpointsSatisfied(); + } + + @Test + public void testUpdateExistingRoute() throws Exception { + deleteDirectory("target/dummy"); + createDirectory("target/dummy"); + + // the bar route is added two times, at first, and then when updated + final CountDownLatch latch = new CountDownLatch(2); + context.getManagementStrategy().addEventNotifier(new EventNotifierSupport() { + @Override + public void notify(CamelEvent event) throws Exception { + latch.countDown(); + } + + @Override + public boolean isEnabled(CamelEvent event) { + return event instanceof CamelEvent.RouteAddedEvent; + } + }); + + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:bar").routeId("bar").to("mock:foo"); + } + }); + + context.start(); + + assertEquals(1, context.getRoutes().size()); + + // and the route should work sending to mock:foo + getMockEndpoint("mock:bar").expectedMessageCount(0); + getMockEndpoint("mock:foo").expectedMessageCount(1); + template.sendBody("direct:bar", "Hello World"); + assertMockEndpointsSatisfied(); + + resetMocks(); + + LOG.info("Copying file to target/dummy"); + + // create an xml file with some routes + FileUtil.copyFile(new File("src/test/resources/org/apache/camel/reload/barRoute.xml"), + new File("target/dummy/barRoute.xml")); + + // wait for that file to be processed and remove/add the route + // (is slow on osx, so wait up till 20 seconds) + boolean done = latch.await(20, TimeUnit.SECONDS); + assertTrue(done, "Should reload file within 20 seconds"); + + // and the route should be changed to route to mock:bar instead of mock:foo + Thread.sleep(500); + getMockEndpoint("mock:bar").expectedMessageCount(1); + getMockEndpoint("mock:foo").expectedMessageCount(0); + template.sendBody("direct:bar", "Bye World"); + assertMockEndpointsSatisfied(); + } + + @Test + public void testUpdateXmlRoute() throws Exception { + deleteDirectory("target/dummy"); + createDirectory("target/dummy"); + + // the bar route is added two times, at first, and then when updated + final CountDownLatch latch = new CountDownLatch(2); + context.getManagementStrategy().addEventNotifier(new EventNotifierSupport() { + @Override + public void notify(CamelEvent event) throws Exception { + latch.countDown(); + } + + @Override + public boolean isEnabled(CamelEvent event) { + return event instanceof CamelEvent.RouteAddedEvent; + } + }); + + context.start(); + + // there are 0 routes to begin with + assertEquals(0, context.getRoutes().size()); + + LOG.info("Copying file to target/dummy"); + + // create an xml file with some routes + FileUtil.copyFile(new File("src/test/resources/org/apache/camel/reload/barRoute.xml"), + new File("target/dummy/barRoute.xml")); + + // wait for that file to be processed + // (is slow on osx, so wait up till 20 seconds) + await().atMost(20, TimeUnit.SECONDS).untilAsserted(() -> assertEquals(1, context.getRoutes().size())); + + // and the route should work + getMockEndpoint("mock:bar").expectedMessageCount(1); + template.sendBody("direct:bar", "Hello World"); + assertMockEndpointsSatisfied(); + + resetMocks(); + + // now update the file + LOG.info("Updating file in target/dummy"); + + // create an xml file with some routes + FileUtil.copyFile(new File("src/test/resources/org/apache/camel/reload/barUpdatedRoute.xml"), + new File("target/dummy/barRoute.xml")); + + // wait for that file to be processed and remove/add the route + // (is slow on osx, so wait up till 20 seconds) + boolean done = latch.await(20, TimeUnit.SECONDS); + assertTrue(done, "Should reload file within 20 seconds"); + + // and the route should work with the update + Thread.sleep(500); + getMockEndpoint("mock:bar").expectedBodiesReceived("Bye Camel"); + template.sendBody("direct:bar", "Camel"); + assertMockEndpointsSatisfied(); + } +} diff --git a/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/reload/barRoute.xml b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/reload/barRoute.xml new file mode 100644 index 0000000..e3b5136 --- /dev/null +++ b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/reload/barRoute.xml @@ -0,0 +1,29 @@ +<?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. + +--> +<routes xmlns="http://camel.apache.org/schema/spring"> + <!-- here we define the bar route --> + <route id="bar"> + <from uri="direct:bar"/> + <to uri="mock:bar"/> + </route> + + <!-- we could add more routes if we like, + but in this example we stick to one route only --> +</routes> diff --git a/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/reload/barUpdatedRoute.xml b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/reload/barUpdatedRoute.xml new file mode 100644 index 0000000..e7ce805 --- /dev/null +++ b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/reload/barUpdatedRoute.xml @@ -0,0 +1,34 @@ +<?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. + +--> +<!-- START SNIPPET: e1 --> +<routes xmlns="http://camel.apache.org/schema/spring"> + <!-- here we define the bar route --> + <route id="bar"> + <from uri="direct:bar"/> + <transform> + <simple>Bye ${body}</simple> + </transform> + <to uri="mock:bar"/> + </route> + + <!-- we could add more routes if we like, + but in this example we stick to one route only --> +</routes> +<!-- END SNIPPET: e1 --> \ No newline at end of file
