Tuesday, June 12, 2012

How to develop CXF based JAX-WS with WSO2 Developer Studio

This blog post shows the basics of using the WSO2 Developer Studio to develop a JAX-WS. After creating the web service, you can write web services clients that use the web service on a network.

Java API for XML-Based Web Services (JAX-WS), which is also known as JSR-224, is the next generation Web services programming model that extends the foundation provided by the Java API for XML-based RPC (JAX-RPC) programming model. Using JAX-WS, developing Web services and clients is simplified with greater platform independence for Java applications by the use of dynamic proxies and Java annotations.

Apache CXF is an open source web service framework that provides an easy to use, standard-based programming model for developing web services. Web services can be implemented using different application protocols like SOAP, XML, JSON, RESTful HTTP, and support various transport protocols like HTTP or JMS.

WSO2 Developer Studio (formerly named WSO2 Carbon Studio) is a complete Eclipse-based SOA development environment for the award-winning WSO2 Carbon platform, WSO2 Developer Studio supports the development of Web applications, gadgets, services, business processes and more, enabling a developer to first build an application and then deploy and debug it from the IDE itself

In my articles I will use following software:

SoftwareVersion Required
WSO2 Developer Studio2.0.0
Java Development Kit (JDK)JDK 6 Update 32
WSO2 Application Server4.5.0 M3
Apache CXF2.5.4

Contents
  1. Creating a Web Service
    1. Creating a Web Service Project
    2. Creating a Web Service from a Java Class
  2. Deploying the Web Service
  3. Testing the Web Service
  4. Consuming the Web Service
  5. Samples

Creating a Web Service

Creating a Web Service Project

