Web Service

JAX-WS Custom Exception with FaultBean in TomEE and WebSphere Application Server

Posted on

In our last post we were able to deploy a simple JAX-WS service on both TomEE and WebSphere Application Server.

JAX-WS Specification suggests that three thing should be followed for us to implement Custom Exception as SOAP Fault.

WrapperException(String message, FaultBean faultInfo) A constructor where WrapperException
is replaced with the name of the generated wrapper exception and FaultBean is replaced by the
name of the generated fault bean.
WrapperException(String message, FaultBean faultInfo, Throwable cause) A constructor
whereWrapperException is replaced with the name of the generated wrapper exception and FaultBean
is replaced by the name of the generated fault bean. The last argument, cause, may be used to convey
protocol specific fault information, see section 6.4.1.
FaultBean getFaultInfo() Getter to obtain the fault information, where FaultBean is replaced by the
name of the generated fault bean.

But as it turns out to be this is not very restrictive and not honored across Application Server. Let’s take the IMyService.java and MyServiceImpl.java from previous post and then we will modify the exception part.

Our updated Exception class will have a faultBean which will accept errorCode and errorMessage.

First the exception class MyException.java, in below code we have introduced a new class MyExceptionBean which holds our errorCode and errorMessage. We initialize this class with values which are passed to the constructor of our MyException.

package com.test.mumz.soap.soapexp;

import javax.xml.ws.WebFault;

/**
 * The Class MyException.
 * 
 * @author prabhat.jha
 */
@WebFault(name = "MyException")
public class MyException extends Exception {

	/** The Constant serialVersionUID. */
	private static final long	serialVersionUID	= -861826770198517502L;

	/** The my exception bean. */
	private MyExceptionBean		faultBean			= null;

	/**
	 * Instantiates a new my exception.
	 * 
	 * @param errorCode
	 *            the error code
	 * @param message
	 *            the message
	 */
	public MyException(String errorCode, String message) {
		prepareFaultBean(errorCode, message);
	}

	/**
	 * Instantiates a new my exception.
	 * 
	 * @param errorCode
	 *            the error code
	 * @param message
	 *            the message
	 * @param cause
	 *            the cause
	 */
	public MyException(String errorCode, String message, Throwable cause) {
		super(message, cause);
		prepareFaultBean(errorCode, message);
	}


	/**
	 * Adds the exception details.
	 *
	 * @param errorCode            the error code
	 * @param errorMessage            the error message
	 * @return the my exception
	 */
	private void prepareFaultBean(String errorCode, String errorMessage) {
		this.faultBean = new MyExceptionBean(errorCode, errorMessage);
	}
	
	/**
	 * Gets the fault bean.
	 *
	 * @return the fault bean
	 */
	public MyExceptionBean getFaultBean() {
		return faultBean;
	}
}

Next is our MyExceptionBean.java which is POJO and holds errorCode and errorMessage.

package com.test.mumz.soap.soapexp;

/**
 * The Class MyExceptionBean.
 * 
 * @author prabhat.jha
 */
public class MyExceptionBean {

	/** The error code. */
	private String	errorCode		= null;

	/** The error message. */
	private String	errorMessage	= null;

	/**
	 * Instantiates a new my exception bean.
	 * 
	 * @param errorCode
	 *            the error code
	 * @param errorMessage
	 *            the error message
	 */
	public MyExceptionBean(String errorCode, String errorMessage) {
		this.errorCode = errorCode;
		this.errorMessage = errorMessage;
	}

	/**
	 * @return the errorCode
	 */
	public String getErrorCode() {
		return errorCode;
	}

	/**
	 * @param errorCode
	 *            the errorCode to set
	 */
	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	/**
	 * @return the errorMessage
	 */
	public String getErrorMessage() {
		return errorMessage;
	}

	/**
	 * @param errorMessage
	 *            the errorMessage to set
	 */
	public void setErrorMessage(String errorMessage) {
		this.errorMessage = errorMessage;
	}
}

Next deploy it in TomEE and use SoapUI to test. Sample Input and Output are given below
Input

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mpr="http://mprabhat.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <mpr:sayHello>
         <arg0></arg0>
      </mpr:sayHello>
   </soapenv:Body>
