Return-Path: Delivered-To: apmail-camel-dev-archive@www.apache.org Received: (qmail 52270 invoked from network); 19 Sep 2009 08:51:18 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 19 Sep 2009 08:51:18 -0000 Received: (qmail 28556 invoked by uid 500); 19 Sep 2009 08:51:18 -0000 Delivered-To: apmail-camel-dev-archive@camel.apache.org Received: (qmail 28511 invoked by uid 500); 19 Sep 2009 08:51:18 -0000 Mailing-List: contact dev-help@camel.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@camel.apache.org Delivered-To: mailing list dev@camel.apache.org Received: (qmail 28501 invoked by uid 500); 19 Sep 2009 08:51:18 -0000 Delivered-To: apmail-activemq-camel-dev@activemq.apache.org Received: (qmail 28498 invoked by uid 99); 19 Sep 2009 08:51:18 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 19 Sep 2009 08:51:18 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.140] (HELO brutus.apache.org) (140.211.11.140) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 19 Sep 2009 08:51:13 +0000 Received: from brutus (localhost [127.0.0.1]) by brutus.apache.org (Postfix) with ESMTP id EC4F5234C044 for ; Sat, 19 Sep 2009 01:50:51 -0700 (PDT) Message-ID: <1899429573.1253350251949.JavaMail.jira@brutus> Date: Sat, 19 Sep 2009 01:50:51 -0700 (PDT) From: "Claus Ibsen (JIRA)" To: camel-dev@activemq.apache.org Subject: [jira] Updated: (CAMEL-2026) Enable async request-reply by enhancing the CamelInvocationHandler so that it is serializable, so that camel-spring Proxies can be passed as callback objects In-Reply-To: <40030673.1253296672071.JavaMail.jira@brutus> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-JIRA-FingerPrint: ae95407df07c98740808b2ef9da0087c X-Virus-Checked: Checked by ClamAV on apache.org [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Claus Ibsen updated CAMEL-2026: ------------------------------- Description: With minor alteration, the CamelInvocationHandler could be made serializable, and then camel-spring bean proxies could be passed as callback objects in method calls on other camel-spring proxies...enabling async request-reply via spring remoting. I have achieved this by Wrapping the CamelInvocationHandler, subclassing the CamelProxyFactoryBean, and by attaching a processor to routes that can recieve BeanInvocations that have a callback object. Integrated into the codebase, this could be much more straightforward, and not require a processor be attached. =================CamelInvocationHandlerWrapper {code} /** * Serializable wrapper for Camel/Spring remoting proxies. */ public class CamelInvocationHandlerWrapper implements InvocationHandler, Serializable { /* Findbugs will complain that inner dosent get set at deserialization time. This is ok. You need to have a CamelRemotingProcessor in your inbound camel route that will reset the handler. */ private transient CamelInvocationHandler inner; private String serviceUrl; private static final long serialVersionUID = 7635312279175935612L; /** * Create a CamelInvocationHandlerWrapper. * * @param handler the handler to use in this VM. * @param serviceUrl the serviceUrl to use to rebuild the CamelInvocationHandler if we are serialized and used in a different VM. */ public CamelInvocationHandlerWrapper(CamelInvocationHandler handler, String serviceUrl) { this.inner = handler; this.serviceUrl = serviceUrl; } /** * {@inheritDoc} */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass().equals(Object.class)) { return method.invoke(this, args); } else { if (inner == null) { throw new IllegalStateException("The inner CamelInvocationHandler is null, perhaps there was no CamelRemotingProcessor on your inbound route???"); } else { return inner.invoke(proxy, method, args); } } } /** * Package Private so the CamelRemotingProcessor can rewire when we are passed remotely. * * @param context the current camel context. * @throws Exception if we cant build an endpoint for the service url or create a producer. */ void rebuildInvocationHandler(CamelContext context) throws Exception { Endpoint endpoint = CamelContextHelper.getMandatoryEndpoint(context, serviceUrl); Producer producer = endpoint.createProducer(); producer.start(); inner = new CamelInvocationHandler(endpoint, producer, new MethodInfoCache(endpoint.getCamelContext())); } void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; } } {code} ================Proxy Factory {code} /** * ProxyFactory that wraps a camel proxy in a serializable form. */ public class CamelProxyWrapperFactoryBean extends CamelProxyFactoryBean { /** * Override the CamelProxyFactoryBean to return a different proxy that uses a CamelInvocationHandlerWrapper. * * @return a Proxy backed by a CamelInvocationHandlerWrapper for the specified interface. * @throws Exception if we cant create the proxy. */ @Override public Object getObject() throws Exception { Object proxy = super.getObject(); CamelInvocationHandler handler = (CamelInvocationHandler) Proxy.getInvocationHandler(proxy); return Proxy.newProxyInstance(getObjectType().getClassLoader(), new Class[]{getObjectType()}, new CamelInvocationHandlerWrapper(handler, getServiceUrl())); } } {code} ========processor that "rewires" the transient CamelInvocationHandler by using the service url {code} public class CamelRemotingProcessor implements Processor { /** * Rebuild the CamelInvocationHandler if we were passed a Proxy that has a CamelInvocationHandlerWrapper as its handler. * * @param invocation the BeanInvocation whose args we check for the Proxy. * @param context the current Camel Context. * @throws Exception if something blows up. */ public void rewireProxy(BeanInvocation invocation, CamelContext context) throws Exception { Object[] args = invocation.getArgs(); if (args != null) { for (Object arg : args) { if (Proxy.isProxyClass(arg.getClass())) { InvocationHandler handler = Proxy.getInvocationHandler(arg); if (handler instanceof CamelInvocationHandlerWrapper) { CamelInvocationHandlerWrapper wrapper = (CamelInvocationHandlerWrapper) handler; wrapper.rebuildInvocationHandler(context); } } } } } /** * {@inheritDoc} */ public void process(Exchange exchange) throws Exception { CamelContext context = exchange.getContext(); BeanInvocation invocation = exchange.getIn().getBody(BeanInvocation.class); rewireProxy(invocation, context); } } {code} was: With minor alteration, the CamelInvocationHandler could be made serializable, and then camel-spring bean proxies could be passed as callback objects in method calls on other camel-spring proxies...enabling async request-reply via spring remoting. I have achieved this by Wrapping the CamelInvocationHandler, subclassing the CamelProxyFactoryBean, and by attaching a processor to routes that can recieve BeanInvocations that have a callback object. Integrated into the codebase, this could be much more straightforward, and not require a processor be attached. =================CamelInvocationHandlerWrapper /** * Serializable wrapper for Camel/Spring remoting proxies. */ public class CamelInvocationHandlerWrapper implements InvocationHandler, Serializable { /* Findbugs will complain that inner dosent get set at deserialization time. This is ok. You need to have a CamelRemotingProcessor in your inbound camel route that will reset the handler. */ private transient CamelInvocationHandler inner; private String serviceUrl; private static final long serialVersionUID = 7635312279175935612L; /** * Create a CamelInvocationHandlerWrapper. * * @param handler the handler to use in this VM. * @param serviceUrl the serviceUrl to use to rebuild the CamelInvocationHandler if we are serialized and used in a different VM. */ public CamelInvocationHandlerWrapper(CamelInvocationHandler handler, String serviceUrl) { this.inner = handler; this.serviceUrl = serviceUrl; } /** * {@inheritDoc} */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass().equals(Object.class)) { return method.invoke(this, args); } else { if (inner == null) { throw new IllegalStateException("The inner CamelInvocationHandler is null, perhaps there was no CamelRemotingProcessor on your inbound route???"); } else { return inner.invoke(proxy, method, args); } } } /** * Package Private so the CamelRemotingProcessor can rewire when we are passed remotely. * * @param context the current camel context. * @throws Exception if we cant build an endpoint for the service url or create a producer. */ void rebuildInvocationHandler(CamelContext context) throws Exception { Endpoint endpoint = CamelContextHelper.getMandatoryEndpoint(context, serviceUrl); Producer producer = endpoint.createProducer(); producer.start(); inner = new CamelInvocationHandler(endpoint, producer, new MethodInfoCache(endpoint.getCamelContext())); } void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; } } ================Proxy Factory /** * ProxyFactory that wraps a camel proxy in a serializable form. */ public class CamelProxyWrapperFactoryBean extends CamelProxyFactoryBean { /** * Override the CamelProxyFactoryBean to return a different proxy that uses a CamelInvocationHandlerWrapper. * * @return a Proxy backed by a CamelInvocationHandlerWrapper for the specified interface. * @throws Exception if we cant create the proxy. */ @Override public Object getObject() throws Exception { Object proxy = super.getObject(); CamelInvocationHandler handler = (CamelInvocationHandler) Proxy.getInvocationHandler(proxy); return Proxy.newProxyInstance(getObjectType().getClassLoader(), new Class[]{getObjectType()}, new CamelInvocationHandlerWrapper(handler, getServiceUrl())); } } ========processor that "rewires" the transient CamelInvocationHandler by using the service url public class CamelRemotingProcessor implements Processor { /** * Rebuild the CamelInvocationHandler if we were passed a Proxy that has a CamelInvocationHandlerWrapper as its handler. * * @param invocation the BeanInvocation whose args we check for the Proxy. * @param context the current Camel Context. * @throws Exception if something blows up. */ public void rewireProxy(BeanInvocation invocation, CamelContext context) throws Exception { Object[] args = invocation.getArgs(); if (args != null) { for (Object arg : args) { if (Proxy.isProxyClass(arg.getClass())) { InvocationHandler handler = Proxy.getInvocationHandler(arg); if (handler instanceof CamelInvocationHandlerWrapper) { CamelInvocationHandlerWrapper wrapper = (CamelInvocationHandlerWrapper) handler; wrapper.rebuildInvocationHandler(context); } } } } } /** * {@inheritDoc} */ public void process(Exchange exchange) throws Exception { CamelContext context = exchange.getContext(); BeanInvocation invocation = exchange.getIn().getBody(BeanInvocation.class); rewireProxy(invocation, context); } } added code snippets > Enable async request-reply by enhancing the CamelInvocationHandler so that it is serializable, so that camel-spring Proxies can be passed as callback objects > ------------------------------------------------------------------------------------------------------------------------------------------------------------- > > Key: CAMEL-2026 > URL: https://issues.apache.org/activemq/browse/CAMEL-2026 > Project: Apache Camel > Issue Type: Improvement > Components: camel-core, camel-spring > Affects Versions: 2.0.0 > Reporter: Scott Clasen > > With minor alteration, the CamelInvocationHandler could be made serializable, and then camel-spring bean proxies could be passed as callback objects in method calls on other camel-spring proxies...enabling async request-reply via spring remoting. > I have achieved this by Wrapping the CamelInvocationHandler, subclassing the CamelProxyFactoryBean, and by attaching a processor to routes that can recieve BeanInvocations that have a callback object. Integrated into the codebase, this could be much more straightforward, and not require a processor be attached. > =================CamelInvocationHandlerWrapper > {code} > /** > * Serializable wrapper for Camel/Spring remoting proxies. > */ > public class CamelInvocationHandlerWrapper implements InvocationHandler, Serializable { > /* > Findbugs will complain that inner dosent get set at deserialization time. This is ok. > You need to have a CamelRemotingProcessor in your inbound camel route that will reset the handler. > */ > private transient CamelInvocationHandler inner; > private String serviceUrl; > private static final long serialVersionUID = 7635312279175935612L; > /** > * Create a CamelInvocationHandlerWrapper. > * > * @param handler the handler to use in this VM. > * @param serviceUrl the serviceUrl to use to rebuild the CamelInvocationHandler if we are serialized and used in a different VM. > */ > public CamelInvocationHandlerWrapper(CamelInvocationHandler handler, String serviceUrl) { > this.inner = handler; > this.serviceUrl = serviceUrl; > } > /** > * {@inheritDoc} > */ > public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { > if (method.getDeclaringClass().equals(Object.class)) { > return method.invoke(this, args); > } else { > if (inner == null) { > throw new IllegalStateException("The inner CamelInvocationHandler is null, perhaps there was no CamelRemotingProcessor on your inbound route???"); > } else { > return inner.invoke(proxy, method, args); > } > } > } > /** > * Package Private so the CamelRemotingProcessor can rewire when we are passed remotely. > * > * @param context the current camel context. > * @throws Exception if we cant build an endpoint for the service url or create a producer. > */ > void rebuildInvocationHandler(CamelContext context) throws Exception { > Endpoint endpoint = CamelContextHelper.getMandatoryEndpoint(context, serviceUrl); > Producer producer = endpoint.createProducer(); > producer.start(); > inner = new CamelInvocationHandler(endpoint, producer, new MethodInfoCache(endpoint.getCamelContext())); > } > void setServiceUrl(String serviceUrl) { > this.serviceUrl = serviceUrl; > } > } > {code} > ================Proxy Factory > {code} > /** > * ProxyFactory that wraps a camel proxy in a serializable form. > */ > public class CamelProxyWrapperFactoryBean extends CamelProxyFactoryBean { > /** > * Override the CamelProxyFactoryBean to return a different proxy that uses a CamelInvocationHandlerWrapper. > * > * @return a Proxy backed by a CamelInvocationHandlerWrapper for the specified interface. > * @throws Exception if we cant create the proxy. > */ > @Override > public Object getObject() throws Exception { > Object proxy = super.getObject(); > CamelInvocationHandler handler = (CamelInvocationHandler) Proxy.getInvocationHandler(proxy); > return Proxy.newProxyInstance(getObjectType().getClassLoader(), new Class[]{getObjectType()}, new CamelInvocationHandlerWrapper(handler, getServiceUrl())); > } > } > {code} > ========processor that "rewires" the transient CamelInvocationHandler by using the service url > {code} > public class CamelRemotingProcessor implements Processor { > /** > * Rebuild the CamelInvocationHandler if we were passed a Proxy that has a CamelInvocationHandlerWrapper as its handler. > * > * @param invocation the BeanInvocation whose args we check for the Proxy. > * @param context the current Camel Context. > * @throws Exception if something blows up. > */ > public void rewireProxy(BeanInvocation invocation, CamelContext context) throws Exception { > Object[] args = invocation.getArgs(); > if (args != null) { > for (Object arg : args) { > if (Proxy.isProxyClass(arg.getClass())) { > InvocationHandler handler = Proxy.getInvocationHandler(arg); > if (handler instanceof CamelInvocationHandlerWrapper) { > CamelInvocationHandlerWrapper wrapper = (CamelInvocationHandlerWrapper) handler; > wrapper.rebuildInvocationHandler(context); > } > } > } > } > } > /** > * {@inheritDoc} > */ > public void process(Exchange exchange) throws Exception { > CamelContext context = exchange.getContext(); > BeanInvocation invocation = exchange.getIn().getBody(BeanInvocation.class); > rewireProxy(invocation, context); > } > } > {code} -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.