You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cxf.apache.org by Przemysław Bielicki <pb...@gmail.com> on 2013/12/12 15:08:29 UTC

Custom fault response (JAX-WS)

Hi,

I spent couple of last days, debugging CXF and trying to intercept/inject
custom fault response but I give up. I need your help guys.

I am currently getting this kind of response when an exception is thrown
(either in In or Out interceptor).

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <soap:Fault>
         <faultcode>blahblah</faultcode>
         <faultstring>exception message</faultstring>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

 I would like to send a custom response as (example):

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<MessageHeader>
....
</MessageHeader>
</soap:Header>
<soap:Body>
     <Response>
            <Data>
            <Status>Failure</Status>
            <ErrorMessage></ErrorMessage>
     </Response>
   </soap:Body>
</soap:Envelope>

How can I do it in the easiest way? Let's assume that my Response and
MessageHeader are Java beans with JAXB annotations so I can use JAXB
binding.

The only thing I succeeded at the moment is to add custom header but I
can't help changing the Body part.

Anyway, customizing the header part was not obvious:

@Override
public void handleFault(SoapMessage message) {
   ...
   message.getExchange().setOutMessage(inMessage);
   Map<String, List<String>> headers = (Map<String, List<String>>)
inMessage.get(Message.PROTOCOL_HEADERS);
   headers.remove("Content-Length");
   Header header = new Header(Constants.HEADER_QNAME, msgHeader,
jaxbBinding);
   message.getHeaders().add(header);
}

I had to clean "Content-Length" header (otherwise CXF was copying the value
of this header from the HTTP request and my response was cut in the middle
as the length was wrong) and set inMessage as outMessage

Many thanks for help.
Przemyslaw Bielicki

Re: Custom fault response (JAX-WS)

Posted by Przemysław Bielicki <pb...@gmail.com>.
Hi Andrei,

thanks a lot for your answer. In my case I don not care about the SOAP
standard.

I will try a second solution.

Thx again,
Przemyslaw


On Tue, Dec 17, 2013 at 9:37 AM, Andrei Shakirin <as...@talend.com>wrote:

> Hi,
>
> I see two possible cases here:
>
> a) If you would like to keep the standard SOAP Fault and just customize
> the faultcode, faultstring, details, the following interceptor can be
> configured in out fault chain:
>
> public class CustomSoapFaultInterceptor extends
> AbstractPhaseInterceptor<SoapMessage> {
>
>         public CustomSoapFaultInterceptor() {
>                 super(Phase.WRITE);
>         }
>
>         @Override
>         public void handleMessage(SoapMessage message) throws Fault {
>                 Exception e = message.getContent(Exception.class);
>                 if (e instanceof Fault) {
>                         Fault fault = (Fault) e;
>                         fault.setMessage("This is a critical fault");
>                         fault.setFaultCode(new QName("ns",
> "CriticalFault"));
>                         try {
>                                 DocumentBuilder builder = getBuilder();
>                                 Document doc = builder.parse(new
> ByteArrayInputStream("<detail><critical>critical
> details</critical></detail>".getBytes()));
>                                 fault.setDetail(doc.getDocumentElement());
>                         } catch (Exception e1) {
>                                 System.out.println("Cannot build detail
> element: " + e.getMessage());
>                         }
>                 }
>         }
> ...
> }
>
> b) If you would like to replace SOAP fault with normal SOAP message, you
> likely should replace the fault with SOAPMessage in message content:
> http://stackoverflow.com/questions/8066474/how-to-transform-soapfault-to-soapmessage-via-interceptor-in-cxf
>
>
> Regards,
> Andrei.
>
> > -----Original Message-----
> > From: Przemyslaw Bielicki [mailto:pbielicki@gmail.com]
> > Sent: Donnerstag, 12. Dezember 2013 16:50
> > To: dev@cxf.apache.org
> > Subject: Re: Custom fault response (JAX-WS)
> >
> > OK I found a workaround that works but it's very obscure:
> >
> > @Override
> > public void handleFault(SoapMessage message) {
> >   ...
> >   Marshaller marshaller =
> > JAXBContext.newInstance(MessageHeader.class).createMarshaller();
> >   SOAPMessage soap = message.getContent(SOAPMessage.class);
> >   soap.getSOAPHeader().removeContents();
> >   marshaller.marshal(msgHeader, soap.getSOAPHeader());
> >   HttpServletResponse response = (HttpServletResponse)
> > message.get(AbstractHTTPDestination.HTTP_RESPONSE);
> >   message.setContent(OutputStream.class, response.getOutputStream());
> >   Exception e = message.getContent(Exception.class);
> >   soap.getSOAPBody().removeContents();
> >   marshaller.marshal(OneAXmlUtil.buildErrorList(msgHeader, e),
> > soap.getSOAPBody());
> >   soap.writeTo(response.getOutputStream());
> >   response.getOutputStream().close();
> >
> > Is there any "nice" way to do this?
> >
> > Cheers,
> > Przemyslaw
> >
> >
> >
> > --
> > View this message in context: http://cxf.547215.n5.nabble.com/Custom-
> > fault-response-JAX-WS-tp5737771p5737775.html
> > Sent from the cxf-dev mailing list archive at Nabble.com.
>

RE: Custom fault response (JAX-WS)

Posted by Andrei Shakirin <as...@talend.com>.
Hi,

I see two possible cases here:

a) If you would like to keep the standard SOAP Fault and just customize the faultcode, faultstring, details, the following interceptor can be configured in out fault chain:
 
public class CustomSoapFaultInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
	
	public CustomSoapFaultInterceptor() {
		super(Phase.WRITE);
	}

	@Override
	public void handleMessage(SoapMessage message) throws Fault {
		Exception e = message.getContent(Exception.class);
		if (e instanceof Fault) {
			Fault fault = (Fault) e;
			fault.setMessage("This is a critical fault");
			fault.setFaultCode(new QName("ns", "CriticalFault"));
			try {
				DocumentBuilder builder = getBuilder();
				Document doc = builder.parse(new ByteArrayInputStream("<detail><critical>critical details</critical></detail>".getBytes()));
				fault.setDetail(doc.getDocumentElement());
			} catch (Exception e1) {
				System.out.println("Cannot build detail element: " + e.getMessage());
			}
		}
	}
...
}

b) If you would like to replace SOAP fault with normal SOAP message, you likely should replace the fault with SOAPMessage in message content: http://stackoverflow.com/questions/8066474/how-to-transform-soapfault-to-soapmessage-via-interceptor-in-cxf


