You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@camel.apache.org by "Scott Clasen (JIRA)" <ji...@apache.org> on 2009/09/18 19:57:52 UTC

[jira] Created: (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

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
/**
 * 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);
    }
}





-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (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

Posted by "Hadrian Zbarcea (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=56769#action_56769 ] 

Hadrian Zbarcea commented on CAMEL-2026:
----------------------------------------

Exactly. Plus bam has it's own dsl, which could be extended.

I think your use case makes sense, and we are always interested in improving camel and support useful scenarios. The question is where in camel is best to plug in new functionality. The part I, personally, am not very fond of is the XA transactions. I think they are very brittle and too resource intensive with long running transactions, but that's just my opinion. Thread management/admin stuff does belong in camel.

We also highly appreciate contributions. Kudos for taking the time and send some code.

> 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
>            Assignee: Claus Ibsen
>             Fix For: 2.2.0
>
>         Attachments: camel-2026.zip
>
>
> 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.


[jira] Commented: (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

Posted by "Scott Clasen (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=56764#action_56764 ] 

Scott Clasen commented on CAMEL-2026:
-------------------------------------

In all of our cases there is a correlation UUID being passed in each service request and callback invocation so that we know what is going on for each request...generally these are very long running operations, like moving a 500GB file across the network.

so usually like

public class Request{

   public UUID getCorrelationUUID(){
        ...
   }

}

public interface Callback {
         @InOnly void serviceExecuted(Request request);
}

public interface Service {
         @InOnly void doService(Request request, Callback callback);
}

I didnt want to force any specific interfaces into this but we do have a set of base interaces that enforce the UUID stuff.

Off the top of my head, I could see blowing this out a bit and adding a new exchange pattern annotation like @InOnlyAsyncReply that has parameter annotations for @Correlation and @Callback, and maybe @Terminating annotations on the callback interface to indicate that calling a method terminates conversation and its associated state...

So something like 


public class Request{
   
   @CorrelationID
   public UUID getCorrelationUUID(){
        ...
   }

}

public interface ICallback {
         @InOnly void serviceStarting(Request request);
         @InOnly @Terminating void serviceExecuted(Request request);
}

public interface Service {
         @InOnlyAsyncReply void doService(@Correlation Request request, @Callback ICallback callback);
}

But this would get camel into the business of holding converstaion state which Im not sure you want to do....



> 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
>            Assignee: Claus Ibsen
>             Fix For: 2.2.0
>
>         Attachments: camel-2026.zip
>
>
> 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.


[jira] Commented: (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

Posted by "Scott Clasen (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=54402#action_54402 ] 

Scott Clasen commented on CAMEL-2026:
-------------------------------------

example of the approach attached as a maven project

> 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
>         Attachments: camel-2026.zip
>
>
> 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.


[jira] Commented: (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

Posted by "Scott Clasen (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=56767#action_56767 ] 

Scott Clasen commented on CAMEL-2026:
-------------------------------------

Very nice, looks like camel bam is already in the business of tracking state, and the expression based extraction of the correlation identifier is already there. Seems like it could be leveraged. 

We arent using this service/callback stuff as bam, but as steps in business workflows, there will be BAM done on the invocations but through other means, such as wiretaps sending to monitoring topics.

How much interest is there in taking this further...I think the serializable proxy stuff is pretty useful on its own, but there is a whole bunch more that might be useful.

Our services are generally in standalone vms,  running in java service wrapper, that boot up a camel context, in cases where losing requests is unacceptable we will do XA consumption of the JMS request along with logging it in a berkeley DB, and then XA removal of the request and sending the callback when a @Terminating method is called.

There is also thread management, and administrative functions built in to the base classes we use, cancelation/reprioritization/status on in -light work, but Im not sure this is something that belongs in camel.





> 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
>            Assignee: Claus Ibsen
>             Fix For: 2.2.0
>
>         Attachments: camel-2026.zip
>
>
> 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.


[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

Posted by "Scott Clasen (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Scott Clasen updated CAMEL-2026:
--------------------------------

    Attachment: camel-2026.zip

Zipped maven project that demonstrates this approach.

unzip camel-2026.zip
cd camel-2026
(Start up the "service side"  vm, camel context, activemq broker)
mvn camel:run &
(run a "client side" test)
mvn test



> 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
>         Attachments: camel-2026.zip
>
>
> 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.


[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

Posted by "Claus Ibsen (JIRA)" <ji...@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.


[jira] Commented: (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

Posted by "Hadrian Zbarcea (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=56766#action_56766 ] 

Hadrian Zbarcea commented on CAMEL-2026:
----------------------------------------

Scott, did you try using camel-bam for this? Unfortunately camel-bam is under used and under documented.

> 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
>            Assignee: Claus Ibsen
>             Fix For: 2.2.0
>
>         Attachments: camel-2026.zip
>
>
> 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.


[jira] Commented: (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

Posted by "Claus Ibsen (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=54355#action_54355 ] 

Claus Ibsen commented on CAMEL-2026:
------------------------------------

Scott can you attach an unit test that demonstrates this.

Is helpful to implement this smarter in the core.

> 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.


[jira] Assigned: (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

Posted by "Claus Ibsen (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Claus Ibsen reassigned CAMEL-2026:
----------------------------------

    Assignee: Claus Ibsen

> 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
>            Assignee: Claus Ibsen
>         Attachments: camel-2026.zip
>
>
> 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.


[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

Posted by "Claus Ibsen (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Claus Ibsen updated CAMEL-2026:
-------------------------------

    Fix Version/s: 2.2.0

> 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
>            Assignee: Claus Ibsen
>             Fix For: 2.2.0
>
>         Attachments: camel-2026.zip
>
>
> 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.


[jira] Commented: (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

Posted by "Scott Clasen (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=56229#action_56229 ] 

Scott Clasen commented on CAMEL-2026:
-------------------------------------

If it isn't obvious in the example, a rel-life application of this approach would not use locks and conditions to wait for the async reply. This is just to prevent the unit test from exiting before the async reply is recieved

> 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
>            Assignee: Claus Ibsen
>             Fix For: 2.2.0
>
>         Attachments: camel-2026.zip
>
>
> 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.


[jira] Commented: (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

Posted by "Claus Ibsen (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=56763#action_56763 ] 

Claus Ibsen commented on CAMEL-2026:
------------------------------------

Scott I wonder when you are going to use this for real use cases?

Having async behavior flying around at will makes it hard to track down what happens.

> 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
>            Assignee: Claus Ibsen
>             Fix For: 2.2.0
>
>         Attachments: camel-2026.zip
>
>
> 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.


[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

Posted by "Claus Ibsen (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Claus Ibsen updated CAMEL-2026:
-------------------------------

    Fix Version/s: Future
                       (was: 2.3.0)

> 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
>            Assignee: Claus Ibsen
>             Fix For: Future
>
>         Attachments: camel-2026.zip
>
>
> 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.


[jira] Commented: (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

Posted by "Scott Clasen (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/activemq/browse/CAMEL-2026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=56814#action_56814 ] 

Scott Clasen commented on CAMEL-2026:
-------------------------------------

Agreed on XA, perhaps I should generalize it a bit more and and just say the service will log the request when it arrives, in the consumer thread. It would then hand off to a work queue/worker pool which performs the actual work.  The worker thread would call methods on the callback proxy, and when one of the methods has @Terminating, the service would mark work as complete/failed/etc..

This would provide some crash tolerance, without necessarily going XA.

 In the case of a graceful shutdown, work is "requeued" to its originating destination (jms, etc), using another camel proxy.

And in the case of XA its 2 short running TX, 1 to log the request, and 1 to log its disposition.

I will do some more digging into the bam stuff...

The code I am thinking of that we could contribute is centered around an AbstractAsyncService class that has a defined lifecycle, and generically manages the execution of  tasks with an Executor, provides adminstrative methods to get status on,  reprioritize work, cancel in-flight work,  and like I mentioned above track in-flight work in case of a crash, and "requeue" existing work to the originating endpoint on graceful shutdown. It has a getRouteBuilder() method which builds up the camel routes to make all this happen at startup.

Not sure if you think that belongs in camel or just closely integrated with it.


> 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
>            Assignee: Claus Ibsen
>             Fix For: 2.2.0
>
>         Attachments: camel-2026.zip
>
>
> 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.