Just FYI, here is a commit to do with the optional support for decoupled faults in case of oneway requests :
http://svn.apache.org/viewvc?rev=1005784&view=rev See also CXF-3052. If users find that they need to bypass the restrictions around dealing with oneway requests and decoupled faults then they can simply set a contextual boolean property "org.apache.cxf.ws.addressing.oneway.decoupled_fault_support" to true or explicitly register a OneWayDecoupledFaultHandler via annotations, programmatically, etc. Hope this is a reasonable compromise cheers, Sergey On Tue, Oct 5, 2010 at 6:16 PM, Sergey Beryozkin <[email protected]>wrote: > Hi > > I decided to go ahead and experiment with implementing a support for > decoupled faults for oneway requests so that we at least could tell users > how that can be done using custom interceptors if that is what is needed in > a particular case. > Originally I was planning just to have a MAPCodec interceptor dealing with > posting a fault in its handleFault callback due to PhaseInterceptorChain not > delegating to the faultObserver in case of oneways. That is not the most > elegant solution though given that handleFault is meant to notify that a > given in/out interceptor should do some cleanup. Additionally, it is not > quite clear how to dynamically setup a fault interceptor chain so that the > fault can be properly serialized and sent. > > So Dan suggested that PhaseInterceptorChain gets updated so that a oneway > check is done after the unwind() is called on the current chain. Next, the > custom in or out interceptor would trick PhaseInterceptorChain by chnaging > the oneway status on the exchange to a two way one and also set up a Conduit > with the destination address pointing to a faultTo EPR address. > > Here is a sample code : > > public void handleFault(SoapMessage message) { > if (!message.getExchange().isOneWay()) { > // do some two way specific cleanup > } else if (!ContextUtils.isRequestor(message)) { > Exchange exchange = message.getExchange(); > Message inMessage = exchange.getInMessage(); > final AddressingPropertiesImpl maps = > ContextUtils.retrieveMAPs(inMessage, false, false, true); > final EndpointReferenceType reference = maps.getFaultTo(); > > if (maps != null && > !ContextUtils.isGenericAddress(exReference)) { > exchange.setOneWay(false); > > > // set the new Conduit > final EndpointInfo ei = > exchange.get(Endpoint.class).getEndpointInfo(); > exchange.setDestination(new Destination() { > public EndpointReferenceType getAddress() { > return reference; > } > public Conduit getBackChannel(Message inMessage, > Message partialResponse, > EndpointReferenceType > address) throws IOException { > > Bus bus = inMessage.getExchange().get(Bus.class); > ConduitInitiator conduitInitiator > = > bus.getExtension(ConduitInitiatorManager.class) > > .getConduitInitiatorForUri(reference.getAddress().getValue()); > if (conduitInitiator != null) { > Conduit c = > conduitInitiator.getConduit(ei,reference); > // ensure decoupled back channel input stream > is closed > c.setMessageObserver(new MessageObserver() { > public void onMessage(Message m) { > InputStream is = > m.getContent(InputStream.class); > if (is != null) { > try { > is.close(); > } catch (Exception e) { > // ignore > } > } > } > }); > return c; > } > return null; > } > public MessageObserver getMessageObserver() { > return null; > } > public void shutdown() { > } > public void setMessageObserver(MessageObserver > observer) { > } > }); > > } > > } > } > > This code to do with setting up a destination is complicated but is > boilerplate.... > > > The end result is that a fault is processed properly by a fault observer > even for oneways and is forwarded to the faultTo decoupled address. And an > empty SOAP response is sent to ReplyTo as well. > > So - I'm assuming it is safe enough to update PhaseInterceptorChain so that > fault interceptors are involved even for oneway requests failing for > whatever reasons - a fault can be sent to a decoupled destination even as > part of some custom protocol. > > I'm presuming that updating a MapCodec with the above code is not something > which we can do right now, right, due to the compliance concerns ? In this > case a custom interceptor can be added if needed > > cheers, Sergey > > > > On Fri, Oct 1, 2010 at 2:31 PM, Oliver Wulff <[email protected]>wrote: > >> Hi Sergey >> >> IMHO, if you use WSDL 1.1 and want to return a fault you must define an >> empty outpt message - even it's just a kind of place holder. >> >> >> If you use FaultTo and ReplyTo the anonymous EPR, the service send the >> response on the back channel. >> >> Oli >> >> ________________________________________ >> Von: Sergey Beryozkin [[email protected]] >> Gesendet: Freitag, 1. Oktober 2010 13:42 >> An: [email protected] >> Cc: Daniel Kulp >> Betreff: Re: Interceptor chains, one way requests, WSA FaultTo >> >> Hi Oli, >> >> thanks for the clarifications, >> >> I'm wondering, is it indeed "Robust In-Only" case that we are talking >> about >> here : >> >> >> http://www.pacificspirit.com/Authoring/async/async-scenarios.html#twoway-robust-inonly-b >> >> so we have a client sending a oneway request, getting a 202 ACK, and then >> possibly getting a fault back at some local endpoint. But CXF does not >> support WSDL 2.0... >> >> cheers, Sergey >> >> On Fri, Oct 1, 2010 at 8:03 AM, Oliver Wulff <[email protected] >> >wrote: >> >> > Hi Sergey >> > >> > I thought that wsdl 1.1 specification requires that a fault message is >> used >> > only in combination with an output message. >> > WSDL 2.0 defines the MEP called "Robust In-Only" where you could define >> an >> > input and a fault message. >> > >> > I'm only aware of WS-ReliableMessaging where a soap envelope can be >> > returned for a one-way message to send the acknowledges back where soap >> body >> > itself is empty. This is only valid if the Anonymous epr is used for >> AcksTo >> > element. >> > >> > Oli >> > >> > ________________________________________ >> > Von: Sergey Beryozkin [[email protected]] >> > Gesendet: Freitag, 1. Oktober 2010 00:19 >> > An: Daniel Kulp >> > Cc: [email protected] >> > Betreff: Re: Interceptor chains, one way requests, WSA FaultTo >> > >> > Hi >> > >> > I'm wondering, does Fault qualify as a response in case of one way >> > requests. >> > >> > I'm thinking that may be specifying a decoupled FaultTo as part of >> oneways >> > is an attempt to find out if a given oneway request ultimately succeeded >> or >> > not. >> > >> > Thus I'm not sure what the right answer is here. It's part of the >> advanced >> > WSA-related transactions framework test suite but if it is a valid test >> - I >> > do not know... >> > >> > But I guess that code I'm prototyping may also help in cases where we >> have >> > a >> > 2 way request and decoupled ReplyTo and FaultTo values. At the moment, >> the >> > fault will be sent to the decoupled ReplyTo (because >> > ContextUtils.rebaseUtils uses replyTo to rebase)... >> > >> > We then can decide if we want that code to execute in case of oneways or >> > not. >> > >> > cheers, Sergey >> > >> > >> > On Thu, Sep 30, 2010 at 7:45 PM, Daniel Kulp <[email protected]> wrote: >> > >> > > >> > > My question is: is this even a valid use case? >> > > >> > > According to the WS-I Basic Profile: >> > > >> > > >> > > R2714 For one-way operations, an INSTANCE MUST NOT return a HTTP >> response >> > > that >> > > contains an envelope. Specifically, the HTTP response entity-body must >> be >> > > empty. >> > > >> > > R2750 A CONSUMER MUST ignore an envelope carried in a HTTP response >> > message >> > > in >> > > a one-way operation. >> > > >> > > R2727 For one-way operations, a CONSUMER MUST NOT interpret a >> successful >> > > HTTP >> > > response status code (i.e., 2xx) to mean the message is valid or that >> the >> > > receiver would process it. >> > > >> > > One-way operations do not produce SOAP responses. Therefore, the >> Profile >> > > prohibits sending a SOAP envelope in response to a one-way operation. >> > > >> > > >> > > Thus, producing a Fault as part of processing a One-Way operation >> would >> > be >> > > against the spec. >> > > >> > > >> > > Dan >> > > >> > > >> > > >> > > >> > > On Thursday 30 September 2010 1:32:11 pm Sergey Beryozkin wrote: >> > > > Hi >> > > > >> > > > I'm looking at the following issue. >> > > > A oneway request with a decoupled WSA FaultTo address is processed >> on >> > the >> > > > server side and then a fault is thrown. >> > > > MapCodec and MapAggregator interceptors are not handling this case >> at >> > the >> > > > moment. >> > > > >> > > > Eoghan clarified how ContextUtils.rebaseAddress used by >> MapAggregator >> > > > works. Particularly, a partial response is sent back asap, and then >> > > > an out message is prepared such that a normal response is sent to >> the >> > > > decoupled ReplyTo (during this process an out interceptor chain is >> > > > created). >> > > > >> > > > The question is how to forward a fault to the decoupled address in >> case >> > > of >> > > > oneway requests and particularly, how to build a proper chain. >> > > > I'm prototyping the following code in MapCodec.handleFault() : >> > > > >> > > > // MapCodec::handleFault(Message message) >> > > > if (oneWay and !isRequestor()) >> > > > { >> > > > Exchange exchange = message.getExchange(); >> > > > >> > > > // we need the input message so that we can get the >> WSA >> > > > properties from it >> > > > >> > > > Message inMessage = exchange.getInMessage(); >> > > > AddressingPropertiesImpl maps = >> > > > ContextUtils.retrieveMAPs(inMessage, false, >> false, >> > > > true); if (maps != null && >> > > > !ContextUtils.isGenericAddress(maps.getFaultTo())) { >> > > > >> > > > // boilerplate code for getting a backChannel, using >> > > > inMessage >> > > > Destination target = inMessage.getDestination(); >> > > > exchange.setOutMessage(message); >> > > > >> > > > Conduit backChannel = >> target.getBackChannel(inMessage, >> > > > >> > message, >> > > > >> > > > maps.getFaultTo()); >> > > > >> > > > // Set up the chain >> > > > InterceptorChain chain = >> > > > OutgoingChainInterceptor.getOutInterceptorChain(exchange); >> > > > message.setInterceptorChain(chain); >> > > > >> > > > exchange.put(ConduitSelector.class, >> > > > new >> > > > PreexistingConduitSelector(backChannel, >> > > > >> > > > exchange.get(Endpoint.class))); >> > > > >> > > > chain.doIntercept(message) >> > > > } >> > > > >> > > > >> > > > The question is basically how to set up an out chain properly to >> deal >> > > with >> > > > delivering a fault message in case of oneway requests. >> > > > >> > > > Some clarifications would help >> > > > thanks, Sergey >> > > >> > > -- >> > > Daniel Kulp >> > > [email protected] >> > > http://dankulp.com/blog >> > > >> > >> > >