First, we create an empty JAX-WS service Project, to create a JAX-WS Service Project,
  1. Go to the J2EE perspective

  2. select File->New->Project and select WSO2 category

  3. under WSO2 category select Service Hosting->Project Types->JAX-WS Service Project from the new project wizard dialog

  4. There are two ways to create a JAX-WS project. "Create a JAX-WS Project" and "Create a JAX-WS Project using WSDL", to create a empty project we select  "Create a JAX-WS Project"

  5. Name the project AccountServiceProject. Select a location for the project. Click Finish.

  1. Right-click the AccountServiceProject porject and choose New > JAX-WS Service Class

  2. Name the web service class 'AccountServiceImpl' and type "org.example.webservice" (or any other qualified package name) in package name field
  3. In Service Interface section, name the web service interface class 'AccountService' and type "org.example.webservice" (or any other qualified package name) in package name field
  4. deselect "Add sample web service method to new class".
  5. Click Finish. The Projects Explore view displays the structure of the project and the source code is shown in the java editor area.

  6. open service interface class (AccountService.java)  that you generated in the previous steps and add following method to interface

    public int createAccount(boolean print);
    public boolean checkAccount(int accountNo);
    public int checkAccountBalance(int accountNo);
    public boolean creditAccount(int accountNo, int amount);
    public boolean debitAccount(int accountNo, int amount);

    AccountService interface would look like this
    package org.example.webservice;
    
    import javax.jws.WebService;
    
    @WebService
    public interface AccountService {
    
     public int createAccount(boolean print);
    
     public boolean checkAccount(int accountNo);
    
     public int checkAccountBalance(int accountNo);
    
     public boolean creditAccount(int accountNo, int amount);
    
     public boolean debitAccount(int accountNo, int amount);
    
    }
    
  7. open web service implementation class (AccountServiceImpl.java) and implement missing methods as below
    package org.example.webservice;
    
    import java.util.Hashtable;
    import java.util.Random;
    
    import javax.jws.WebMethod;
    import javax.jws.WebParam;
    import javax.jws.WebService;
    
    @WebService(serviceName = "AccountServiceImpl")
    public class AccountServiceImpl implements AccountService {
    
     // account no list of the customers
     static Hashtable<integer, integer> accountStore = new Hashtable<integer, integer>();
    
     /**
      * generates the random account no at registration
      * 
      * @return the random account number integer
      */
     private int randomAccountGenerate() {
      Random randomGenerator = new Random();
      return randomGenerator.nextInt(1000);
     }
    
     /**
      * create a new account and store
      * 
      * @return accountNo
      * 
      */
    @WebMethod(operationName = "createAccount")
     public int createAccount(@WebParam(name = "printOnConsole") boolean print) {
    
      int accountNo = 0;
      // Generate the random account no
      accountNo = randomAccountGenerate();
      // create the entry in the account store
      accountStore.put(accountNo, 0);
      if(print){
       System.out.println("New account created, No= " + accountNo);
      }
      return accountNo;
     }
    
     /**
      * check whether the account is available
      * 
      * @param accountNo
      * @return isAvailable
      * 
      */
     @WebMethod(operationName = "checkAccount")
     public boolean checkAccount(@WebParam(name = "accountNo") int accountNo) {
      if (accountStore.containsKey(accountNo)) {
       return true;
      }
      return false;
     }
    
     /**
      * @param accountNo
      * @return balance
      */
     @WebMethod(operationName = "checkAccountBalance")
     public int checkAccountBalance(@WebParam(name = "accountNo") int accountNo) {
      if (checkAccount(accountNo)) {
       return accountStore.get(accountNo);
      }
      return 0;
     }
    
     /**
      * Increase the balance by credit amount
      * 
      * @param accountNo
      * @param amount
      * @return success
      * 
      */
     @WebMethod(operationName = "creditAccount")
     public boolean creditAccount(@WebParam(name = "accountNo") int accountNo,
       @WebParam(name = "amount") int amount) {
      if (checkAccount(accountNo)) {
       accountStore.put(accountNo,
         (accountStore.remove(accountNo) + amount));
       return true;
      }
      return false;
     }
    
     /**
      * Decrease the balance by the debit amount
      * 
      * @param accountNo
      * @param amount
      * @return Operation successfulness
      * 
      */
     @WebMethod(operationName = "debitAccount")
     public boolean debitAccount(@WebParam(name = "accountNo") int accountNo,
       @WebParam(name = "amount") int amount) {
      if (checkAccount(accountNo) && (accountStore.get(accountNo) >= amount)) {
       accountStore.put(accountNo,
         (accountStore.remove(accountNo) - amount));
       return true;
      }
      return false;
     }
    
    }
    

Deploying the Web Service

There are two method to deploy our JAX-WS service into WSO2 Application server

We can export JAX-WS project as a web application (war) file and deploy it on WSO2 Appliation server via web console
To create a deployable archive (WAR) and deploy on WSO2 Application server
  1. Right-click on project, 
  2. Select Export Project as Deployable Archive
  3. Then choose destination location.
  4. log into WSO2 Application server
  5. In the navigator, under Manage/JAX-WS/JAX-RS, click Add .
  6. Click Browse to locate the file you want to upload. If you want to add multiple JAX-WS/JAX-RS apps at the same time, click on the '+' sign at the right side, and new additional entry to upload a JAX-WS/JAX-RS archive will appear each time you click. So you can select all the archives you want and deploy them at the same time.
  7. Click Upload. The Running JAX-WS/JAX-RS Applications page appears. Subsequently, if the deployment is successful, it will appear in the list. If the application is faulty, a Faulty JAX-WS/JAX-RS Application link will appear. You can click the link to view the errors
We can add it as dependency of Carbon Application project which can deploy on WSO2 Application Server. 

