Sonic Connect (8.5) Web Service SOAP Faults

Posted by sedge on 07-Nov-2011 00:08

We have a WSDL for a Web Service with a single operation.

There are no Faults defined in the WSDL.

The Web Service is published by importing the Web Service as "Top-Down" and attaching the operation to an ESB Process.

That all works: I can invoke the web service from SOAP UI and ESB Process Tracking shows me that the process runs.

What do I need to do to have the Web Service return a SOAP Fault and HTTP Status Code 500 to the client?

(In my innocense) I expected to just Execute a Fault Step and Sonic would create a general SOAP Fault, but it doesn't happen.

Do I have to go through the hassle of adding a Fault to the WSDL (which was supplied to us by a trading partner)? I tried to do that, and follow the instructions in the Help for creating a SOAP Fault in an ESB Process that is exposed as a Web Service, but I haven't been able to get that to work either. If this is what I need to do, can someone help out with a working sample?

Thanks

Steve

All Replies

Posted by cwiseman on 10-Nov-2011 10:51

Stephen - I'm looking at this very same thing.  My WSDL doesn't specify faults either.

I think when I implemented this in a fault handler, I simply had to populate these header properties and push the message to the outbox (presumably to REPLY-To):

SonicESB.FaultName

SonicESB.FaultCode, and

SonicESB.FaultString

The SonicConnect service took care of using that data to create the SOAP Fault message for the response to the requestor.

Maybe someone could clarify.

Posted by wtam on 10-Nov-2011 13:40

It is a known issue in 8.5 (although I don't have a defect #) that Fault Handler eats "SonicESB.FaultName" header.  It is causing the problem that you saw.  You don't need to add Fault in WSDL. The bug has been fixed and the fix will likely be released as a patch.  In the meantime, you can workaround the defect by populating the headers as Chris has suggested.

Thanks.

Posted by sedge on 10-Nov-2011 17:41

Thanks for the response Chris and William.

William, presumably this fix will come out in a Service Pack soon?

Chris, I'm still struggling with this.I created a simple ESB Process that just uses the Prototype Service to use Mapping to set the SonicESB.Fault* headers from constants, then ends.

Nothing happens. All I get back to SoapUI is the request that I sent. Certainly not a SOAP Fault.

Your answer said: "and push the message to the outbox (presumably to REPLY-To):" What does that mean? I thought that the Process ending would go to REPLY-To?

Does your answer implies that I'll need a Java Service Type to create the headers then route the message? If so, can you show me the bit of code that routes the message?

Posted by cwiseman on 11-Nov-2011 09:19

Stephen - I implied to simply let the FaultHandler end - I suspect if it's a web service you're processing, the Exit endpoint is "Reply-To".

I stumbled across the same issue I found in 8.0.1.01 earlier just yesterday where an exception thrown in a process tied to a SonicConnect operation was not being trapped and handled by the designated FaultHandler process.  In researching this, I found text in the Web Services documentation for SonicConnect which says that a SOAP fault will only be generated from a Fault Step or a Fault Handler process.  Initially, I was trying to just set the SonicESB.FaultCode, SonicESB.FaultName, and SonicESB.FaultString head properties from within my try/catch block in the main process custom service.  That didn't work.  According to the documentation,  these header properties need to be set in a Fault Step or a Fault Handler in order to generate a SOAP Fault response.

Posted by sedge on 13-Nov-2011 22:56

Thanks Chris, that was really helpful.

I'm trying to follow these instructins from the help (Of course point 1 doesn't apply due to the aforementioned bug)

Returning a SOAP fault

When you expose an ESB process, you might need to return a SOAP fault in a particular scenario. To do this, define a Fault (for example, Fault0) on the Interface page of  the ESB process. For each fault, add a fault part (for example, Param1). This definition of fault will be written to  the generated WSDL file. It is recommended that you describe the structure of  the fault in an XSD file  and set the type of the fault accordingly. You must also set the Input and  the Output parameters on the Interface page.

In the ESB process definition, you need to define a decision logic (for  example, CBR) to decide when to return a SOAP fault.

To return a SOAP fault:

  1. Add a Fault step at the end of the branch from which a SOAP fault must be returned.

  2. Set the SonicESB.Fault.Name ESB message  header. The value for the header must be same as the fault name defined on the Interface page. You can  also set the Error Name runtime  parameter of the Fault step. If the header is not set, the SOAP fault detail will not be  generated.

  3. Set the message part with the same name as defined for the fault part on the Interface page  (for example, Param1). This will be used as the SOAP fault detail.

  4. Set the SonicESB.Fault.String ESB  message header. The value of the header will be the fault string of the SOAP fault. You can also set the Error Message runtime parameter of the Fault step.

  5. Set the SonicESB.Fault.Code ESB  message header. The value of the header will be the fault code of the SOAP fault. You can also set the Error Code runtime parameter of the Fault step.

But no matter what I try I only ever get the same SOAP Fault returned.

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode xmlns:ns1="http://www.progress.com/sonic/esb">ns1:ApplicationFault</faultcode>
<faultstring>Unknown application fault</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>

Which doesn't contain the Fault details I set, as described above.

Were you successful in getting any useful information (an actual error message) returned in the SOAP Fault?

Posted by cwiseman on 14-Nov-2011 10:56

Stephen,

