You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cxf.apache.org by "Peter Palaga (Jira)" <ji...@apache.org> on 2023/11/04 15:53:00 UTC

[jira] [Comment Edited] (CXF-8911) Allow creating a custom CXFHttpAsyncResponseConsumer

    [ https://issues.apache.org/jira/browse/CXF-8911?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17782899#comment-17782899 ] 

Peter Palaga edited comment on CXF-8911 at 11/4/23 3:52 PM:
------------------------------------------------------------

Sorry for the late response and thanks for the ideas, [~reta] and [~dufoli]!

{quote}
{code}
public interface AsyncResponseListenerFactory {     
    AsyncResponseListener create();
}

public interface AsyncResponseListener {
    void onBeforeReceived(HttpResponse response);
    void onAfterReceived(HttpResponse response);
} 
         CXFResponseCallback responseCallback = new CXFResponseCallback() {                
             @Override                
             public void responseReceived(HttpResponse response) {                   
                listener.onBeforeReceived(response);
                setHttpResponse(response);      
                listener.onAfterReceived(response);                        
             }
         }; 
{code}
{quote}

I think this would not work, because I need to "be on the stack" of the code called by {{setHttpResponse(response);}}. 

But your earlier proposal with {{interface AsyncResponseCallbackFactory}} would work. I could do something like

{code}
class AsyncResponseCallbackFactory implements AsyncResponseCallbackFactory {
    
    AsyncResponseCallback create() {
        ThreadContext threadContext = Arc.container().select(ThreadContext.class).get();
        /*
         * We need to call this threadContext.contextualConsumer() here in the constructor to store the context
         * because consumeResponse() is called from another thread where the context is not available anymore
         */
        BiConsumer<HttpResponse, CXFResponseCallback> contextualConsumer = 
                threadContext.contextualConsumer(
                        (HttpResponse response, CXFResponseCallback callback) 
                                -> callback.responseReceived(response));
        return new MyAsyncResponseCallback(contextualConsumer);
    }
}

class MyAsyncResponseCallback implements AsyncResponseCallback {
    final BiConsumer<HttpResponse, CXFResponseCallback> contextualConsumer;
    MyAsyncResponseCallback(BiConsumer<HttpResponse, CXFResponseCallback> contextualConsumer) {
        this.contextualConsumer = contextualConsumer;
    }
    void responseReceived(HttpResponse response, CXFResponseCallback callback) {
        contextualConsumer.accept(response, callback);
    }
}
{code}

Could you perhaps draft a CXF pull request so that I can check that it really works?


was (Author: ppalaga):
Sorry for the late response and thanks for the ideas, [~reta] and [~dufoli]!

{quote}
{code}
public interface AsyncResponseListenerFactory {     
    AsyncResponseListener create();
}

public interface AsyncResponseListener {
    void onBeforeReceived(HttpResponse response);
    void onAfterReceived(HttpResponse response);
} 
         CXFResponseCallback responseCallback = new CXFResponseCallback() {                
             @Override                
             public void responseReceived(HttpResponse response) {                   
                listener.onBeforeReceived(response);
                setHttpResponse(response);      
                listener.onAfterReceived(response);                        
             }
         }; 
{code}
{quote}

I think this would not work, because I need to "be on the stack" of the code called by {{setHttpResponse(response);}}. 

But your earlier proposal with {{interface AsyncResponseCallbackFactory} }} would work. I could do something like

{code}
class AsyncResponseCallbackFactory implements AsyncResponseCallbackFactory {
    
    AsyncResponseCallback create() {
        ThreadContext threadContext = Arc.container().select(ThreadContext.class).get();
        /*
         * We need to call this threadContext.contextualConsumer() here in the constructor to store the context
         * because consumeResponse() is called from another thread where the context is not available anymore
         */
        BiConsumer<HttpResponse, CXFResponseCallback> contextualConsumer = 
                threadContext.contextualConsumer(
                        (HttpResponse response, CXFResponseCallback callback) 
                                -> callback.responseReceived(response));
        return new MyAsyncResponseCallback(contextualConsumer);
    }
}

class MyAsyncResponseCallback implements AsyncResponseCallback {
    final BiConsumer<HttpResponse, CXFResponseCallback> contextualConsumer;
    MyAsyncResponseCallback(BiConsumer<HttpResponse, CXFResponseCallback> contextualConsumer) {
        this.contextualConsumer = contextualConsumer;
    }
    void responseReceived(HttpResponse response, CXFResponseCallback callback) {
        contextualConsumer.accept(response, callback);
    }
}
{code}

Could you perhaps draft a CXF pull request so that I can check that it really works?

> Allow creating a custom CXFHttpAsyncResponseConsumer
> ----------------------------------------------------
>
>                 Key: CXF-8911
>                 URL: https://issues.apache.org/jira/browse/CXF-8911
>             Project: CXF
>          Issue Type: New Feature
>            Reporter: Peter Palaga
>            Priority: Major
>
> We recently got a [bug report|https://github.com/quarkiverse/quarkus-cxf/issues/947] in Quarkus CXF complaining about non-working context propagation with CXF HC5 client.
> The problem was that if the client is called in context of a Quarkus REST endpoint, whose vert.x thread has the request context setup properly, the request scoped beans are then not accessible e.g. from ContainerRequestFilters which run in in a different thread.
> To make it work, we would need wrap the creation of CXFHttpAsyncResponseConsumer in some code storing the context of the creation thread into a wrapping method that can then be executed by some other thread. I was able to do this by overriding some default classes. What I did can be seen around here: https://github.com/quarkiverse/quarkus-cxf/pull/950/files#diff-568a3d75d004f9f41c6130854755ebb2beae2f30308cc45aa98492d09bac2ecc
> This solution is by no means elegant and I wonder whether it would be feasible to implement some new API to allow creating custom CXFHttpAsyncResponseConsumers?
> Maybe we could introduce some kind of CXFHttpAsyncResponseConsumerFactory?
> I am quite new to CXF internals, so I'd be thankful for any hints how to proceed.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)