SOAP Fault handling using Exception in JAX-WS webservice

This tutorial will show you how we can generate SOAP fault error code and message using Exception handling in SOAP based JAX-WS webservice. For this tutorial we will create a standalone project in Eclipse.

If you already have an idea on how to create a maven project in Eclipse will be great otherwise I will tell you here how to create a maven project in Eclipse.

Prerequisites

The following configurations are required in order to run the application

Eclipse Kepler
JDK 1.8
Have maven installed and configured
JAX-WS dependencies in pom.xml

Now we will see the below steps how to create a maven based spring project in Eclipse

First we will create service project
Step 1. Create a maven based web project in Eclipse

Go to File -> New -> Other. On popup window under Maven select Maven Project. Then click on Next. Select the workspace location – either default or browse the location. Click on Next. Now in next window select the row as highlighted from the below list of archtypes and click on Next button.

maven-arctype-quickstart
Now enter the required fields (Group Id, Artifact Id) as shown below
Group Id : com.roytuts
Artifact Id : soapws
Step 2. Modify the pom.xml file as shown below.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.roytuts</groupId>
    <artifactId>soapws</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>soapws</name>
    <url>http://maven.apache.org</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jdk.version>1.8</jdk.version>
        <jaxws.version>2.1.3</jaxws.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>jaxws-rt</artifactId>
            <version>${jaxws.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <!-- for jdk 1.6 start -->
                <!--<groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxws-maven-plugin</artifactId>
                    <version>1.12</version> -->
                <!-- for jdk 1.6 end -->
                <groupId>org.jvnet.jax-ws-commons</groupId>
                <artifactId>jaxws-maven-plugin</artifactId>
                <version>2.2</version>
                <executions>
                    <execution>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>wsgen</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sei>com.roytuts.ws.service.BillDeskBOImpl</sei>
                    <genWsdl>true</genWsdl>
                    <keep>true</keep>
                    <resourceDestDir>${basedir}/src/main/webapp/WEB-INF/wsdl</resourceDestDir>
                    <sourceDestDir>${basedir}/src/main/java</sourceDestDir>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Step 3. If you see JRE System Library[J2SE-1.5] then change the version by below process

Do right-click on the project and go to Build -> Configure build path, under Libraries tab click on JRE System Library[J2SE-1.5], click on Edit button and select the appropriate jdk 1.8 from the next window. Click on Finish then Ok.

Step 4. Create below service endpoint interface BillDeskBO.java

package com.roytuts.ws.service;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.jws.soap.SOAPBinding.Use;
import com.roytuts.ws.exception.FortuneBankException;
import com.roytuts.ws.vo.BillDeskVO;
@WebService
@SOAPBinding(style = Style.DOCUMENT, use = Use.LITERAL)
public interface BillDeskBO {
    @WebMethod
    public void validateDetails(String userName, String password) throws FortuneBankException;
    @WebMethod
    public String payBill(BillDeskVO billdeskVO) throws FortuneBankException;
}

Step 5. Create below service implementation class

package com.roytuts.ws.service;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.jws.WebService;
import com.roytuts.ws.exception.FortuneBankException;
import com.roytuts.ws.exception.ServiceFault;
import com.roytuts.ws.vo.BillDeskVO;
@WebService(endpointInterface = "com.roytuts.ws.service.BillDeskBO")
public class BillDeskBOImpl implements BillDeskBO {
    @Override
    public void validateDetails(String userName, String password) throws FortuneBankException {
        try {
            if (userName != null && password != null
                    && !("admin".equals(userName.trim()) && "admin".equals(password.trim()))) {
                ServiceFault fault = new ServiceFault();
                fault.setFaultCode("1000");
                fault.setFaultString("Username and password are incorrect");
                throw new FortuneBankException("1000", "Username and password are incorrect");
            }
        } catch (FortuneBankException e) {
            ServiceFault fault = new ServiceFault();
            fault.setFaultCode("2000");
            fault.setFaultString("Unknown error");
            throw new FortuneBankException("Unknown error => ", e);
        }
    }
    @Override
    public String payBill(BillDeskVO billdeskVO) throws FortuneBankException {
        try {
            if (billdeskVO != null) {
                float paymentAmount = billdeskVO.getPaymentAmount();
                if (paymentAmount > 1) {
                    final DateFormat df = new SimpleDateFormat("yyMMddHHmmss");
                    final Date date = new Date();
                    String formattedDate = df.format(date);
                    String customerID = billdeskVO.getCustomerID();
                    String transactionId = customerID + formattedDate;
                    return transactionId;
                } else {
                    ServiceFault fault = new ServiceFault();
                    fault.setFaultCode("3000");
                    fault.setFaultString("Payment Amount must be greated than 1 to get a Transaction ID");
                    throw new FortuneBankException("3000",
                            "Payment Amount must be greated than 1 to get a Transaction ID");
                }
            } else {
                ServiceFault fault = new ServiceFault();
                fault.setFaultCode("4000");
                fault.setFaultString("BillDeskVO billdeskVO is null");
                throw new FortuneBankException("4000", "BillDeskVO billdeskVO is null");
            }
        } catch (FortuneBankException e) {
            ServiceFault fault = new ServiceFault();
            fault.setFaultCode("2000");
            fault.setFaultString("Unknown error");
            throw new FortuneBankException("Unknown error => ", e);
        }
    }
}

Step 6. Create below POJO class

package com.roytuts.ws.vo;
public class BillDeskVO {
    private String customerID;
    private String password;
    private Float paymentAmount;
    public String getCustomerID() {
        return customerID;
    }
    public void setCustomerID(String customerID) {
        this.customerID = customerID;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public Float getPaymentAmount() {
        return paymentAmount;
    }
    public void setPaymentAmount(Float paymentAmount) {
        this.paymentAmount = paymentAmount;
    }
}

Step 7. Create below class for handling SOAP fault error code and error message

package com.roytuts.ws.exception;
public class ServiceFault {
    private String faultCode;
    private String faultString;
    public String getFaultCode() {
        return faultCode;
    }
    public void setFaultCode(String faultCode) {
        this.faultCode = faultCode;
    }
    public String getFaultString() {
        return faultString;
    }
    public void setFaultString(String faultString) {
        this.faultString = faultString;
    }
}

Step 8. Create below custom Exception class for handling fault error code and error message using Exception

package com.roytuts.ws.exception;
public class FortuneBankException extends Exception {
    private static final long serialVersionUID = 1L;
    private ServiceFault fault;
    public FortuneBankException(String message) {
        super(message);
    }
    public FortuneBankException(Throwable throwable) {
        super(throwable);
    }
    public FortuneBankException(String message, Throwable throwable) {
        super(message, throwable);
    }
    public FortuneBankException() {
    }
    protected FortuneBankException(ServiceFault fault) {
        super(fault.getFaultString());
        this.fault = fault;
    }
    public FortuneBankException(String message, ServiceFault faultInfo) {
        super(message);
        this.fault = faultInfo;
    }
    public FortuneBankException(String message, ServiceFault faultInfo, Throwable cause) {
        super(message, cause);
        this.fault = faultInfo;
    }
    public ServiceFault getFaultInfo() {
        return fault;
    }
    public FortuneBankException(String code, String message) {
        super(message);
        this.fault = new ServiceFault();
        this.fault.setFaultString(message);
        this.fault.setFaultCode(code);
    }
}

Step 9. Now build the project by executing below command from command prompt. Navigate to the project root directory and execute the below command

<physical drive location>soapws>mvn clean compile install -Dmaven.test.skip

If you see BUILD SUCCESSFUL message after executing above command then refresh the project in Eclipse, you will see  below few classes have been generated under the package com.roytuts.ws.service.jaxws

SOAP Fault handling using Exception

The generated xsd is below under WEB-INF/wsdl

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="http://service.ws.roytuts.com/" xmlns:tns="http://service.ws.roytuts.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="FortuneBankException" type="tns:FortuneBankException"/>
  <xs:element name="payBill" type="tns:payBill"/>
  <xs:element name="payBillResponse" type="tns:payBillResponse"/>
  <xs:element name="validateDetails" type="tns:validateDetails"/>
  <xs:element name="validateDetailsResponse" type="tns:validateDetailsResponse"/>
  <xs:complexType name="validateDetails">
    <xs:sequence>
      <xs:element name="arg0" type="xs:string" minOccurs="0"/>
      <xs:element name="arg1" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="validateDetailsResponse">
    <xs:sequence/>
  </xs:complexType>
  <xs:complexType name="FortuneBankException">
    <xs:sequence>
      <xs:element name="faultInfo" type="tns:serviceFault" minOccurs="0"/>
      <xs:element name="message" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="serviceFault">
    <xs:sequence>
      <xs:element name="faultCode" type="xs:string" minOccurs="0"/>
      <xs:element name="faultString" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="payBill">
    <xs:sequence>
      <xs:element name="arg0" type="tns:billDeskVO" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="billDeskVO">
    <xs:sequence>
      <xs:element name="customerID" type="xs:string" minOccurs="0"/>
      <xs:element name="password" type="xs:string" minOccurs="0"/>
      <xs:element name="paymentAmount" type="xs:float" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="payBillResponse">
    <xs:sequence>
      <xs:element name="return" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

The generated wsdl file is below under WEB-INF/wsdl

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.6b21  svn-revision#12959. -->
<definitions targetNamespace="http://service.ws.roytuts.com/" name="BillDeskBOImplService" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:tns="http://service.ws.roytuts.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://service.ws.roytuts.com/" schemaLocation="BillDeskBOImplService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="validateDetails">
    <part name="parameters" element="tns:validateDetails"/>
  </message>
  <message name="validateDetailsResponse">
    <part name="parameters" element="tns:validateDetailsResponse"/>
  </message>
  <message name="FortuneBankException">
    <part name="fault" element="tns:FortuneBankException"/>
  </message>
  <message name="payBill">
    <part name="parameters" element="tns:payBill"/>
  </message>
  <message name="payBillResponse">
    <part name="parameters" element="tns:payBillResponse"/>
  </message>
  <portType name="BillDeskBO">
    <operation name="validateDetails">
      <input wsam:Action="http://service.ws.roytuts.com/BillDeskBO/validateDetailsRequest" message="tns:validateDetails"/>
      <output wsam:Action="http://service.ws.roytuts.com/BillDeskBO/validateDetailsResponse" message="tns:validateDetailsResponse"/>
      <fault message="tns:FortuneBankException" name="FortuneBankException" wsam:Action="http://service.ws.roytuts.com/BillDeskBO/validateDetails/Fault/FortuneBankException"/>
    </operation>
    <operation name="payBill">
      <input wsam:Action="http://service.ws.roytuts.com/BillDeskBO/payBillRequest" message="tns:payBill"/>
      <output wsam:Action="http://service.ws.roytuts.com/BillDeskBO/payBillResponse" message="tns:payBillResponse"/>
      <fault message="tns:FortuneBankException" name="FortuneBankException" wsam:Action="http://service.ws.roytuts.com/BillDeskBO/payBill/Fault/FortuneBankException"/>
    </operation>
  </portType>
  <binding name="BillDeskBOImplPortBinding" type="tns:BillDeskBO">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="validateDetails">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
      <fault name="FortuneBankException">
        <soap:fault name="FortuneBankException" use="literal"/>
      </fault>
    </operation>
    <operation name="payBill">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
      <fault name="FortuneBankException">
        <soap:fault name="FortuneBankException" use="literal"/>
      </fault>
    </operation>
  </binding>
  <service name="BillDeskBOImplService">
    <port name="BillDeskBOImplPort" binding="tns:BillDeskBOImplPortBinding">
      <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
    </port>
  </service>
</definitions>

Step 10. Create a webservice publisher class which will publish the webservice

package com.roytuts.ws.publisher;
import javax.xml.ws.Endpoint;
import com.roytuts.ws.service.BillDeskBOImpl;
public class BillDeskPublisher {
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:8888/soap/billdesk", new BillDeskBOImpl());
    }
}

Step 11. Create below client class to consume the service

package com.roytuts.ws.client;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.roytuts.ws.service.BillDeskBO;
import com.roytuts.ws.vo.BillDeskVO;
public class BillDeskClient {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://localhost:8888/soap/billdesk?wsdl");
        QName qname = new QName("http://service.ws.roytuts.com/", "BillDeskBOImplService");
        Service service = Service.create(url, qname);
        BillDeskBO billDesk = service.getPort(BillDeskBO.class);
        billDesk.validateDetails("admin", "");
        BillDeskVO billdeskVO = new BillDeskVO();
        billdeskVO.setCustomerID("1000");
        billdeskVO.setPassword("admin");
        billdeskVO.setPaymentAmount(4500214f);
        System.out.println(billDesk.payBill(billdeskVO));
    }
}

