Repository: camel
Updated Branches:
  refs/heads/master 1862cfc82 -> d20cfc8fe


CAMEL-5402: Camel proxy allows to bind to method interface using @Body @Header 
and @ExchangeProperty to bind arguments to the exchange


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/178b84d0
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/178b84d0
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/178b84d0

Branch: refs/heads/master
Commit: 178b84d00c23e805929d8bb6f5a7604b9073ce58
Parents: 1862cfc
Author: Claus Ibsen <davscl...@apache.org>
Authored: Mon Aug 10 17:29:47 2015 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Mon Aug 10 17:29:47 2015 +0200

----------------------------------------------------------------------
 .../bean/AbstractCamelInvocationHandler.java    | 58 +++++++++++++++++++-
 .../component/bean/CamelInvocationHandler.java  |  3 +-
 .../apache/camel/component/bean/MethodInfo.java | 12 +++-
 .../camel/component/bean/ParameterInfo.java     | 12 ++++
 .../camel/component/bean/MyAuditService.java    | 28 ++++++++++
 .../component/bean/MyAuditServiceProxyTest.java | 46 ++++++++++++++++
 6 files changed, 153 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/178b84d0/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
 
b/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
index 059f10b..3677c11 100644
--- 
a/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
+++ 
b/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.bean;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
@@ -28,11 +29,14 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.FutureTask;
 
+import org.apache.camel.Body;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelExchangeException;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
+import org.apache.camel.ExchangeProperty;
+import org.apache.camel.Header;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.Producer;
 import org.apache.camel.RuntimeCamelException;
@@ -95,10 +99,62 @@ public abstract class AbstractCamelInvocationHandler 
implements InvocationHandle
 
     public abstract Object doInvokeProxy(final Object proxy, final Method 
method, final Object[] args) throws Throwable;
 
