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 5ced786ad0b307cf032f6a50d0780c399da6f477 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sun Jun 16 08:13:22 2019 +0200 CAMEL-13647: Allow to do autowrire by classpath. Quick and dirty prototype. --- .../java/org/apache/camel/maven/AutowireMojo.java | 75 ++++++++++++++++++---- .../src/main/resources/known-types.properties | 22 +++++++ .../camel/support/PropertyBindingSupport.java | 1 + .../org/apache/camel/example/MyRouteBuilder.java | 2 + .../src/main/resources/application.properties | 3 + 5 files changed, 90 insertions(+), 13 deletions(-) diff --git a/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/AutowireMojo.java b/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/AutowireMojo.java index 02616f7..ab205f3 100644 --- a/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/AutowireMojo.java +++ b/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/AutowireMojo.java @@ -18,6 +18,7 @@ package org.apache.camel.maven; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; @@ -103,6 +104,10 @@ public class AutowireMojo extends AbstractExecMojo { private transient ClassLoader classLoader; + // TODO: Allow to configure known types in xml config, or refer to external file + // TODO: Allow to configure include/exclude names on components,names + // TODO: Skip some known types + // CHECKSTYLE:OFF @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -159,7 +164,13 @@ public class AutowireMojo extends AbstractExecMojo { .addClassLoader(classLoader) .setScanners(new SubTypesScanner())); - List<String> autowires = findAutowireComponentOptionsByClasspath(catalog, components, reflections); + // load known types + Properties knownTypes = loadKnownTypes(); + getLog().debug("Loaded known-types: " + knownTypes); + + // find the autowire via classpath scanning + List<String> autowires = findAutowireComponentOptionsByClasspath(catalog, components, reflections, knownTypes); + if (!autowires.isEmpty()) { outFolder.mkdirs(); File file = new File(outFolder, "autowire.properties"); @@ -178,7 +189,21 @@ public class AutowireMojo extends AbstractExecMojo { } } - protected List<String> findAutowireComponentOptionsByClasspath(CamelCatalog catalog, Set<String> components, Reflections reflections) { + protected Properties loadKnownTypes() throws MojoFailureException { + Properties knownTypes = new Properties(); + try { + InputStream is = AutowireMojo.class.getResourceAsStream("/known-types.properties"); + if (is != null) { + knownTypes.load(is); + } + } catch (IOException e) { + throw new MojoFailureException("Cannot load known-types.properties from classpath"); + } + return knownTypes; + } + + protected List<String> findAutowireComponentOptionsByClasspath(CamelCatalog catalog, Set<String> components, + Reflections reflections, Properties knownTypes) { List<String> autowires = new ArrayList<>(); for (String componentName : components) { @@ -199,25 +224,21 @@ public class AutowireMojo extends AbstractExecMojo { if ("object".equals(type)) { try { Class clazz = classLoader.loadClass(javaType); - if (clazz.isInterface()) { + if (clazz.isInterface() && isComplexUserType(clazz)) { Set<Class<?>> classes = reflections.getSubTypesOf(clazz); // filter classes to not be interfaces or not a top level class classes = classes.stream().filter(c -> !c.isInterface() && c.getEnclosingClass() == null).collect(Collectors.toSet()); - if (classes.size() == 1) { - Class cls = classes.iterator().next(); - if (isValidAutowireClass(cls)) { - String line = "camel.component." + componentName + "." + name + "=#class:" + cls.getName(); - getLog().debug(line); - autowires.add(line); - } - } else if (classes.size() > 1) { - getLog().debug("Found " + classes.size() + " for autowire: " + componentName + "." + name + ". Cannot chose one class: " + classes); + Class best = chooseBestKnownType(clazz, classes, knownTypes); + if (isValidAutowireClass(best)) { + String line = "camel.component." + componentName + "." + name + "=#class:" + best.getName(); + getLog().debug(line); + autowires.add(line); } } } catch (Exception e) { - getLog().debug("Cannot load class: " + name, e); // ignore + getLog().debug("Cannot load class: " + name, e); } } } @@ -226,6 +247,34 @@ public class AutowireMojo extends AbstractExecMojo { return autowires; } + protected Class chooseBestKnownType(Class type, Set<Class<?>> candidates, Properties knownTypes) { + String known = knownTypes.getProperty(type.getName()); + if (known != null) { + for (String k : known.split(",")) { + // special as we should skip this option + if ("#skip#".equals(k)) { + return null; + } + Class found = candidates.stream().filter(c -> c.getName().equals(k)).findFirst().orElse(null); + if (found != null) { + return found; + } + } + } + + if (candidates.size() == 1) { + return candidates.iterator().next(); + } else if (candidates.size() > 1) { + getLog().debug("Cannot chose best type: " + type.getName() + " among " + candidates.size() + " implementations: " + candidates); + } + return null; + } + + private static boolean isComplexUserType(Class type) { + // lets consider all non java, as complex types + return type != null && !type.isPrimitive() && !type.getName().startsWith("java."); + } + protected boolean isValidAutowireClass(Class clazz) { // skip all from Apache Camel and regular JDK as they would be default anyway return !clazz.getName().startsWith("org.apache.camel"); diff --git a/catalog/camel-main-maven-plugin/src/main/resources/known-types.properties b/catalog/camel-main-maven-plugin/src/main/resources/known-types.properties new file mode 100644 index 0000000..78971fe --- /dev/null +++ b/catalog/camel-main-maven-plugin/src/main/resources/known-types.properties @@ -0,0 +1,22 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# favour these classes if there are multiple on the classpath +javax.jms.ConnectionFactory=org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory,org.apache.activemq.ActiveMQConnectionFactory + +# skip these types +org.springframework.jms.core.JmsOperations=#skip# diff --git a/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java index 7298242..10306f0 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java @@ -279,6 +279,7 @@ public final class PropertyBindingSupport { * @param target the target object * @return true if one ore more properties was auto wired */ + @Deprecated public static boolean autowireInterfacePropertiesFromClasspath(CamelContext camelContext, Object target) { return autowireInterfacePropertiesFromClasspath(camelContext, target, false, false, null); } diff --git a/examples/camel-example-main/src/main/java/org/apache/camel/example/MyRouteBuilder.java b/examples/camel-example-main/src/main/java/org/apache/camel/example/MyRouteBuilder.java index d98ae5f..09546c0 100644 --- a/examples/camel-example-main/src/main/java/org/apache/camel/example/MyRouteBuilder.java +++ b/examples/camel-example-main/src/main/java/org/apache/camel/example/MyRouteBuilder.java @@ -27,5 +27,7 @@ public class MyRouteBuilder extends RouteBuilder { .log("${body}") .bean("myBean", "bye") .log("${body}"); + + from("jms:queue:cheese").to("log:cheese"); } } diff --git a/examples/camel-example-main/src/main/resources/application.properties b/examples/camel-example-main/src/main/resources/application.properties index 71ab7ab..334af88 100644 --- a/examples/camel-example-main/src/main/resources/application.properties +++ b/examples/camel-example-main/src/main/resources/application.properties @@ -42,6 +42,9 @@ camel.component.quartz2.start-delayed-seconds = 3 # you can configure whether OS environment should override (=2 which is default) or as fallback (=1) ### camel.component.properties.environment-variable-mode=1 +camel.component.jms.configuration.connectionFactory=#class:org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory +camel.component.jms.configuration.connectionFactory.brokerUrl=localhost:61616 + # properties used in the route myCron = 0/2 * * * * ?