You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/06/04 08:18:53 UTC

[camel] 04/05: CAMEL-13608: Add route filter to model camel context so you can filter out unwanted routes, such as from unit testing.

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 029da580b2c1f26a20e715be403d65adb9f1c7ab
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Jun 4 10:06:23 2019 +0200

    CAMEL-13608: Add route filter to model camel context so you can filter out unwanted routes, such as from unit testing.
---
 .../src/main/docs/spring-boot.adoc                 |   4 +-
 .../camel/spring/boot/CamelAutoConfiguration.java  |   5 +-
 .../spring/boot/CamelConfigurationProperties.java  |  45 +++++--
 .../camel/spring/boot/routefilter/DrinkRoute.java  |   2 +-
 .../boot/routefilter/RoutePatternFilterTest.java   |  60 ---------
 .../MixedBootAndXmlConfigurationTest.java          |   2 +-
 .../boot/{ => zlast}/MixedJavaDslAndXmlTest.java   |   4 +-
 .../src/test/resources/test-camel-context.xml      |   2 +-
 components/camel-test/src/main/docs/test.adoc      | 137 ++++++---------------
 .../apache/camel/test/junit4/CamelTestSupport.java |  29 ++++-
 .../camel/impl/AbstractModelCamelContext.java      |   4 +-
 .../java/org/apache/camel/impl/DefaultModel.java   |   4 +-
 .../camel/main/MainConfigurationProperties.java    |  87 ++++++++++---
 .../java/org/apache/camel/main/MainSupport.java    |   6 +-
 .../main/java/org/apache/camel/model/Model.java    |  13 +-
 .../java/org/apache/camel/model/RouteFilters.java  |  67 +++++++---
 ...ava => ModelRouteFilterPatternExcludeTest.java} |   6 +-
 ...ModelRouteFilterPatternIncludeExcludeTest.java} |   8 +-
 ...ava => ModelRouteFilterPatternIncludeTest.java} |   4 +-
 19 files changed, 266 insertions(+), 223 deletions(-)

diff --git a/components/camel-spring-boot/src/main/docs/spring-boot.adoc b/components/camel-spring-boot/src/main/docs/spring-boot.adoc
index 679a7e7..fc7e71b 100644
--- a/components/camel-spring-boot/src/main/docs/spring-boot.adoc
+++ b/components/camel-spring-boot/src/main/docs/spring-boot.adoc
@@ -91,7 +91,7 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 ----
 
 
-The component supports 140 options, which are listed below.
+The component supports 142 options, which are listed below.
 
 
 
@@ -169,6 +169,8 @@ The component supports 140 options, which are listed below.
 | *camel.springboot.message-history* | Sets whether message history is enabled or not. Default is true. | true | Boolean
 | *camel.springboot.name* | Sets the name of the CamelContext. |  | String
 | *camel.springboot.producer-template-cache-size* | Producer template endpoints cache size. | 1000 | Integer
+| *camel.springboot.route-filter-exclude-pattern* | Used for filtering routes routes matching the given pattern, which follows the following rules: - Match by route id - Match by route input endpoint uri The matching is using exact match, by wildcard and regular expression. For example to only include routes which starts with foo in their route id's, use: include=foo&#42; And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42; Multiple patterns can be separated by c [...]
+| *camel.springboot.route-filter-include-pattern* | Used for filtering routes routes matching the given pattern, which follows the following rules: - Match by route id - Match by route input endpoint uri The matching is using exact match, by wildcard and regular expression. For example to only include routes which starts with foo in their route id's, use: include=foo&#42; And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42; Multiple patterns can be separated by c [...]
 | *camel.springboot.shutdown-log-inflight-exchanges-on-timeout* | Sets whether to log information about the inflight Exchanges which are still running during a shutdown which didn't complete without the given timeout. | true | Boolean
 | *camel.springboot.shutdown-now-on-timeout* | Sets whether to force shutdown of all consumers when a timeout occurred and thus not all consumers was shutdown within that period. You should have good reasons to set this option to false as it means that the routes keep running and is halted abruptly when CamelContext has been shutdown. | true | Boolean
 | *camel.springboot.shutdown-routes-in-reverse-order* | Sets whether routes should be shutdown in reverse or the same order as they where started. | true | Boolean
diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
index 4eeb98d..9ee72ae 100644
--- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
+++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
@@ -232,8 +232,9 @@ public class CamelAutoConfiguration {
             camelContext.getExecutorServiceManager().setThreadNamePattern(config.getThreadNamePattern());
         }
 
-        if (config.getRouteFilterPattern() != null) {
-            camelContext.getExtension(Model.class).setRouteFilterPattern(config.getRouteFilterPattern());
+        if (config.getRouteFilterIncludePattern() != null || config.getRouteFilterExcludePattern() != null) {
+            LOG.info("Route filtering pattern: include={}, exclude={}", config.getRouteFilterIncludePattern(), config.getRouteFilterExcludePattern());
+            camelContext.getExtension(Model.class).setRouteFilterPattern(config.getRouteFilterIncludePattern(), config.getRouteFilterExcludePattern());
         }
 
         // additional advanced configuration which is not configured using CamelConfigurationProperties
diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
index f88f4f0..eb01bb9 100644
--- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
+++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
@@ -165,17 +165,38 @@ public class CamelConfigurationProperties {
     private String fileConfigurations;
 
     /**
-     * Used for filtering routes to only include routes matching the given pattern, which follows the following rules:
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
      *
      * - Match by route id
      * - Match by route input endpoint uri
      *
      * The matching is using exact match, by wildcard and regular expression.
      *
-     * For example to only include routes which starts with foo in their route id's, use: foo&#42;
-     * And to only include routes which starts from JMS endpoints, use: jms:&#42;
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
+     *
+     * Multiple patterns can be separated by comma, for example to exclude both foo and bar routes, use: exclude=foo&#42;,bar&#42;
+     *
+     * Exclude takes precedence over include.
      */
-    private String routeFilterPattern;
+    private String routeFilterIncludePattern;
+
+    /**
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
+     *
+     * - Match by route id
+     * - Match by route input endpoint uri
+     *
+     * The matching is using exact match, by wildcard and regular expression.
+     *
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
+     *
+     * Multiple patterns can be separated by comma, for example to exclude both foo and bar routes, use: exclude=foo&#42;,bar&#42;
+     *
+     * Exclude takes precedence over include.
+     */
+    private String routeFilterExcludePattern;
 
     /**
      * Whether to use the main run controller to ensure the Spring-Boot application
@@ -855,12 +876,20 @@ public class CamelConfigurationProperties {
         this.fileConfigurations = fileConfigurations;
     }
 
-    public String getRouteFilterPattern() {
-        return routeFilterPattern;
+    public String getRouteFilterIncludePattern() {
+        return routeFilterIncludePattern;
+    }
+
+    public void setRouteFilterIncludePattern(String routeFilterIncludePattern) {
+        this.routeFilterIncludePattern = routeFilterIncludePattern;
+    }
+
+    public String getRouteFilterExcludePattern() {
+        return routeFilterExcludePattern;
     }
 
-    public void setRouteFilterPattern(String routeFilterPattern) {
-        this.routeFilterPattern = routeFilterPattern;
+    public void setRouteFilterExcludePattern(String routeFilterExcludePattern) {
+        this.routeFilterExcludePattern = routeFilterExcludePattern;
     }
 
     public boolean isTraceFormatterShowBody() {
diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/DrinkRoute.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/DrinkRoute.java
index 7684e49..0378810 100644
--- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/DrinkRoute.java
+++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/DrinkRoute.java
@@ -24,7 +24,7 @@ public class DrinkRoute extends RouteBuilder {
 
     @Override
     public void configure() throws Exception {
-        from("direct:start")
+        from("direct:start").routeId("drink")
             .to("mock:foo");
     }
 }
diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/RoutePatternFilterTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/RoutePatternFilterTest.java
deleted file mode 100644
index aa06a57..0000000
--- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/RoutePatternFilterTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.spring.boot.routefilter;
-
-import org.apache.camel.ProducerTemplate;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.model.ModelCamelContext;
-import org.apache.camel.test.spring.CamelSpringBootRunner;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@RunWith(CamelSpringBootRunner.class)
-@SpringBootApplication
-@SpringBootTest(classes = RoutePatternFilterTest.class,
-    properties = {"camel.springboot.route-filter-pattern=bar*"})
-public class RoutePatternFilterTest {
-
-    @Autowired
-    ProducerTemplate producerTemplate;
-
-    @Autowired
-    ModelCamelContext camelContext;
-
-    @Test
-    public void shouldSendToBar() throws Exception {
-        // should only be 1 route
-        Assert.assertEquals(1, camelContext.getRoutes().size());
-        Assert.assertEquals(1, camelContext.getRouteDefinitions().size());
-        Assert.assertEquals("bar", camelContext.getRouteDefinitions().get(0).getId());
-
-        // Given
-        MockEndpoint mock = camelContext.getEndpoint("mock:bar", MockEndpoint.class);
-        mock.expectedBodiesReceived("Hello Bar");
-
-        // When
-        producerTemplate.sendBody("direct:start", "Hello Bar");
-
-        // Then
-        mock.assertIsSatisfied();
-    }
-
-}
diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/MixedBootAndXmlConfigurationTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/zlast/MixedBootAndXmlConfigurationTest.java
similarity index 97%
rename from components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/MixedBootAndXmlConfigurationTest.java
rename to components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/zlast/MixedBootAndXmlConfigurationTest.java
index 1993dab..27e858d 100644
--- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/MixedBootAndXmlConfigurationTest.java
+++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/zlast/MixedBootAndXmlConfigurationTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.spring.boot;
+package org.apache.camel.spring.boot.zlast;
 
 import org.apache.camel.CamelContext;
 import org.junit.Assert;
diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/MixedJavaDslAndXmlTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/zlast/MixedJavaDslAndXmlTest.java
similarity index 96%
rename from components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/MixedJavaDslAndXmlTest.java
rename to components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/zlast/MixedJavaDslAndXmlTest.java
index 28a94dc..54be1c4 100644
--- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/MixedJavaDslAndXmlTest.java
+++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/zlast/MixedJavaDslAndXmlTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.spring.boot;
+package org.apache.camel.spring.boot.zlast;
 
 import java.util.List;
 import java.util.stream.Collectors;
@@ -32,10 +32,12 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.ImportResource;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit4.SpringRunner;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+@DirtiesContext
 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class MixedJavaDslAndXmlTest {
diff --git a/components/camel-spring-boot/src/test/resources/test-camel-context.xml b/components/camel-spring-boot/src/test/resources/test-camel-context.xml
index 5cb7808..a88a05c 100644
--- a/components/camel-spring-boot/src/test/resources/test-camel-context.xml
+++ b/components/camel-spring-boot/src/test/resources/test-camel-context.xml
@@ -27,7 +27,7 @@
     <camelContext xmlns="http://camel.apache.org/schema/spring">
         <route id="xml">
             <from uri="timer://foo?period=1000"/>
-            <setBody><simple>Hello World from camel-contex.xml</simple></setBody>
+            <setBody><simple>Hello World from camel-context.xml</simple></setBody>
             <log message=">>> ${body}"/>
         </route>
     </camelContext>
diff --git a/components/camel-test/src/main/docs/test.adoc b/components/camel-test/src/main/docs/test.adoc
index 5f2256d..f4c6013 100644
--- a/components/camel-test/src/main/docs/test.adoc
+++ b/components/camel-test/src/main/docs/test.adoc
@@ -1,104 +1,47 @@
-[[Test-TestComponent]]
-== Test Component
+[[Test]]
+== Test Module
 
-Testing of distributed and asynchronous processing is
-notoriously difficult. The <<mock-component,Mock>>, <<mock-component,Test>>
-and <<dataset-component,DataSet>> endpoints work great with the
-Camel Testing Framework to simplify your unit and
-integration testing using
-link:enterprise-integration-patterns.html[Enterprise Integration
-Patterns] and Camel's large range of Components
-together with the powerful Bean Integration.
+The `camel-test` module is used for unit testing Camel.
 
-The *test* component extends the <<mock-component,Mock>> component to
-support pulling messages from another endpoint on startup to set the
-expected message bodies on the underlying <<mock-component,Mock>> endpoint.
-That is, you use the test endpoint in a route and messages arriving on
-it will be implicitly compared to some expected messages extracted from
-some other location.
+The class `org.apache.camel.test.junit4.CamelTestSupport` provides a base JUnit class which you would extend
+and implement your Camel unit test.
 
-So you can use, for example, an expected set of message bodies as files.
-This will then set up a properly configured <<mock-component,Mock>>
-endpoint, which is only valid if the received messages match the number
-of expected messages and their message payloads are equal.
+=== Simple unit test example
 
-Maven users will need to add the following dependency to their `pom.xml`
-for this component when using *Camel 2.8* or older:
-
-[source,xml]
-------------------------------------------------------------
-<dependency>
-    <groupId>org.apache.camel</groupId>
-    <artifactId>camel-spring</artifactId>
-    <version>x.x.x</version>
-    <!-- use the same version as your Camel core version -->
-</dependency>
-------------------------------------------------------------
-
-From Camel 2.9 onwards the <<test-component,Test>> component is provided
-directly in the camel-core.
-
-[[Test-URIformat]]
-=== URI format
+As shown below is a basic junit test which uses `camel-test`. The `createRouteBuilder` method is used
+for build the routes to be tested. Then the methods with `@Test` annotations are JUnit test methods which
+will be executed. The base class `CamelTestSupport` has a number of helper methods to configure testing,
+see more at the javadoc of this class.
 
 [source,java]
---------------------------------
-test:expectedMessagesEndpointUri
---------------------------------
-
-Where *expectedMessagesEndpointUri* refers to some other
-Component URI that the expected message bodies are
-pulled from before starting the test.
-
-[[Test-URIOptions]]
-=== URI Options
-
-[width="100%",cols="10%,10%,80%",options="header",]
-|=======================================================================
-|Name |Default Value |Description
-
-|`timeout` |`2000` |*Camel 2.12:* The timeout to use when polling for message bodies from
-the URI.
-
-|anyOrder |false |*Camel 2.17:* Whether the expected messages should arrive in the same
-order or can be in any order.
-
-|split |false |*Camel 2.17:* If enabled the messages loaded from the test endpoint
-will be split using \n\r delimiters (new lines) so each line is an
-expected message. +
-For example to use a file endpoint to load a file where each line is an
-expected message. 
-
-|delimiter |\n,\r |*Camel 2.17:* The split delimiter to use when split is enabled. By
-default the delimiter is new line based. The delimiter can be a regular
-expression.
-|=======================================================================
-
-[[Test-Example]]
-=== Example
-
-For example, you could write a test case as follows:
-
-[source,java]
---------------------------------------------------
-from("seda:someEndpoint").
-  to("test:file://data/expectedOutput?noop=true");
---------------------------------------------------
-
-If your test then invokes the
-http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#assertIsSatisfied(org.apache.camel.CamelContext)[MockEndpoint.assertIsSatisfied(camelContext)
-method], your test case will perform the necessary assertions.
-
-To see how you can set other expectations on the test endpoint, see the
-<<mock-component,Mock>> component.
-
-[[Test-SeeAlso]]
-=== See Also
-
-* Configuring Camel
-* Component
-* Endpoint
-* Getting Started
-
-* Spring Testing
+----
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class SimpleMockTest extends CamelTestSupport {
+
+    @Test
+    public void testMock() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
+----
 
diff --git a/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java b/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
index 8425bc6..6841f0f 100644
--- a/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
+++ b/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
@@ -34,7 +34,6 @@ import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
-
 import javax.management.AttributeNotFoundException;
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanException;
@@ -75,6 +74,7 @@ import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.impl.JndiRegistry;
 import org.apache.camel.impl.engine.DefaultCamelBeanPostProcessor;
 import org.apache.camel.impl.engine.InterceptSendToMockEndpointStrategy;
+import org.apache.camel.model.Model;
 import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.processor.interceptor.BreakpointSupport;
@@ -116,6 +116,8 @@ public abstract class CamelTestSupport extends TestSupport {
     protected volatile ConsumerTemplate consumer;
     protected volatile Service camelContextService;
     protected boolean dumpRouteStats;
+    private String routeFilterIncludePattern;
+    private String routeFilterExcludePattern;
     private boolean useRouteBuilder = true;
     private final DebugBreakpoint breakpoint = new DebugBreakpoint();
     private final StopWatch watch = new StopWatch();
@@ -211,6 +213,26 @@ public abstract class CamelTestSupport extends TestSupport {
     }
 
     /**
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
+     *
+     * - Match by route id
+     * - Match by route input endpoint uri
+     *
+     * The matching is using exact match, by wildcard and regular expression.
+     *
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
+     *
+     * Multiple patterns can be separated by comma, for example to exclude both foo and bar routes, use: exclude=foo&#42;,bar&#42;
+     *
+     * Exclude takes precedence over include.
+     */
+    public void setRouteFilterPattern(String include, String exclude) {
+        this.routeFilterIncludePattern = include;
+        this.routeFilterExcludePattern = exclude;
+    }
+
+    /**
      * Override to enable debugger
      * <p/>
      * Is default <tt>false</tt>
@@ -383,6 +405,11 @@ public abstract class CamelTestSupport extends TestSupport {
             pc.setIgnoreMissingLocation(ignore);
         }
 
+        if (routeFilterIncludePattern != null || routeFilterExcludePattern != null) {
+            log.info("Route filtering pattern: include={}, exclude={}", routeFilterIncludePattern, routeFilterExcludePattern);
+            context.getExtension(Model.class).setRouteFilterPattern(routeFilterIncludePattern, routeFilterExcludePattern);
+        }
+
         // prepare for in-between tests
         postProcessTest();
 
diff --git a/core/camel-core/src/main/java/org/apache/camel/impl/AbstractModelCamelContext.java b/core/camel-core/src/main/java/org/apache/camel/impl/AbstractModelCamelContext.java
index 68a54d2..ffa1783 100644
--- a/core/camel-core/src/main/java/org/apache/camel/impl/AbstractModelCamelContext.java
+++ b/core/camel-core/src/main/java/org/apache/camel/impl/AbstractModelCamelContext.java
@@ -233,8 +233,8 @@ public abstract class AbstractModelCamelContext extends AbstractCamelContext imp
     }
 
     @Override
-    public void setRouteFilterPattern(String pattern) {
-        model.setRouteFilterPattern(pattern);
+    public void setRouteFilterPattern(String include, String exclude) {
+        model.setRouteFilterPattern(include, exclude);
     }
 
     @Override
diff --git a/core/camel-core/src/main/java/org/apache/camel/impl/DefaultModel.java b/core/camel-core/src/main/java/org/apache/camel/impl/DefaultModel.java
index 8fe68e9..0cf700e 100644
--- a/core/camel-core/src/main/java/org/apache/camel/impl/DefaultModel.java
+++ b/core/camel-core/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -293,8 +293,8 @@ public class DefaultModel implements Model {
     }
 
     @Override
-    public void setRouteFilterPattern(String pattern) {
-        setRouteFilter(RouteFilters.filterByPattern(pattern));
+    public void setRouteFilterPattern(String include, String exclude) {
+        setRouteFilter(RouteFilters.filterByPattern(include, exclude));
     }
 
     @Override
diff --git a/core/camel-core/src/main/java/org/apache/camel/main/MainConfigurationProperties.java b/core/camel-core/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
index 116e6fe..d8b0489 100644
--- a/core/camel-core/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
+++ b/core/camel-core/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
@@ -18,6 +18,7 @@ package org.apache.camel.main;
 
 import org.apache.camel.ManagementStatisticsLevel;
 import org.apache.camel.spi.ReloadStrategy;
+import org.apache.camel.support.PatternHelper;
 
 /**
  * Global configuration for Camel Main to setup context name, stream caching and other global configurations.
@@ -72,7 +73,8 @@ public class MainConfigurationProperties {
     private String fileWatchDirectory;
     private boolean fileWatchDirectoryRecursively;
     private ReloadStrategy reloadStrategy;
-    private String routeFilterPattern;
+    private String routeFilterIncludePattern;
+    private String routeFilterExcludePattern;
 
     // getter and setters
     // --------------------------------------------------------------
@@ -715,25 +717,55 @@ public class MainConfigurationProperties {
         this.reloadStrategy = reloadStrategy;
     }
 
-    public String getRouteFilterPattern() {
-        return routeFilterPattern;
+    public String getRouteFilterIncludePattern() {
+        return routeFilterIncludePattern;
     }
 
     /**
-     * Used for filtering routes to only include routes matching the given pattern, which follows the following rules:
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
      *
      * - Match by route id
      * - Match by route input endpoint uri
      *
-     * The matching is using exact match, by wildcard and regular expression.
+     * The matching is using exact match, by wildcard and regular expression as documented by {@link PatternHelper#matchPattern(String, String)}.
      *
-     * For example to only include routes which starts with foo in their route id's, use: foo&#42;
-     * And to only include routes which starts from JMS endpoints, use: jms:&#42;
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
+     *
+     * Multiple patterns can be separated by comma, for example to exclude both foo and bar routes, use: exclude=foo&#42;,bar&#42;
+     *
+     * Exclude takes precedence over include.
+     *
+     * @param include  the include pattern
      */
-    public void setRouteFilterPattern(String routeFilterPattern) {
-        this.routeFilterPattern = routeFilterPattern;
+    public void setRouteFilterIncludePattern(String include) {
+        this.routeFilterIncludePattern = include;
+    }
+
+    public String getRouteFilterExcludePattern() {
+        return routeFilterExcludePattern;
     }
 
+    /**
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
+     *
+     * - Match by route id
+     * - Match by route input endpoint uri
+     *
+     * The matching is using exact match, by wildcard and regular expression as documented by {@link PatternHelper#matchPattern(String, String)}.
+     *
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
+     *
+     * Multiple patterns can be separated by comma, for example to exclude both foo and bar routes, use: exclude=foo&#42;,bar&#42;
+     *
+     * Exclude takes precedence over include.
+     *
+     * @param exclude  the exclude pattern
+     */
+    public void setRouteFilterExcludePattern(String exclude) {
+        this.routeFilterExcludePattern = exclude;
+    }
 
     // fluent builders
     // --------------------------------------------------------------
@@ -1232,19 +1264,44 @@ public class MainConfigurationProperties {
         return this;
     }
 
+
     /**
-     * Used for filtering routes to only include routes matching the given pattern, which follows the following rules:
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
      *
      * - Match by route id
      * - Match by route input endpoint uri
      *
-     * The matching is using exact match, by wildcard and regular expression.
+     * The matching is using exact match, by wildcard and regular expression as documented by {@link PatternHelper#matchPattern(String, String)}.
+     *
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
+     *
+     * Multiple patterns can be separated by comma, for example to exclude both foo and bar routes, use: exclude=foo&#42;,bar&#42;
+     *
+     * Exclude takes precedence over include.
+     */
+    public MainConfigurationProperties withRouteFilterIncludePattern(String routeFilterIncludePattern) {
+        this.routeFilterIncludePattern = routeFilterIncludePattern;
+        return this;
+    }
+
+    /**
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
+     *
+     * - Match by route id
+     * - Match by route input endpoint uri
+     *
+     * The matching is using exact match, by wildcard and regular expression as documented by {@link PatternHelper#matchPattern(String, String)}.
+     *
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
+     *
+     * Multiple patterns can be separated by comma, for example to exclude both foo and bar routes, use: exclude=foo&#42;,bar&#42;
      *
-     * For example to only include routes which starts with foo in their route id's, use: foo&#42;
-     * And to only include routes which starts from JMS endpoints, use: jms:&#42;
+     * Exclude takes precedence over include.
      */
-    public MainConfigurationProperties withRouteFilterPattern(String routeFilterPattern) {
-        this.routeFilterPattern = routeFilterPattern;
+    public MainConfigurationProperties withRouteFilterExcludePattern(String routeFilterExcludePattern) {
+        this.routeFilterExcludePattern = routeFilterExcludePattern;
         return this;
     }
 }
diff --git a/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java b/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java
index 37b9b58..dd0b85b 100644
--- a/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java
+++ b/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java
@@ -51,9 +51,7 @@ import org.apache.camel.health.HealthCheckService;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.impl.FileWatcherReloadStrategy;
 import org.apache.camel.model.Model;
-import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.model.RouteFilters;
 import org.apache.camel.processor.interceptor.BacklogTracer;
 import org.apache.camel.processor.interceptor.HandleFault;
 import org.apache.camel.spi.AsyncProcessorAwaitManager;
@@ -977,8 +975,8 @@ public abstract class MainSupport extends ServiceSupport {
             camelContext.getExecutorServiceManager().setThreadNamePattern(config.getThreadNamePattern());
         }
 
-        if (config.getRouteFilterPattern() != null) {
-            camelContext.getExtension(Model.class).setRouteFilterPattern(config.getRouteFilterPattern());
+        if (config.getRouteFilterIncludePattern() != null || config.getRouteFilterExcludePattern() != null) {
+            camelContext.getExtension(Model.class).setRouteFilterPattern(config.getRouteFilterIncludePattern(), config.getRouteFilterExcludePattern());
         }
 
         // additional advanced configuration which is not configured using CamelConfigurationProperties
diff --git a/core/camel-core/src/main/java/org/apache/camel/model/Model.java b/core/camel-core/src/main/java/org/apache/camel/model/Model.java
index 5bd09c5..e84b008 100644
--- a/core/camel-core/src/main/java/org/apache/camel/model/Model.java
+++ b/core/camel-core/src/main/java/org/apache/camel/model/Model.java
@@ -264,19 +264,22 @@ public interface Model {
     void startRouteDefinitions() throws Exception;
 
     /**
-     * Used for filtering routes to only include routes matching the given pattern, which follows the following rules:
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
      *
      * - Match by route id
      * - Match by route input endpoint uri
      *
      * The matching is using exact match, by wildcard and regular expression as documented by {@link PatternHelper#matchPattern(String, String)}.
      *
-     * For example to only include routes which starts with foo in their route id's, use: foo&#42;
-     * And to only include routes which starts from JMS endpoints, use: jms:&#42;
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
      *
-     * @param pattern  the pattern
+     * Exclude takes precedence over include.
+     *
+     * @param include  the include pattern
+     * @param exclude  the exclude pattern
      */
-    void setRouteFilterPattern(String pattern);
+    void setRouteFilterPattern(String include, String exclude);
 
     /**
      * Sets a custom route filter to use for filtering unwanted routes when routes are added.
diff --git a/core/camel-core/src/main/java/org/apache/camel/model/RouteFilters.java b/core/camel-core/src/main/java/org/apache/camel/model/RouteFilters.java
index 21e5652..babbf8e 100644
--- a/core/camel-core/src/main/java/org/apache/camel/model/RouteFilters.java
+++ b/core/camel-core/src/main/java/org/apache/camel/model/RouteFilters.java
@@ -19,45 +19,84 @@ package org.apache.camel.model;
 import java.util.function.Function;
 
 import org.apache.camel.support.PatternHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Used for filtering routes to only include routes matching a function.
  */
 public class RouteFilters implements Function<RouteDefinition, Boolean> {
 
-    public final String pattern;
+    private static final Logger LOG = LoggerFactory.getLogger(RouteFilters.class);
+
+    private final String includesText;
+    private final String excludesText;
+    private final String[] includes;
+    private final String[] excludes;
 
     /**
-     * Used for filtering routes to only include routes matching the given pattern, which follows the following rules:
+     * Used for filtering routes routes matching the given pattern, which follows the following rules:
      *
      * - Match by route id
      * - Match by route input endpoint uri
      *
      * The matching is using exact match, by wildcard and regular expression as documented by {@link PatternHelper#matchPattern(String, String)}.
      *
-     * For example to only include routes which starts with foo in their route id's, use: foo&#42;
-     * And to only include routes which starts from JMS endpoints, use: jms:&#42;
+     * For example to only include routes which starts with foo in their route id's, use: include=foo&#42;
+     * And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42;
+     *
+     * Multiple patterns can be separated by comma, for example to exclude both foo and bar routes, use: exclude=foo&#42;,bar&#42;
+     *
+     * Exclude takes precedence over include.
+     *
+     * @param include  the include pattern
+     * @param exclude  the exclude pattern
      */
-    public static RouteFilters filterByPattern(String pattern) {
-        return new RouteFilters(pattern);
+    public static RouteFilters filterByPattern(String include, String exclude) {
+        return new RouteFilters(include, exclude);
     }
 
-    private RouteFilters(String pattern) {
-        this.pattern = pattern;
+    private RouteFilters(String include, String exclude) {
+        this.includesText = include;
+        this.excludesText = exclude;
+        this.includes = include != null ? include.split(",") : null;
+        this.excludes = exclude != null ? exclude.split(",") : null;
     }
 
     @Override
     public Boolean apply(RouteDefinition route) {
+        String id = route.getId();
+        String uri = route.getInput() != null ? route.getInput().getEndpointUri() : null;
+
+        boolean answer = filter(route, id, uri);
+        LOG.debug("Route filter: include={}, exclude={}, id={}, from={} -> {}", includesText, excludesText, id, uri, answer);
+        return answer;
+    }
+
+    private boolean filter(RouteDefinition route, String id, String uri) {
         boolean match = false;
 
-        String id = route.getId();
-        if (id != null) {
-            match = PatternHelper.matchPattern(id, pattern);
+        // exclude takes precedence
+        if (excludes != null) {
+            for (String part : excludes) {
+                if (PatternHelper.matchPattern(id, part) || PatternHelper.matchPattern(uri, part)) {
+                    return false;
+                }
+            }
         }
-        if (!match && route.getInput() != null) {
-            String uri = route.getInput().getEndpointUri();
-            match = PatternHelper.matchPattern(uri, pattern);
+
+        if (includes != null) {
+            for (String part : includes) {
+                if (PatternHelper.matchPattern(id, part) || PatternHelper.matchPattern(uri, part)) {
+                    match = true;
+                    break;
+                }
+            }
+        } else {
+            // if include has not been set then, we assume its matched as it was not excluded
+            match = true;
         }
+
         return match;
     }
     
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java b/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternExcludeTest.java
similarity index 94%
copy from core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java
copy to core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternExcludeTest.java
index 014444a..e7f3ecc 100644
--- a/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternExcludeTest.java
@@ -21,13 +21,13 @@ import org.apache.camel.ContextTestSupport;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.Test;
 
-public class ModelRouteFilterPatternTest extends ContextTestSupport {
+public class ModelRouteFilterPatternExcludeTest extends ContextTestSupport {
 
     @Override
     protected CamelContext createCamelContext() throws Exception {
         CamelContext context = super.createCamelContext();
-        // filter to only include foo route
-        context.getExtension(Model.class).setRouteFilterPattern("foo*");
+        // filter to exclude bar
+        context.getExtension(Model.class).setRouteFilterPattern(null, "bar*");
         return context;
     }
 
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java b/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternIncludeExcludeTest.java
similarity index 91%
copy from core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java
copy to core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternIncludeExcludeTest.java
index 014444a..b65d805 100644
--- a/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternIncludeExcludeTest.java
@@ -21,13 +21,12 @@ import org.apache.camel.ContextTestSupport;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.Test;
 
-public class ModelRouteFilterPatternTest extends ContextTestSupport {
+public class ModelRouteFilterPatternIncludeExcludeTest extends ContextTestSupport {
 
     @Override
     protected CamelContext createCamelContext() throws Exception {
         CamelContext context = super.createCamelContext();
-        // filter to only include foo route
-        context.getExtension(Model.class).setRouteFilterPattern("foo*");
+        context.getExtension(Model.class).setRouteFilterPattern("foo*", "jms:*");
         return context;
     }
 
@@ -54,6 +53,9 @@ public class ModelRouteFilterPatternTest extends ContextTestSupport {
 
                 from("direct:bar").routeId("bar")
                         .to("mock:bar");
+
+                from("jms:beer").routeId("foolish")
+                        .to("mock:beer");
             }
         };
     }
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java b/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternIncludeTest.java
similarity index 95%
rename from core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java
rename to core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternIncludeTest.java
index 014444a..b394428 100644
--- a/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/model/ModelRouteFilterPatternIncludeTest.java
@@ -21,13 +21,13 @@ import org.apache.camel.ContextTestSupport;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.Test;
 
-public class ModelRouteFilterPatternTest extends ContextTestSupport {
+public class ModelRouteFilterPatternIncludeTest extends ContextTestSupport {
 
     @Override
     protected CamelContext createCamelContext() throws Exception {
         CamelContext context = super.createCamelContext();
         // filter to only include foo route
-        context.getExtension(Model.class).setRouteFilterPattern("foo*");
+        context.getExtension(Model.class).setRouteFilterPattern("foo*", null);
         return context;
     }