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"); + } + }; + } +}