Page 1 of 3 123 LastLast
Results 1 to 10 of 21

Thread: Wanting to return the message from a custom Exception as a SOAP Fault string

  1. #1
    Join Date
    Jul 2006
    Location
    Plano, TX
    Posts
    3

    Default Wanting to return the message from a custom Exception as a SOAP Fault string

    I have wired the bean ...
    Code:
    <bean id="endpointExceptionResolver" class="org.springframework.ws.soap.endpoint.SoapFaultMappingExceptionResolver">
            <property name="defaultFault">
                <value>RECEIVER,Server error</value>
            </property>
            <property name="exceptionMappings">
            	<props>
            		<prop key="org.springframework.oxm.UnmarshallingException">SENDER,Invalid request</prop>
            		<prop key="org.springframework.oxm.ValidationFailureException">SENDER,Invalid request</prop>
            		<prop key="com.company.exception.DateNotFoundException">RECEIVER,Date not Found in Launch Calendar</prop>
                             <prop key="com.company.exception.LockdownException">RECEIVER,Site is in lockdown.</prop>
            		      	</props>
            </property>
        </bean>


    My goal is to get the message inside my custom exception objects and send that message back as the faultstring. How can I do this?

  2. #2
    Join Date
    Jul 2005
    Location
    Rotterdam, the Netherlands
    Posts
    1,562

    Default

    You could use the SimpleSoapExceptionResolver, which uses the exception message as a faultstring.
    Arjen Poutsma

    Spring Web Services Dev Lead
    Please read the FAQ

  3. #3
    Join Date
    Aug 2006
    Posts
    13

    Default

    I've worked with both SoapFaultMappingExceptionResolver and SimpleSoapExceptionResolver, and they do what they're supposed to do: turn an Exception into a fairly simple SOAP Fault. I've wanted to include more structure than a simple message in some Faults, though (It's all about the XML...) and it hasn't been as easy as I had hoped.

    Working with org.springframework.ws.soap.SoapFault and its friends (SoapFaultDetail, SoapFaultDetailElement) it looks like I can only add simple text elements to the Fault detail. I've played with setting the text content to a string containing the XML that I want to see in the fault details, but that has issues (and just seems wrong).

    Is there something I'm missing, like
    a) some other way to add structure to the details, or
    b) it's a Bad Thing(tm) to use anything but simple text details in a fault?

    Thanks for any help.

  4. #4
    Join Date
    Jul 2005
    Location
    Rotterdam, the Netherlands
    Posts
    1,562

    Default

    Quote Originally Posted by wlsmith
    I've worked with both SoapFaultMappingExceptionResolver and SimpleSoapExceptionResolver, and they do what they're supposed to do: turn an Exception into a fairly simple SOAP Fault. I've wanted to include more structure than a simple message in some Faults, though (It's all about the XML...) and it hasn't been as easy as I had hoped.

    Working with org.springframework.ws.soap.SoapFault and its friends (SoapFaultDetail, SoapFaultDetailElement) it looks like I can only add simple text elements to the Fault detail. I've played with setting the text content to a string containing the XML that I want to see in the fault details, but that has issues (and just seems wrong).
    A SOAP 1.1 Fault has a qname code, a faultstring, an actor and a detail. You can add multiple detail elements, as you can see here. In Spring-WS, you can set these with setters. You might have to cast the SoapFault to a Soap11Fault though, if you need specific functionality. You can add a fault detail using addFaultDetail(), add specific entries using addFaultDetailEntry() and write XML to that using getResult().

    Quote Originally Posted by wlsmith
    Is there something I'm missing, like
    a) some other way to add structure to the details, or
    b) it's a Bad Thing(tm) to use anything but simple text details in a fault?
    Some SOAP stacks completely ignore the details, so it's not a good idea to put valuable information in it.
    Arjen Poutsma

    Spring Web Services Dev Lead
    Please read the FAQ

  5. #5
    Join Date
    Aug 2006
    Posts
    13

    Default

    Quote Originally Posted by poutsma
    You can add a fault detail using addFaultDetail(), add specific entries using addFaultDetailEntry() and write XML to that using getResult().
    Ah... So instead of SoapFaultDetailElement.addText() (which produces the simple text element), I would pull the Result from SoapFaultDetailElement.getResult(), figure out whether it's a DOM, SAX, or StreamResult, and push my details that way? Kind of painful, but it should work. Better than generating an XML string and adding it as the text.

    Quote Originally Posted by poutsma
    Some SOAP stacks completely ignore the details, so it's not a good idea to put valuable information in it.
    I had designed the XML contract for our services with a few Faults indicating alternate return values (plus the common Fault == Exception logic). For example, a job-submittal service that normally returns a job-ID but can produce a Fault if the job is invalid in some way. Some extra details on why the job was invalid are useful to the client, but not required. I had thought this was an OK thing to do, but the WS-I profiles aren't the easiest thing to absorb. In other words, I figured that if some SOAP client stack ignored the Fault details, then they were at fault, not my service

    I really like Spring-WS, especially the "focus on the XML" approach. Following that path leads to the occasional Fault with structured details. Does anybody have thoughts on the tradeoff between interoperability and Fault detail structure? How many of the common SOAP stacks discard the details element?

  6. #6
    Join Date
    Jul 2005
    Location
    Rotterdam, the Netherlands
    Posts
    1,562

    Default

    Quote Originally Posted by wlsmith
    Ah... So instead of SoapFaultDetailElement.addText() (which produces the simple text element), I would pull the Result from SoapFaultDetailElement.getResult(), figure out whether it's a DOM, SAX, or StreamResult, and push my details that way? Kind of painful, but it should work. Better than generating an XML string and adding it as the text.
    Well, the idea would be to create some XML that you want to put into the detail, and use a Transformer to transform that into the Result. This might be a bit painful, but the Source/Result provide a valuable abstraction, which - among others - allow you to switch between a DOM-based model to a streaming StAX-model with just a configuration setting.


    Quote Originally Posted by wlsmith
    I had designed the XML contract for our services with a few Faults indicating alternate return values (plus the common Fault == Exception logic). For example, a job-submittal service that normally returns a job-ID but can produce a Fault if the job is invalid in some way. Some extra details on why the job was invalid are useful to the client, but not required. I had thought this was an OK thing to do, but the WS-I profiles aren't the easiest thing to absorb. In other words, I figured that if some SOAP client stack ignored the Fault details, then they were at fault, not my service
    You are right, but it is of little use being right when the majority is wrong. For instance, while the .NET framework does carry the details, its RPC-like model doesn't make it easier to get the details (though it is possible).

    Quote Originally Posted by wlsmith
    I really like Spring-WS, especially the "focus on the XML" approach. Following that path leads to the occasional Fault with structured details. Does anybody have thoughts on the tradeoff between interoperability and Fault detail structure? How many of the common SOAP stacks discard the details element?
    None that I know of discard them completely, it's just that most SOAP stack models don't actually focus on it. This mostly has to do with the whole Exception == SOAP Fault approach, which is wrong IMO.
    Arjen Poutsma

    Spring Web Services Dev Lead
    Please read the FAQ

  7. #7
    Join Date
    Jul 2006
    Location
    Plano, TX
    Posts
    3

    Unhappy

    I was trying to use the SoapMessageUtils.addReceiverFaultResponse(...,...) but was unable to find it in the jar of the -m2 SNAPSHOT.

    My thought was to start with the code of the SimpleSoapExceptionResolver which uses this SoapMessageUtils.

    But replace this line
    Code:
    SoapMessageUtils.addReceiverFault(response, faultString);
    with this to return and use the SoapFault
    Code:
    SaopFault soapFault = SoapMessageUtils.addReceiverFault(response, faultString);
    with SoapFault object use the .addFaultDetail() to return a SoapFaultDetail object.

    With the SoapFaultDetail use the .addFaultDetailElement(QName) to return a SoapFaultDetailElement.

    With the SoapFaultDetailElement use the .getResult() to return a SaxResult.

    With the SaxResult use the .getHandler() to return a ContentHandler.

    With the ContentHandler use the .startElement and other methods to create something that ends up looks similiar to within the <soapenv:Fault>
    ....

    Code:
              <detail>
                   <e:myfaultdetails xmlns:e="Some-URI">
                     <message>
                       My application didn't work
                     </message>
                     <errorcode>
                       1001
                     </errorcode>
                   </e:myfaultdetails>
               </detail>
    Am I on the write track on this?

  8. #8
    Join Date
    Jul 2005
    Location
    Rotterdam, the Netherlands
    Posts
    1,562

    Default

    Quote Originally Posted by TAOSBORNE
    I was trying to use the SoapMessageUtils.addReceiverFaultResponse(...,...) but was unable to find it in the jar of the -m2 SNAPSHOT.

    My thought was to start with the code of the SimpleSoapExceptionResolver which uses this SoapMessageUtils.

    But replace this line
    Code:
    SoapMessageUtils.addReceiverFault(response, faultString);
    with this to return and use the SoapFault
    Code:
    SaopFault soapFault = SoapMessageUtils.addReceiverFault(response, faultString);
    with SoapFault object use the .addFaultDetail() to return a SoapFaultDetail object.
    The addReceiverFault() method has been moved to the SoapBody itself, and has been renamed addServerOrReceiverFault(). It works the same as SoapMessageUtils used to.

    Quote Originally Posted by TAOSBORNE
    With the SoapFaultDetail use the .addFaultDetailElement(QName) to return a SoapFaultDetailElement.

    With the SoapFaultDetailElement use the .getResult() to return a SaxResult.

    With the SaxResult use the .getHandler() to return a ContentHandler.

    With the ContentHandler use the .startElement and other methods to create something that ends up looks similiar to within the <soapenv:Fault>
    ....

    Code:
              <detail>
                   <e:myfaultdetails xmlns:e="Some-URI">
                     <message>
                       My application didn't work
                     </message>
                     <errorcode>
                       1001
                     </errorcode>
                   </e:myfaultdetails>
               </detail>
    Am I on the write track on this?
    Well, it's not a good idea to cast the Result to a StaxResult directly. It's better to create a Source (DOMSource or StreamSource), and to transform that source to the result, like so:

    Code:
    SoapFaultDetail detail = fault.addFaultDetail();
    SoapFaultDetailElement el = detail.addFaultDetailElement("SomeUri", "myfaultdetails", "e");
    Source elSource = new StringSource("<message>My application didn't work</message><errorcode>1001</errorcode>");
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    transformer.transform(elSource, el.getResult());
    This way, you are not dependent on the underlying XML technology (DOM, StAX, etc).
    Arjen Poutsma

    Spring Web Services Dev Lead
    Please read the FAQ

  9. #9
    Join Date
    Mar 2006
    Location
    Germany, Karlsruhe
    Posts
    157

    Default

    Hi!

    I want to be JWSDK2 and axis1 compatible, therefore i want to add a "fault bean", which i defined my my WSDL/XSL.

    In your example Arjen, your are first adding a wrapper element (StringSource) and then you add some additional elements.

    I want to add only one instance of my fault bean in the details element. In your approach, i have to call "faultDetail.addFaultDetailElement(QNAME)" to get an "SoapFaultDetailElement". I can't use that, because of the wrapper element which this method produces.
    Is there any other way to get SoapFaultDetailElement?

    I need the SoapFaultDetailElementit because of the required Result element one line later:
    marshaller.marshal(faultType, faultDetailElement.getResult());

    Cheers,

    Ingo

    PS.: My aim is this xml snippet:

    <details> <!-- details element of a soap fault -->
    <ns2:ObjectDoesNotExistFault> <!-- This is my marshalled bean -->
    <ns2:mycode>XYZ</ns2:code>
    <ns2:message>ABC</ns2:message>
    </ns2:ObjectDoesNotExistFault>
    </details>

  10. #10
    Join Date
    Aug 2006
    Posts
    13

    Default

    I wanted to do essentially the same thing. My fault objects/beans are marshalled to XML just like all of the other objects passed through the WS interface. In essence, you need to do the following:
    • Pull the top element of your fault and build a QName,
    • Create/Add the SoapFaultDetailElement with the QName,
    • Output each child element of your fault (e.g., <mycode>, <message>) to a String, and
    • Insert each String into the detail element with a transform.

    The following method inserts the marshalled XML into the message's fault (simply invoked from resolveExceptionInternal() in an extension of SoapFaultMappingExceptionResolver):
    Code:
    import javax.xml.namespace.QName;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.TransformerFactory;
    
    import org.jdom.Element;
    import org.jdom.output.Format;
    import org.jdom.output.XMLOutputter;
    import org.springframework.ws.context.MessageContext;
    import org.springframework.ws.soap.SoapFault;
    import org.springframework.ws.soap.SoapFaultDetail;
    import org.springframework.ws.soap.SoapFaultDetailElement;
    import org.springframework.ws.soap.SoapMessage;
    import org.springframework.ws.soap.context.SoapMessageContext;
    import org.springframework.xml.transform.StringSource;
    
    protected void addFault(SoapMessageContext theSoapContext, 
                            CommonFault theFault) 
                                                  throws TransformerException {
        SoapMessage response = theSoapContext.getSoapResponse();
        String msg = theFault.getMessage();
        SoapFault soapFault =
            response.getSoapBody().addClientOrSenderFault(msg);
    
        // Create a fault <detail> and the single element under the detail.
        // You can have multiple children of the <detail> element, but we're
        // going for a single "payload" within the fault detail.
    
        SoapFaultDetail detail = soapFault.addFaultDetail();
        Element jdomFault = theFault.marshal();
        QName qname = new QName(jdomFault.getNamespaceURI(), 
                                jdomFault.getName(),
                                jdomFault.getNamespacePrefix());
        SoapFaultDetailElement detailElt = detail.addFaultDetailElement(qname);
    
        // Now we need to transform the CONTENTS of the fault into the element
        // we just created.  Problem is, we've got to skip the top-level element
        // in the marshalled fault and do each of the child elements separately.
        // Note: The "source" needs to be well-formed, so we can't do multiple
        // children at once.
    
        // Note: Can't add attributes to the top-level Fault element.
    
        XMLOutputter out = new XMLOutputter(Format.getCompactFormat());
        Transformer trn = TransformerFactory.newInstance().newTransformer();
        for (Iterator it = jdomFault.getChildren().iterator(); it.hasNext(); ) {
            String child = out.outputString((Element)it.next());
            trn.transform(new StringSource(child), detailElt.getResult());
        }
    }
    Imports are included so you can see where things are coming from. I use JDOM for marshalling, but the only trick is outputting the XML to a string to feed into the transformer as a StringSource. You would need a different approach depending on what you use to model your marshalled XML (DOM, SAX, etc).

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •