Would like to send custom XML back whenever a 400 or 500 category error happens

View: New views
8 Messages — Rating Filter:   Alert me  

Would like to send custom XML back whenever a 400 or 500 category error happens

by Henrik Martin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Greetings. I need to intercept any kind of error happening in our
application that's built on CXF. I'm designing a general purpose error
handling framework for the application, and it also needs to intercept
errors that may happen before our application code is executed. I.e.,
I'd like to treat ALL errors uniformly, whether they happen during
marshalling, etc.

I've been playing around with the interceptors and filters. At first I
had decided on using an interceptor. But then I read on a wiki page that
it wasn't possible to change the HTTP status code if the interceptor ran
after the JAXRSInOutInterceptor, so I chose to write a filter instead.
I'm using Spring to configure everything. The handleResponse() method in
my filter gets called, but I've found that if I return any kind of
error, i.e. a category 400 or 500 type error, the XML that I'm returning
as the content doesn't get rendered in the browser (I'm testing things
from the browser or wget).

So, what is the best strategy for creating a "catch-all" error handler
for CXF? What I need to do is basically to create custom XML content for
any kind of error that may happen, and return that to the client. BTW,
we're mainly using JAXRS and REST calls, and do not anticipate having to
handle SOAP at all. At first glance it seems like interceptors are more
flexible, and that I have more control since I can choose which phase it
gets invoked at. Any help is much appreciated. My environment:

OS: OpenSUSE Linux 11.1
Java: Sun's JDK version 1.6.0_16-b01
CXF: 2.2.3 bundle
App server: Tomcat 6.0.X
Spring: 2.5.5

Thanks,

/Henrik

Parent Message unknown Re: Would like to send custom XML back whenever a 400 or 500 category error happens

by Sergey Beryozkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Henrik

 

For some reasons I can only see your message in Archives, but not
Nabble.

 

>>The handleResponse() method in
>>my filter gets called, but I've found that if I return any kind of
>>error, i.e. a category 400 or 500 type error, the XML that I'm
returning
>>as the content doesn't get rendered in the browser
 
If one returns a custom Response from a filter, then its entity, if any,
will be
serialized by the available writers.
 
So if you set a String instance as a custom entity and you happen to
have a custom message body writer which can
wrap Strings then the browser would show it as a plain text sequence.
 
Starting from CXF 2.2.4 it is possible to indicate that writers have to
be ignored. In meantime, the best way would be to return
an object like ExceptionInfo which will be serialized by the appropriate
XML writer.
 
Is it what might be happening in your case ?
 
If you're thinking of doing JAXRS only then filters should do well.  
 
Cheers, Sergey
 
 
   

 

 

 


Re: Would like to send custom XML back whenever a 400 or 500 category error happens

