You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Mandy Warren <ma...@gmail.com> on 2014/10/11 12:20:52 UTC

How to add content to an empty message body

Hi,

We have developed a way for Rest calls sent using WebClient to be transparently sent either to a real backend or to our stubbing system. We have implemented this via an interceptor which intercepts the outgoing request and changes the url if certain headers (to indicate stubbing should be used) are present.

The stubbing system only supports POST at the moment and basically just matches the content of the POST body to determine the response to send back. So I am trying to work around this by converting a GET to a POST and placing the URL into the POST body as something to match against. Bizarre I know :-)

I have managed to change the HTTP request method ok, and can get access to the uri string but I just can't work out how to set the message content (which will be empty) to be the uri string.

This is what I have so far...

  if (HttpMethod.GET.equalsIgnoreCase((String) message.get(Message.HTTP_REQUEST_METHOD))) {
            
            // turn the GET into a POST
            message.put(Message.HTTP_REQUEST_METHOD, HttpMethod.POST);

            // and put the URL (minus the base path) into the POST body
            String uri = (String) message.get(Message.REQUEST_URI);

            OutputStream os = message.getContent(OutputStream.class);
            CachedOutputStream cs = new CachedOutputStream();
            try {
                cs.write(uri.getBytes());

                message.setContent(OutputStream.class, cs);
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }​

Note my interceptor runs at SETUP phase and I am using CXF 2.7.12

Any help much appreciated!

Many thanks
Mandy

Sent from my iPad

Re: How to add content to an empty message body

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Mandy

Thanks for validating this workaround,
On 15/10/14 22:38, Mandy Warren wrote:
> ​Hi Sergey,
>
> Thanks so much for your fix.. we tested it by writing a CustomBodyWriter as you suggested today and all worked fine except we needed to include this line to make the code work:
>
> outMessage.remove("org.apache.cxf.empty.request");
>
Indeed, this line is also in CXF 2.7.14-SNAPSHOT (in 
ClientFilterContextImpl)
​
> We look forward to 2.7.14 :-)