I simply defined a FaultHandlerProcess and custom service and associated this Fault Hanlder with the SonicConnect Service step (inbound with response) or SonicConnect Client Service step (outbound).  By populating these header property values in this step, the SonicConnect service created the SOAP Fault response I was looking for if we ran into any issues.  Here's the redacted code from my custom service service() method in my FaultHandler:

        try {
           
            /*= DEBUG =*/ if ( this.getLogService().isDebugLog( log ) ) log.debug( "***** Fault Message Complete Headers:    " + MessageUtils.AllHeadersToString( a_XQEnvelope.getMessage() ) ) ;
           
            // Get the fault XML from the incoming message.
            msgContent = (String) a_XQEnvelope.getMessage().getPart( 0 ).getContent() ;
            /*= DEBUG =*/ if ( this.getLogService().isDebugLog( log ) ) log.debug( "***** Fault Message Content = [" + msgContent + "]" ) ;
           
            /*
             *  Set the message headers to the appropriate values for name, string, and code accordingly
             */
            a_XQEnvelope.getMessage().setStringHeader( XQConstants.HEADER_FAULT_NAME, "Processing Error" ) ;
            a_XQEnvelope.getMessage().setStringHeader( XQConstants.HEADER_FAULT_STRING, msgContent ) ;
            a_XQEnvelope.getMessage().setStringHeader( XQConstants.HEADER_FAULT_CODE, "500" ) ;
           
        } catch ( XQMessageException xqme ) {
            log.error( "Fault handled processing response", xqme ) ;
        } catch ( Exception e ) {
            log.error( "General exception", e ) ;
        }

This in fact created a SOAP Fault which was returned to a synchronous request/response requestor on a SonicConnect service.

Posted by sedge on 14-Nov-2011 15:48

Thanks Chris. Again very helpful.

Instead of a custom Java Service Type I was just using a Prototype Service with mapping.

Now the embarrassing bit... Yesterday, I worked on it for a couple of hours before I replied to your post asking for more information. I could only get back the generic fault and nothing I did would get the Fault information in the SonicESB.Fault.* headers. This morning, I tried it again and it works fine. I didn't need the custom service, just need to make sure the SonicESB.Fault.Name is there.

Regards

Steve

Posted by cwiseman on 21-Nov-2011 10:09

Glad it worked out.  Thanks Stephen.

Posted by cwiseman on 05-Dec-2011 13:14

Is there any difference in the implementation web service operations and considerations that must be taken to return SOAP Faults when the operations could be request/response or one-way oeprations?

When a WSDL contains request/response operatons, the default endpoints for the SonicConnect service are an entry endpoint, REPLY_TO for both exit endpoint and fault endpoint, and some default RME endpoint for the RME endpoint.

For the one-way operations, if the process which implements the operation has a REPLY_TO exit endpoint, the framework throws an XQEndpoint exception indicating the JMSReplyTo is not populated.  However, there still may be a case where a SOAP Fault needs to be returned, even for a one-way web service operation.

So, should there be any difference in the fault handling in the process/service implementation to catch exceptions and set the SonicESB.Fault.Name, Code, and String header properties for request/response vs one-way?

Posted by sedge on 05-Dec-2011 15:20

Hi Chris

I've been learning a lot about one-way web services over the last few months and I now know enough to avoid using them when I can. The specification for one-way Web Services makes them just that. According to the standards, the client for a one-way service just sends the message and assumes it got there, and therefore cannot trap a SOAP Fault. Likewise, a published Web Service does not expect to send a response. In Sonic Connect this translates to the problem you saw.  I've seen it too.

Having been stuck with some legacy one-way services my approach has been to turn the one-way web service into a two-way web service, with an empty response. Seems to work a treat as long as the guy at the other end is also treating it as a two-way service. I've attached one of my doctored WSDLs so you can see how it looks.

HTH

Steve

Posted by cwiseman on 07-Dec-2011 11:01

Stephen,

What you're saying appears accurate with respect to the one-way specification.  The problem is that even with the one-way request from a client, if the server which publishes the one-way operation can't process the request - for whatever reason - then perhaps something other than a 200 OK code should be returned.  It's not uncommon to need to return a 500 type error to the client if the request cannot be processed.  That's effectively all I am attempting to do with handling a SOAP Fault situation on the one-way services.

I'm probably going to make the assumption that if the SonicConnect Service will return a 200 OK or  202 Accepted code to the client for a one-way operation, that I will not need to populate the headers required to generate a SOAP fault response to the client.  I was using these headers to try and generate a 500 type code response to the client.

Thanks,

Chris

Posted by sedge on 07-Dec-2011 22:18

Hi Chris

It sounds as if, like us, you were supplied with a WSDL that you have no control over and specified a one-way operation. In our case the supplier provided a one-way WSDL but had actually implemented it as two-way, expecting an empty Soap Envelope and HTTP 202 or 200 response code (at least that's what I think they did because they seem able to trap the 500 and SOAP Fault).  In our previous .NET incarnation I simply specified the Web Service operation as oneway=false and it all worked OK, and sent an empty response. That's how I figured out how to change the WSDL.

If you have the option I'd negotiate a change so that the web service is two-way, with a "canned" acknowledgement. If, like us, you can't my approach was to implement the two-way service as I showed you and treat it as the client's  problem if they can't trap the SOAP Fault. I'm using CXF Interceptors to trap and save all incoming and outgoing SOAP Envelopes so we have evidence of what we send and receive through every web service exchange.

BTW: This change for the two-way service works just as well if you are the client and allows Sonic to trap a SOAP fault from their Web Service.

Regards

Steve

This thread is closed