This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch on-header in repository https://gitbox.apache.org/repos/asf/camel.git
commit b5fe59623e91865b8cbab2f1da3606ef96d155fe Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sat Feb 6 10:56:31 2021 +0100 CAMEL-16102: Source code generate @InvokeOnHeader for reflection free --- .../java/org/apache/camel/spi/InvokeOnHeader.java | 5 ++ .../apache/camel/spi/InvokeOnHeaderStrategy.java | 5 +- .../camel/support/HeaderSelectorProducer.java | 8 +- .../packaging/GenerateInvokeOnHeaderMojo.java | 91 +++++++++++++--------- 4 files changed, 67 insertions(+), 42 deletions(-) diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/InvokeOnHeader.java b/core/camel-api/src/main/java/org/apache/camel/spi/InvokeOnHeader.java index 0dc11e9..55008ce 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/InvokeOnHeader.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/InvokeOnHeader.java @@ -42,12 +42,17 @@ import org.apache.camel.Message; * <p/> * This can be used by Component implementations that uses org.apache.camel.support.HeaderSelectorProducer. * + * This requires to use Camel maven tooling (camel-package-maven-plugin) to generate java source code + * that selects and invokes the method at runtime. + * * @see Message#getHeader(String) */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface InvokeOnHeader { + // TODO: Update javadoc as parameter binding has improved + /** * Name of header. */ diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/InvokeOnHeaderStrategy.java b/core/camel-api/src/main/java/org/apache/camel/spi/InvokeOnHeaderStrategy.java index 83f6b8d..487b2e6 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/InvokeOnHeaderStrategy.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/InvokeOnHeaderStrategy.java @@ -23,17 +23,20 @@ import org.apache.camel.Exchange; * Pluggable strategy for invoking {@link InvokeOnHeader}. * <p> * Camel provides source code generated strategies via the camel maven tooling. + * + * @see InvokeOnHeader */ public interface InvokeOnHeaderStrategy { /** * Invoke the method based on the header key * - * @param target the target such as HeaderSelectorProducer + * @param target the target such as a producer extending HeaderSelectorProducer * @param key the header key * @param exchange the exchange * @param callback the async callback * @return option response from invoking the method, or <tt>null</tt> if the method is void + * if a value is returned, then this value is stored as result on the message body. * @throws Exception is thrown if error invoking the method. */ Object invoke(Object target, String key, Exchange exchange, AsyncCallback callback) throws Exception; diff --git a/core/camel-support/src/main/java/org/apache/camel/support/HeaderSelectorProducer.java b/core/camel-support/src/main/java/org/apache/camel/support/HeaderSelectorProducer.java index 6837c68..523923e 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/HeaderSelectorProducer.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/HeaderSelectorProducer.java @@ -44,7 +44,7 @@ public abstract class HeaderSelectorProducer extends DefaultAsyncProducer implem private final Object target; private CamelContext camelContext; private InvokeOnHeaderStrategy strategy; - private InvokeOnHeaderStrategy strategy2; + private InvokeOnHeaderStrategy parentStrategy; public HeaderSelectorProducer(Endpoint endpoint, Supplier<String> headerSupplier) { this(endpoint, headerSupplier, () -> null, null); @@ -154,7 +154,7 @@ public abstract class HeaderSelectorProducer extends DefaultAsyncProducer implem // some components may have a common base class they extend from (such as camel-infinispan) String key2 = this.getClass().getSuperclass().getName(); String fqn2 = RESOURCE_PATH + key2; - strategy2 = camelContext.adapt(ExtendedCamelContext.class).getBootstrapFactoryFinder(RESOURCE_PATH) + parentStrategy = camelContext.adapt(ExtendedCamelContext.class).getBootstrapFactoryFinder(RESOURCE_PATH) .newInstance(key2, InvokeOnHeaderStrategy.class) .orElseThrow(() -> new IllegalArgumentException("Cannot find " + fqn2 + " in classpath.")); } @@ -175,8 +175,8 @@ public abstract class HeaderSelectorProducer extends DefaultAsyncProducer implem LOGGER.debug("Invoking @InvokeOnHeader method: {}", action); Object answer = strategy.invoke(target, action, exchange, callback); - if (answer == null && strategy2 != null) { - answer = strategy2.invoke(target, action, exchange, callback); + if (answer == null && parentStrategy != null) { + answer = parentStrategy.invoke(target, action, exchange, callback); } LOGGER.trace("Invoked @InvokeOnHeader method: {} -> {}", action, answer); if (answer != null) { diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateInvokeOnHeaderMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateInvokeOnHeaderMojo.java index 3a4b27c..a78b90a 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateInvokeOnHeaderMojo.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateInvokeOnHeaderMojo.java @@ -23,11 +23,13 @@ import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.StringJoiner; import java.util.TreeSet; import org.apache.maven.plugin.MojoExecutionException; @@ -40,6 +42,7 @@ import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.DotName; import org.jboss.jandex.Index; import org.jboss.jandex.IndexReader; +import org.jboss.jandex.MethodInfo; import org.jboss.jandex.Type; /** @@ -66,9 +69,8 @@ public class GenerateInvokeOnHeaderMojo extends AbstractGeneratorMojo { private static class InvokeOnHeaderModel { private String key; private String methodName; - private boolean isVoid; - private boolean callback; - private boolean exchange; + private String returnType; + private final List<String> args = new ArrayList<>(); public String getKey() { return key; @@ -86,28 +88,20 @@ public class GenerateInvokeOnHeaderMojo extends AbstractGeneratorMojo { this.methodName = methodName; } - public boolean isVoid() { - return isVoid; + public String getReturnType() { + return returnType; } - public void setVoid(boolean aVoid) { - isVoid = aVoid; + public void setReturnType(String returnType) { + this.returnType = returnType; } - public boolean isCallback() { - return callback; + public List<String> getArgs() { + return args; } - public void setCallback(boolean callback) { - this.callback = callback; - } - - public boolean isExchange() { - return exchange; - } - - public void setExchange(boolean exchange) { - this.exchange = exchange; + public void addArgs(String arg) { + args.add(arg); } } @@ -142,18 +136,24 @@ public class GenerateInvokeOnHeaderMojo extends AbstractGeneratorMojo { annotations.forEach(a -> { String currentClass = a.target().asMethod().declaringClass().name().toString(); String value = a.value().asString(); - String methodName = a.target().asMethod().name(); - boolean isVoid = Type.Kind.VOID == a.target().asMethod().returnType().kind(); - boolean callback = a.target().asMethod().parameters().size() == 2; - boolean exchange = "org.apache.camel.Exchange".equals(a.target().asMethod().parameters().get(0).name().toString()); - Set<InvokeOnHeaderModel> set = classes.computeIfAbsent(currentClass, - k -> new TreeSet<>(Comparator.comparing(InvokeOnHeaderModel::getKey))); + MethodInfo mi = a.target().asMethod(); + InvokeOnHeaderModel model = new InvokeOnHeaderModel(); model.setKey(value); - model.setMethodName(methodName); - model.setVoid(isVoid); - model.setCallback(callback); - model.setExchange(exchange); + model.setMethodName(mi.name()); + + boolean isVoid = Type.Kind.VOID == mi.returnType().kind(); + if (isVoid) { + model.setReturnType("VOID"); + } else { + model.setReturnType(mi.returnType().toString()); + } + for (Type type : mi.parameters()) { + String arg = type.name().toString(); + model.addArgs(arg); + } + Set<InvokeOnHeaderModel> set = classes.computeIfAbsent(currentClass, + k -> new TreeSet<>(Comparator.comparing(InvokeOnHeaderModel::getKey))); set.add(model); }); @@ -221,18 +221,21 @@ public class GenerateInvokeOnHeaderMojo extends AbstractGeneratorMojo { if (!models.isEmpty()) { w.write(" switch (key) {\n"); for (InvokeOnHeaderModel option : models) { - String invoke; - String arg1 = option.isExchange() ? "exchange" : "exchange.getMessage()"; - String arg2 = option.isCallback() ? "callback" : null; - if (arg2 != null) { - invoke = "target." + option.getMethodName() + "(" + arg1 + ", " + arg2 + ")"; - } else { - invoke = "target." + option.getMethodName() + "(" + arg1 + ")"; + String invoke = "target." + option.getMethodName() + "("; + if (!option.getArgs().isEmpty()) { + StringJoiner sj = new StringJoiner(", "); + for (String arg : option.getArgs()) { + String ba = bindArg(arg); + sj.add(ba); + } + invoke += sj.toString(); } + invoke += ")"; + if (!option.getKey().toLowerCase().equals(option.getKey())) { w.write(String.format(" case \"%s\":\n", option.getKey().toLowerCase())); } - if (option.isVoid()) { + if (option.getReturnType().equals("VOID")) { w.write(String.format(" case \"%s\": %s; return null;\n", option.getKey(), invoke)); } else { w.write(String.format(" case \"%s\": return %s;\n", option.getKey(), invoke)); @@ -248,4 +251,18 @@ public class GenerateInvokeOnHeaderMojo extends AbstractGeneratorMojo { w.write("\n"); } + protected String bindArg(String type) { + if ("org.apache.camel.Exchange".equals(type)) { + return "exchange"; + } else if ("org.apache.camel.Message".equals(type)) { + return "exchange.getMessage()"; + } else if ("org.apache.camel.AsyncCallback".equals(type)) { + return "callback"; + } else if ("org.apache.camel.CamelContext".equals(type)) { + return "exchange.getContext()"; + } else { + return "exchange.getMessage().getBody(" + type + ".class)"; + } + } + }