Sounds good, thanks
Sergey
>
>
> Sent from a mobile device
>
>> On 13 Oct 2014, at 13:27, Sergey Beryozkin <sb...@gmail.com> wrote:
>>
>> Hi Mandy
>>
>> I've looked at the code, unfortunately it is not possible to add an entity from the filter if the original message had no entity set up.
>>
>> I.e, the filter can be used to change the current entity but not turn an 'empty' request into a non-empty one - this is due to the optimization where a WebClient or BodyWriter interceptor is added only if a body is currently available - which fails to support the case where the body is added later in the chain from the filter.
>>
>> I've just fixed it [1], unfortunate again that it won't make it into CXF 2.7.13 due to be released early this week.
>>
>> The only workaround is to basically create a custom BodyWriter interceptor (copy the code from WebClient.BodyWriter) and add it when converting GET to POST in your custom interceptor, like this: message.getInterceptorChain().add(new CustomBodyWriter());
>>
>> It's a bit of a mess :-), sorry about it. But it will work well in 2.7.14
>>
>> Thanks, Sergey
>>
>> [1] https://issues.apache.org/jira/browse/CXF-6045
>>> On 12/10/14 23:40, Mandy Warren wrote:
>>> Many thanks for the fast reply Sergey. I tried using the ClientRequestFilter instead and set the msg body using:
>>>
>>> requestContext.setEntity(uri, null, null) ;
>>>
>>> When I do a getEntity() straight after all looks ok but the post body is empty when it sends to the stubbing system. I noticed a property on the message org.apache.cxf.empty.request was set to true so I set this to false but still no luck. Are there any other properties I might need to change?
>>>
>>> Not sure if it's relevant but I also use logging in/out interceptors around the call to WebClient.
>>>
>>> Many thanks
>>> Mandy
>>>
>>> Sent from a mobile device
>>>
>>>> On 12 Oct 2014, at 18:43, Sergey Beryozkin <sb...@gmail.com> wrote:
>>>>
>>>> Hi Mandy
>>>>> On 11/10/14 11:20, Mandy Warren wrote:
>>>>> Hi,
>>>>>
>>>>> We have developed a way for Rest calls sent using WebClient to be transparently sent either to a real backend or to our stubbing system. We have implemented this via an interceptor which intercepts the outgoing request and changes the url if certain headers (to indicate stubbing should be used) are present.
>>>>>
>>>>> The stubbing system only supports POST at the moment and basically just matches the content of the POST body to determine the response to send back. So I am trying to work around this by converting a GET to a POST and placing the URL into the POST body as something to match against. Bizarre I know :-)
>>>>>
>>>>> I have managed to change the HTTP request method ok, and can get access to the uri string but I just can't work out how to set the message content (which will be empty) to be the uri string.
>>>>>
>>>>> This is what I have so far...
>>>>>
>>>>>    if (HttpMethod.GET.equalsIgnoreCase((String) message.get(Message.HTTP_REQUEST_METHOD))) {
>>>>>
>>>>>              // turn the GET into a POST
>>>>>              message.put(Message.HTTP_REQUEST_METHOD, HttpMethod.POST);
>>>>>
>>>>>              // and put the URL (minus the base path) into the POST body
>>>>>              String uri = (String) message.get(Message.REQUEST_URI);
>>>>>
>>>>>              OutputStream os = message.getContent(OutputStream.class);
>>>>>              CachedOutputStream cs = new CachedOutputStream();
>>>>>              try {
>>>>>                  cs.write(uri.getBytes());
>>>>>
>>>>>                  message.setContent(OutputStream.class, cs);
>>>>>              } catch (IOException ioe) {
>>>>>                  ioe.printStackTrace();
>>>>>              }​
>>>>>
>>>>> Note my interceptor runs at SETUP phase and I am using CXF 2.7.12
>>>>
>>>> WebClient depends on the interceptor running in a Write phase and it skips the processing is no actual request object is set, it has this code:
>>>>
>>>> MessageContentsList objs = MessageContentsList.getContentsList(outMessage);
>>>>             if (objs == null || objs.size() == 0) {
>>>>                 return;
>>>>             }
>>>>
>>>> So may be you should set it too
>>>> outMessage.setContent(List.class, Collections.singletonList(uri));
>>>>
>>>> Or may be you should do it from a JAX-RS 2.0 ClientRequestFilter ?
>>>>
>>>> Cheers, Sergey
>>>>
>>>>>
>>>>> Any help much appreciated!
>>>>>
>>>>> Many thanks
>>>>> Mandy
>>>>>
>>>>> Sent from my iPad
>>
>


Re: How to add content to an empty message body

Posted by Mandy Warren <ma...@gmail.com>.
​Hi Sergey,

Thanks so much for your fix.. we tested it by writing a CustomBodyWriter as you suggested today and all worked fine except we needed to include this line to make the code work:

outMessage.remove("org.apache.cxf.empty.request");​

We look forward to 2.7.14 :-)


Sent from a mobile device

