How-To Develop a Web Service From an Existing Java Class

First Created: 04-Nov-04
Last Updated: 18-Jan-06
Author: Jon Maron

Introduction

The Oracle Application Server provides the facilities for making a standard java object accessible via a web service interface.  This how-to will detail the steps required for exposing an existing class as a web service available to remote clients.

The process of exposing an existing java object as a web service and creating an associated client application involves:
  • Creating a service interface.  This interface exposes the functionality and operations the service provides.
  • Creating a service implementation class.  This class simply provides implementations for each of the methods declared in the service interface.  In this example the implementation class will instantiate, and delegate method calls to, the underlying bank object.
  • Generating the web service's WSDL file and associated artifacts (mapping file, etc.).  A WSDL file is generated based on the service interface provided so that clients can now be created to access the web service.
  • Packaging the service as an application module.  The service classes and all associated generated artifacts are packaged up as standard J2EE deployment modules.
  • 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 existing java class and expose it directly as a web service (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?

  • OracleAS 10.1.3 is installed, available from OTN
  • Sun's JDK 1.4.2_03 or above
  • Apache Ant 1.6.2 or above, to build the application, available from here

What are the Notations?

The following conventions are used throughout the document:
  • %ORACLE_HOME% - The directory 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) throws AccountException;
    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.
 
Instances of the Bank interface (e.g. BankMemDB) are created by a BankFactory:
public class BankFactory {
    public BankFactory();
    public Bank createBank();
}

Exposing the Bank as a web service

In order to expose an instance of the existing Bank as a web service we will:

  1. Create a service interface. The service interface represents the functionality and operations we wish to provide to client applications:
interface BankService extends java.rmi.Remote{
    String createAccount(String acctName,float initBalance) throws RemoteException, AccountException;
    void deposit(String acctID, float amount) throws RemoteException, AccountException;
    void withdraw(String acctID, float amount) throws RemoteException, AccountException;
    float getBalance(String acctID, String acctName)throws RemoteException, AccountException;
    String getAccountID(String acctName) throws RemoteException, AccountException;
}
You will note that this service interface extends the java.rmi.Remote interface and that all methods throw (at least) the java.rmi.RemoteException exception, a requirement of the JAX-RPC specification.
  1. Create a service implementation.  The implementation class (BankServiceImpl) implements the service interface (BankService) and delegates various calls to a Bank instance it creates.  For example, the createAccount() method simply calls the underlying Bank's addNewAccount() method (m_bank is an instance of BankMemDB obtained from the BankFactory):
    public String createAccount(String acctName,float initBalance) throws RemoteException,AccountException {
        return m_bank.addNewAccount(acctName,initBalance);
    }

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:

  • bottomup/src/ - contains all Java source code for the example.
    • client/bottomup/client
      •  BankAccountClient.java - A client application that invokes the bank service's methods.
    • service/bottomup/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.
      • BankService.java - The implementation of the bank web service (implements BankServiceInterface).
      • BankServiceInteface.java - The interface exposed by the bank web service.
  • bottomup/ bottomup-how-to.html - This document.
  • bottomup/build.xml - An Ant build file.
  • bottomup/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.
  • botomup/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).

Configuring the Environment for a Managed OracleAS Instance

