Fix #617 Registerable and discoverable Camel services
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/BuildProcessor.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/BuildProcessor.java
index 594ec28..63c6e8d 100644
--- a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/BuildProcessor.java
+++ b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/BuildProcessor.java
@@ -21,7 +21,6 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -54,8 +53,11 @@
import org.apache.camel.quarkus.core.CamelProducers;
import org.apache.camel.quarkus.core.CamelRecorder;
import org.apache.camel.quarkus.core.CoreAttachmentsRecorder;
+import org.apache.camel.quarkus.core.FastFactoryFinderResolver.Builder;
import org.apache.camel.quarkus.core.Flags;
import org.apache.camel.quarkus.core.UploadAttacher;
+import org.apache.camel.quarkus.core.deployment.CamelServicePatternBuildItem.CamelServiceDestination;
+import org.apache.camel.quarkus.core.deployment.util.PathFilter;
import org.apache.camel.quarkus.support.common.CamelCapabilities;
import org.apache.camel.spi.TypeConverterLoader;
import org.apache.camel.spi.TypeConverterRegistry;
@@ -125,6 +127,68 @@
new CamelServiceFilterBuildItem(CamelServiceFilter.forService("properties-component-factory")));
}
+ @BuildStep
+ void coreServicePatterns(BuildProducer<CamelServicePatternBuildItem> services) {
+
+ services.produce(new CamelServicePatternBuildItem(
+ CamelServiceDestination.REGISTRY,
+ true,
+ "META-INF/services/org/apache/camel/component/*",
+ "META-INF/services/org/apache/camel/language/*",
+ "META-INF/services/org/apache/camel/dataformat/*"));
+
+ services.produce(new CamelServicePatternBuildItem(
+ CamelServiceDestination.DISCOVERY,
+ true,
+ "META-INF/services/org/apache/camel/*",
+ "META-INF/services/org/apache/camel/management/*",
+ "META-INF/services/org/apache/camel/model/*",
+ "META-INF/services/org/apache/camel/configurer/*"));
+ }
+
+ @BuildStep
+ void userServicePatterns(
+ CamelConfig camelConfig,
+ BuildProducer<CamelServicePatternBuildItem> services) {
+
+ camelConfig.service.discovery.includePatterns.ifPresent(list -> services.produce(new CamelServicePatternBuildItem(
+ CamelServiceDestination.DISCOVERY,
+ true,
+ list)));
+
+ camelConfig.service.discovery.excludePatterns.ifPresent(list -> services.produce(new CamelServicePatternBuildItem(
+ CamelServiceDestination.DISCOVERY,
+ false,
+ list)));
+
+ camelConfig.service.registry.includePatterns.ifPresent(list -> services.produce(new CamelServicePatternBuildItem(
+ CamelServiceDestination.REGISTRY,
+ true,
+ list)));
+
+ camelConfig.service.registry.excludePatterns.ifPresent(list -> services.produce(new CamelServicePatternBuildItem(
+ CamelServiceDestination.REGISTRY,
+ false,
+ list)));
+ }
+
+ @BuildStep
+ void camelServices(
+ ApplicationArchivesBuildItem applicationArchives,
+ List<CamelServicePatternBuildItem> servicePatterns,
+ BuildProducer<CamelServiceBuildItem> camelServices) {
+
+ final PathFilter pathFilter = servicePatterns.stream()
+ .filter(patterns -> patterns.getDestination() == CamelServiceDestination.DISCOVERY)
+ .collect(
+ PathFilter.Builder::new,
+ (bldr, patterns) -> bldr.patterns(patterns.isInclude(), patterns.getPatterns()),
+ PathFilter.Builder::combine)
+ .build();
+ CamelSupport.services(applicationArchives, pathFilter)
+ .forEach(camelServices::produce);
+ }
+
/*
* Discover {@link TypeConverterLoader}.
*/
@@ -145,8 +209,8 @@
// account even if it should not.
//
// TODO: we could add a filter to discard AnnotationTypeConverterLoader but maybe we should introduce
- // a marker interface like StaticTypeConverterLoader for loaders that do not require to perform
- // any discovery at runtime.
+ // a marker interface like StaticTypeConverterLoader for loaders that do not require to perform
+ // any discovery at runtime.
//
for (ApplicationArchive archive : applicationArchives.getAllApplicationArchives()) {
Path path = archive.getArchiveRoot().resolve(BaseTypeConverterRegistry.META_INF_SERVICES_TYPE_CONVERTER_LOADER);
@@ -182,14 +246,26 @@
CamelRegistryBuildItem registry(
CamelRecorder recorder,
RecorderContext recorderContext,
+ CamelConfig camelConfig,
ApplicationArchivesBuildItem applicationArchives,
ContainerBeansBuildItem containerBeans,
List<CamelBeanBuildItem> registryItems,
- List<CamelServiceFilterBuildItem> serviceFilters) {
+ List<CamelServiceFilterBuildItem> serviceFilters,
+ List<CamelServicePatternBuildItem> servicePatterns) {
final RuntimeValue<org.apache.camel.spi.Registry> registry = recorder.createRegistry();
- CamelSupport.services(applicationArchives)
+ final PathFilter pathFilter = servicePatterns.stream()
+ .filter(patterns -> patterns.getDestination() == CamelServiceDestination.REGISTRY)
+ .collect(
+ PathFilter.Builder::new,
+ (builder, patterns) -> builder.patterns(patterns.isInclude(), patterns.getPatterns()),
+ PathFilter.Builder::combine)
+ .include(camelConfig.service.registry.includePatterns)
+ .exclude(camelConfig.service.registry.excludePatterns)
+ .build();
+
+ CamelSupport.services(applicationArchives, pathFilter)
.filter(si -> !containerBeans.getBeans().contains(si))
.filter(si -> {
//
@@ -268,6 +344,7 @@
CamelTypeConverterRegistryBuildItem typeConverterRegistry,
CamelModelJAXBContextFactoryBuildItem contextFactory,
CamelRoutesLoaderBuildItems.Xml xmlLoader,
+ CamelFactoryFinderResolverBuildItem factoryFinderResolverBuildItem,
BeanContainerBuildItem beanContainer) {
RuntimeValue<CamelContext> context = recorder.createContext(
@@ -275,6 +352,7 @@
typeConverterRegistry.getRegistry(),
contextFactory.getContextFactory(),
xmlLoader.getLoader(),
+ factoryFinderResolverBuildItem.getFactoryFinderResolver(),
beanContainer.getValue());
return new CamelContextBuildItem(context);
@@ -312,6 +390,27 @@
return new CamelRuntimeRegistryBuildItem(registry.getRegistry());
}
+
+ @Record(ExecutionTime.STATIC_INIT)
+ @BuildStep
+ CamelFactoryFinderResolverBuildItem factoryFinderResolver(
+ RecorderContext recorderContext,
+ CamelRecorder recorder,
+ List<CamelServiceBuildItem> camelServices) {
+
+ RuntimeValue<Builder> builder = recorder.factoryFinderResolverBuilder();
+
+ camelServices.stream()
+ .forEach(service -> {
+ recorder.factoryFinderResolverEntry(
+ builder,
+ service.path.toString(),
+ recorderContext.classProxy(service.type));
+ });
+
+ return new CamelFactoryFinderResolverBuildItem(recorder.factoryFinderResolver(builder));
+ }
+
}
/*
@@ -343,10 +442,10 @@
// public and non-abstract
.filter(ci -> ((ci.flags() & (Modifier.ABSTRACT | Modifier.PUBLIC)) == Modifier.PUBLIC))
.map(ClassInfo::name)
- .filter(dotName -> CamelSupport.isPathIncluded(
- dotName.toString('/'),
- config.main.routesDiscovery.excludePatterns.orElse(Collections.emptyList()),
- config.main.routesDiscovery.includePatterns.orElse(Collections.emptyList())))
+ .filter(new PathFilter.Builder()
+ .exclude(config.main.routesDiscovery.excludePatterns)
+ .include(config.main.routesDiscovery.includePatterns)
+ .build().asDotNamePredicate())
.map(CamelRoutesBuilderClassBuildItem::new)
.collect(Collectors.toList());
}
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelFactoryFinderResolverBuildItem.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelFactoryFinderResolverBuildItem.java
new file mode 100644
index 0000000..be9bbfa
--- /dev/null
+++ b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelFactoryFinderResolverBuildItem.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.quarkus.builder.item.SimpleBuildItem;
+import io.quarkus.runtime.RuntimeValue;
+import org.apache.camel.spi.FactoryFinderResolver;
+
+/**
+ * A {@link SimpleBuildItem} holding a {@link FastFactoryFinderResolver} {@link RuntimeValue}.
+ */
+public final class CamelFactoryFinderResolverBuildItem extends SimpleBuildItem {
+ private final RuntimeValue<FactoryFinderResolver> factoryFinderResolver;
+
+ public CamelFactoryFinderResolverBuildItem(RuntimeValue<FactoryFinderResolver> factoryFinderResolverBuilder) {
+ this.factoryFinderResolver = factoryFinderResolverBuilder;
+ }
+
+ public RuntimeValue<FactoryFinderResolver> getFactoryFinderResolver() {
+ return factoryFinderResolver;
+ }
+}
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceBuildItem.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceBuildItem.java
new file mode 100644
index 0000000..b460bf0
--- /dev/null
+++ b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceBuildItem.java
@@ -0,0 +1,90 @@
+/*
+ * 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.nio.file.Path;
+import java.util.Objects;
+
+import io.quarkus.builder.item.MultiBuildItem;
+
+/**
+ * A {@link MultiBuildItem} holding information about a service defined in a property file somewhere under
+ * {@code META-INF/services/org/apache/camel}.
+ */
+public final class CamelServiceBuildItem extends MultiBuildItem implements CamelBeanInfo {
+
+ final Path path;
+
+ final String name;
+
+ final String type;
+
+ public CamelServiceBuildItem(Path path, String type) {
+ this(path, path.getFileName().toString(), type);
+ }
+
+ public CamelServiceBuildItem(Path path, String name, String type) {
+ Objects.requireNonNull(path, "path");
+ Objects.requireNonNull(type, () -> "type for path " + path);
+ this.path = path;
+ this.name = name;
+ this.type = type;
+ }
+
+ /**
+ * @return the path of the service file like {@code META-INF/services/org/apache/camel/component/file}.
+ */
+ public Path getPath() {
+ return path;
+ }
+
+ /**
+ * @return the name under which this service will be registered in the Camel registry.
+ * This name may or may not be the same as the last segment of {@link #path}.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return The fully qualified class name of the service.
+ */
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ /* This must be the same as in other implementations of CamelBeanInfo */
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof CamelBeanInfo)) {
+ return false;
+ }
+ CamelBeanInfo info = (CamelBeanInfo) o;
+ return Objects.equals(getName(), info.getName()) &&
+ Objects.equals(getType(), info.getType());
+ }
+
+ @Override
+ public int hashCode() {
+ /* This must be the same as in other implementations of CamelBeanInfo */
+ return Objects.hash(getName(), getType());
+ }
+
+}
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceFilter.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceFilter.java
index 87c96a9..9e9c508 100644
--- a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceFilter.java
+++ b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceFilter.java
@@ -19,7 +19,7 @@
import java.util.function.Predicate;
@FunctionalInterface
-public interface CamelServiceFilter extends Predicate<CamelServiceInfo> {
+public interface CamelServiceFilter extends Predicate<CamelServiceBuildItem> {
String CAMEL_SERVICE_BASE_PATH = "META-INF/services/org/apache/camel";
static CamelServiceFilter forPathEndingWith(String path) {
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceInfo.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceInfo.java
deleted file mode 100644
index 8c46e13..0000000
--- a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServiceInfo.java
+++ /dev/null
@@ -1,90 +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.quarkus.core.deployment;
-
-import java.nio.file.Path;
-import java.util.Objects;
-
-/**
- * Utility class to describe a camel service which is a result of reading
- * services from resources belonging to META-INF/services/org/apache/camel.
- */
-public class CamelServiceInfo implements CamelBeanInfo {
- /**
- * The path of the service file like META-INF/services/org/apache/camel/component/file.
- */
- public final Path path;
-
- /**
- * The name of the service entry which is derived from the service path. As example the
- * name for a service with path <code>META-INF/services/org/apache/camel/component/file</code>
- * will be <code>file</code>
- */
- public final String name;
-
- /**
- * The full qualified class name of the service.
- */
- public final String type;
-
- public CamelServiceInfo(Path path, String type) {
- this(path, path.getFileName().toString(), type);
- }
-
- public CamelServiceInfo(Path path, String name, String type) {
- this.path = path;
- this.name = name;
- this.type = type;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- @Override
- public String getType() {
- return this.type;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof CamelBeanInfo)) {
- return false;
- }
- CamelBeanInfo info = (CamelBeanInfo) o;
- return Objects.equals(getName(), info.getName()) &&
- Objects.equals(getType(), info.getType());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(getName(), getType());
- }
-
- @Override
- public String toString() {
- return "ServiceInfo{"
- + "path='" + path.toString() + '\''
- + ", name=" + name
- + ", type=" + type
- + '}';
- }
-}
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServicePatternBuildItem.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServicePatternBuildItem.java
new file mode 100644
index 0000000..906b21e
--- /dev/null
+++ b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelServicePatternBuildItem.java
@@ -0,0 +1,84 @@
+/*
+ * 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.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import io.quarkus.builder.item.MultiBuildItem;
+
+/**
+ * A {@link MultiBuildItem} holding a collection of path patterns to select files under
+ * {@code META-INF/services/org/apache/camel} which define discoverable Camel services.
+ */
+public final class CamelServicePatternBuildItem extends MultiBuildItem {
+
+ /**
+ * Where a Camel service should be further processed
+ */
+ public enum CamelServiceDestination {
+ /** Service marked with {@link #DISCOVERY} should be made discoverable via FactoryFinder mechanism */
+ DISCOVERY,
+ /** Service marked with {@link #DISCOVERY} should be registered in the Camel registry */
+ REGISTRY
+ }
+
+ public CamelServicePatternBuildItem(CamelServiceDestination destination, boolean include,
+ String... patterns) {
+ this(destination, include, Arrays.asList(patterns));
+ }
+
+ public CamelServicePatternBuildItem(CamelServiceDestination destination, boolean include,
+ Collection<String> patterns) {
+ this.destination = destination;
+ this.include = include;
+ this.patterns = Collections.unmodifiableList(new ArrayList<>(patterns));
+ }
+
+ private final CamelServiceDestination destination;
+
+ private final boolean include;
+
+ private final List<String> patterns;
+
+ /**
+ * @return a {@link CamelServiceDestination} that says where this service should be further processed. See
+ * {@link CamelServiceDestination} and its members.
+ */
+ public CamelServiceDestination getDestination() {
+ return destination;
+ }
+
+ /**
+ * @return {@code true} if the {@link #patterns} should be interpreted as includes; otherwise the {@link #patterns}
+ * should be interpreted as excludes
+ */
+ public boolean isInclude() {
+ return include;
+ }
+
+ /**
+ * @return a {@link List} or Ant-like path patterns. By convention these
+ */
+ public List<String> getPatterns() {
+ return patterns;
+ }
+
+}
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelSupport.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelSupport.java
index f8f7d10..296229d 100644
--- a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelSupport.java
+++ b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelSupport.java
@@ -22,19 +22,15 @@
import java.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.AbstractMap;
import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
-import org.apache.camel.util.AntPathMatcher;
-import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.quarkus.core.deployment.util.PathFilter;
import org.jboss.jandex.ClassInfo;
public final class CamelSupport {
@@ -60,29 +56,6 @@
}
}
- 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))
@@ -91,29 +64,22 @@
.filter(Files::isRegularFile);
}
- public static Stream<CamelServiceInfo> services(ApplicationArchivesBuildItem applicationArchivesBuildItem) {
- return CamelSupport.resources(applicationArchivesBuildItem, CamelSupport.CAMEL_SERVICE_BASE_PATH)
- .map(CamelSupport::services)
- .flatMap(Collection::stream);
+ public static Stream<CamelServiceBuildItem> services(ApplicationArchivesBuildItem archives, PathFilter pathFilter) {
+ return resources(archives, CAMEL_SERVICE_BASE_PATH)
+ .filter(pathFilter.asPathPredicate())
+ .map(path -> new AbstractMap.SimpleImmutableEntry<>(path, readProperties(path)))
+ .filter(entry -> entry.getValue().getProperty("class") != null)
+ .map(entry -> new CamelServiceBuildItem(entry.getKey(), entry.getValue().getProperty("class")));
}
- private static List<CamelServiceInfo> services(Path p) {
- List<CamelServiceInfo> answer = new ArrayList<>();
-
- try (InputStream is = Files.newInputStream(p)) {
- Properties props = new Properties();
- props.load(is);
- for (Map.Entry<Object, Object> entry : props.entrySet()) {
- String k = entry.getKey().toString();
- if (k.equals("class")) {
- answer.add(new CamelServiceInfo(p, entry.getValue().toString()));
- }
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
+ private static Properties readProperties(Path path) {
+ try (InputStream in = Files.newInputStream(path)) {
+ final Properties result = new Properties();
+ result.load(in);
+ return result;
+ } catch (IOException e) {
+ throw new RuntimeException("Could not read " + path, e);
}
-
- return answer;
}
@SafeVarargs
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/NativeImageProcessor.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/NativeImageProcessor.java
index 9c9f346..034b191 100644
--- a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/NativeImageProcessor.java
+++ b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/NativeImageProcessor.java
@@ -16,14 +16,9 @@
*/
package org.apache.camel.quarkus.core.deployment;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
-import java.util.Properties;
import java.util.stream.Collectors;
import io.quarkus.deployment.annotations.BuildProducer;
@@ -41,6 +36,7 @@
import org.apache.camel.Producer;
import org.apache.camel.TypeConverter;
import org.apache.camel.quarkus.core.Flags;
+import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.ExchangeFormatter;
import org.apache.camel.spi.PropertiesComponent;
import org.apache.camel.spi.ScheduledPollConsumerScheduler;
@@ -69,7 +65,8 @@
CamelContext.class,
StreamCachingStrategy.class,
StreamCachingStrategy.SpoolUsedHeapMemoryLimit.class,
- PropertiesComponent.class);
+ PropertiesComponent.class,
+ DataFormat.class);
@BuildStep
void reflectiveItems(
@@ -125,36 +122,24 @@
}
@BuildStep
- void resourcesAndServices(
+ void resources(
ApplicationArchivesBuildItem applicationArchivesBuildItem,
- BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
BuildProducer<NativeImageResourceBuildItem> resource) {
CamelSupport.resources(applicationArchivesBuildItem, "META-INF/maven/org.apache.camel/camel-base")
.forEach(p -> resource.produce(new NativeImageResourceBuildItem(p.toString().substring(1))));
- CamelSupport.resources(applicationArchivesBuildItem, CamelSupport.CAMEL_SERVICE_BASE_PATH)
- .forEach(path -> addCamelService(path, reflectiveClass, resource));
}
- static void addCamelService(
- Path p,
- BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
- BuildProducer<NativeImageResourceBuildItem> resource) {
- try (InputStream is = Files.newInputStream(p)) {
- Properties props = new Properties();
- props.load(is);
- for (Map.Entry<Object, Object> entry : props.entrySet()) {
- String k = entry.getKey().toString();
- if (k.equals("class")) {
- reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, entry.getValue().toString()));
- } else if (k.endsWith(".class")) {
- reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, entry.getValue().toString()));
- resource.produce(new NativeImageResourceBuildItem(p.toString().substring(1)));
- }
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ @BuildStep
+ void camelServices(
+ List<CamelServiceBuildItem> camelServices,
+ BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
+
+ camelServices.stream()
+ .forEach(service -> {
+ reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, service.type));
+ });
+
}
}
diff --git a/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/util/PathFilter.java b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/util/PathFilter.java
new file mode 100644
index 0000000..4c6772d
--- /dev/null
+++ b/extensions/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/util/PathFilter.java
@@ -0,0 +1,156 @@
+/*
+ * 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.util;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+
+import org.apache.camel.util.AntPathMatcher;
+import org.apache.camel.util.ObjectHelper;
+import org.jboss.jandex.DotName;
+
+/**
+ * A utility able to filter resource paths using Ant-like includes and excludes.
+ */
+public class PathFilter {
+ private final AntPathMatcher matcher = new AntPathMatcher();
+ private final List<String> includePatterns;
+ private final List<String> excludePatterns;
+ private final Predicate<String> stringPredicate;
+
+ PathFilter(List<String> includePatterns, List<String> excludePatterns) {
+ this.includePatterns = includePatterns;
+ this.excludePatterns = excludePatterns;
+
+ if (ObjectHelper.isEmpty(excludePatterns) && ObjectHelper.isEmpty(includePatterns)) {
+ this.stringPredicate = path -> true;
+ } else {
+ this.stringPredicate = path -> {
+ path = sanitize(path);
+ // same logic as org.apache.camel.main.DefaultRoutesCollector so exclude
+ // take precedence over include
+ for (String part : excludePatterns) {
+ if (matcher.match(part, path)) {
+ return false;
+ }
+ }
+ for (String part : includePatterns) {
+ if (matcher.match(part, path)) {
+ return true;
+ }
+ }
+ return ObjectHelper.isEmpty(includePatterns);
+ };
+ }
+ ;
+ }
+
+ public Predicate<String> asStringPredicate() {
+ return stringPredicate;
+ }
+
+ public Predicate<DotName> asDotNamePredicate() {
+ if (ObjectHelper.isEmpty(excludePatterns) && ObjectHelper.isEmpty(includePatterns)) {
+ return dotName -> true;
+ } else {
+ return dotName -> stringPredicate.test(dotName.toString().replace('.', '/'));
+ }
+ }
+
+ public Predicate<Path> asPathPredicate() {
+ if (ObjectHelper.isEmpty(excludePatterns) && ObjectHelper.isEmpty(includePatterns)) {
+ return path -> true;
+ } else {
+ return path -> stringPredicate.test(sanitize(path.toString()));
+ }
+ }
+
+ static String sanitize(String path) {
+ path = path.trim();
+ return (!path.isEmpty() && path.charAt(0) == '/')
+ ? path.substring(1)
+ : path;
+ }
+
+ public static class Builder {
+ private List<String> includePatterns = new ArrayList<String>();
+ private List<String> excludePatterns = new ArrayList<String>();
+
+ public Builder patterns(boolean isInclude, Collection<String> patterns) {
+ if (isInclude) {
+ include(patterns);
+ } else {
+ exclude(patterns);
+ }
+ return this;
+ }
+
+ public Builder include(String pattern) {
+ includePatterns.add(sanitize(pattern));
+ return this;
+ }
+
+ public Builder include(Collection<String> patterns) {
+ patterns.stream().map(PathFilter::sanitize).forEach(includePatterns::add);
+ return this;
+ }
+
+ public Builder include(Optional<? extends Collection<String>> patterns) {
+ patterns.ifPresent(ps -> include(ps));
+ return this;
+ }
+
+ public Builder exclude(String pattern) {
+ excludePatterns.add(sanitize(pattern));
+ return this;
+ }
+
+ public Builder exclude(Collection<String> patterns) {
+ patterns.stream().map(PathFilter::sanitize).forEach(excludePatterns::add);
+ return this;
+ }
+
+ public Builder exclude(Optional<? extends Collection<String>> patterns) {
+ patterns.ifPresent(ps -> exclude(ps));
+ return this;
+ }
+
+ public Builder combine(Builder other) {
+ includePatterns.addAll(other.includePatterns);
+ excludePatterns.addAll(other.excludePatterns);
+ return this;
+ }
+
+ /**
+ * @throws NullPointerException if this method is called more than once for the same {@link Builder} instance.
+ * @return a new {@link PathFilter}
+ */
+ public PathFilter build() {
+ final List<String> incl = includePatterns;
+ includePatterns = null; // avoid leaking the collection trough reuse of the builder
+ final List<String> excl = excludePatterns;
+ excludePatterns = null; // avoid leaking the collection trough reuse of the builder
+ return new PathFilter(incl, excl);
+ }
+
+ }
+
+}
diff --git a/extensions/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelSupportTest.java b/extensions/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelSupportTest.java
deleted file mode 100644
index a93d05f..0000000
--- a/extensions/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelSupportTest.java
+++ /dev/null
@@ -1,61 +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.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")));
- }
-}
diff --git a/extensions/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/util/PathFilterTest.java b/extensions/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/util/PathFilterTest.java
new file mode 100644
index 0000000..2956860
--- /dev/null
+++ b/extensions/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/util/PathFilterTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.util;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+import org.jboss.jandex.DotName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class PathFilterTest {
+
+ @Test
+ public void stringFilter() {
+ 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")));
+ }
+
+ @Test
+ public void pathFilter() {
+ Predicate<Path> predicate = new PathFilter.Builder()
+ .include("/foo/bar/*")
+ .include("moo/mar/*")
+ .exclude("/foo/baz/*")
+ .exclude("moo/maz/*")
+ .build().asPathPredicate();
+ assertTrue(predicate.test(Paths.get("/foo/bar/file")));
+ assertTrue(predicate.test(Paths.get("foo/bar/file")));
+ assertFalse(predicate.test(Paths.get("/foo/baz/file")));
+ assertFalse(predicate.test(Paths.get("foo/baz/file")));
+
+ assertTrue(predicate.test(Paths.get("/moo/mar/file")));
+ assertTrue(predicate.test(Paths.get("moo/mar/file")));
+ assertFalse(predicate.test(Paths.get("/moo/marz/file")));
+ assertFalse(predicate.test(Paths.get("moo/maz/file")));
+ }
+
+ @Test
+ public void dotNameFilter() {
+ Predicate<DotName> predicate = new PathFilter.Builder()
+ .include("foo/bar/*")
+ .exclude("foo/baz/*")
+ .build().asDotNamePredicate();
+ assertTrue(predicate.test(DotName.createSimple("foo.bar.Class")));
+ assertFalse(predicate.test(DotName.createSimple("foo.baz.Class")));
+ }
+
+ static boolean isPathIncluded(String path, List<String> excludePatterns, List<String> includePatterns) {
+ return new PathFilter(includePatterns, excludePatterns).asStringPredicate().test(path);
+ }
+
+}
diff --git a/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelConfig.java b/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelConfig.java
index d10f6f5..b564d8f 100644
--- a/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelConfig.java
+++ b/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelConfig.java
@@ -32,6 +32,12 @@
@ConfigItem
public MainConfig main;
+ /**
+ * Build time configuration options for Camel services.
+ */
+ @ConfigItem
+ public ServiceConfig service;
+
@ConfigGroup
public static class MainConfig {
/**
@@ -87,4 +93,85 @@
@ConfigItem
public Optional<List<String>> includePatterns;
}
+
+ @ConfigGroup
+ public static class ServiceConfig {
+
+ /**
+ * Build time configuration related to discoverability of Camel services via the
+ * {@code org.apache.camel.spi.FactoryFinder} mechanism
+ */
+ @ConfigItem
+ public ServiceDiscoveryConfig discovery;
+
+ /** Build time configuration related to registering of Camel services to the Camel registry */
+ @ConfigItem
+ public ServiceRegistryConfig registry;
+ }
+
+ @ConfigGroup
+ public static class ServiceDiscoveryConfig {
+
+ /**
+ * A comma-separated list of Ant-path style patterns to match Camel service definition files in the classpath.
+ * The services defined in the matching files will <strong>not<strong> be discoverable via the
+ * {@code org.apache.camel.spi.FactoryFinder} mechanism.
+ * <p>
+ * The excludes have higher precedence than includes. The excludes defined here can also be used to veto the
+ * discoverability of services included by Camel Quarkus extensions.
+ * <p>
+ * Example values:
+ * <code>META-INF/services/org/apache/camel/foo/*,META-INF/services/org/apache/camel/foo/**/bar</code>
+ */
+ @ConfigItem
+ public Optional<List<String>> excludePatterns;
+
+ /**
+ * A comma-separated list of Ant-path style patterns to match Camel service definition files in the classpath.
+ * The services defined in the matching files will be discoverable via the
+ * {@code org.apache.camel.spi.FactoryFinder} mechanism unless the given file is excluded via
+ * {@code exclude-patterns}.
+ * <p>
+ * Note that Camel Quarkus extensions may include some services by default. The services selected here added
+ * to those services and the exclusions defined in {@code exclude-patterns} are applied to the union set.
+ * <p>
+ * Example values:
+ * <code>META-INF/services/org/apache/camel/foo/*,META-INF/services/org/apache/camel/foo/**/bar</code>
+ */
+ @ConfigItem
+ public Optional<List<String>> includePatterns;
+ }
+
+ @ConfigGroup
+ public static class ServiceRegistryConfig {
+
+ /**
+ * A comma-separated list of Ant-path style patterns to match Camel service definition files in the classpath.
+ * The services defined in the matching files will <strong>not<strong> be added to Camel registry during
+ * application's static initialization.
+ * <p>
+ * The excludes have higher precedence than includes. The excludes defined here can also be used to veto the
+ * registration of services included by Camel Quarkus extensions.
+ * <p>
+ * Example values:
+ * <code>META-INF/services/org/apache/camel/foo/*,META-INF/services/org/apache/camel/foo/**/bar</code>
+ */
+ @ConfigItem
+ public Optional<List<String>> excludePatterns;
+
+ /**
+ * A comma-separated list of Ant-path style patterns to match Camel service definition files in the classpath.
+ * The services defined in the matching files will be added to Camel registry during application's static
+ * initialization unless the given file is excluded via {@code exclude-patterns}.
+ * <p>
+ * Note that Camel Quarkus extensions may include some services by default. The services selected here added
+ * to those services and the exclusions defined in {@code exclude-patterns} are applied to the union set.
+ * <p>
+ * Example values:
+ * <code>META-INF/services/org/apache/camel/foo/*,META-INF/services/org/apache/camel/foo/**/bar</code>
+ */
+ @ConfigItem
+ public Optional<List<String>> includePatterns;
+ }
+
}
diff --git a/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRecorder.java b/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRecorder.java
index ab2d8c5..5a5824d 100644
--- a/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRecorder.java
+++ b/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRecorder.java
@@ -22,8 +22,10 @@
import org.apache.camel.CamelContext;
import org.apache.camel.model.ValidateDefinition;
import org.apache.camel.model.validator.PredicateValidatorDefinition;
+import org.apache.camel.quarkus.core.FastFactoryFinderResolver.Builder;
import org.apache.camel.reifier.ProcessorReifier;
import org.apache.camel.reifier.validator.ValidatorReifier;
+import org.apache.camel.spi.FactoryFinderResolver;
import org.apache.camel.spi.ModelJAXBContextFactory;
import org.apache.camel.spi.Registry;
import org.apache.camel.spi.TypeConverterLoader;
@@ -58,8 +60,9 @@
RuntimeValue<TypeConverterRegistry> typeConverterRegistry,
RuntimeValue<ModelJAXBContextFactory> contextFactory,
RuntimeValue<XmlRoutesLoader> xmlLoader,
+ RuntimeValue<FactoryFinderResolver> factoryFinderResolver,
BeanContainer beanContainer) {
- FastCamelContext context = new FastCamelContext();
+ FastCamelContext context = new FastCamelContext(factoryFinderResolver.getValue());
context.setRegistry(registry.getValue());
context.setTypeConverterRegistry(typeConverterRegistry.getValue());
context.setLoadTypeConverters(false);
@@ -121,4 +124,16 @@
public RuntimeValue<RegistryRoutesLoader> newDefaultRegistryRoutesLoader() {
return new RuntimeValue<>(new RegistryRoutesLoaders.Default());
}
+
+ public RuntimeValue<Builder> factoryFinderResolverBuilder() {
+ return new RuntimeValue<>(new FastFactoryFinderResolver.Builder());
+ }
+
+ public void factoryFinderResolverEntry(RuntimeValue<Builder> builder, String resourcePath, Class<?> cl) {
+ builder.getValue().entry(resourcePath, cl);
+ }
+
+ public RuntimeValue<FactoryFinderResolver> factoryFinderResolver(RuntimeValue<Builder> builder) {
+ return new RuntimeValue<>(builder.getValue().build());
+ }
}
diff --git a/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastCamelContext.java b/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastCamelContext.java
index e864c84..8e8ff03 100644
--- a/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastCamelContext.java
+++ b/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastCamelContext.java
@@ -42,7 +42,6 @@
import org.apache.camel.impl.engine.DefaultCamelContextNameStrategy;
import org.apache.camel.impl.engine.DefaultClassResolver;
import org.apache.camel.impl.engine.DefaultEndpointRegistry;
-import org.apache.camel.impl.engine.DefaultFactoryFinderResolver;
import org.apache.camel.impl.engine.DefaultInflightRepository;
import org.apache.camel.impl.engine.DefaultInjector;
import org.apache.camel.impl.engine.DefaultMessageHistoryFactory;
@@ -109,9 +108,9 @@
public class FastCamelContext extends AbstractCamelContext {
private Model model;
- public FastCamelContext() {
+ public FastCamelContext(FactoryFinderResolver factoryFinderResolver) {
super(false);
- setInitialization(Initialization.Eager);
+ setFactoryFinderResolver(factoryFinderResolver);
setTracing(Boolean.FALSE);
setDebugging(Boolean.FALSE);
setMessageHistory(Boolean.FALSE);
@@ -238,7 +237,8 @@
@Override
protected FactoryFinderResolver createFactoryFinderResolver() {
- return new DefaultFactoryFinderResolver();
+ throw new UnsupportedOperationException(
+ "FactoryFinderResolver should have been set in the FastCamelContext constructor");
}
@Override
diff --git a/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastFactoryFinderResolver.java b/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastFactoryFinderResolver.java
new file mode 100644
index 0000000..0c8f7db
--- /dev/null
+++ b/extensions/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastFactoryFinderResolver.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.camel.impl.engine.DefaultFactoryFinderResolver;
+import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.FactoryFinder;
+import org.apache.camel.spi.FactoryFinderResolver;
+import org.apache.camel.support.ObjectHelper;
+import org.jboss.logging.Logger;
+
+/**
+ * A build time assembled {@link FactoryFinderResolver}.
+ */
+public class FastFactoryFinderResolver extends DefaultFactoryFinderResolver {
+ private static final Logger LOG = Logger.getLogger(FastFactoryFinderResolver.class);
+ private final Map<String, Class<?>> classMap;
+
+ FastFactoryFinderResolver(Map<String, Class<?>> classMap) {
+ this.classMap = classMap;
+ }
+
+ @Override
+ public FactoryFinder resolveFactoryFinder(ClassResolver classResolver, String resourcePath) {
+ return new FastFactoryFinder(resourcePath);
+ }
+
+ static String mapKey(String resourcePath, String prefix, String key) {
+ final int len = resourcePath.length() + (prefix == null ? 0 : prefix.length()) + key.length() + 1;
+ final StringBuilder sb = new StringBuilder(len);
+ if (resourcePath.startsWith("/")) {
+ sb.append(resourcePath, 1, resourcePath.length());
+ } else {
+ sb.append(resourcePath);
+ }
+ if (!resourcePath.endsWith("/")) {
+ sb.append("/");
+ }
+ if (prefix != null) {
+ sb.append(prefix);
+ }
+ sb.append(key);
+ return sb.toString();
+ }
+
+ public static class Builder {
+ private Map<String, Class<?>> classMap = new HashMap<>();
+
+ public Builder entry(String resourcePath, Class<?> cl) {
+ if (resourcePath.startsWith("/")) {
+ resourcePath = resourcePath.substring(1);
+ }
+ classMap.put(resourcePath, cl);
+ return this;
+ }
+
+ public FastFactoryFinderResolver build() {
+ Map<String, Class<?>> cm = classMap;
+ classMap = null; // make sure the classMap does not leak through re-using the builder
+
+ if (LOG.isDebugEnabled()) {
+ cm.entrySet().forEach(
+ e -> LOG.debugf("FactoryFinder entry " + e.getKey() + ": " + e.getValue().getName()));
+ }
+
+ return new FastFactoryFinderResolver(cm);
+ }
+ }
+
+ public class FastFactoryFinder implements FactoryFinder {
+
+ private final String path;
+
+ FastFactoryFinder(String resourcePath) {
+ this.path = resourcePath;
+ }
+
+ @Override
+ public String getResourcePath() {
+ return path;
+ }
+
+ @Override
+ public Optional<Object> newInstance(String key) {
+ return Optional.ofNullable(doNewInstance(key, null));
+ }
+
+ @Override
+ public <T> Optional<T> newInstance(String key, Class<T> type) {
+ Object obj = doNewInstance(key, null);
+ return Optional.ofNullable(type.cast(obj));
+ }
+
+ @Override
+ public Optional<Class<?>> findClass(String key) {
+ return findClass(key, null);
+ }
+
+ @Override
+ public Optional<Class<?>> findClass(String key, String propertyPrefix) {
+ final String mapKey = mapKey(path, propertyPrefix, key);
+ final Class<?> cl = classMap.get(mapKey);
+ if (cl == null) {
+ LOG.warnf("Could not find a non-optional class for key %s", mapKey);
+ }
+ return Optional.ofNullable(cl);
+ }
+
+ @Override
+ public Optional<Class<?>> findClass(String key, String propertyPrefix, Class<?> clazz) {
+ // Just ignore clazz which is only useful for OSGiFactoryFinder
+ return findClass(key, propertyPrefix);
+ }
+
+ @Override
+ public Optional<Class<?>> findOptionalClass(String key, String propertyPrefix) {
+ final String mapKey = mapKey(path, propertyPrefix, key);
+ LOG.tracef("Found an optional class for key %s: %s", mapKey);
+ return Optional.ofNullable(classMap.get(mapKey));
+ }
+
+ private Object doNewInstance(String key, String propertyPrefix) {
+ Optional<Class<?>> clazz = findClass(key, propertyPrefix);
+ return clazz.map(ObjectHelper::newInstance).orElse(null);
+ }
+
+ }
+
+}
diff --git a/extensions/file/deployment/src/main/java/org/apache/camel/quarkus/component/file/deployment/FileProcessor.java b/extensions/file/deployment/src/main/java/org/apache/camel/quarkus/component/file/deployment/FileProcessor.java
index 8a38547..3739d70 100644
--- a/extensions/file/deployment/src/main/java/org/apache/camel/quarkus/component/file/deployment/FileProcessor.java
+++ b/extensions/file/deployment/src/main/java/org/apache/camel/quarkus/component/file/deployment/FileProcessor.java
@@ -20,6 +20,7 @@
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import org.apache.camel.component.file.GenericFile;
+import org.apache.camel.component.file.strategy.GenericFileProcessStrategyFactory;
class FileProcessor {
@@ -32,6 +33,8 @@
@BuildStep
ReflectiveClassBuildItem registerForReflection() {
- return new ReflectiveClassBuildItem(true, false, GenericFile.class);
+ return new ReflectiveClassBuildItem(true, false,
+ GenericFile.class,
+ GenericFileProcessStrategyFactory.class);
}
}
diff --git a/extensions/hystrix/deployment/src/main/java/org/apache/camel/quarkus/component/hystrix/deployment/HystrixProcessor.java b/extensions/hystrix/deployment/src/main/java/org/apache/camel/quarkus/component/hystrix/deployment/HystrixProcessor.java
index e0ecd6d..acd7554 100644
--- a/extensions/hystrix/deployment/src/main/java/org/apache/camel/quarkus/component/hystrix/deployment/HystrixProcessor.java
+++ b/extensions/hystrix/deployment/src/main/java/org/apache/camel/quarkus/component/hystrix/deployment/HystrixProcessor.java
@@ -19,7 +19,6 @@
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageSystemPropertyBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import org.apache.camel.model.CircuitBreakerDefinition;
@@ -38,7 +37,6 @@
@BuildStep
void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
- BuildProducer<NativeImageResourceBuildItem> resource,
BuildProducer<NativeImageSystemPropertyBuildItem> systemProperty) {
reflectiveClass.produce(new ReflectiveClassBuildItem(true, true,
@@ -47,8 +45,6 @@
CircuitBreakerDefinition.class,
OnFallbackDefinition.class));
- resource.produce(new NativeImageResourceBuildItem("META-INF/services/org/apache/camel/model/CircuitBreakerDefinition"));
-
// Force RxJava to not use Unsafe API
systemProperty.produce(new NativeImageSystemPropertyBuildItem("rx.unsafe-disable", "true"));
}
diff --git a/integration-tests/dozer/src/main/resources/application.properties b/integration-tests/dozer/src/main/resources/application.properties
index f0917e9..9540e06 100644
--- a/integration-tests/dozer/src/main/resources/application.properties
+++ b/integration-tests/dozer/src/main/resources/application.properties
@@ -15,6 +15,8 @@
## limitations under the License.
## ---------------------------------------------------------------------------
+#quarkus.log.category."org.apache.camel.quarkus.core.FastFactoryFinderResolver".level = TRACE
+
#
# Quarkus - Camel Dozer
#