Honestly, the EASIEST way to accomplish this, since you are using soap, is to add the SAAJOutInterceptor to the fault chain. Then, your interceptor would live right before it's "ending" interceptor and do:
message.getContext(SOAPMessage.class) to get the SAAJ model out. Since the SAAJ model implements the DOM interfaces, you can then feed that into an XSLT processor or similar to transform it and then set a new version back with the setContent call. Dan On Fri December 18 2009 4:13:29 am Gary Gregory wrote: > Hi All: > > I need to apply an XSL transformation to messages coming out of CXF (our > users configure what the XSL looks like.) For a normal (successful) > message, I have an interceptor (during Phase.PRE_MARSHAL) that uses the > DOM aspect of a message. That works great. BTW, I get to the DOM like > this: > > Node node = (Node) message.getContent(List.class).get(0); > > That seems brittle, is there a safer way to get to an aspect of the message > I can feed to javax.xml.transform? > > The real issue comes with fault messages because the fault chain uses an > XMLStreamWriter<http://java.sun.com/javase/6/docs/api/javax/xml/stream/XML > StreamWriter.html>. The fault chain looks like this: > > Chain org.apache.cxf.phase.phaseinterceptorch...@3015b303. Current flow: > setup [ServerPolicyOutFaultInterceptor] > prepare-send [MessageSenderInterceptor, Soap11FaultOutInterceptor] > pre-stream [LoggingOutInterceptor, XmlDeclOutInterceptor*, > StaxOutInterceptor] pre-protocol [WebFaultOutInterceptor, > SOAPHandlerFaultOutInterceptor] write [SoapOutInterceptor] > pre-marshal [LogicalHandlerFaultOutInterceptor] > marshal [Soap11FaultOutInterceptorInternal] > pre-stream-ending [StaxOutEndingInterceptor, > TransformOutFaultInterceptor*] prepare-send-ending > [MessageSenderEndingInterceptor] > > FYI, the interceptors marked with * are our own: > > * XmlDeclOutInterceptor forces an XML declaration to be written. > > * TransformOutFaultInterceptor is where I thought I could transform > the fault XML message. > > The > XMLStreamWriter<http://java.sun.com/javase/6/docs/api/javax/xml/stream/XML > StreamWriter.html> looks like this: > > [StreamWriter: class com.ctc.wstx.sw.SimpleNsStreamWriter, underlying > outputter: > com.ctc.wstx.sw.isolatin1xmlwri...@1125cf44<mailto:com.ctc.wstx.sw.ISOLati > n1xmlwri...@1125cf44> > > The com.ctc.wstx.sw.ISOLatin1XmlWriter wraps a > org.apache.cxf.io.CachedOutputStream, which in turns wraps: > > * currentStream - LoadingByteArrayOutputStream > > * flowThroughStream - AbstractHTTPDestination$WrappedOutputStream > > All of this to say that when the chain's interceptors are working with the > message's > XMLStreamWriter<http://java.sun.com/javase/6/docs/api/javax/xml/stream/XML > StreamWriter.html>, the bytes are cached and written to the wire. It is not > possible to catch the fault XML message and change it. > > The only thing I've come up with but not implemented yet would be to insert > an interceptor before the XML declaration is written and put the > XMLStreamWriter<http://java.sun.com/javase/6/docs/api/javax/xml/stream/XML > StreamWriter.html> into a temp spot in the message content map, then put a > new > XMLStreamWriter<http://java.sun.com/javase/6/docs/api/javax/xml/stream/XML > StreamWriter.html> on a byte array in its place. A pre-stream-ending > interceptor can take those bytes, apply XSL to them and then write them to > the original > XMLStreamWriter<http://java.sun.com/javase/6/docs/api/javax/xml/stream/XML > StreamWriter.html>, before putting the original > XMLStreamWriter<http://java.sun.com/javase/6/docs/api/javax/xml/stream/XML > StreamWriter.html> back in it original slot in the message content map. > > That seems like big old hack. > > Any ideas on a cleaner solution? > > Thank you, > Gary Gregory > Seagull Software > [email protected] > www.seagullsoftware.com > -- Daniel Kulp [email protected] http://www.dankulp.com/blog
