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
> > >
> >
>