by Henrik Martin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Sergey, thanks for the response. I should have given you a little more
detail. In my handleResponse() method, I do return a Response, which
contains something similar to your suggested ExceptionInfo. It's just a
Java bean containing some properties and some XStream annotations. When
I run everything in the debugger, I can see that my entity (containing
the exception information) gets handled by our MessageWriter, and proper
XML gets generated (I'm printing it out inside the MessageWriter). This
is what's puzzling me, I never see the XML after that.

I don't get any exceptions being thrown anywhere, so I don't think it's
a failure of any kind. Our MessageWriter is registered to handle any
type thrown at it. It basically uses XStream to stream out the beans
into XML. It seems to work fine. If I set the HTTP status code to 200
and return the exact same exception data, it gets streamed out properly
all the way back to the client. I'm curious to what the difference is in
execution path when I'm setting the HTTP status to a 400 or 500? I've
tried following along in the debugger, but there are so many levels of
calls that it's a little overwhelming. Is there some sort of error
handler in the CXF framework that takes different paths depending on the
value of the HTTP status code? Thanks,

/Henrik

On Mon, 2009-11-02 at 17:11 -0500, Sergey Beryozkin wrote:

> Hi Henrik
>
>  
>
> For some reasons I can only see your message in Archives, but not
> Nabble.
>
>  
>
> >>The handleResponse() method in
> >>my filter gets called, but I've found that if I return any kind of
> >>error, i.e. a category 400 or 500 type error, the XML that I'm
> returning
> >>as the content doesn't get rendered in the browser
>  
> If one returns a custom Response from a filter, then its entity, if any,
> will be
> serialized by the available writers.
>  
> So if you set a String instance as a custom entity and you happen to
> have a custom message body writer which can
> wrap Strings then the browser would show it as a plain text sequence.
>  
> Starting from CXF 2.2.4 it is possible to indicate that writers have to
> be ignored. In meantime, the best way would be to return
> an object like ExceptionInfo which will be serialized by the appropriate
> XML writer.
>  
> Is it what might be happening in your case ?
>  
> If you're thinking of doing JAXRS only then filters should do well.  
>  
> Cheers, Sergey
>  
>
>    
>
>  
>
>
>
>  
>

RE: Would like to send custom XML back whenever a 400 or 500 category error happens

by Sergey Beryozkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Henrik

I reckon looking at the wire representation would really help in
figuring out what's going on. Also, can it be that say the XStream
writer needs to have some kind of close() method being called ?  

Please send a wget/browser request through a tcp trace utility and let
me know the details

Thanks, Sergey

-----Original Message-----
From: Henrik Martin [mailto:henrik.martin@...]
Sent: 03 November 2009 22:03
To: users@...
Subject: Re: Would like to send custom XML back whenever a 400 or 500
category error happens

Sergey, thanks for the response. I should have given you a little more
detail. In my handleResponse() method, I do return a Response, which
contains something similar to your suggested ExceptionInfo. It's just a
Java bean containing some properties and some XStream annotations. When
I run everything in the debugger, I can see that my entity (containing
the exception information) gets handled by our MessageWriter, and proper
XML gets generated (I'm printing it out inside the MessageWriter). This
is what's puzzling me, I never see the XML after that.

I don't get any exceptions being thrown anywhere, so I don't think it's
a failure of any kind. Our MessageWriter is registered to handle any
type thrown at it. It basically uses XStream to stream out the beans
into XML. It seems to work fine. If I set the HTTP status code to 200
and return the exact same exception data, it gets streamed out properly
all the way back to the client. I'm curious to what the difference is in
execution path when I'm setting the HTTP status to a 400 or 500? I've
tried following along in the debugger, but there are so many levels of
calls that it's a little overwhelming. Is there some sort of error
handler in the CXF framework that takes different paths depending on the
value of the HTTP status code? Thanks,

/Henrik

On Mon, 2009-11-02 at 17:11 -0500, Sergey Beryozkin wrote:

> Hi Henrik
>
>  
>
> For some reasons I can only see your message in Archives, but not
> Nabble.
>
>  
>
> >>The handleResponse() method in
> >>my filter gets called, but I've found that if I return any kind of
> >>error, i.e. a category 400 or 500 type error, the XML that I'm
> returning
> >>as the content doesn't get rendered in the browser
>  
> If one returns a custom Response from a filter, then its entity, if
any,
> will be
> serialized by the available writers.
>  
> So if you set a String instance as a custom entity and you happen to
> have a custom message body writer which can
> wrap Strings then the browser would show it as a plain text sequence.
>  
> Starting from CXF 2.2.4 it is possible to indicate that writers have
to
> be ignored. In meantime, the best way would be to return
> an object like ExceptionInfo which will be serialized by the
appropriate

> XML writer.
>  
> Is it what might be happening in your case ?
>  
> If you're thinking of doing JAXRS only then filters should do well.  
>  
> Cheers, Sergey
>  
>
>    
>
>  
>
>
>
>  
>

RE: Would like to send custom XML back whenever a 400 or 500 category error happens

by Henrik Martin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Sergey. Thanks again for the response. I stepped through the
JAXRSOutInterceptor in the debugger and found out that the content type
for the Response I had created was "octet/stream" instead of
"application/xml". Once I created the appropriate content type entry in
the MultivaluedMap returned by getMetadata() method, everything worked.

While on that subject, is that the appropriate way of doing it? What I
ended up doing was something like the code snippet below. Apologies for
the bad formatting, I'm using Evolution to send the email...

// "error" is our error placeholder bean sent back as the entity
final Response newResponse = builder.entity(error.validate()).build();
newResponse.getMetadata().putAll(oldResponse.getMetadata());
final MultivaluedMap<String, Object> map = newResponse.getMetadata();

if (! map.containsKey(HttpHeaders.CONTENT_TYPE))
{
  final List<Object> contentTypes = new ArrayList<Object>();
  contentTypes.add("application/xml");
  map.put(HttpHeaders.CONTENT_TYPE, contentTypes);
}
else
{
  final List<Object> contentTypes = map.get(HttpHeaders.CONTENT_TYPE);

  if (! contentTypes.contains("application/xml"))
  {
    contentTypes.add("application/xml");
  }
}

A little clumsy maybe, but I was trying to preserve whatever content
types the original response had as well as making sure that the new
response declares "application/xml". Any suggestions on how to clean
this up and do it properly are appreciated. Anyway, after inserting this
code snippet, things work all the way back to the browser, and I see the
exception entity in XML form. Thanks,

/Henrik

On Tue, 2009-11-03 at 18:25 -0500, Sergey Beryozkin wrote:

> Hi Henrik
>
> I reckon looking at the wire representation would really help in
> figuring out what's going on. Also, can it be that say the XStream
> writer needs to have some kind of close() method being called ?  
>
> Please send a wget/browser request through a tcp trace utility and let
> me know the details
>
> Thanks, Sergey
>
> -----Original Message-----
> From: Henrik Martin [mailto:henrik.martin@...]
> Sent: 03 November 2009 22:03
> To: users@...
> Subject: Re: Would like to send custom XML back whenever a 400 or 500
> category error happens
>
> Sergey, thanks for the response. I should have given you a little more
> detail. In my handleResponse() method, I do return a Response, which
> contains something similar to your suggested ExceptionInfo. It's just a
> Java bean containing some properties and some XStream annotations. When
> I run everything in the debugger, I can see that my entity (containing
> the exception information) gets handled by our MessageWriter, and proper
> XML gets generated (I'm printing it out inside the MessageWriter). This
> is what's puzzling me, I never see the XML after that.
>
> I don't get any exceptions being thrown anywhere, so I don't think it's
> a failure of any kind. Our MessageWriter is registered to handle any
> type thrown at it. It basically uses XStream to stream out the beans
> into XML. It seems to work fine. If I set the HTTP status code to 200
> and return the exact same exception data, it gets streamed out properly
> all the way back to the client. I'm curious to what the difference is in
> execution path when I'm setting the HTTP status to a 400 or 500? I've
> tried following along in the debugger, but there are so many levels of
> calls that it's a little overwhelming. Is there some sort of error
> handler in the CXF framework that takes different paths depending on the
> value of the HTTP status code? Thanks,
>
> /Henrik
>
> On Mon, 2009-11-02 at 17:11 -0500, Sergey Beryozkin wrote:
> > Hi Henrik
> >
> >  
> >
> > For some reasons I can only see your message in Archives, but not
> > Nabble.
> >
> >  
> >
> > >>The handleResponse() method in
> > >>my filter gets called, but I've found that if I return any kind of
> > >>error, i.e. a category 400 or 500 type error, the XML that I'm
> > returning
> > >>as the content doesn't get rendered in the browser
> >  
> > If one returns a custom Response from a filter, then its entity, if
> any,
> > will be
> > serialized by the available writers.
> >  
> > So if you set a String instance as a custom entity and you happen to
> > have a custom message body writer which can
> > wrap Strings then the browser would show it as a plain text sequence.
> >  
> > Starting from CXF 2.2.4 it is possible to indicate that writers have
> to
> > be ignored. In meantime, the best way would be to return
> > an object like ExceptionInfo which will be serialized by the
> appropriate
> > XML writer.
> >  
> > Is it what might be happening in your case ?
> >  
> > If you're thinking of doing JAXRS only then filters should do well.  
> >  
> > Cheers, Sergey
> >  
> >
> >    
> >
> >  
> >
> >
> >
> >  
> >

Re: Would like to send custom XML back whenever a 400 or 500 category error happens

by Sergey Beryozkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Henrik

> Hi Sergey. Thanks again for the response. I stepped through the
> JAXRSOutInterceptor in the debugger and found out that the content type
> for the Response I had created was "octet/stream" instead of
> "application/xml". Once I created the appropriate content type entry in
> the MultivaluedMap returned by getMetadata() method, everything worked.

JAXRS spec requires "octet/stream" be set if no content type has been set by the user code (either implicitly by specifying
@Produces or returning a custom Response, etc)....Please see more comments below

>
> While on that subject, is that the appropriate way of doing it? What I
> ended up doing was something like the code snippet below. Apologies for
> the bad formatting, I'm using Evolution to send the email...
>
> // "error" is our error placeholder bean sent back as the entity
> final Response newResponse = builder.entity(error.validate()).build();
> newResponse.getMetadata().putAll(oldResponse.getMetadata());
> final MultivaluedMap<String, Object> map = newResponse.getMetadata();
>
> if (! map.containsKey(HttpHeaders.CONTENT_TYPE))
> {
>  final List<Object> contentTypes = new ArrayList<Object>();
>  contentTypes.add("application/xml");
>  map.put(HttpHeaders.CONTENT_TYPE, contentTypes);
> }
> else
> {
>  final List<Object> contentTypes = map.get(HttpHeaders.CONTENT_TYPE);
>
>  if (! contentTypes.contains("application/xml"))
>  {
>    contentTypes.add("application/xml");
>  }
> }
>
> A little clumsy maybe, but I was trying to preserve whatever content
> types the original response had as well as making sure that the new
> response declares "application/xml". Any suggestions on how to clean
> this up and do it properly are appreciated. Anyway, after inserting this
> code snippet, things work all the way back to the browser, and I see the
> exception entity in XML form. Thanks,

This code is fine, and indeed, it is importnat that the headers which might'be been set earlier on are not lost. Though you might
want to simplify it a bit, MultivaluedMap supports a putSingle() method, so you can do :

final MultivaluedMap<String, Object> map = newResponse.getMetadata();
map.putSingle(HttpHeaders.CONTENT_TYPE, "application/xml");

given that it is "application/xml" which is required in this case ?

One thing I'm concerned a bit about is that if the generic exception reporting logic is done in a ResponseHandler and/or
RequestHandler filters then even normal non-exceptional requests or responses will go through them, so you probably do some kind of
a check to see if it's an exceptional invocation or not...I don't think it affects in any measurable way the overall performance but
it's worth mentioning that few more options are available (sorry for not mentioning them in the first place)...

First, all the exceptions which have not been mapped to responses by registered providers will be propogated (or is it 'propagated'
:-) ?)
to the container wrapped in ServletExceptions. So one other option is to register a simple ServletFilter which will only will only
handle ServletExceptions and check the causes and write to the HttpServletResponse as needed.

Another option is is to register a CXF out fault interceptor with the jaxrs:server. I'll be working on a test which will show how to
do it. This fault interceptor will be executed only if the propogation has been disabled through a jaxrs:server property and if no
matching ExceptionMappers are available. I'll let you know once the system test is ready.

That said, I reckon using JAXRS filters should do well - may be I will add the support for the in/out  fault JAXRS filters too...

thanks, Sergey

>
> /Henrik
>
> On Tue, 2009-11-03 at 18:25 -0500, Sergey Beryozkin wrote:
>> Hi Henrik
>>
>> I reckon looking at the wire representation would really help in
>> figuring out what's going on. Also, can it be that say the XStream
>> writer needs to have some kind of close() method being called ?
>>
>> Please send a wget/browser request through a tcp trace utility and let
>> me know the details
>>
>> Thanks, Sergey
>>
>> -----Original Message-----
>> From: Henrik Martin [mailto:henrik.martin@...]
>> Sent: 03 November 2009 22:03
>> To: users@...
>> Subject: Re: Would like to send custom XML back whenever a 400 or 500
>> category error happens
>>
>> Sergey, thanks for the response. I should have given you a little more
>> detail. In my handleResponse() method, I do return a Response, which
>> contains something similar to your suggested ExceptionInfo. It's just a
>> Java bean containing some properties and some XStream annotations. When
>> I run everything in the debugger, I can see that my entity (containing
>> the exception information) gets handled by our MessageWriter, and proper
>> XML gets generated (I'm printing it out inside the MessageWriter). This
>> is what's puzzling me, I never see the XML after that.
>>
>> I don't get any exceptions being thrown anywhere, so I don't think it's
>> a failure of any kind. Our MessageWriter is registered to handle any
>> type thrown at it. It basically uses XStream to stream out the beans
>> into XML. It seems to work fine. If I set the HTTP status code to 200
>> and return the exact same exception data, it gets streamed out properly
>> all the way back to the client. I'm curious to what the difference is in
>> execution path when I'm setting the HTTP status to a 400 or 500? I've
>> tried following along in the debugger, but there are so many levels of
>> calls that it's a little overwhelming. Is there some sort of error
>> handler in the CXF framework that takes different paths depending on the
>> value of the HTTP status code? Thanks,
>>
>> /Henrik
>>
>> On Mon, 2009-11-02 at 17:11 -0500, Sergey Beryozkin wrote:
>> > Hi Henrik
>> >
>> >
>> >
>> > For some reasons I can only see your message in Archives, but not
>> > Nabble.
>> >
>> >
>> >
>> > >>The handleResponse() method in
>> > >>my filter gets called, but I've found that if I return any kind of
>> > >>error, i.e. a category 400 or 500 type error, the XML that I'm
>> > returning
>> > >>as the content doesn't get rendered in the browser
>> >
>> > If one returns a custom Response from a filter, then its entity, if
>> any,
>> > will be
>> > serialized by the available writers.
>> >
>> > So if you set a String instance as a custom entity and you happen to
>> > have a custom message body writer which can
>> > wrap Strings then the browser would show it as a plain text sequence.
>> >
>> > Starting from CXF 2.2.4 it is possible to indicate that writers have
>> to
>> > be ignored. In meantime, the best way would be to return
>> > an object like ExceptionInfo which will be serialized by the
>> appropriate
>> > XML writer.
>> >
>> > Is it what might be happening in your case ?
>> >
>> > If you're thinking of doing JAXRS only then filters should do well.
>> >
>> > Cheers, Sergey
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >


Re: Would like to send custom XML back whenever a 400 or 500 category error happens

by Henrik Martin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks Sergey. I'm interested in this topic. Please keep me posted on
any progress you make on new features. I'll be happy to help out with
testing etc. Cheers,

/Henrik

On Wed, 2009-11-04 at 10:05 +0000, Sergey Beryozkin wrote:

> Hi Henrik
>
> > Hi Sergey. Thanks again for the response. I stepped through the
> > JAXRSOutInterceptor in the debugger and found out that the content type
> > for the Response I had created was "octet/stream" instead of
> > "application/xml". Once I created the appropriate content type entry in
> > the MultivaluedMap returned by getMetadata() method, everything worked.
>
> JAXRS spec requires "octet/stream" be set if no content type has been set by the user code (either implicitly by specifying
> @Produces or returning a custom Response, etc)....Please see more comments below
>
> >
> > While on that subject, is that the appropriate way of doing it? What I
> > ended up doing was something like the code snippet below. Apologies for
> > the bad formatting, I'm using Evolution to send the email...
> >
> > // "error" is our error placeholder bean sent back as the entity
> > final Response newResponse = builder.entity(error.validate()).build();
> > newResponse.getMetadata().putAll(oldResponse.getMetadata());
> > final MultivaluedMap<String, Object> map = newResponse.getMetadata();
> >
> > if (! map.containsKey(HttpHeaders.CONTENT_TYPE))
> > {
> >  final List<Object> contentTypes = new ArrayList<Object>();
> >  contentTypes.add("application/xml");
> >  map.put(HttpHeaders.CONTENT_TYPE, contentTypes);
> > }
> > else
> > {
> >  final List<Object> contentTypes = map.get(HttpHeaders.CONTENT_TYPE);
> >
> >  if (! contentTypes.contains("application/xml"))
> >  {
> >    contentTypes.add("application/xml");
> >  }
> > }
> >
> > A little clumsy maybe, but I was trying to preserve whatever content
> > types the original response had as well as making sure that the new
> > response declares "application/xml". Any suggestions on how to clean
> > this up and do it properly are appreciated. Anyway, after inserting this
> > code snippet, things work all the way back to the browser, and I see the
> > exception entity in XML form. Thanks,
>
> This code is fine, and indeed, it is importnat that the headers which might'be been set earlier on are not lost. Though you might
> want to simplify it a bit, MultivaluedMap supports a putSingle() method, so you can do :
>
> final MultivaluedMap<String, Object> map = newResponse.getMetadata();
> map.putSingle(HttpHeaders.CONTENT_TYPE, "application/xml");
>
> given that it is "application/xml" which is required in this case ?
>
> One thing I'm concerned a bit about is that if the generic exception reporting logic is done in a ResponseHandler and/or
> RequestHandler filters then even normal non-exceptional requests or responses will go through them, so you probably do some kind of
> a check to see if it's an exceptional invocation or not...I don't think it affects in any measurable way the overall performance but
> it's worth mentioning that few more options are available (sorry for not mentioning them in the first place)...
>
> First, all the exceptions which have not been mapped to responses by registered providers will be propogated (or is it 'propagated'
> :-) ?)
> to the container wrapped in ServletExceptions. So one other option is to register a simple ServletFilter which will only will only
> handle ServletExceptions and check the causes and write to the HttpServletResponse as needed.
>
> Another option is is to register a CXF out fault interceptor with the jaxrs:server. I'll be working on a test which will show how to
> do it. This fault interceptor will be executed only if the propogation has been disabled through a jaxrs:server property and if no
> matching ExceptionMappers are available. I'll let you know once the system test is ready.
>
> That said, I reckon using JAXRS filters should do well - may be I will add the support for the in/out  fault JAXRS filters too...
>
> thanks, Sergey
>
> >
> > /Henrik
> >
> > On Tue, 2009-11-03 at 18:25 -0500, Sergey Beryozkin wrote:
> >> Hi Henrik
> >>
> >> I reckon looking at the wire representation would really help in
> >> figuring out what's going on. Also, can it be that say the XStream
> >> writer needs to have some kind of close() method being called ?
> >>
> >> Please send a wget/browser request through a tcp trace utility and let
> >> me know the details
> >>
> >> Thanks, Sergey
> >>
> >> -----Original Message-----
> >> From: Henrik Martin [mailto:henrik.martin@...]
> >> Sent: 03 November 2009 22:03
> >> To: users@...
> >> Subject: Re: Would like to send custom XML back whenever a 400 or 500
> >> category error happens
> >>
> >> Sergey, thanks for the response. I should have given you a little more
> >> detail. In my handleResponse() method, I do return a Response, which
> >> contains something similar to your suggested ExceptionInfo. It's just a
> >> Java bean containing some properties and some XStream annotations. When
> >> I run everything in the debugger, I can see that my entity (containing
> >> the exception information) gets handled by our MessageWriter, and proper
> >> XML gets generated (I'm printing it out inside the MessageWriter). This
> >> is what's puzzling me, I never see the XML after that.
> >>
> >> I don't get any exceptions being thrown anywhere, so I don't think it's
> >> a failure of any kind. Our MessageWriter is registered to handle any
> >> type thrown at it. It basically uses XStream to stream out the beans
> >> into XML. It seems to work fine. If I set the HTTP status code to 200
> >> and return the exact same exception data, it gets streamed out properly
> >> all the way back to the client. I'm curious to what the difference is in
> >> execution path when I'm setting the HTTP status to a 400 or 500? I've
> >> tried following along in the debugger, but there are so many levels of
> >> calls that it's a little overwhelming. Is there some sort of error
> >> handler in the CXF framework that takes different paths depending on the
> >> value of the HTTP status code? Thanks,
> >>
> >> /Henrik
> >>
> >> On Mon, 2009-11-02 at 17:11 -0500, Sergey Beryozkin wrote:
> >> > Hi Henrik
> >> >
> >> >
> >> >
> >> > For some reasons I can only see your message in Archives, but not
> >> > Nabble.
> >> >
> >> >
> >> >
> >> > >>The handleResponse() method in
> >> > >>my filter gets called, but I've found that if I return any kind of
> >> > >>error, i.e. a category 400 or 500 type error, the XML that I'm
> >> > returning
> >> > >>as the content doesn't get rendered in the browser
> >> >
> >> > If one returns a custom Response from a filter, then its entity, if
> >> any,
> >> > will be
> >> > serialized by the available writers.
> >> >
> >> > So if you set a String instance as a custom entity and you happen to
> >> > have a custom message body writer which can
> >> > wrap Strings then the browser would show it as a plain text sequence.
> >> >
> >> > Starting from CXF 2.2.4 it is possible to indicate that writers have
> >> to
> >> > be ignored. In meantime, the best way would be to return
> >> > an object like ExceptionInfo which will be serialized by the
> >> appropriate
> >> > XML writer.
> >> >
> >> > Is it what might be happening in your case ?
> >> >
> >> > If you're thinking of doing JAXRS only then filters should do well.
> >> >
> >> > Cheers, Sergey
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
>

Re: Would like to send custom XML back whenever a 400 or 500 category error happens

by Sergey Beryozkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Henrik

A simple CustomOutFaultInterceptor has been added :

http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/CustomOutFaultInterceptor.java

it writes directly to HttpServletResponse but it could've used XMLStreamWriter simiularly to :

http://svn.apache.org/repos/asf/cxf/trunk/rt/bindings/xml/src/main/java/org/apache/cxf/binding/xml/interceptor/XMLFaultOutInterceptor.java


CustomOutFaultInterceptor  ahndles exceptions thrown from the (test)application code (see a BookStore test with /propogateexception4
in system tests) and from a faulty RequestFilter :

http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/FaultyRequestHandler.java

it uses a custom property just so that it does not interfere with other tests which test exceptions

hope it helps, Sergey


----- Original Message -----
From: "Henrik Martin" <henrik.martin@...>
To: <users@...>
Sent: Thursday, November 05, 2009 5:18 AM
Subject: Re: Would like to send custom XML back whenever a 400 or 500 category error happens


> Thanks Sergey. I'm interested in this topic. Please keep me posted on
> any progress you make on new features. I'll be happy to help out with
> testing etc. Cheers,
>
> /Henrik
>
> On Wed, 2009-11-04 at 10:05 +0000, Sergey Beryozkin wrote:
>> Hi Henrik
>>
>> > Hi Sergey. Thanks again for the response. I stepped through the
>> > JAXRSOutInterceptor in the debugger and found out that the content type
>> > for the Response I had created was "octet/stream" instead of
>> > "application/xml". Once I created the appropriate content type entry in
>> > the MultivaluedMap returned by getMetadata() method, everything worked.
>>
>> JAXRS spec requires "octet/stream" be set if no content type has been set by the user code (either implicitly by specifying
>> @Produces or returning a custom Response, etc)....Please see more comments below
>>
>> >
>> > While on that subject, is that the appropriate way of doing it? What I
>> > ended up doing was something like the code snippet below. Apologies for
>> > the bad formatting, I'm using Evolution to send the email...
>> >
>> > // "error" is our error placeholder bean sent back as the entity
>> > final Response newResponse = builder.entity(error.validate()).build();
>> > newResponse.getMetadata().putAll(oldResponse.getMetadata());
>> > final MultivaluedMap<String, Object> map = newResponse.getMetadata();
>> >
>> > if (! map.containsKey(HttpHeaders.CONTENT_TYPE))
>> > {
>> >  final List<Object> contentTypes = new ArrayList<Object>();
>> >  contentTypes.add("application/xml");
>> >  map.put(HttpHeaders.CONTENT_TYPE, contentTypes);
>> > }
>> > else
>> > {
>> >  final List<Object> contentTypes = map.get(HttpHeaders.CONTENT_TYPE);
>> >
>> >  if (! contentTypes.contains("application/xml"))
>> >  {
>> >    contentTypes.add("application/xml");
>> >  }
>> > }
>> >
>> > A little clumsy maybe, but I was trying to preserve whatever content
>> > types the original response had as well as making sure that the new
>> > response declares "application/xml". Any suggestions on how to clean
>> > this up and do it properly are appreciated. Anyway, after inserting this
>> > code snippet, things work all the way back to the browser, and I see the
>> > exception entity in XML form. Thanks,
>>
>> This code is fine, and indeed, it is importnat that the headers which might'be been set earlier on are not lost. Though you might
>> want to simplify it a bit, MultivaluedMap supports a putSingle() method, so you can do :
>>
>> final MultivaluedMap<String, Object> map = newResponse.getMetadata();
>> map.putSingle(HttpHeaders.CONTENT_TYPE, "application/xml");
>>
>> given that it is "application/xml" which is required in this case ?
>>
>> One thing I'm concerned a bit about is that if the generic exception reporting logic is done in a ResponseHandler and/or
>> RequestHandler filters then even normal non-exceptional requests or responses will go through them, so you probably do some kind
>> of
>> a check to see if it's an exceptional invocation or not...I don't think it affects in any measurable way the overall performance
>> but
>> it's worth mentioning that few more options are available (sorry for not mentioning them in the first place)...
>>
>> First, all the exceptions which have not been mapped to responses by registered providers will be propogated (or is it
>> 'propagated'
>> :-) ?)
>> to the container wrapped in ServletExceptions. So one other option is to register a simple ServletFilter which will only will
>> only
>> handle ServletExceptions and check the causes and write to the HttpServletResponse as needed.
>>
>> Another option is is to register a CXF out fault interceptor with the jaxrs:server. I'll be working on a test which will show how
>> to
>> do it. This fault interceptor will be executed only if the propogation has been disabled through a jaxrs:server property and if
>> no
>> matching ExceptionMappers are available. I'll let you know once the system test is ready.
>>
>> That said, I reckon using JAXRS filters should do well - may be I will add the support for the in/out  fault JAXRS filters too...
>>
>> thanks, Sergey
>>
>> >
>> > /Henrik
>> >
>> > On Tue, 2009-11-03 at 18:25 -0500, Sergey Beryozkin wrote:
>> >> Hi Henrik
>> >>
>> >> I reckon looking at the wire representation would really help in
>> >> figuring out what's going on. Also, can it be that say the XStream
>> >> writer needs to have some kind of close() method being called ?
>> >>
>> >> Please send a wget/browser request through a tcp trace utility and let
>> >> me know the details
>> >>
>> >> Thanks, Sergey
>> >>
>> >> -----Original Message-----
>> >> From: Henrik Martin [mailto:henrik.martin@...]
>> >> Sent: 03 November 2009 22:03
>> >> To: users@...
>> >> Subject: Re: Would like to send custom XML back whenever a 400 or 500
>> >> category error happens
>> >>
>> >> Sergey, thanks for the response. I should have given you a little more
>> >> detail. In my handleResponse() method, I do return a Response, which
>> >> contains something similar to your suggested ExceptionInfo. It's just a
>> >> Java bean containing some properties and some XStream annotations. When
>> >> I run everything in the debugger, I can see that my entity (containing
>> >> the exception information) gets handled by our MessageWriter, and proper
>> >> XML gets generated (I'm printing it out inside the MessageWriter). This
>> >> is what's puzzling me, I never see the XML after that.
>> >>
>> >> I don't get any exceptions being thrown anywhere, so I don't think it's
>> >> a failure of any kind. Our MessageWriter is registered to handle any
>> >> type thrown at it. It basically uses XStream to stream out the beans
>> >> into XML. It seems to work fine. If I set the HTTP status code to 200
>> >> and return the exact same exception data, it gets streamed out properly
>> >> all the way back to the client. I'm curious to what the difference is in
>> >> execution path when I'm setting the HTTP status to a 400 or 500? I've
>> >> tried following along in the debugger, but there are so many levels of
>> >> calls that it's a little overwhelming. Is there some sort of error
>> >> handler in the CXF framework that takes different paths depending on the
>> >> value of the HTTP status code? Thanks,
>> >>
>> >> /Henrik
>> >>
>> >> On Mon, 2009-11-02 at 17:11 -0500, Sergey Beryozkin wrote:
>> >> > Hi Henrik
>> >> >
>> >> >
>> >> >
>> >> > For some reasons I can only see your message in Archives, but not
>> >> > Nabble.
>> >> >
>> >> >
>> >> >
>> >> > >>The handleResponse() method in
>> >> > >>my filter gets called, but I've found that if I return any kind of
>> >> > >>error, i.e. a category 400 or 500 type error, the XML that I'm
>> >> > returning
>> >> > >>as the content doesn't get rendered in the browser
>> >> >
>> >> > If one returns a custom Response from a filter, then its entity, if
>> >> any,
>> >> > will be
>> >> > serialized by the available writers.
>> >> >
>> >> > So if you set a String instance as a custom entity and you happen to
>> >> > have a custom message body writer which can
>> >> > wrap Strings then the browser would show it as a plain text sequence.
>> >> >
>> >> > Starting from CXF 2.2.4 it is possible to indicate that writers have
>> >> to
>> >> > be ignored. In meantime, the best way would be to return
>> >> > an object like ExceptionInfo which will be serialized by the
>> >> appropriate
>> >> > XML writer.
>> >> >
>> >> > Is it what might be happening in your case ?
>> >> >
>> >> > If you're thinking of doing JAXRS only then filters should do well.
>> >> >
>> >> > Cheers, Sergey
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>>