</soapenv:Envelope>

Output

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Server</faultcode>
         <faultstring>Fault occurred while processing.</faultstring>
         <detail>
            <ns1:MyException xmlns:ns1="http://mprabhat.com/">
               <faultBean xsi:type="ns2:myExceptionBean" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://mprabhat.com/">
                  <errorCode>Code</errorCode>
                  <errorMessage>Message</errorMessage>
               </faultBean>
            </ns1:MyException>
         </detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

Brilliant everything works perfectly???? Wait let’s deploy it in WebSphere now. Please follow the same steps as described in previous post and then run with above input.

This is not to show demerit or loop hole in the spec or by the implementation provider, this is just another way of doing it but I would say follow the spec the chances of this not working is higher then the spec.

  • If you provide both getFaultInfo and getFaultBean in above MyException, you will find that control will always come to getFaultInfo. So the spec is honored 🙂
  • If in MyExceptionBean you remove getter and setters you will not see any Soap Fault but if you make your fields public it will again work ;), I know it’s simple Java bean specification.

JAX-WS Exception Handling with TomEE and WebSphere Application Server 8.5

Posted on Updated on

Let’s write a simple JAX-WS example which will throw an Exception. We will then deploy it in TomEE and then to WebSphere 8.5 and see the difference.

  1. Download TomEE ( I have downloaded the plus version which at the time of writing was 1.7.1)
  2. Download and install WebSphere Application Server (Developer version is free)
  3. Download and install SoapUI

Once servers are downloaded and installed, open your eclipse and create a new “Dynamic Web Project”. Our project will have three Source Files namely:

  1. EndPoint interface IMyService
  2. Implementation class MyServiceImpl
  3. Exception class MyException

I will not get into what these annotations are, rather you can visit any of the many available tutorials for a quick/detailed walk through.

First our interface IMyService.java

package com.test.mumz.soap.soapexp;

import javax.jws.WebService;

/**
 * The Interface IMyService.
 *
 * @author prabhat.jha
 */
@WebService(targetNamespace = "http://mprabhat.com/")
public interface IMyService {

	/**
	 * Say hello.
	 *
	 * @param userName the user name
	 * @return the string
	 * @throws MyException the my exception if <code>username</code> is null or blank
	 */
	public String sayHello(String userName) throws MyException;
}

Our interface is simple enough just has one method sayHello which accepts a String and if the parameter is null or empty will throw an instance of MyException

Next our Web Service implementation class.

package com.test.mumz.soap.soapexp;

import java.util.Date;

import javax.ejb.Stateless;
import javax.jws.WebService;

/**
 * The Class MyServiceImpl.
 * @author prabhat.jha
 */
@Stateless
@WebService(portName = "myport", serviceName = "MyService", targetNamespace = "http://mprabhat.com/", endpointInterface = "com.test.mumz.soap.soapexp.IMyService")
public class MyServiceImpl implements IMyService {

	/**
	 * Instantiates a new my service impl.
	 */
	public MyServiceImpl() {
	}

	/* (non-Javadoc)
	 * @see com.test.mumz.soap.soapexp.IMyService#sayHello(java.lang.String)
	 */
	@Override
	public String sayHello(String userName) throws MyException {
		if (userName == null || userName.trim().length() == 0 || "".equals(userName)) {
			throw new MyException("Username cannot be null");
		}
		return "Hello : " + userName + " ,server time is : " + new Date();
	}
}

This again is self-explanatory, just returns hello message with server time. If parameter is null with throw MyException.

Finally our exception class MyException.java

package com.test.mumz.soap.soapexp;

import javax.xml.ws.WebFault;

/**
 * The Class MyException.
 * 
 * @author prabhat.jha
 */
@WebFault(name="MyException")
public class MyException extends Exception {

	/** The Constant serialVersionUID. */
	private static final long	serialVersionUID	= -861826770198517502L;
	
	/**
	 * Instantiates a new my exception.
	 * 
	 * @param message
	 *            the message
	 */
	public MyException(String message) {
		super(message);
	}

