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/abdef618 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/abdef618 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/abdef618 Branch: refs/heads/master Commit: abdef61881e845df5c6a8077d0732e73175295be Parents: c2396c3 Author: Claus Ibsen <[email protected]> Authored: Mon Aug 10 19:01:23 2015 +0200 Committer: Claus Ibsen <[email protected]> Committed: Mon Aug 10 19:01:23 2015 +0200 ---------------------------------------------------------------------- .../org/apache/camel/builder/ProxyBuilder.java | 4 +- .../bean/AbstractCamelInvocationHandler.java | 33 +-- .../camel/component/bean/ProxyHelper.java | 18 +- .../component/bean/BeanProxyNoBindingTest.java | 211 +++++++++++++++++++ .../camel/blueprint/CamelProxyFactoryBean.java | 3 +- .../spring/remoting/CamelProxyFactoryBean.java | 3 +- 6 files changed, 246 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/abdef618/camel-core/src/main/java/org/apache/camel/builder/ProxyBuilder.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/builder/ProxyBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/ProxyBuilder.java index 523f420..6bee379 100644 --- a/camel-core/src/main/java/org/apache/camel/builder/ProxyBuilder.java +++ b/camel-core/src/main/java/org/apache/camel/builder/ProxyBuilder.java @@ -30,7 +30,7 @@ public final class ProxyBuilder { private final CamelContext camelContext; private Endpoint endpoint; - private boolean binding; + private boolean binding = true; public ProxyBuilder(CamelContext camelContext) { this.camelContext = camelContext; @@ -61,6 +61,8 @@ public final class ProxyBuilder { /** * Whether to use binding or not. * <p/> + * Binding is enabled by default. Set this to <tt>false</tt> to use old behavior without binding. + * <p/> * If binding is enabled then Camel will bind the method parameters to the input {@link org.apache.camel.Message} * on the {@link org.apache.camel.Exchange} when invoking the proxy. * http://git-wip-us.apache.org/repos/asf/camel/blob/abdef618/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 69e9f8c..c346690 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 @@ -107,20 +107,25 @@ public abstract class AbstractCamelInvocationHandler implements InvocationHandle 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); - } else if (ann.annotationType().isAssignableFrom(ExchangeProperty.class)) { - ExchangeProperty ep = (ExchangeProperty) ann; - String name = ep.value(); - exchange.setProperty(name, value); - } else if (ann.annotationType().isAssignableFrom(Body.class)) { - exchange.getIn().setBody(value); - } else { - // assume its message body when there is no annotations - exchange.getIn().setBody(value); + if (row == null || row.length == 0) { + // assume its message body when there is no annotations + exchange.getIn().setBody(value); + } else { + for (Annotation ann : row) { + if (ann.annotationType().isAssignableFrom(Header.class)) { + Header header = (Header) ann; + String name = header.value(); + exchange.getIn().setHeader(name, value); + } else if (ann.annotationType().isAssignableFrom(ExchangeProperty.class)) { + ExchangeProperty ep = (ExchangeProperty) ann; + String name = ep.value(); + exchange.setProperty(name, value); + } else if (ann.annotationType().isAssignableFrom(Body.class)) { + exchange.getIn().setBody(value); + } else { + // assume its message body when there is no annotations + exchange.getIn().setBody(value); + } } } index++; http://git-wip-us.apache.org/repos/asf/camel/blob/abdef618/camel-core/src/main/java/org/apache/camel/component/bean/ProxyHelper.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/bean/ProxyHelper.java b/camel-core/src/main/java/org/apache/camel/component/bean/ProxyHelper.java index 95e6524..541e07a 100644 --- a/camel-core/src/main/java/org/apache/camel/component/bean/ProxyHelper.java +++ b/camel-core/src/main/java/org/apache/camel/component/bean/ProxyHelper.java @@ -43,7 +43,7 @@ public final class ProxyHelper { @SuppressWarnings("unchecked") @Deprecated public static <T> T createProxyObject(Endpoint endpoint, Producer producer, ClassLoader classLoader, Class<T>[] interfaces, MethodInfoCache methodCache) { - return createProxyObject(endpoint, false, producer, classLoader, interfaces, methodCache); + return createProxyObject(endpoint, true, producer, classLoader, interfaces, methodCache); } /** @@ -61,7 +61,7 @@ public final class ProxyHelper { */ @Deprecated public static <T> T createProxy(Endpoint endpoint, ClassLoader cl, Class<T> interfaceClass, MethodInfoCache methodCache) throws Exception { - return createProxy(endpoint, false, cl, toArray(interfaceClass), methodCache); + return createProxy(endpoint, true, cl, toArray(interfaceClass), methodCache); } /** @@ -78,7 +78,7 @@ public final class ProxyHelper { */ @Deprecated public static <T> T createProxy(Endpoint endpoint, ClassLoader cl, Class<T>[] interfaceClasses, MethodInfoCache methodCache) throws Exception { - return createProxy(endpoint, false, cl, interfaceClasses, methodCache); + return createProxy(endpoint, true, cl, interfaceClasses, methodCache); } /** @@ -94,7 +94,7 @@ public final class ProxyHelper { * Creates a Proxy which sends the exchange to the endpoint. */ public static <T> T createProxy(Endpoint endpoint, ClassLoader cl, Class<T> interfaceClass) throws Exception { - return createProxy(endpoint, false, cl, toArray(interfaceClass)); + return createProxy(endpoint, true, cl, toArray(interfaceClass)); } /** @@ -104,7 +104,7 @@ public final class ProxyHelper { */ @Deprecated public static <T> T createProxy(Endpoint endpoint, ClassLoader cl, Class<T>... interfaceClasses) throws Exception { - return createProxy(endpoint, false, cl, interfaceClasses); + return createProxy(endpoint, true, cl, interfaceClasses); } /** @@ -118,7 +118,7 @@ public final class ProxyHelper { * Creates a Proxy which sends the exchange to the endpoint. */ public static <T> T createProxy(Endpoint endpoint, Class<T> interfaceClass) throws Exception { - return createProxy(endpoint, false, toArray(interfaceClass)); + return createProxy(endpoint, true, toArray(interfaceClass)); } /** @@ -128,7 +128,7 @@ public final class ProxyHelper { */ @Deprecated public static <T> T createProxy(Endpoint endpoint, Class<T>... interfaceClasses) throws Exception { - return createProxy(endpoint, false, interfaceClasses); + return createProxy(endpoint, true, interfaceClasses); } /** @@ -142,7 +142,7 @@ public final class ProxyHelper { * Creates a Proxy which sends the exchange to the endpoint. */ public static <T> T createProxy(Endpoint endpoint, Producer producer, Class<T> interfaceClass) throws Exception { - return createProxy(endpoint, false, producer, toArray(interfaceClass)); + return createProxy(endpoint, true, producer, toArray(interfaceClass)); } /** @@ -152,7 +152,7 @@ public final class ProxyHelper { */ @Deprecated public static <T> T createProxy(Endpoint endpoint, Producer producer, Class<T>... interfaceClasses) throws Exception { - return createProxyObject(endpoint, false, producer, getClassLoader(interfaceClasses), interfaceClasses, createMethodInfoCache(endpoint)); + return createProxyObject(endpoint, true, producer, getClassLoader(interfaceClasses), interfaceClasses, createMethodInfoCache(endpoint)); } /** http://git-wip-us.apache.org/repos/asf/camel/blob/abdef618/camel-core/src/test/java/org/apache/camel/component/bean/BeanProxyNoBindingTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/bean/BeanProxyNoBindingTest.java b/camel-core/src/test/java/org/apache/camel/component/bean/BeanProxyNoBindingTest.java new file mode 100644 index 0000000..0f94a5d --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/component/bean/BeanProxyNoBindingTest.java @@ -0,0 +1,211 @@ +/** + * 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.Endpoint; +import org.apache.camel.InvalidPayloadException; +import org.apache.camel.builder.ProxyBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.w3c.dom.Document; + + +/** + * @version + */ +public class BeanProxyNoBindingTest extends ContextTestSupport { + + public void testBeanProxyStringReturnString() throws Exception { + // START SNIPPET: e2 + Endpoint endpoint = context.getEndpoint("direct:start"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + String reply = service.submitOrderStringReturnString("<order type=\"book\">Camel in action</order>"); + assertEquals("<order id=\"123\">OK</order>", reply); + // END SNIPPET: e2 + } + + public void testBeanProxyStringReturnDocument() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:start"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + Document reply = service.submitOrderStringReturnDocument("<order type=\"book\">Camel in action</order>"); + assertNotNull(reply); + String s = context.getTypeConverter().convertTo(String.class, reply); + assertEquals("<order id=\"123\">OK</order>", s); + } + + public void testBeanProxyDocumentReturnString() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:start"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + Document doc = context.getTypeConverter().convertTo(Document.class, "<order type=\"book\">Camel in action</order>"); + + String reply = service.submitOrderDocumentReturnString(doc); + assertEquals("<order id=\"123\">OK</order>", reply); + } + + public void testBeanProxyDocumentReturnDocument() throws Exception { + // START SNIPPET: e3 + Endpoint endpoint = context.getEndpoint("direct:start"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + Document doc = context.getTypeConverter().convertTo(Document.class, "<order type=\"book\">Camel in action</order>"); + + Document reply = service.submitOrderDocumentReturnDocument(doc); + assertNotNull(reply); + String s = context.getTypeConverter().convertTo(String.class, reply); + assertEquals("<order id=\"123\">OK</order>", s); + // END SNIPPET: e3 + } + + public void testBeanProxyFailure() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:start"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + String reply = service.submitOrderStringReturnString("<order type=\"beer\">Carlsberg</order>"); + assertEquals("<order>FAIL</order>", reply); + } + + public void testBeanProxyFailureNotXMLBody() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:start"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + try { + service.submitOrderStringReturnString("Hello World"); + fail("Should have thrown exception"); + } catch (Exception e) { + // expected + } + } + + public void testBeanProxyVoidReturnType() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:start"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + service.doNothing("<order>ping</order>"); + } + + public void testBeanProxyFailureInvalidReturnType() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:start"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + try { + service.invalidReturnType("<order type=\"beer\">Carlsberg</order>"); + fail("Should have thrown exception"); + } catch (Exception e) { + // expected + InvalidPayloadException cause = assertIsInstanceOf(InvalidPayloadException.class, e.getCause()); + assertEquals(Integer.class, cause.getType()); + } + } + + public void testBeanProxyCallAnotherBean() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:bean"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + String reply = service.submitOrderStringReturnString("World"); + assertEquals("Hello World", reply); + } + + // START SNIPPET: e4 + public void testProxyBuilderProxyCallAnotherBean() throws Exception { + // use ProxyBuilder to easily create the proxy + OrderService service = new ProxyBuilder(context).endpoint("direct:bean").binding(false).build(OrderService.class); + + String reply = service.submitOrderStringReturnString("World"); + assertEquals("Hello World", reply); + } + // END SNIPPET: e4 + + public void testBeanProxyCallAnotherBeanWithNoArgs() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:bean"); + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + String reply = service.doAbsolutelyNothing(); + assertEquals("Hi nobody", reply); + } + + public void testProxyBuilderProxyCallAnotherBeanWithNoArgs() throws Exception { + Endpoint endpoint = context.getEndpoint("direct:bean"); + OrderService service = new ProxyBuilder(context).endpoint(endpoint).binding(false).build(OrderService.class); + + String reply = service.doAbsolutelyNothing(); + assertEquals("Hi nobody", reply); + } + + public void testBeanProxyVoidAsInOut() throws Exception { + Endpoint endpoint = context.getEndpoint("seda:delay"); + // will by default let all exchanges be InOut + OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class); + + getMockEndpoint("mock:delay").expectedBodiesReceived("Hello World", "Bye World"); + service.doNothing("Hello World"); + template.sendBody("mock:delay", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + public void testProxyBuilderVoidAsInOut() throws Exception { + // will by default let all exchanges be InOut + OrderService service = new ProxyBuilder(context).endpoint("seda:delay").binding(false).build(OrderService.class); + + getMockEndpoint("mock:delay").expectedBodiesReceived("Hello World", "Bye World"); + service.doNothing("Hello World"); + template.sendBody("mock:delay", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + // START SNIPPET: e1 + from("direct:start") + .choice() + .when(xpath("/order/@type = 'book'")).to("direct:book") + .otherwise().to("direct:other") + .end(); + + from("direct:book").transform(constant("<order id=\"123\">OK</order>")); + + from("direct:other").transform(constant("<order>FAIL</order>")); + // END SNIPPET: e1 + + from("direct:bean") + .bean(MyFooBean.class, "hello"); + + from("seda:delay") + .delay(1000) + .to("mock:delay"); + } + }; + } + + public static class MyFooBean { + + public String hello(String name) { + if (name != null) { + return "Hello " + name; + } else { + return "Hi nobody"; + } + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/abdef618/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelProxyFactoryBean.java ---------------------------------------------------------------------- diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelProxyFactoryBean.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelProxyFactoryBean.java index c22fa38..6491bbc 100644 --- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelProxyFactoryBean.java +++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelProxyFactoryBean.java @@ -105,7 +105,8 @@ public class CamelProxyFactoryBean extends AbstractCamelFactoryBean<Object> { } } - boolean bind = getBinding() != null ? getBinding() : false; + // binding is enabled by default + boolean bind = getBinding() != null ? getBinding() : true; try { producer = endpoint.createProducer(); http://git-wip-us.apache.org/repos/asf/camel/blob/abdef618/components/camel-spring/src/main/java/org/apache/camel/spring/remoting/CamelProxyFactoryBean.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/remoting/CamelProxyFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/remoting/CamelProxyFactoryBean.java index ecd3d56..d2d7132 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/spring/remoting/CamelProxyFactoryBean.java +++ b/components/camel-spring/src/main/java/org/apache/camel/spring/remoting/CamelProxyFactoryBean.java @@ -71,7 +71,8 @@ public class CamelProxyFactoryBean extends UrlBasedRemoteAccessor implements Fac } } - boolean bind = getBinding() != null ? getBinding() : false; + // binding is enabled by default + boolean bind = getBinding() != null ? getBinding() : true; try { producer = endpoint.createProducer();
