Skip to content

Commit

Permalink
Add an option to filter auto-discovered routes #396
Browse files Browse the repository at this point in the history
  • Loading branch information
lburgazzoli committed Nov 12, 2019
1 parent e765b00 commit 68b6096
Show file tree
Hide file tree
Showing 12 changed files with 362 additions and 18 deletions.
10 changes: 10 additions & 0 deletions extensions/core/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@
</dependency>

<!-- test dependencies -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-direct</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-log</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.apache.camel.impl.converter.BaseTypeConverterRegistry;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.quarkus.core.CamelConfig;
import org.apache.camel.quarkus.core.CamelMain;
import org.apache.camel.quarkus.core.CamelMainProducers;
import org.apache.camel.quarkus.core.CamelMainRecorder;
Expand Down Expand Up @@ -284,12 +285,13 @@ public List<CamelRoutesBuilderClassBuildItem> discoverRoutesBuilderClassNames(
}

@Record(ExecutionTime.STATIC_INIT)
@BuildStep(onlyIf = Flags.MainEnabled.class)
@BuildStep(onlyIf = { Flags.MainEnabled.class, Flags.RoutesDiscoveryEnabled.class })
public List<CamelBeanBuildItem> collectRoutes(
List<CamelRoutesBuilderClassBuildItem> camelRoutesBuilderClasses,
CamelMainRecorder recorder,
BeanRegistrationPhaseBuildItem beanRegistrationPhase,
RecorderContext recorderContext) {
RecorderContext recorderContext,
CamelConfig config) {

final Set<DotName> arcBeanClasses = beanRegistrationPhase.getContext().get(BuildExtension.Key.BEANS)
.stream()
Expand All @@ -300,6 +302,12 @@ public List<CamelBeanBuildItem> collectRoutes(
return camelRoutesBuilderClasses.stream()
.map(CamelRoutesBuilderClassBuildItem::getDotName)
.filter(dotName -> !arcBeanClasses.contains(dotName))
.filter(dotName -> {
return CamelSupport.isPathIncluded(
dotName.toString('/'),
config.main.routesDiscovery.excludePatterns,
config.main.routesDiscovery.includePatterns);
})
.map(dotName -> {
try {
return Class.forName(dotName.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
import org.apache.camel.quarkus.core.CamelServiceInfo;
import org.apache.camel.util.AntPathMatcher;
import org.apache.camel.util.ObjectHelper;
import org.jboss.jandex.ClassInfo;

public final class CamelSupport {
Expand All @@ -56,6 +58,29 @@ public static Stream<Path> safeWalk(Path p) {
}
}

public static boolean isPathIncluded(String path, Collection<String> excludePatterns, Collection<String> includePatterns) {
final AntPathMatcher matcher = new AntPathMatcher();

if (ObjectHelper.isEmpty(excludePatterns) && ObjectHelper.isEmpty(includePatterns)) {
return true;
}

// same logic as org.apache.camel.main.DefaultRoutesCollector so exclude
// take precedence over include
for (String part : excludePatterns) {
if (matcher.match(part.trim(), path)) {
return false;
}
}
for (String part : includePatterns) {
if (matcher.match(part.trim(), path)) {
return true;
}
}

return ObjectHelper.isEmpty(includePatterns);
}

public static Stream<Path> resources(ApplicationArchivesBuildItem archives, String path) {
return archives.getAllApplicationArchives().stream()
.map(arch -> arch.getArchiveRoot().resolve(path))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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.quarkus.core.deployment;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Properties;
import javax.inject.Inject;

import io.quarkus.test.QuarkusUnitTest;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.BaseMainSupport;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import static org.assertj.core.api.Assertions.assertThat;

public class CamelRoutesDiscoveryTest {
@RegisterExtension
static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource(applicationProperties(), "application.properties"));

@Inject
CamelContext camelContext;
@Inject
BaseMainSupport mainSupport;

public static final Asset applicationProperties() {
Writer writer = new StringWriter();

Properties props = new Properties();
props.setProperty("quarkus.camel.main.routes-discovery.enabled", "false");

try {
props.store(writer, "");
} catch (IOException e) {
throw new RuntimeException(e);
}

return new StringAsset(writer.toString());
}

@Test
public void testRoutesDiscovery() {
assertThat(camelContext.getRoutes()).isEmpty();
assertThat(mainSupport.getRoutesBuilders()).isEmpty();
}

public static class MyRoute extends RouteBuilder {
@Override
public void configure() throws Exception {
from("direct:in").routeId("my-route").to("log:out");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.quarkus.core.deployment;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Properties;
import javax.inject.Inject;

import io.quarkus.test.QuarkusUnitTest;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.BaseMainSupport;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import static org.assertj.core.api.Assertions.assertThat;

public class CamelRoutesFilterTest {
@RegisterExtension
static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource(applicationProperties(), "application.properties"));

@Inject
CamelContext camelContext;
@Inject
BaseMainSupport mainSupport;

public static final Asset applicationProperties() {
Writer writer = new StringWriter();

Properties props = new Properties();
props.setProperty("quarkus.camel.main.routes-discovery.enabled", "true");
props.setProperty("quarkus.camel.main.routes-discovery.exclude-patterns", "**/*Filtered");

try {
props.store(writer, "");
} catch (IOException e) {
throw new RuntimeException(e);
}

return new StringAsset(writer.toString());
}

@Test
public void testRoutesFilter() {
assertThat(camelContext.getRoutes()).hasSize(1);
assertThat(camelContext.getRoutes()).first().hasFieldOrPropertyWithValue("id", "my-route");
assertThat(mainSupport.getRoutesBuilders()).hasSize(1);
assertThat(mainSupport.getRoutesBuilders()).first().isInstanceOf(MyRoute.class);
}

public static class MyRoute extends RouteBuilder {
@Override
public void configure() throws Exception {
from("direct:in").routeId("my-route").to("log:out");
}
}

public static class MyRouteFiltered extends RouteBuilder {
@Override
public void configure() throws Exception {
from("direct:filtered").routeId("my-route-filtered").to("log:filtered");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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.quarkus.core.deployment;

import java.util.Arrays;

import org.junit.jupiter.api.Test;

import static org.apache.camel.quarkus.core.deployment.CamelSupport.isPathIncluded;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class CamelSupportTest {

@Test
public void testPathFiltering() {
assertFalse(isPathIncluded(
"org/acme/MyClass",
Arrays.asList("org/**"),
Arrays.asList()));
assertFalse(isPathIncluded(
"org/acme/MyClass",
Arrays.asList("org/**"),
Arrays.asList("org/**", "org/acme/MyClass")));
assertFalse(isPathIncluded(
"org/acme/MyClass",
Arrays.asList("org/acme/M*"),
Arrays.asList("org/acme/MyClass")));
assertFalse(isPathIncluded(
"org/acme/MyClass",
Arrays.asList(),
Arrays.asList("org/acme/A*")));

assertTrue(isPathIncluded(
"org/acme/MyClass",
Arrays.asList(),
Arrays.asList()));
assertTrue(isPathIncluded(
"org/acme/MyClass",
Arrays.asList(),
Arrays.asList("org/**")));
assertTrue(isPathIncluded(
"org/acme/MyClass",
Arrays.asList("org/acme/A*"),
Arrays.asList("org/acme/MyClass")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
package org.apache.camel.quarkus.core;

import java.util.List;

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
Expand All @@ -40,5 +42,48 @@ public static class MainConfig {
*/
@ConfigItem(defaultValue = "true")
public boolean enabled;

/**
* Build time configuration options for routes discovery.
*/
@ConfigItem
public RoutesDiscoveryConfig routesDiscovery;
}

@ConfigGroup
public static class RoutesDiscoveryConfig {
/**
* Enable automatic discovery of routes during static initialization.
*/
@ConfigItem(defaultValue = "true")
public boolean enabled;

/**
* Used for exclusive filtering scanning of RouteBuilder classes.
* The exclusive filtering takes precedence over inclusive filtering.
* The pattern is using Ant-path style pattern.
* Multiple patterns can be specified separated by comma.
*
* For example to exclude all classes starting with Bar use: &#42;&#42;/Bar&#42;
* To exclude all routes form a specific package use: com/mycompany/bar/&#42;
* To exclude all routes form a specific package and its sub-packages use double wildcards: com/mycompany/bar/&#42;&#42;
* And to exclude all routes from two specific packages use: com/mycompany/bar/&#42;,com/mycompany/stuff/&#42;
*/
@ConfigItem
public List<String> excludePatterns;

/**
* Used for inclusive filtering scanning of RouteBuilder classes.
* The exclusive filtering takes precedence over inclusive filtering.
* The pattern is using Ant-path style pattern.
*
* Multiple patterns can be specified separated by comma.
* For example to include all classes starting with Foo use: &#42;&#42;/Foo*
* To include all routes form a specific package use: com/mycompany/foo/&#42;
* To include all routes form a specific package and its sub-packages use double wildcards: com/mycompany/foo/&#42;&#42;
* And to include all routes from two specific packages use: com/mycompany/foo/&#42;,com/mycompany/stuff/&#42;
*/
@ConfigItem
public List<String> includePatterns;
}
}

0 comments on commit 68b6096

Please sign in to comment.