	/**
	 * Instantiates a new my exception.
	 * 
	 * @param cause
	 *            the cause
	 */
	public MyException(Throwable cause) {
		super(cause);
	}

	/**
	 * Instantiates a new my exception.
	 * 
	 * @param message
	 *            the message
	 * @param cause
	 *            the cause
	 */
	public MyException(String message, Throwable cause) {
		super(message, cause);
	}

	/**
	 * Instantiates a new my exception.
	 * 
	 * @param message
	 *            the message
	 * @param cause
	 *            the cause
	 * @param enableSuppression
	 *            the enable suppression
	 * @param writableStackTrace
	 *            the writable stack trace
	 */
	public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}
}

Now export your project as war and deploy it in TomEE first (Simple way: Right Click on project -> Export -> War and then place this war inside /webapps). Or you can even deploy it through Eclipse. After deployment start TomEE and on console you should see the wsdl location. It should look like this:

INFO: Webservice(wsdl=http://localhost:8080/SoapException/webservices/MyServiceImpl, qname={http://mprabhat.com/}MyService) --> Ejb(id=MyServiceImpl)

To test:

  1. Launch SoapUI
  2. File -> New Soap Project
  3. Give Project Name like MyServiceSoapUIPrj and wsdl. Just append “?wsdl” to what is printed on the console. It should be like:
    http://localhost:8080/SoapException/webservices/MyServiceImpl?wsdl

  4. Now send a request with some parameter:
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mpr="http://mprabhat.com/">
       <soapenv:Header/>
       <soapenv:Body>
          <mpr:sayHello>
             <arg0>User</arg0>
          </mpr:sayHello>
       </soapenv:Body>
    </soapenv:Envelope>
    

    You should get the response back like below:

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
       <soap:Body>
          <ns2:sayHelloResponse xmlns:ns2="http://mprabhat.com/">
             <return>Hello : User ,server time is : Sun Nov 02 23:40:06 IST 2014</return>
          </ns2:sayHelloResponse>
       </soap:Body>
    </soap:Envelope>
    

    Input with null parameter:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mpr="http://mprabhat.com/">
       <soapenv:Header/>
       <soapenv:Body>
          <mpr:sayHello>
             <arg0></arg0>
          </mpr:sayHello>
       </soapenv:Body>
    </soapenv:Envelope>
    

    Here is your SOAP fault

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
       <soapenv:Body>
          <soapenv:Fault>
             <faultcode>soapenv:Server</faultcode>
             <faultstring>Username cannot be null</faultstring>
             <detail>
                <a:MyException xmlns:a="http://mprabhat.com/">
                   <message>Username cannot be null</message>
                </a:MyException>
             </detail>
          </soapenv:Fault>
       </soapenv:Body>
    </soapenv:Envelope>
    

    So all in all, everything works expected and we have our JAX-WS working. Wait only in TomEE!!!
    Now let’s deploy the same in our WebSphere Application Server. Steps to deploy:

    1. Make sure your WebSphere Application Server is installed and you have already created profile
    2. Start your server
    3. Go to administrator Console -> Applications -> WebSphere Enterprise Application and click on Install
    4. Click on Choose File, browse and select your war file
    5. Click Next and then choose “Fast Path – Prompt only when additional information is required.”
    6. Click Next, in the following screen make sure “Deploy Web Services” is selected/checked and click Next
    7. Click Next and again Click Next
    8. Provide some context root like /soapexptest and click Next and again Next and then Finish
    9. After some time it should ask you to save or Review the deployment, click on Save.
    10. From list of available applications, select your Application and click on Start. You should see something like below

      Application SoapException_war on server server1 and node DRLTRN0002Node01 started successfully. The collection may need to be refreshed to show the current status.

    11. Now go to SoapUI and create a new project, your WSDL should look like this:
      http://localhost:9080/soapexptest/MyService/MyService.wsdl
      
    12. Sample input and output remains the same

    That’s it everything worked perfectly, now in the next post we will see how things get complicated when we use a custom bean for providing SOAP Fault.