To do this,
  1. Select File->New->Project...
  2. Select "Carbon Application Project" under WSO2 category
  3. Named the project as "CappProject" and select "AccountServiceProject" under dependencies and click Finish.  
  4. Go to Servers view, Right-click on the blank space -> New-> Server
  5. Select WSO2 Carbon 4.0 based server under WSO2 category
  6. Provide name for server name (e.g. WSO2 Application Server 4.5) and click next
  7. You will need to specify location of the WSO2 Application Server instance and click next. 
  8. In Next window, you can change configuration setting for server instance such as Carbon server port, server offset, etc.. You can change ports if you want. If the default ports are not used by any other application, you can keep them as they are. After setting the ports click  next. 
  9. In Next window, You will able to view available carbon application project in left panel, select   "CappProject" and click Add, then click finish 

Testing the Web Service

we can test our web service using WSO2 Application server's web console

log into WSO2 Application server console, In the navigator, under Manage/JAX-WS/JAX-RS, click List. The Running JAX-WS/JAX-RS Applications page appears.



Click on "Find Services", It will list all SOAP and RESTful services deployed through our web service project

We can copy WSDL's of the services  (e.g. http://10.100.3.42:9763/AccountServiceProject-1.0.0/services/account_service?wsdl) and try those services using the external Try-It tool which can be found under Tools/Try-It menu of WSO2 Application server.


we can try out "createAccount" method, it will return the account number of newly created account.



Consuming the Web Service

To consume our web service, we need to create web service client. CXF provides us with many options to build clients for our services. you can use CXF wsdl2java tool to generate web service client stubs. Make sure you installed and configured the Apache CXF runtime environment in your system and CXF Tools available in your system path.

wsdl2java -client <wsdl-path>

e.g.
wsdl2java -client http://10.100.3.42:9763/AccountServiceProject-1.0.0/services/account_service?wsdl

You will need to endorse the JAX-WS API 2.2 jar, otherwise run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1 compliant code instead.

wsdl2java tool  generates all of the code needed to consume our web service including sample client with main(), would look like this (AccountService_AccountServicePort_Client)

package org.example.webservice;

/**
 * Please modify this class to meet your needs
 * This class is not complete
 */

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;

/**
 * This class was generated by Apache CXF 2.5.2
 * 2012-06-12T17:33:20.094+05:30
 * Generated source version: 2.5.2
 * 
 */
public final class AccountService_AccountServicePort_Client {

    private static final QName SERVICE_NAME = new QName("http://webservice.example.org/", "AccountServiceService");

    private AccountService_AccountServicePort_Client() {
    }

