views:

18

answers:

1

Hi

I've created a webservice and used Axis2 to generate all "skeleton" java classes. Then I of course implemented the service operations myself.

In the implementation, I can throw a MyException which is then caught by the generated classes and converted to an AxisFault object, which in turn is converted to a soap fault (deep down in the Axis framework) with the attribute <faultcode>soapenv:Server</faultcode>

My problem is I would like a custom dynamic faultcode, not "soapenv:Server".

I tried to manually create an AxisFault object and throw this, but AxisFault is a RemoteException, and the generated interface which my implementation must implement, does not allow to throw RemoteException.

Is it possible to get some kind of hook or filter on the output, so that I can change the faultcode? Or any other way to control the faultcode?

Thanks in advance
Ulrik

A: 

The SOAP specification describes how custom fault information appears under the detail tag. The faultcode is a fixed set of value dealing with where in the SOAP processing the error was thrown.

The following is an example of throwing a custom fault message

WSDL

Declare the faults in your WSDL so that the associated classes are generated:

<wsdl:definitions targetNamespace="http://example"
    xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:tns="http://example"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
    <wsdl:types>
        <schema elementFormDefault="qualified" targetNamespace="http://example"
            xmlns="http://www.w3.org/2001/XMLSchema"
            xmlns:apachesoap="http://xml.apache.org/xml-soap"
            xmlns:tns="http://example" xmlns:intf="http://example"
            xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"&gt;

            <element name="withdraw">
                <complexType>
                    <sequence>
                        <element name="account" type="xsd:string"/>
                        <element name="amount" type="xsd:int"/>
                    </sequence>
                </complexType>
            </element>

            <element name="withdrawResponse">
                <complexType>
                    <sequence>
                        <element name="balance" type="xsd:int"/>
                    </sequence>
                </complexType>
            </element>

            <element name="AccountNotExistFault">
                <complexType>
                    <sequence>
                        <element name="account" type="xsd:string"/>
                    </sequence>
                </complexType>
            </element>

            <element name="InsufficientFundFault">
                <complexType>
                    <sequence>
                        <element name="account" type="xsd:string"/>
                        <element name="balance" type="xsd:int"/>
                        <element name="requestedFund" type="xsd:int"/>
                    </sequence>
                </complexType>
            </element>

        </schema>
    </wsdl:types>

    <wsdl:message name="withdrawRequest">
        <wsdl:part element="tns:withdraw" name="parameters"/>
    </wsdl:message>

    <wsdl:message name="withdrawResponse">
        <wsdl:part element="tns:withdrawResponse" name="return"/>
    </wsdl:message>

    <wsdl:message name="InsufficientFundFaultMessage">
        <wsdl:part element="tns:InsufficientFundFault" name="fault"/>
    </wsdl:message>

    <wsdl:message name="AccountNotExistFaultMessage">
        <wsdl:part element="tns:AccountNotExistFault" name="fault"/>
    </wsdl:message>

    <wsdl:portType name="Bank">
        <wsdl:operation name="withdraw">
            <wsdl:input message="tns:withdrawRequest" name="withdrawRequest"/>
            <wsdl:output message="tns:withdrawResponse" name="withdrawResponse"/>
            <wsdl:fault message="tns:AccountNotExistFaultMessage" name="AccountNotExistException"/>
            <wsdl:fault message="tns:InsufficientFundFaultMessage" name="InsufficientFundException"/>
        </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="BankSoapBinding" type="tns:Bank">
        <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/&gt;
        <wsdl:operation name="withdraw">
            <wsdlsoap:operation soapAction=""/>
            <wsdl:input name="withdrawRequest">
                <wsdlsoap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="withdrawResponse">
                <wsdlsoap:body use="literal"/>
            </wsdl:output>
            <wsdl:fault name="InsufficientFundException">
                <wsdlsoap:fault name="InsufficientFundException" use="literal"/>
            </wsdl:fault>
            <wsdl:fault name="AccountNotExistException">
                <wsdlsoap:fault name="AccountNotExistException" use="literal"/>
            </wsdl:fault>
        </wsdl:operation>
    </wsdl:binding>

    <wsdl:service name="BankService">
        <wsdl:port binding="tns:BankSoapBinding" name="Bank">
            <wsdlsoap:address location="http://localhost:8080/bank/services/Bank"/&gt;
        </wsdl:port>
    </wsdl:service>

</wsdl:definitions>

Service code

The following code demonstrates how the custom fault messages are thrown:

package example;

public class BankServiceSkeleton {

    public  WithdrawResponse withdraw(Withdraw param1) throws InsufficientFundFaultMessage, AccountNotExistFaultMessage {

        //
        // Parameter handling
        //
        String account = param1.getAccount();
        int amount     = param1.getAmount();

        //
        // Error checks
        //
        if ("13".equals(account)) {
            AccountNotExistFault fault = new AccountNotExistFault();

            fault.setAccount(account);

            AccountNotExistFaultMessage ex = new AccountNotExistFaultMessage("Account does not exist!");
            ex.setFaultMessage(fault);
            throw ex;
        }

        if (amount > 1000) {
            InsufficientFundFault fault = new InsufficientFundFault();

            fault.setAccount(account);
            fault.setBalance(1000);
            fault.setRequestedFund(amount);

            InsufficientFundFaultMessage ex = new InsufficientFundFaultMessage("Insufficient funds");
            ex.setFaultMessage(fault);
            throw ex;
        }

        //
        // Normal response
        //
        WithdrawResponse response = new WithdrawResponse();

        response.setBalance(1000 - amount);

        return response;
    }
}

TESTING

The following SOAP message

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:exam="http://example"&gt;
   <soapenv:Header/>
   <soapenv:Body>
      <exam:withdraw>
         <exam:account>10</exam:account>
         <exam:amount>2000</exam:amount>
      </exam:withdraw>
   </soapenv:Body>
</soapenv:Envelope>

Generates the following SOAP fault response

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"&gt;
   <soapenv:Body>
      <soapenv:Fault>
         <faultcode>soapenv:Server</faultcode>
         <faultstring>Insufficient funds</faultstring>
         <detail>
            <ns1:InsufficientFundFault xmlns:ns1="http://example"&gt;
               <ns1:account>10</ns1:account>
               <ns1:balance>1000</ns1:balance>
               <ns1:requestedFund>2000</ns1:requestedFund>
            </ns1:InsufficientFundFault>
         </detail>
      </soapenv:Fault>
   </soapenv:Body>
</soapenv:Envelope>
Mark O'Connor
Mark, what will the SOAP faultcode be set to in your example? It would be nice, if you could post a full soap response showing a fault example.
Ulrik
Custom fault information appears under the fault **detail** tag.The SOAP **faultcode** is a fixed set of values. Here's the doco http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383510
Mark O'Connor
Okay. So I shouldn't change the faultcode even if I found a way :)Thank you very much!
Ulrik