How to generate a Web service using Web service Metadata Annotations (JSR 181)

Date: July 10, 2005
Last Updated: 18-Jan-06
Author:   Jonathan Maron


Introduction

One of the guiding principles for the next iteration of the Java Enterprise Platform (Java EE 5) is to provide ease-of-use features for the enterprise developer.  To that end, the Web Services Metadata for the Java Platform Specification (JCP JSR 181) simplifies the Java Web service programming model by providing a set of annotations that can be used to declaratively specify the Web services of an application.  The metadata annotates the Java source files that implement the Web services, eliminating the need to modify and maintain additional service artifacts such as deployment descriptors and JAX-RPC mapping files.  Thus, the process of developing and deploying a Web service is greatly simplified.

The Oracle Application Server provides the facilities for developing and deploying annotated Java source files as Web services.  This how-to will demonstrate some of the more common annotations, how they are leveraged in the source code, and how these source files are compiled and deployed to the server.

Prerequisites

What you need to know

  • Some familiarity with the standard J2EE deployment model.
  • Some familiarity with JAX-RPC 1.1

Software Requirements

  • OracleAS 10.1.3 is installed, available from OTN
  • JDK 5 or above, available here.
    • NOTE:  The Web service metadata processing in the Java EE platform depends on the Java SE Metadata facility (JCP JSR 175) that is only available starting with Java SE 5.

Notations.

  • %ORACLE_HOME% - The directory in which you installed OC4J.
  • %JAVA_HOME% - The directory where your JDK is installed

Building the Application

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

The Existing Bank Service 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 Using Metadata Annotations

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

  1. Mark the BankServiceImpl class as a Web service using the @WebService metadata annotation:

  2. @WebService (
        serviceName = "annotatedBank",
        targetNamespace = "http://service.annotatedBank"
    )
    public class BankServiceImpl {

    // service implementation code ...
    Note that in addition to marking the class as a Web service implementation, the annotation attributes provides the facilities for designating the service name and target name space.  These attributes will map to the generated WSDL <service> name attribute and <definitions> targetNameSpace attributes, respectively.

  3. Annotate the class methods with @WebMethod metadata annotations to expose them as Web service operations; methods that are not marked will not be publicly exposed.  The implementation class (BankServiceImpl) 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).  It is these methods that need to be annotated:

  4. @WebMethod (operationName="create-account")
    public String createAccount( @WebParam(name="accountName") String acctName,float initBalance) throws
           RemoteException,AccountException {
        return m_bank.addNewAccount(acctName,initBalance);
    }
    Note that in addition to marking the method as a Web service operation, this annotation designates the name of corresponding WSDL operation ( operationName attribute).  The annotation also provides the ability to specify the SOAP action header with the action attribute (not shown here).  The annotation above yields the following WSDL fragment:

    <portType name="BankServiceImpl" >
        <operation name=" create-account">
    . . .
     
  5. Annotate the class method parameters with the @WebParam metadata annotation.  This annotation allows the developer to specify the name of the parameter as it appears in the WSDL.  For RPC bindings this would yield the name of the WSDL <part> representing the parameter; for document bindings, this is the local name of the XML element representing the parameter (as is the case for this example):
  6.  
    @WebMethod (operationName="create-account")
    public String createAccount( @WebParam(name="accountName") String acctName,float initBalance) throws
           RemoteException,AccountException {
        return m_bank.addNewAccount(acctName,initBalance);
    }
The @WebParam annotation also allows the developer to specify whether the attribute is pulled from a SOAP header, the parameter mode (IN, OUT, or INOUT),  and the parameter's namespace  The annotation in this sample yields the following WSDL fragment:

<complexType name="create-account">
    <sequence>
        <element name=" accountName" type="string" nillable="true"/>
        <element name="param1" type="float"/>
    </sequence>
</complexType>
. . .

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.

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);
    }

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

Running the Application

Examining the Sample File Directories

List the contents of the ZIP file, for example

  • how-to-ws-annotations/src/java - contains all Java source code for the example.
    • client/annotations/client
      •  BankingApplication.java - A client application that invokes the bank service's methods.
    • service/annotations/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.
      • BankServiceImpl.java - The implementation of the bank web service (implements BankServiceInterface).
      • BankServiceInteface.java - The interface exposed by the bank web service.
  • how-to-ws-annotations/doc/
    • how-to-ws-annotations.html - This document.
    • blaf.css and blaf_otn.css - Style sheets used by this document.
  • how-to-jazn/build.xml - An Ant build file.
  • how-to-jazn/ant-oracle.xml - Used by build.xml
  • how-to-jazn/ant-oracle.properties - A list of properties used by ant build.

Configuring the Environment

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).

Note that you need to set the JAVA_HOME/bin (where the javac is located) in your PATH to perform the Web Service assembly operation using annotations.

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).

Note that you need to set the JAVA_HOME/bin (where the javac is located) in your PATH to perform the Web Service assembly operation using annotations.

Starting the 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.  In the case of this how-to, it is imperative that the JAVA_HOME environment variable if for a JDK 5 installation.

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

Generating, Compiling and Deploying the Application

To build the application, type the following command from the %HOWTO_HOME% directory:

ant

Note that for this sample, the ant command should be executed in a shell in which the %JAVA_HOME% environment point to a JDK 5 installation (as noted above, this is required since Web services metadata implementations leverage the Java SE metadata facility available starting with version 5).

You should now have the newly created annotatedBank .ear in your %HOWTO_HOME%/lib directory.

if the build is successful, the default ant target will also test whether OC4J is running and then attempt to deploy the application .

Note that you can also deploy the application separately . Ensure the %ORACLE_HOME% environment variable is defined, and from the %HOWTO_HOME% directory, type the command:

ant deploy

Running the Application

Run the sample by providing the following command, including a name as the program argument:

ant run

You should see the following output in your console:

[java] Created an account for DemoUser1 with $2000.50
[java] AccountID for DemoUser is 192.168.0.101_DemoUser1
[java] Depositing $500.50 into account.
[java] Current balance is now 2501.0
[java] Withdrawing $250.00 from account
[java] Current balance is now 2251.0
[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

Summary

This how-to provided a detailed look at how to generate a web service from an annotated Java source file  We have seen that the process involves:

  • Creating a service implementation class that exposes the desired functionality.
  • Annotating the service Java source file with the Web Service Metadata annotations.
  • Generating the deployable service module.
  • 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