I'll see if I can create a standalone test... in the meantime I am trying to see if my fix breaks 2.2.6-SNAPSHOT tests.
Gary > -----Original Message----- > From: Daniel Kulp [mailto:[email protected]] > Sent: Tuesday, December 22, 2009 10:06 > To: [email protected] > Cc: Gary Gregory > Subject: Re: Inflexible fault interceptor chain? > > > Can you create a small test case and attach to a jira? > > This definitely sounds like bug of some sort. When I redid the > Provider > based services, I noticed that strange code in the StaxOutInterceptor > as well > and tried to remove it. However, that broke some of the JAX-WS tck > tests. > I don't remember the exact reason. I think it has something to do > with > faults thrown from the logical or soap handlers on the outgoing chain > needed > some strange and wacky processing. Don't really remember. > > If we can get your test case, we may be able to get it to work better. > > That said, you could probably write your own interceptor (you seem to > be good > at that :-) that would run on the fault chain prior to the SAAJOut and > have > it remove the SAAJ model from the message. You may need to trace > through a > couple other interceptors (like SoapOutInterceptor) to see if other > properties > need to be removed/reset. > > Dan > > > On Mon December 21 2009 8:12:50 pm Gary Gregory wrote: > > Hello Dan and all, > > > > Ok, the SAAJOutInterceptor solution almost worked. The behavior I > describe > > below is the same in CXF 2.2.4 and 2.2.6-SNAPSHOT (as of Saturday's > > build). I am not on 2.2.5 due to some bugs that are fixed in 2.2.6. > The > > debugging information I gathered for this message is with 2.2.4. > > > > I have two scenarios, one works and one does not with the > > SAAJOutInterceptor solution. > > > > If a Fault is thrown by a custom interceptor at a certain point in > the > > output chain, the wrong SOAP XML is generated, specifically no SOAP > fault > > XML elements are generated. Let me start by showing what works and > why > > before showing what does not and why. > > > > In the first scenario, which works, a SoapFault is thrown by our > provider's > > invoke(SOAPMessage) method under certain conditions, basically if > our > > server detects certain errors. Our provider looks like this: > > > > @WebServiceProvider > > @ServiceMode(value = Service.Mode.MESSAGE) > > public static class LdeWebServiceProvider implements > Provider<SOAPMessage> > > { @Override > > public SOAPMessage invoke(SOAPMessage soapRequest) { > > ... > > throw new SoapFault("Our message", > > Soap11.getInstance().getReceiver()); } > > } > > > > In SAAJOutInterceptor.handleMessage, the local variable saaj is null, > so > > the code path taken builds a SOAP message from scratch and plugs in > a > > W3CDOMStreamWriter. All of the interceptors then write to > > W3CDOMStreamWriter instead of the default XMLStreamWriter which > normally > > caches and writes to the HTTP wire. The W3CDOMStreamWriter allows me > to > > transform the DOM before it gets on the wire. Great stuff, it works. > > > > In the second scenario, I test our output feature where in addition > to an > > optional transformation, we have custom interceptors to do optional > XML > > validation before and after the XML transformation. After our > provider > > successfully processed a message, the output chain processing kicks > in and > > looks like this: > > > > Chain org.apache.cxf.phase.phaseinterceptorch...@c375934. Current > flow: > > setup [PolicyOutInterceptor] > > pre-logical [SwAOutInterceptor, SoapHeaderOutFilterInterceptor] > > post-logical [SoapPreProtocolOutInterceptor] > > prepare-send [MessageSenderInterceptor, MessageModeOutInterceptor] > > pre-stream [LoggingOutInterceptor, XmlDeclOutInterceptor*, > > AttachmentOutInterceptor, StaxOutInterceptor] pre-protocol > > [MessageModeOutInterceptorInternal, SAAJOutInterceptor, > > SOAPHandlerInterceptor, OurWSS4JOutInterceptor] write > [SoapOutInterceptor] > > pre-marshal [LogicalHandlerOutInterceptor, > ValidatingOutInterceptor*, > > TransformOutInterceptor*, ValidatingOutInterceptor*] marshal > > [BareOutInterceptor] > > write-ending [SoapOutEndingInterceptor] > > pre-protocol-ending [SAAJOutEndingInterceptor] > > pre-stream-ending [StaxOutEndingInterceptor] > > prepare-send-ending [MessageSenderEndingInterceptor] > > > > The interceptors marked with * are mine: > > - XmlDeclOutInterceptor forces the XML declaration to be written. > > - ValidatingOutInterceptor validates XML > > - TransformOutInterceptor transforms XML > > - ValidatingOutInterceptor validates XML > > > > The problem occurs if XML validation fails (the first validation in > this > > test). > > > > When the XML validation fails, an exception thrown, caught, and re- > thrown > > as a fault. > > > > At the start of fault processing, the chain when SAAJOutInterceptor > is > > called looks like this: > > > > Chain org.apache.cxf.phase.phaseinterceptorch...@77c16c5f. Current > flow: > > setup [ServerPolicyOutFaultInterceptor] > > prepare-send [MessageSenderInterceptor, Soap11FaultOutInterceptor] > > pre-stream [LoggingOutInterceptor, XmlDeclOutInterceptor*, > > StaxOutInterceptor] pre-protocol [WebFaultOutInterceptor, > > SAAJOutInterceptor, SOAPHandlerFaultOutInterceptor] write > > [SoapOutInterceptor] > > pre-marshal [LogicalHandlerFaultOutInterceptor] > > marshal [Soap11FaultOutInterceptorInternal] > > pre-protocol-ending [TransformOutFaultInterceptor*] > > prepare-send-ending [MessageSenderEndingInterceptor] > > > > The interceptors marked with * are mine: > > - XmlDeclOutInterceptor forces the XML declaration to be written. > > - TransformOutFaultInterceptor validates XML > > > > When I step through this SAAJOutInterceptor invocation, the saaj > variable > > is NOT null, so the code path taken is different from what I > described > > above. Instead of a W3CDOMStreamWriter, a dummy XMLStreamWriter is > created > > that throws away whatever is written to it: > > > > //as the SOAPMessage already has everything in place, we > do not > > need XMLStreamWriter to write //anything for us, so we just set > > XMLStreamWriter's output to a dummy output stream. XMLStreamWriter > > origWriter = message.getContent(XMLStreamWriter.class); > > message.put(ORIGINAL_XML_WRITER, origWriter); > > > > XMLStreamWriter dummyWriter = > > StaxUtils.createXMLStreamWriter(new OutputStream() { public void > write(int > > b) throws IOException { > > } > > public void write(byte b[], int off, int len) > throws > > IOException { } > > }); > > message.setContent(XMLStreamWriter.class, dummyWriter); > > > > No wonder I get no SOAP fault information back, I get: > > > > <?xml version='1.0' encoding='ISO-8859-1'?> > > <SOAP-ENV:Envelope > > xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > > xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP- > ENV:Header > > xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> > <ais:requestID > > > xmlns:ais="http://com.seagullsw.appinterface/AppInterfaceServer">{c0a80 > 102 > > -00ce16ad0000010e75da25398002}</ais:requestID> </SOAP-ENV:Header> > > <SOAP-ENV:Body xmlns:SOAP- > ENV="http://schemas.xmlsoap.org/soap/envelope/" > > /> </SOAP-ENV:Envelope> > > > > Is this a bug? Why would there be a dummy writer put in place? Is > there > > another CXF way to do this? > > > > Thank you, > > Gary > > > > > -----Original Message----- > > > From: Gary Gregory > > > Sent: Friday, December 18, 2009 18:11 > > > To: 'Daniel Kulp'; [email protected] > > > Subject: RE: Inflexible fault interceptor chain? > > > > > > Ok, that worked! > > > > > > Thank you Dan, > > > Gary > > > > > > > -----Original Message----- > > > > From: Daniel Kulp [mailto:[email protected]] > > > > Sent: Friday, December 18, 2009 07:33 > > > > To: [email protected] > > > > Cc: Gary Gregory; Lee Breisacher; Nikolay Glazyrin > > > > Subject: Re: Inflexible fault interceptor chain? > > > > > > > > > > > > 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.ISOL > > > > > > > ati > > > > > > > > > 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 > > > > -- > Daniel Kulp > [email protected] > http://www.dankulp.com/blog