Step 12. Now run first publisher class then run client class, you will see below output

Nov 29, 2015 11:52:04 AM com.sun.xml.ws.server.sei.EndpointMethodHandler invoke
INFO: Unknown error =>
com.roytuts.ws.exception.FortuneBankException: Unknown error =>
    at com.roytuts.ws.service.BillDeskBOImpl.validateDetails(BillDeskBOImpl.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.xml.ws.api.server.InstanceResolver$1.invoke(InstanceResolver.java:246)
    at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:146)
    at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:257)
    at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:93)
    at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:595)
    at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:554)
    at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:539)
    at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:436)
    at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:243)
    at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:444)
    at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:244)
    at com.sun.xml.ws.transport.http.server.WSHttpHandler.handleExchange(WSHttpHandler.java:106)
    at com.sun.xml.ws.transport.http.server.WSHttpHandler.handle(WSHttpHandler.java:91)
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79)
    at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83)
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82)
    at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675)
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79)
    at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:647)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: com.roytuts.ws.exception.FortuneBankException: Username and password are incorrect
    at com.roytuts.ws.service.BillDeskBOImpl.validateDetails(BillDeskBOImpl.java:24)
    ... 26 more

Now replace

billDesk.validateDetails("admin", "");

by

billDesk.validateDetails("admin", "admin");

you will get similar output like below

1000151129115342

Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *