How-To Develop a JAX-WS Service From a Web Service Description Language (WSDL) Document

First Publication: 03-May-2007
Author: Tugdual Grall


Introduction

The Oracle Application Server provides the facilities for generating a web service from an existing Web Service Description Language (WSDL) document.  This top-down approach, although not as simple as the bottom-up approach (exposing an existing class as a web service), is preferable for a number of reasons:

  • Careful consideration of the operations and messages you will expose leads to much more usable and maintainable web services.
  • Implementation artifacts are much less likely to be exposed by the web service, and
  • Interoperability with other web services is much more likely given that the developer has much more control over the WSDL.

The process of generating a web service from a WSDL document and creating an associated client application involves:

  • Generating a service endpoint interface (SEI) from the WSDL.  This interface exposes the functionality and operations defined in the WSDL, using Java annotations.
  • Creating a service implementation comprised of an SEI implementation class and supporting classes.  These classes simply provide implementations for each of the methods declared in the service interface.  In this example the implementation class will instantiate, and delegate method calls to, an underlying bank object.
  • Packaging the service as an application module.  The service classes and all associated generated artifacts are packaged up as standard J2EE deployment modules. For simplicity, this application will be composed of a Web application (WAR file)
  • Deploying the service.  The service module is deployed to the Oracle Application Server.
  • Generating the client proxies.  Client proxies/stubs are generated from the WSDL file for the deployed service.
  • Writing a client application.  An application is written that leverages the client proxies to invoke remote service operations.

Admittedly, the argument could be made that it may be simpler to simply modify the underlying implementation class and expose it directly as a web service by having it implement the SEI (removing the requirement for creating the service implementation class as noted above).  Although that is a possibility the more general, and potentially more frequent, case is that the existing class can not be modified.  Rather, the functionality provided by the existing class needs to be exposed to remote clients without alteration to the target class.  It is this scenario we will explore in the following sample.

What are the Prerequisites?

What Should You Know?

  • Some familiarity with the standard J2EE deployment model.

What are the Software Requirements?

  • Oracle Containers for Java EE (11.1.1.0.0) Technology Preview, available from OTN
  • Sun's JDK 1.5, available here

What are the Notations?

The following conventions are used throughout the document:

  • %ORACLE_HOME% - The directory where you installed OC4J or Oracle Application Server
  • %JAVA_HOME% - The directory where your JDK is installed

How to Build the Application?

Let's take a closer look at the steps involved in creating the web service application from an existing Java class.  These steps have already been performed for this sample but are provided for illustrative purposes.

The Existing Bank Implementation

The BankMemDB class is an implementation of the Bank interface and provides standard banking functionality:

public class BankMemDB implements Bank{
 public static BankMemDB newInstance(){}
  public String addNewAccount(String name, float initBalance){}
  public Account getAccount(String id) {}
  public List getAccounts() {}
}


This class is the existing class whose functionality we wish to provide access to via a web service interface.

Exposing the Bank as a web service

In order to expose an instance of the existing Bank as a web service using the top-down development approach we will:

 

1.Generate a service interface from the service WSDL. The complete WSDL file for can be found here.   The following portion of the WSDL file shows the operations that end up in the SEI:

    <portType name="BankService">
        <operation name="getBalance">
            <input message="tns:getBalanceInput" />
            <output message="tns:getBalanceOutput" />
            <fault name="AccountException" message="tns:AccountException"/>
        </operation>
        <operation name="getAccountID">
            <input message="tns:getAccountIDInput" />
            <output message="tns:getAccountIDOutput" />
            <fault name="AccountException" message="tns:AccountException"/>
        </operation>
        <operation name="deposit">
            <input message="tns:depositInput" />
            <output message="tns:depositOutput"/>
            <fault name="AccountException" message="tns:AccountException"/>
        </operation>
        <operation name="withdraw">
            <input message="tns:withdrawInput" />
            <output message="tns:withdrawOutput"/>
            <fault name="AccountException" message="tns:AccountException"/>
        </operation>
        <operation name="createAccount">
            <input message="tns:createAccountInput"/>
            <output message="tns:createAccountOutput"/>
            <fault name="AccountException" message="tns:AccountException"/>
        </operation>
    </portType>

 

The service interface generated from the WSDL represents the functionality and operations we wish to provide to client applications:

@WebService(targetNamespace="http://howto.jaxws.topdown.service/", name="BankService")
public interface BankService
{
  @WebMethod
  @ResponseWrapper(targetNamespace="http://howto.jaxws.topdown.service/",
    className="howto.jaxws.topdown.service.generated.types.GetBalanceResponse",
    localName="getBalanceResponse")
  @RequestWrapper(targetNamespace="http://howto.jaxws.topdown.service/",
    className="howto.jaxws.topdown.service.generated.types.GetBalance",
    localName="getBalance")
  @Action(input="http://howto.jaxws.topdown.service/BankService/getBalance/Request", fault =
      { @FaultAction(value="http://howto.jaxws.topdown.service/BankService/getBalance/Fault/AccountException",
          className = AccountException.class)
        } , output="http://howto.jaxws.topdown.service/BankService/getBalance/Response")
  @WebResult(targetNamespace="")
  public float getBalance(@WebParam(targetNamespace="", name="acctID")
    String acctID, @WebParam(targetNamespace="", name="acctName")
    String acctName)
    throws AccountException;
...
...
}


You will note that this service interface use the @WebService annotation  at the class level and other JAX-WS annotations at method and parameters level to define the service operations and fault. All these annotations and values are used by the container to generate proper WSDL and SOAP messages.
2. Create a service implementation.  The implementation class (BankServiceImpl) implements the service interface (BankService) and delegates various calls to a Bank instance it creates. 

@WebService( endpointInterface="howto.jaxws.topdown.service.generated.BankService", serviceName="BankService")
public class BankServiceImpl implements BankService{
    ...
    ...

    public float getBalance(String acctID, String acctName) throws
             AccountException {
        Account theAccount = m_bank.getAccount(acctID);
        if(theAccount == null){
            throw new AccountException("No account found for " + acctID,null);
        }
        return theAccount.getBalance();
    }


 ...
 ...
}

You will note that the implementation class uses the @WebService annotation to define the endpoint interface to use to define the service. This annotation is used during deployment to define the behavior of the Web Service itself, for example the name of the operations, parameters and namespaces, that are in this example extract from the WSDL during the generation of the interfaces.


Creating a client application

Once the service has been created and deployed a client application that leverages the service can be created from the WSDL file generated as part of the service generation process (see Generating, Compiling, and Deploying the Application). 

The Oracle Application Server's client generation tool creates, in addition to the classes required by the JAX-RPC runtime, a convenience class that shields the developer from some of the more mundane JAX-RPC service instantiation tasks.  This class, referred to as a utility client, is leveraged to invoke methods on the remote service by the banking application (BankApplication) ( m_endpoint is the class attribute for the utility client):

        void demoGoodAccount() throws Exception {
        String accountID = m_endpoint.createAccount(DEMO_USER1,2000.50f);
        // ... print statements removed for clarity ...
        m_endpoint.deposit(accountID,500.50f);
        float balance = m_endpoint.getBalance(accountID,DEMO_USER1);
        System.out.println("Current balance is now " + balance);
        System.out.println("Withdrawing $250.00 from account");
        m_endpoint.withdraw(accountID,250.00f);
        balance = m_endpoint.getBalance(accountID,DEMO_USER1);
    }

The javadocs for the components above can be found here.

Given the bank implementation and support classes, the service interface, and the service implementation we can proceed with the generation and deployment of a web service.

How to Run the Sample

In this sample we will create a banking web service that wraps and delegates its functionality to an underlying bank object.

Examining the How-To Distribution

The How-To zip file should contain the following:

  • ./src/ - contains all Java source code for the example.
    • client/topdown/client
      •  BankAccountClient.java - A client application that invokes the bank service's methods.
    • service/topdown/service
      • Account.java - A bank account object.
      • AccountException .java - An exception for indicating account transgressions (insufficient funds, maximum withdrawl exceeded, etc.).
      • Bank .java - The interface exposed by the bank object wrapped by the service implementation.
      • BankFactory.java -  A factory that instantiates objects that implement the Bank interface.
      • BankMemDB.java - An in-memory implementation of the Bank interface.
      • BankServiceInteface.java - The interface exposed by the bank web service.
  • ./ doc/topdown-how-to.html - This document.
  • ./ etc/bank.wsdl- The WSDL document used to generate the service
  • ./ etc/logging.properties- Logger properties file to configure the client side Java logging.
  •  
  • ./build.xml - An Ant build file.
  • ./ant-oracle.xml - Used by build.xml to execute the various Oracle Application Server tasks required for assembly and deployment of the web service and client.
  • ./ant-oracle.properties - Properties required for the proper execution of the sample's build script.

Setting Up the Application

Please check to make sure that the following properties are configured correctly in the ant-oracle.properties file located in the root of the sample's distribution (NOTE:  Some of these properties will default to the values of corresponding environment variables as noted below.  If you have these variables setup in your environment you may not have to alter the values in the file).  If necessary, modify these variable to the proper values for you environment:
  • oracle.home - the root directory of oracle installation.  Defaults to ORACLE_HOME environment variable.
  • java.home -  the root directory of JDK installation.  Defaults to JAVA_HOME environment variable.
  • oracleas.host - the hostname of the platform on which the OC4J instance is running.  Defaults to localhost.
  • oracleas.http.port - the port on which the OC4J HTTP listener is listening.  Defaults to 8888.
  • oracleas.admin.port  - the port on which the OC4J administration processor is listening.  Defaults to 23791.
  • oracleas.admin.user - the name of the OC4J administrator.  Defaults to " oc4jadmin".
  • oracleas.admin.password - the password for the OC4J administrator.  Defaults to " welcome".
  • oracleas.binding.module - the name of the HTTP web site to which the deployed application is bound.  Defaults to " default-web-site".

In addition, please make sure that the ant command associated with the OC4J ant distribution is in your execution path ( %ORACLE_HOME%/ant/bin).

Running an OC4J Instance

Start an OC4J 11 g Technology Preview instance as follows:
  • Stand Alone Installation: %ORACLE_HOME%/bin/oc4j start
    Note that the oc4j command expects the JAVA_HOME environment variable to point to a full JDK installation.

 

Generating, Compiling and Deploying the Application

To generate, compile, and deploy the components of this application simply type the following command from a command prompt in the root directory of the sample:

  • ant

Executing the default "all" target of the supplied build.xml file performs the following steps:

  • Generates the service endpoint interface file - generate-interface target.  The generation is performed utilizing the genInterface ant task:
                         <oracle:genInterface wsdl="./etc/bank.wsdl"
                output="${src.webservice.dir}"
                databinding="jaxb20"
                packageName="howto.jaxws.topdown.service.generated"
                valueTypePackagePrefix="howto.jaxws.topdown.service.generated.types">
                <classpath>
                    <pathelement location="${ORACLE_HOME}/webservices/lib/wsa.jar"/>
                </classpath>
            </oracle:genInterface>
The key point here, is the use of the databinding="jaxb20"  parameters that indicates to Oracle WSA tools to use JAXB as binding mechanism and in the same time use JAX-WS annotations to define the service. In addition you can organize your code in different packages to control the location of the generated sources.
  • Compiles all the web service source files (bank and service interfaces and implementations) located in src/service subdirectories - compile-webservice target
  • Packages all the sources in a WAR file to prepare deployment of the application. One interesting things regarding JavaEE 5 is the fact that you do not need deployment descriptor to create J2EE module. So to create a WAR  you only need to package all the classes in the WEB-INF/lib directory of the archive. And during deployment OracleAS will intercept the various annotations and generates the Web Service and its endpoint URI.
    In this how to the packaging is done using the package-web target.
  • Deploys the Web application module.  The .war file generated in the previous step is now deployed to the server using the ant deploy ant task:  - deploy-ear target
            <oracle:deploy deployerUri="${oracleas.deployer.uri}"
            userId="${oracleas.admin.user}"
            password="${oracleas.admin.password}"
            file="${out.dir}/${web.name}.war"
            deploymentName="${app.name}"
            logFile="${log.dir}/deploy-ear.log"
            bindAllWebApps="${oracleas.binding.module}" />
 
In this task, the application is deployed and also binded to the OC4J web site. (see bindAllWebApps parameter)
       
        

  • Creates the client proxy source files.  Once the service is deployed and available the client proxy can be generated from the available WSDL file (you can actually view the generated WSDL file of the service by pointing a browser to the location http://<OC4J host>:<OC4J http port>/how-to-jaxws-topdown/BankService?wsdl).   The genProxy ant task is utilized for this purpose:
            <oracle:genProxy wsdl="http://${oracleas.host}:${oracleas.http.port}/${app.name}/${endpoint.name}?wsdl"
            output="${src.cli.dir}"
            packageName="howto.jaxws.topdown.client.proxy"
            valueTypePackagePrefix="howto.jaxws.topdown.client.proxy.types"
            dataBinding="jaxb20"
            >
            <classpath>
                <pathelement path="${bld.cli.dir}"/>
                <pathelement location="${OC4J_HOME}/webservices/lib/wsa.jar"/>
            </classpath>
        </oracle:genProxy >
 
         Once again by using dataBinding="jaxb20" WSA knows that it must generated JAXB types and create a JAX-WS based service.
  • Compiles the client application and associated proxy files.  The proxy files generated in the previous step and the client application utilizing the proxy for remote communication are compiled and placed in the ./build/how-to-jaxws-topdown/how-to-jaxws-topdown-client directory.

Running the Application

Now that the web service is deployed and the client is generated and compiled we are ready to execute the application.  From a command prompt in the root directory of the sample simply type:

  • ant run

The generated output from the "run" target should be as follows:

         run:
        [java] Created an account for DemoUser1 with $2000.50
        [java] AccountID for DemoUser is 138.2.8.242_DemoUser1
        [java] Depositing $500.50 into account.
        [java] Current balance is now 2501.0
        [java] Withdrawing $250.00 from account
        [java] Attempting to create an account for DemoUser2 with no initial funds
        [java] Could not createAccount for DemoUser2
        [java] Insufficient funds for new account.  You must start an account with more than $0
        [java] Created an account for DemoUser3 with $3000.00
        [java] Attempting to withdraw 2500.00 from the account.  The account cap is 2000.00
        [java] Unable to withdraw funds.
        [java] Exceeded maximum withdrawal of $2000.00

    BUILD SUCCESSFUL

Summary

This how-to provided a detailed look at how to generate a web service from a WSDL document.  We have seen that the process involves:

  • Creating a WSDL document that reflects the types, messages, and operations you wish to expose.
  • Creating a service interface from the WSDL that exposes the desired functionality.
  • Creating an implementation of the service interface that utilizes an instance of the existing class to service requests.
  • Compiling and Pacakging the Web Application 
  • Deploying the service application module to the Oracle Application Server.
  • Generating the client proxy code based on the service WSDL file.
  • Writing a client application the leverages the client proxies to interact with the deployed service.
Left Curve
Popular Downloads
Right Curve
Left Curve Right Curve