Regards,
Andrei.

> -----Original Message-----
> From: Przemyslaw Bielicki [mailto:pbielicki@gmail.com]
> Sent: Donnerstag, 12. Dezember 2013 16:50
> To: dev@cxf.apache.org
> Subject: Re: Custom fault response (JAX-WS)
> 
> OK I found a workaround that works but it's very obscure:
> 
> @Override
> public void handleFault(SoapMessage message) {
>   ...
>   Marshaller marshaller =
> JAXBContext.newInstance(MessageHeader.class).createMarshaller();
>   SOAPMessage soap = message.getContent(SOAPMessage.class);
>   soap.getSOAPHeader().removeContents();
>   marshaller.marshal(msgHeader, soap.getSOAPHeader());
>   HttpServletResponse response = (HttpServletResponse)
> message.get(AbstractHTTPDestination.HTTP_RESPONSE);
>   message.setContent(OutputStream.class, response.getOutputStream());
>   Exception e = message.getContent(Exception.class);
>   soap.getSOAPBody().removeContents();
>   marshaller.marshal(OneAXmlUtil.buildErrorList(msgHeader, e),
> soap.getSOAPBody());
>   soap.writeTo(response.getOutputStream());
>   response.getOutputStream().close();
> 
> Is there any "nice" way to do this?
> 
> Cheers,
> Przemyslaw
> 
> 
> 
> --
> View this message in context: http://cxf.547215.n5.nabble.com/Custom-
> fault-response-JAX-WS-tp5737771p5737775.html
> Sent from the cxf-dev mailing list archive at Nabble.com.

Re: Custom fault response (JAX-WS)

Posted by Przemyslaw Bielicki <pb...@gmail.com>.
OK I found a workaround that works but it's very obscure:

@Override
public void handleFault(SoapMessage message) {
  ...
  Marshaller marshaller =
JAXBContext.newInstance(MessageHeader.class).createMarshaller();
  SOAPMessage soap = message.getContent(SOAPMessage.class);
  soap.getSOAPHeader().removeContents();
  marshaller.marshal(msgHeader, soap.getSOAPHeader());
  HttpServletResponse response = (HttpServletResponse)
message.get(AbstractHTTPDestination.HTTP_RESPONSE);
  message.setContent(OutputStream.class, response.getOutputStream());
  Exception e = message.getContent(Exception.class);
  soap.getSOAPBody().removeContents();
  marshaller.marshal(OneAXmlUtil.buildErrorList(msgHeader, e),
soap.getSOAPBody());
  soap.writeTo(response.getOutputStream());
  response.getOutputStream().close();

Is there any "nice" way to do this?

Cheers,
Przemyslaw



--
View this message in context: http://cxf.547215.n5.nabble.com/Custom-fault-response-JAX-WS-tp5737771p5737775.html
Sent from the cxf-dev mailing list archive at Nabble.com.