+    protected Object invokeProxy(final Method method, final ExchangePattern 
pattern, Object[] args) throws Throwable {
+        final Exchange exchange = new DefaultExchange(endpoint, pattern);
+        // use method info to map to exchange
+
+        // we support @Header, @Body and @ExchangeProperty to map to Exchange
+        boolean found = false;
+
+        int index = 0;
+        for (Annotation[] row : method.getParameterAnnotations()) {
+            Object value = args[index];
+            for (Annotation ann : row) {
+                if (ann.annotationType().isAssignableFrom(Header.class)) {
+                    Header header = (Header) ann;
+                    String name = header.value();
+                    exchange.getIn().setHeader(name, value);
+                    found = true;
+                } else if 
(ann.annotationType().isAssignableFrom(ExchangeProperty.class)) {
+                    ExchangeProperty ep = (ExchangeProperty) ann;
+                    String name = ep.value();
+                    exchange.setProperty(name, value);
+                    found = true;
+                } else if (ann.annotationType().isAssignableFrom(Body.class)) {
+                    exchange.getIn().setBody(value);
+                    found = true;
+                } else {
+                    // assume its message body when there is no annotations
+                    exchange.getIn().setBody(value);
+                }
+            }
+            index++;
+        }
+
+        // backwards compatible where the body is a BeanInvocation
+        if (!found) {
+            BeanInvocation invocation = new BeanInvocation(method, args);
+            exchange.getIn().setBody(invocation);
+        }
+
+        if (found) {
+            LOG.trace("Binding to service interface as 
@Body,@Header,@ExchangeProperty detected when calling proxy method: {}", 
method);
+        } else {
+            LOG.trace("No binding to service interface as 
@Body,@Header,@ExchangeProperty not detected. Using BeanInvocation as message 
body when calling proxy method: {}");
+        }
+
+        return doInvoke(method, exchange);
+    }
+
     protected Object invokeWithBody(final Method method, Object body, final 
ExchangePattern pattern) throws Throwable {
         final Exchange exchange = new DefaultExchange(endpoint, pattern);
         exchange.getIn().setBody(body);
 
+        return doInvoke(method, exchange);
+    }
+
+    protected Object doInvoke(final Method method, final Exchange exchange) 
throws Throwable {
+
         // is the return type a future
         final boolean isFuture = method.getReturnType() == Future.class;
 
@@ -109,7 +165,7 @@ public abstract class AbstractCamelInvocationHandler 
implements InvocationHandle
                 LOG.trace("Proxied method call {} invoking producer: {}", 
method.getName(), producer);
                 producer.process(exchange);
 
-                Object answer = afterInvoke(method, exchange, pattern, 
isFuture);
+                Object answer = afterInvoke(method, exchange, 
exchange.getPattern(), isFuture);
                 LOG.trace("Proxied method call {} returning: {}", 
method.getName(), answer);
                 return answer;
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/178b84d0/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
 
b/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
index 55b993b..120b6b0 100644
--- 
a/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
+++ 
b/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
@@ -39,10 +39,9 @@ public class CamelInvocationHandler extends 
AbstractCamelInvocationHandler imple
 
     @Override
     public Object doInvokeProxy(Object proxy, Method method, Object[] args) 
throws Throwable {
-        BeanInvocation invocation = new BeanInvocation(method, args);
         MethodInfo methodInfo = methodInfoCache.getMethodInfo(method);
         final ExchangePattern pattern = methodInfo != null ? 
methodInfo.getPattern() : ExchangePattern.InOut;
-        return invokeWithBody(method, invocation, pattern);
+        return invokeProxy(method, pattern, args);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/178b84d0/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java 
b/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
index d7ca0fe..5b21409 100644
--- a/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
+++ b/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
@@ -413,7 +413,7 @@ public class MethodInfo {
         }
     }
 
-    protected Expression createParametersExpression() {
+    protected Expression[] createParameterExpressions() {
         final int size = parameters.size();
         LOG.trace("Creating parameters expression for {} parameters", size);
 
@@ -423,10 +423,16 @@ public class MethodInfo {
             expressions[i] = parameterExpression;
             LOG.trace("Parameter #{} has expression: {}", i, 
parameterExpression);
         }
+
+        return expressions;
+    }
+
+    protected Expression createParametersExpression() {
+        final Expression[] expressions = createParameterExpressions();
         return new Expression() {
             @SuppressWarnings("unchecked")
             public <T> T evaluate(Exchange exchange, Class<T> type) {
-                Object[] answer = new Object[size];
+                Object[] answer = new Object[expressions.length];
                 Object body = exchange.getIn().getBody();
                 boolean multiParameterArray = false;
                 if 
(exchange.getIn().getHeader(Exchange.BEAN_MULTI_PARAMETER_ARRAY) != null) {
@@ -460,7 +466,7 @@ public class MethodInfo {
                 
exchange.getIn().removeHeader(Exchange.BEAN_MULTI_PARAMETER_ARRAY);
                 exchange.getIn().removeHeader(Exchange.BEAN_METHOD_NAME);
 
-                for (int i = 0; i < size; i++) {
+                for (int i = 0; i < expressions.length; i++) {
                     // grab the parameter value for the given index
                     Object parameterValue = it != null && it.hasNext() ? 
it.next() : null;
                     // and the expected parameter type

http://git-wip-us.apache.org/repos/asf/camel/blob/178b84d0/camel-core/src/main/java/org/apache/camel/component/bean/ParameterInfo.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/bean/ParameterInfo.java 
b/camel-core/src/main/java/org/apache/camel/component/bean/ParameterInfo.java
index 7ad4800..810e032 100644
--- 
a/camel-core/src/main/java/org/apache/camel/component/bean/ParameterInfo.java
+++ 
b/camel-core/src/main/java/org/apache/camel/component/bean/ParameterInfo.java
@@ -59,6 +59,18 @@ public class ParameterInfo {
         this.expression = expression;
     }
 
+    public <T extends Annotation> T hasAnnotation(T type) {
+        if (annotations == null) {
+            return null;
+        }
+        for (Annotation ann : annotations) {
+            if (ann.annotationType().isAssignableFrom(type.annotationType())) {
+                return (T) ann;
+            }
+        }
+        return null;
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/camel/blob/178b84d0/camel-core/src/test/java/org/apache/camel/component/bean/MyAuditService.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/test/java/org/apache/camel/component/bean/MyAuditService.java 
b/camel-core/src/test/java/org/apache/camel/component/bean/MyAuditService.java
new file mode 100644
index 0000000..7a1518a
--- /dev/null
+++ 
b/camel-core/src/test/java/org/apache/camel/component/bean/MyAuditService.java
@@ -0,0 +1,28 @@
+/**
+ * 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.component.bean;
+
+import org.apache.camel.Body;
+import org.apache.camel.Header;
+import org.apache.camel.InOnly;
+
+public interface MyAuditService {
+
+    @InOnly
+    void auditMessage(@Header("uuid") String uuid, @Body String body);
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/178b84d0/camel-core/src/test/java/org/apache/camel/component/bean/MyAuditServiceProxyTest.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/test/java/org/apache/camel/component/bean/MyAuditServiceProxyTest.java
 
b/camel-core/src/test/java/org/apache/camel/component/bean/MyAuditServiceProxyTest.java
new file mode 100644
index 0000000..daa351b
--- /dev/null
+++ 
b/camel-core/src/test/java/org/apache/camel/component/bean/MyAuditServiceProxyTest.java
@@ -0,0 +1,46 @@
+/**
+ * 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.component.bean;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.ProxyBuilder;
+import org.apache.camel.builder.RouteBuilder;
+
+public class MyAuditServiceProxyTest extends ContextTestSupport {
+
+    public void testMyAuditServiceProxy() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:result").expectedHeaderReceived("uuid", "1234");
+
+        MyAuditService service = new 
ProxyBuilder(context).endpoint("direct:proxy").build(MyAuditService.class);
+
+        service.auditMessage("1234", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:proxy")
+                    .to("mock:result");
+            }
+        };
+    }
+}

Reply via email to