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 2021/02/06 12:05:08 UTC
[camel] 15/18: CAMEL-16102: Source code generate @InvokeOnHeader
for reflection free
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 <cl...@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)";
+ }
+ }
+
}