If you are running a managed version of the Oracle Application Server 10 g, you are using OPMN, you must change the following values to match your configuration:
  • oracleas.http.port - the port on which the Oracle HTTP Server (OHS) is listening.
  • oracleas.admin.port  - The OPMN request port, as specified in opmn.xml, the default value is 6003.  You can also check the OPMN request port using the following command: %ORACLE_HOME%/opmn/bin/opmnctl status -port
  • oracleas.admin.user - the name of the OC4J administrator.  Defaults to " oc4jadmin".
  • oracleas.deployer.uri - the URI to use to do the different administration operation (deployment, undeployment). The file contains different URI depending of the topology of your application: stand alone OC4J, Managed Single Node or Managed Cluster. You just need to un-comment the URI that matches your toplogy.
  • oracleas.oc4j.instance - This is the managed OC4J instance where the application will be deployed or undeployed.

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 OracleAS 10 g (10.1.3) 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.

  • OracleAS Managed Installation: %ORACLE_HOME%/opmn/bin/opmnctl startall

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:

  • Compiles all the web service source files (bank and service interfaces and implementations) located in src/service subdirectories.
  • Generates the WSDL file and associated artifacts (JAX-RPC mapping file, etc.).  The generation is performed utilizing the assemble ant task:
                   <oracle:assemble appName="${app.name}"
            serviceName="${app.name}"
            interfaceName="bottomup.service.BankService"
            className="bottomup.service.BankServiceImpl"
            input="${bld.webservice.dir}"
            output="${out.dir}"
            ear="${lib.dir}/${ear.name}.ear">
            <classpath>
                <pathelement location="${ORACLE_HOME}/webservices/lib/wsa.jar"/>
            </classpath>
        </oracle:assemble>

        The output of this task is a J2EE application module (ear file) that contains the various files required for the deployment of the bank service.
  • Deploys the application module.  The .ear file generated in the previous step is now deployed to the server using the ant deploy ant task:
            <oracle:deploy moduleType="ear"
            host="${oc4j.host}"
            port="${oc4j.admin.port}"
            userId="${oc4j.admin.user}"
            password="${oc4j.admin.password}"
            file="${lib.dir}/${app.name}.ear"
            deploymentName="${app.name}"
            logFile="deploy-ear.log"/>

          In addition, in order for the service to be accessible via the Oracle Application Server's web tier it must be bound to an web site:
       
        <oracle:bindWebApp deploymentName="${app.name}"
            host="${oc4j.host}"
            port="${oc4j.admin.port}"
            userId="${oc4j.admin.user}"
            password="${oc4j.admin.password}"
            webModule="${web.name}"
            webSiteName="${oc4j.binding.module}"
            contextRoot="/${app.name}"/>
  • 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>/bank/bank?wsdl).   The genProxy ant task is utilized for this purpose:
            <oracle:genProxy wsdl="http://${oc4j.host}:${oc4j.http.port}/${app.name}/${app.name}?wsdl"
            output="${src.cli.dir}"
            packageName="bottomup.client.proxy"
            >
            <classpath>
                <pathelement path="${bld.cli.dir}"/>
                <pathelement location="${ORACLE_HOME}/webservices/lib/wsa.jar"/>
            </classpath>
        </oracle:genProxy>

  • 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/bank/bank-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

This command executes the client application that performs the following operations and message exchanges (the messge exchange figures below were captured by the JDeveloper 10g TCP Packet Monitor and are provided to illustrate the underlying message exchanges performed during the execution of the remote service invocations):

  • Creates an account  for DemoUser1 with an initial balance of $2000.50:
Create account message exchange
  • Deposits an additional amount of $500.50 into the account for DemoUser1:
Deposit message exchange
  • Queries for the current balance:
Balance query message exchange
  • Withdraws $250.00 from the account of DemoUser1:
Withdrawl message exchange
  • Attempts to create an account with $0.00 for DemoUser2.  This attempt fails since the amount of funds is instufficient:
Bad account creation msg exchange
  • Creates an account for DemoUser3 with an initial balance of $3000.00:
Large account creation msg exchange
  • Attempts to withdraw $2500.00 from the account of DemoUser3.  This attempt fails since the withdrawl amount exceeds the maximum allowed of $2000.00:
Large withdrawl msg exchanges
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 access to an existing java class can be facilitated using a web service interface.  We have seen that the process involves:
  • Creating a service interface that exposes the desired functionality.
  • Creating an implementation of the service interface that utilizes an instance of the existing class to service requests.
  • Generating the required service artifacts (most imporantly, the WSDL file describing the service).
  • Deploying the service 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
Untitled Document