    public static void main(String args[]) throws java.lang.Exception {
        URL wsdlURL = AccountServiceService.WSDL_LOCATION;
        if (args.length > 0 && args[0] != null && !"".equals(args[0])) { 
            File wsdlFile = new File(args[0]);
            try {
                if (wsdlFile.exists()) {
                    wsdlURL = wsdlFile.toURI().toURL();
                } else {
                    wsdlURL = new URL(args[0]);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
      
        AccountServiceService ss = new AccountServiceService(wsdlURL, SERVICE_NAME);
        AccountService port = ss.getAccountServicePort();  
        
        {
        System.out.println("Invoking debitAccount...");
        int _debitAccount_arg0 = 0;
        int _debitAccount_arg1 = 0;
        boolean _debitAccount__return = port.debitAccount(_debitAccount_arg0, _debitAccount_arg1);
        System.out.println("debitAccount.result=" + _debitAccount__return);


        }
        {
        System.out.println("Invoking checkAccount...");
        int _checkAccount_arg0 = 0;
        boolean _checkAccount__return = port.checkAccount(_checkAccount_arg0);
        System.out.println("checkAccount.result=" + _checkAccount__return);


        }
        {
        System.out.println("Invoking creditAccount...");
        int _creditAccount_arg0 = 0;
        int _creditAccount_arg1 = 0;
        boolean _creditAccount__return = port.creditAccount(_creditAccount_arg0, _creditAccount_arg1);
        System.out.println("creditAccount.result=" + _creditAccount__return);


        }
        {
        System.out.println("Invoking createAccount...");
        boolean _createAccount_arg0 = false;
        int _createAccount__return = port.createAccount(_createAccount_arg0);
        System.out.println("createAccount.result=" + _createAccount__return);


        }
        {
        System.out.println("Invoking checkAccountBalance...");
        int _checkAccountBalance_arg0 = 0;
        int _checkAccountBalance__return = port.checkAccountBalance(_checkAccountBalance_arg0);
        System.out.println("checkAccountBalance.result=" + _checkAccountBalance__return);


        }

        System.exit(0);
    }

}
We modify this class to meet our requirements as below
package org.example.webservice;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;

public final class AccountService_AccountServicePort_Client {

 private static final QName SERVICE_NAME = new QName(
   "http://webservice.example.org/", "AccountServiceService");

 private AccountService_AccountServicePort_Client() {
 }

 public static void main(String args[]) throws java.lang.Exception {
  URL wsdlURL = AccountServiceService.WSDL_LOCATION;
  if (args.length > 0 && args[0] != null && !"".equals(args[0])) {
   File wsdlFile = new File(args[0]);
   try {
    if (wsdlFile.exists()) {
     wsdlURL = wsdlFile.toURI().toURL();
    } else {
     wsdlURL = new URL(args[0]);
    }
   } catch (MalformedURLException e) {
    e.printStackTrace();
   }
  }

  AccountServiceService ss = new AccountServiceService(wsdlURL,
    SERVICE_NAME);
  AccountService port = ss.getAccountServicePort();
  int accountNo = 0;
  int accountBalance = 0;

  // Invoke the create account service.
  boolean printOnConsole = false; // print details on server's console
  accountNo = port.createAccount(printOnConsole);
  System.out.println(String.format(
    "Account Created Under Account Number :%d", accountNo));

  // Invoke the check account service
  System.out.println("Verifying Account Existence......");
  System.out.println("Account Existence Verifyied : "
    + port.checkAccount(accountNo));

  // Invoke the credit account service.
  boolean creditAccountResponse = port.creditAccount(accountNo, 20000);
  System.out.println("Account Credited by US$ 20000 : "
    + creditAccountResponse);

  // Invoke the check account balance service.
  accountBalance = port.checkAccountBalance(accountNo);
  System.out.println(String.format("Current Account Balance (US$): %d",
    accountBalance));

  // Invoke the debit account service.
  boolean debitAccountResponse = port.debitAccount(accountNo, 8000);
  System.out.println("Account Debited by  US$ 8000 : "
    + debitAccountResponse);

  // Invoke the check account balance service.
  accountBalance = port.checkAccountBalance(accountNo);
  System.out.println(String.format("Current Account Balance (US$): %d",
    accountBalance));

  System.exit(0);
 }

}

output of client program would look like this

6 comments:

  1. Hi Melan,

    Nice blog! Is there an email address I can contact you in private?

    ReplyDelete
  2. When I export my project using "Export Project as Deployable Archive" I got a war file.
    But the appserver UI asks for a jar file in the JAX-WS service deployment form.

    I renamed the .war file in .jar, then the deployment fails.
    Do you encounter this issue?

    ReplyDelete
    Replies
    1. Hi,

      Which version of AppServer you are using? You have to use AppServer 4.5.x or 5.x (unreleased) to deploy CXF based JAX-WS/JAX-RS Applications.You can deploy JAX-WS/JAX-RS webapp to AppServer using web console, under Manage -> JAX-WS/JAX-RS-> Add, you will see panel "Upload JAX-WS/JAX-RS Applications"

      Thanks

      Delete
    2. I use the AppServer on Stratoslive, and the WSO2 Carbon studio 2.0.1 as eclipse plugin

      Delete
  3. A web development company can offer your business not only web development services but, also a range of other services which can take your company to the very top. However, most importantly, these companies can offer you with a team of highly skilled web designers who can design the very best page for your company.

    ReplyDelete