> On 13 Oct 2014, at 13:27, Sergey Beryozkin <sb...@gmail.com> wrote:
> 
> Hi Mandy
> 
> I've looked at the code, unfortunately it is not possible to add an entity from the filter if the original message had no entity set up.
> 
> I.e, the filter can be used to change the current entity but not turn an 'empty' request into a non-empty one - this is due to the optimization where a WebClient or BodyWriter interceptor is added only if a body is currently available - which fails to support the case where the body is added later in the chain from the filter.
> 
> I've just fixed it [1], unfortunate again that it won't make it into CXF 2.7.13 due to be released early this week.
> 
> The only workaround is to basically create a custom BodyWriter interceptor (copy the code from WebClient.BodyWriter) and add it when converting GET to POST in your custom interceptor, like this: message.getInterceptorChain().add(new CustomBodyWriter());
> 
> It's a bit of a mess :-), sorry about it. But it will work well in 2.7.14
> 
> Thanks, Sergey
> 
> [1] https://issues.apache.org/jira/browse/CXF-6045
>> On 12/10/14 23:40, Mandy Warren wrote:
>> Many thanks for the fast reply Sergey. I tried using the ClientRequestFilter instead and set the msg body using:
>> 
>> requestContext.setEntity(uri, null, null) ;
>> 
>> When I do a getEntity() straight after all looks ok but the post body is empty when it sends to the stubbing system. I noticed a property on the message org.apache.cxf.empty.request was set to true so I set this to false but still no luck. Are there any other properties I might need to change?
>> 
>> Not sure if it's relevant but I also use logging in/out interceptors around the call to WebClient.
>> 
>> Many thanks
>> Mandy
>> 
>> Sent from a mobile device
>> 
>>> On 12 Oct 2014, at 18:43, Sergey Beryozkin <sb...@gmail.com> wrote:
>>> 
>>> Hi Mandy
>>>> On 11/10/14 11:20, Mandy Warren wrote:
>>>> Hi,
>>>> 
>>>> We have developed a way for Rest calls sent using WebClient to be transparently sent either to a real backend or to our stubbing system. We have implemented this via an interceptor which intercepts the outgoing request and changes the url if certain headers (to indicate stubbing should be used) are present.
>>>> 
>>>> The stubbing system only supports POST at the moment and basically just matches the content of the POST body to determine the response to send back. So I am trying to work around this by converting a GET to a POST and placing the URL into the POST body as something to match against. Bizarre I know :-)
>>>> 
>>>> I have managed to change the HTTP request method ok, and can get access to the uri string but I just can't work out how to set the message content (which will be empty) to be the uri string.
>>>> 
>>>> This is what I have so far...
>>>> 
>>>>   if (HttpMethod.GET.equalsIgnoreCase((String) message.get(Message.HTTP_REQUEST_METHOD))) {
>>>> 
>>>>             // turn the GET into a POST
>>>>             message.put(Message.HTTP_REQUEST_METHOD, HttpMethod.POST);
>>>> 
>>>>             // and put the URL (minus the base path) into the POST body
>>>>             String uri = (String) message.get(Message.REQUEST_URI);
>>>> 
>>>>             OutputStream os = message.getContent(OutputStream.class);
>>>>             CachedOutputStream cs = new CachedOutputStream();
>>>>             try {
>>>>                 cs.write(uri.getBytes());
>>>> 
>>>>                 message.setContent(OutputStream.class, cs);
>>>>             } catch (IOException ioe) {
>>>>                 ioe.printStackTrace();
>>>>             }​
>>>> 
>>>> Note my interceptor runs at SETUP phase and I am using CXF 2.7.12
>>> 
>>> WebClient depends on the interceptor running in a Write phase and it skips the processing is no actual request object is set, it has this code:
>>> 
>>> MessageContentsList objs = MessageContentsList.getContentsList(outMessage);
>>>            if (objs == null || objs.size() == 0) {
>>>                return;
>>>            }
>>> 
>>> So may be you should set it too
>>> outMessage.setContent(List.class, Collections.singletonList(uri));
>>> 
>>> Or may be you should do it from a JAX-RS 2.0 ClientRequestFilter ?
>>> 
>>> Cheers, Sergey
>>> 
>>>> 
>>>> Any help much appreciated!
>>>> 
>>>> Many thanks
>>>> Mandy
>>>> 
>>>> Sent from my iPad
> 

Re: How to add content to an empty message body

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Mandy

I've looked at the code, unfortunately it is not possible to add an 
entity from the filter if the original message had no entity set up.

I.e, the filter can be used to change the current entity but not turn an 
'empty' request into a non-empty one - this is due to the optimization 
where a WebClient or BodyWriter interceptor is added only if a body is 
currently available - which fails to support the case where the body is 
added later in the chain from the filter.

I've just fixed it [1], unfortunate again that it won't make it into CXF 
2.7.13 due to be released early this week.

The only workaround is to basically create a custom BodyWriter 
interceptor (copy the code from WebClient.BodyWriter) and add it when 
converting GET to POST in your custom interceptor, like this: 
message.getInterceptorChain().add(new CustomBodyWriter());

It's a bit of a mess :-), sorry about it. But it will work well in 2.7.14

Thanks, Sergey

[1] https://issues.apache.org/jira/browse/CXF-6045
On 12/10/14 23:40, Mandy Warren wrote:
> Many thanks for the fast reply Sergey. I tried using the ClientRequestFilter instead and set the msg body using:
>
> requestContext.setEntity(uri, null, null) ;
>
> When I do a getEntity() straight after all looks ok but the post body is empty when it sends to the stubbing system. I noticed a property on the message org.apache.cxf.empty.request was set to true so I set this to false but still no luck. Are there any other properties I might need to change?
>
> Not sure if it's relevant but I also use logging in/out interceptors around the call to WebClient.
>
> Many thanks
> Mandy
>
> Sent from a mobile device
>
>> On 12 Oct 2014, at 18:43, Sergey Beryozkin <sb...@gmail.com> wrote:
>>
>> Hi Mandy
>>> On 11/10/14 11:20, Mandy Warren wrote:
>>> Hi,
>>>
>>> We have developed a way for Rest calls sent using WebClient to be transparently sent either to a real backend or to our stubbing system. We have implemented this via an interceptor which intercepts the outgoing request and changes the url if certain headers (to indicate stubbing should be used) are present.
>>>
>>> The stubbing system only supports POST at the moment and basically just matches the content of the POST body to determine the response to send back. So I am trying to work around this by converting a GET to a POST and placing the URL into the POST body as something to match against. Bizarre I know :-)
>>>
>>> I have managed to change the HTTP request method ok, and can get access to the uri string but I just can't work out how to set the message content (which will be empty) to be the uri string.
>>>
>>> This is what I have so far...
>>>
>>>    if (HttpMethod.GET.equalsIgnoreCase((String) message.get(Message.HTTP_REQUEST_METHOD))) {
>>>
>>>              // turn the GET into a POST
>>>              message.put(Message.HTTP_REQUEST_METHOD, HttpMethod.POST);
>>>
>>>              // and put the URL (minus the base path) into the POST body
>>>              String uri = (String) message.get(Message.REQUEST_URI);
>>>
>>>              OutputStream os = message.getContent(OutputStream.class);
>>>              CachedOutputStream cs = new CachedOutputStream();
>>>              try {
>>>                  cs.write(uri.getBytes());
>>>
>>>                  message.setContent(OutputStream.class, cs);
>>>              } catch (IOException ioe) {
>>>                  ioe.printStackTrace();
>>>              }​
>>>
>>> Note my interceptor runs at SETUP phase and I am using CXF 2.7.12
>>
>> WebClient depends on the interceptor running in a Write phase and it skips the processing is no actual request object is set, it has this code:
>>
>> MessageContentsList objs = MessageContentsList.getContentsList(outMessage);
>>             if (objs == null || objs.size() == 0) {
>>                 return;
>>             }
>>
>> So may be you should set it too
>> outMessage.setContent(List.class, Collections.singletonList(uri));
>>
>> Or may be you should do it from a JAX-RS 2.0 ClientRequestFilter ?
>>
>> Cheers, Sergey
>>
>>>
>>> Any help much appreciated!
>>>
>>> Many thanks
>>> Mandy
>>>
>>> Sent from my iPad
>>
>>


Re: How to add content to an empty message body

Posted by Mandy Warren <ma...@gmail.com>.
Many thanks for the fast reply Sergey. I tried using the ClientRequestFilter instead and set the msg body using:

requestContext.setEntity(uri, null, null) ;

When I do a getEntity() straight after all looks ok but the post body is empty when it sends to the stubbing system. I noticed a property on the message org.apache.cxf.empty.request was set to true so I set this to false but still no luck. Are there any other properties I might need to change?

Not sure if it's relevant but I also use logging in/out interceptors around the call to WebClient.

Many thanks
Mandy

Sent from a mobile device

> On 12 Oct 2014, at 18:43, Sergey Beryozkin <sb...@gmail.com> wrote:
> 
> Hi Mandy
>> On 11/10/14 11:20, Mandy Warren wrote:
>> Hi,
>> 
>> We have developed a way for Rest calls sent using WebClient to be transparently sent either to a real backend or to our stubbing system. We have implemented this via an interceptor which intercepts the outgoing request and changes the url if certain headers (to indicate stubbing should be used) are present.
>> 
>> The stubbing system only supports POST at the moment and basically just matches the content of the POST body to determine the response to send back. So I am trying to work around this by converting a GET to a POST and placing the URL into the POST body as something to match against. Bizarre I know :-)
>> 
>> I have managed to change the HTTP request method ok, and can get access to the uri string but I just can't work out how to set the message content (which will be empty) to be the uri string.
>> 
>> This is what I have so far...
>> 
>>   if (HttpMethod.GET.equalsIgnoreCase((String) message.get(Message.HTTP_REQUEST_METHOD))) {
>> 
>>             // turn the GET into a POST
>>             message.put(Message.HTTP_REQUEST_METHOD, HttpMethod.POST);
>> 
>>             // and put the URL (minus the base path) into the POST body
>>             String uri = (String) message.get(Message.REQUEST_URI);
>> 
>>             OutputStream os = message.getContent(OutputStream.class);
>>             CachedOutputStream cs = new CachedOutputStream();
>>             try {
>>                 cs.write(uri.getBytes());
>> 
>>                 message.setContent(OutputStream.class, cs);
>>             } catch (IOException ioe) {
>>                 ioe.printStackTrace();
>>             }​
>> 
>> Note my interceptor runs at SETUP phase and I am using CXF 2.7.12
> 
> WebClient depends on the interceptor running in a Write phase and it skips the processing is no actual request object is set, it has this code:
> 
> MessageContentsList objs = MessageContentsList.getContentsList(outMessage);
>            if (objs == null || objs.size() == 0) {
>                return;
>            }
> 
> So may be you should set it too
> outMessage.setContent(List.class, Collections.singletonList(uri));
> 
> Or may be you should do it from a JAX-RS 2.0 ClientRequestFilter ?
> 
> Cheers, Sergey
> 
>> 
>> Any help much appreciated!
>> 
>> Many thanks
>> Mandy
>> 
>> Sent from my iPad
> 
> 

Re: How to add content to an empty message body

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Mandy
On 11/10/14 11:20, Mandy Warren wrote:
> Hi,
>
> We have developed a way for Rest calls sent using WebClient to be transparently sent either to a real backend or to our stubbing system. We have implemented this via an interceptor which intercepts the outgoing request and changes the url if certain headers (to indicate stubbing should be used) are present.
>
> The stubbing system only supports POST at the moment and basically just matches the content of the POST body to determine the response to send back. So I am trying to work around this by converting a GET to a POST and placing the URL into the POST body as something to match against. Bizarre I know :-)
>
> I have managed to change the HTTP request method ok, and can get access to the uri string but I just can't work out how to set the message content (which will be empty) to be the uri string.
>
> This is what I have so far...
>
>    if (HttpMethod.GET.equalsIgnoreCase((String) message.get(Message.HTTP_REQUEST_METHOD))) {
>
>              // turn the GET into a POST
>              message.put(Message.HTTP_REQUEST_METHOD, HttpMethod.POST);
>
>              // and put the URL (minus the base path) into the POST body
>              String uri = (String) message.get(Message.REQUEST_URI);
>
>              OutputStream os = message.getContent(OutputStream.class);
>              CachedOutputStream cs = new CachedOutputStream();
>              try {
>                  cs.write(uri.getBytes());
>
>                  message.setContent(OutputStream.class, cs);
>              } catch (IOException ioe) {
>                  ioe.printStackTrace();
>              }​
>
> Note my interceptor runs at SETUP phase and I am using CXF 2.7.12

WebClient depends on the interceptor running in a Write phase and it 
skips the processing is no actual request object is set, it has this code:

MessageContentsList objs = MessageContentsList.getContentsList(outMessage);
             if (objs == null || objs.size() == 0) {
                 return;
             }

So may be you should set it too
outMessage.setContent(List.class, Collections.singletonList(uri));

Or may be you should do it from a JAX-RS 2.0 ClientRequestFilter ?

Cheers, Sergey

>
> Any help much appreciated!
>
> Many thanks
> Mandy
>
> Sent from my iPad
>