How to develop a JAX-WS service with WSO2 Developer Studio and deploy it in WSO2 API Manager

How to develop a JAX-WS service with WSO2 Developer Studio and deploy it in WSO2 API Manager

In this post I will show how to write a simple CXF based JAX-WS service using WSO2 Developer Studio and how to deploy it in WSO2 API Manager. My service will use API Manager carbon user store to get an email of a specific user.

Open Developer Studio dashboard (I’m using version 3.7.0). Under Create menu tab select JAX-WS Service Project:

p1-1

Choose Create New JAX-WS Service and click Next:

p1-2

Choose a project name, package and class name for your service and click Next:

p1-3

Adjust project maven info if necessary and click Finish:

p1-4

Notice in your project that there is an automatically generated  service class with a sample method and necessary annotations. All you need is add your methods and their implementation. You can read more about how to use jax-ws annotations here. In short, only @WebService annotation is required, because it marks which Java class needs to be exposed as a web service. All the other annotations are optional and can be used to customize the wsdl file of the web service.

Here is the code of my implementation:

@WebService(serviceName = "EmailService")
public class EmailService{
	
	@WebMethod(action = "getEmail", operationName = "getEmail")
	@WebResult(name = "result")
	public String getEmail(@WebParam(name = "username") String username) throws MyException{
		Connection connection = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		String email = null;
		try{
			DataSource ds = this.getDataSource();
			connection = ds.getConnection();
			stmt = connection.prepareStatement("SELECT ua.UM_ATTR_NAME, ua.UM_ATTR_VALUE "
	    						   + "FROM UM_USER u INNER JOIN  UM_USER_ATTRIBUTE ua "
	    						   + "ON u.UM_ID = ua.UM_USER_ID WHERE u.UM_USER_NAME=?");
			stmt.setString(1,username.substring(username.indexOf('/') + 1));
			rs = stmt.executeQuery();
			while (rs.next()) {
	    	   	       if((rs.getString("UM_ATTR_NAME")).equals("mail")){
	    	   		      email=rs.getString("UM_ATTR_VALUE");
	    	   		      break;
	    	   	       }
			}
	        
		}catch(Exception e){
			throw new MyException(e.getMessage(), new MyExceptionFaultBean(e.getMessage()));
		}finally{
			if(connection!=null){
				try{
					connection.close();
				}catch(Exception e){
					throw new MyException(e.getMessage(), new MyExceptionFaultBean(e.getMessage()));
				}
                        }
		}
		return email;
	}
	private DataSource getDataSource()throws Exception{
		Hashtable<String, Object> environment = new Hashtable<String, Object>();
		environment.put("java.naming.factory.initial", "org.wso2.carbon.tomcat.jndi.CarbonJavaURLContextFactory");
		environment.put("java.naming.webapp.bound", true);
		Context initCtx = new InitialContext(environment);
		Context initialContext = (Context) initCtx.lookup("java:comp/env");
		return (DataSource) initialContext.lookup("jdbc/MyDB");
	}


}

 

Now, some basics about exception handling using JAX-WS. As you can see in my code there is a custom exception thrown from getEmail() method when something goes wrong. To be in compliance with JAX-WS specification a custom exception must:

  • extend java.lang.Exception class and be annotated with @WebFault;
  • use a fault bean to store the error message;
  • implement following constructors and methods:
    • WrapperException(String message, FaultBean faultInfo) A constructor where WrapperException
      is replaced with the name of your custom exception and FaultBean is replaced by the
      name of your fault bean.
    • WrapperException(String message, FaultBean faultInfo, Throwable cause) A constructor
      where WrapperException is replaced with the name of your custom exception and FaultBean
      is replaced by the name of your fault bean.
    • FaultBean getFaultInfo() Getter to obtain the fault information, where FaultBean is replaced by the
      name of your fault bean.

Here is an example of MyException class compliant with JAX-WS spec:

@WebFault(name="MyExceptionFaultBean")
public class MyException extends Exception{
    private MyExceptionFaultBean faultBean;
 
    public MyException(String message, MyExceptionFaultBean faultInfo){
        super(message);
        faultBean = faultInfo;
    }
 
    public MyException(String message, MyExceptionFaultBean faultInfo, Throwable cause) {
        super(message, cause);
        faultBean = faultInfo;
    }
 
    public MyExceptionFaultBean getFaultInfo(){
        return faultBean;
    }
}

The fault bean is a POJO:

public class MyExceptionFaultBean {
    private String message;
    
    public MyExceptionFaultBean() {
    }
    public MyExceptionFaultBean(String message) {
        this.message = message;
    }
 
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
	this.message = message;
    }	
}

 

In my implementation of the service I’ve used a data source to access carbon user store, which I have exposed as a global JNDI resource. To register a JNDI resource globally(it means the resource will be visible to all webapps deployed in the server) do the following steps:

1. Place resource in <APIM_HOME >repository/conf/tomcat/catalina-server.xml:

<GlobalNamingResources>
     <Resource name="jdbc/MyDB" 
          auth="Container"
          type="javax.sql.DataSource" 
          driverClassName="org.h2.Driver"
          maxActive="100" 
          maxIdle="30" 
          maxWait="10000"
          url="jdbc:h2:C:/ wso2am-1.8.0/repository/database/WSO2CARBON_DB"
          username="wso2carbon" 
          password="wso2carbon"/>
</GlobalNamingResources>

2. Link the resource in <APIM_HOME >repository/conf/tomcat/context.xml:

<ResourceLink name="jdbc/MyDB"
     global="jdbc/MyDB"
     type="javax.sql.DataSource"/>

3. Put a reference to your resource in <APIM_HOME >repository/conf/tomcat/web.xml:

<resource-ref>
     <description>CarbonDB datasource</description>
     <res-ref-name>jdbc/MyDB</res-ref-name>
     <res-type>javax.sql.DataSource</res-type>
     <res-auth>Container</res-auth>
</resource-ref>

To use the data source from you application, copy the code from getDataSource() method of my implementation.

 

If you have dependencies in your project, you can add the jars in WEB_INF/lib directory of your project. You can optionally add them in the cxf environment directory of the API Manager( <APIM_HOME>/lib/runtimes/cxf) if your app is deployed in cxf environment. You can read more about product environments and their configuration here.

 

You can now export your project as deployable file. Right-click on the project, select Export Project as Deployable Archive and choose destination location:

p1-5

To deploy your JAX-WS service in the WSO2 API Manager go to API Manager management console. Under Applications select JAX-WS/JAX-RS and upload the archive you have exported in the previous step:

p1-6

To test your service you can use the Tryit WSO2 Carbon feature. Under Applications select List and click on the name of your webapp. This will open Application Dashboard page of your web service:

p1-7

 

As you can see, the wsdl of your web service is also available on this page.

 

Author:Renata

No Comments

Post A Comment