Skip Headers

Oracle® Application Server Web Services Developer's Guide 10g Release 3 (10.1.3) B14434-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# 6 Assembling a Web Service with Java Classes

This chapter describes how to assemble stateless and stateful Web services based on Java classes. The Web service assembly is performed bottom up by WebServicesAssembler.

A stateless Web service does not carry any local state across calls. In contrast, a stateful Web service may carry state across calls, and the results of method invocations depend on the scope. The stateful Web services supported by Oracle Application Server Web Services is HTTP-based. It works only for SOAP/HTTP endpoints and not for SOAP/JMS endpoints.

Stateless Web services interoperate with .NET or any vendor's Web services. Stateful OracleAS Web Services based on Java classes contain Oracle-proprietary extensions and may not operate with other services unless the service provider makes available scopes with the same semantics.

This chapter has the following sections:

- Exposing Java Classes as a Stateless Web Service

- Writing Java Class-Based Web Services

- Exposing Java Classes as a Stateful Web Service

- Tool Support for Exposing Java Classes as Web Services

## Exposing Java Classes as a Stateless Web Service

You can use WebServicesAssembler to assemble Web services from Java classes that conform to the JAX-RPC 1.1 specification. Exposing Java classes as a Web service is convenient if you want a lightweight system and do not need the transactional capabilities that an EJB container offers.

WebServicesAssembler assembles the service bottom up. It starts with the Java classes you want to expose as a Web service and generates a deployable EAR file containing the WSDL, the mapping files, the implementation files, and the deployment descriptors.

JAX-RPC requires you to provide a Java class that contains the methods you want to expose as a service and its interface. For more information on the requirements on the class and interface, see "Writing Java Class-Based Web Services".

A Web service based on Java classes can be invoked by a client written in Java, .NET, or any other programming language. The client can be based on static stub or Dynamic Invocation Interface (DII).

### Prerequisites

Before you begin, provide the following files and information.

- Supply a compiled Java class and interface that contains the methods that you want to expose as a service. The class and its interface must conform to the JAX-RPC standards for a Web service. If you are exposing Java classes as a stateless Web service, see "Writing Stateless Web Services". If you are exposing Java classes as a stateful Web service, see "Exposing Java Classes as a Stateful Web Service".

- Decide whether you want WebServicesAssembler to only generate the service files or if you want it to package the files into a deployable archive. The `ear` argument packages the files into an archive. If you do not specify `ear`, then the files are stored in a directory specified by `output`. For more information on these arguments, see "ear", "output", and "war".

- If the methods in the Java class use nonstandard data types, such as those described in "Mapping Java Types to XML and WSDL Types" in the Oracle Application Server Advanced Web Services Developer's Guide and in Table 4-1, you must specify a custom serializer to process them. For more information on using nonstandard data types, see "Custom Serialization of Java Value Types" in the Oracle Application Server Advanced Web Services Developer's Guide. For a list of the supported data types, see the JAX-RPC 1.1 specification available from: `http://java.sun.com/webservices/jaxrpc/index.jsp`.

- If your Java classes need to work with any additional message processing components, for example to provide reliability and security features, you can specify message handlers. For more information, see "Configuring Handlers in an Ant Task" and Chapter 16, "Processing SOAP Headers".

### How to Assemble a Stateless Web Service

The following steps describe how to use WebServicesAssembler to expose a stateless Web service from a Java class:

1. Provide the compiled Java class that you want to expose as a Web service and its compiled interface.

   This example uses the `HelloInterface` interface and the `HelloImpl` class. You can find code listings of these files in "Defining a Java Interface" and "Defining a Java Class".

2. Generate the service artifacts by running the WebServicesAssembler with the `assemble` command. This example assumes that the interface and implementation classes are compiled to the `./build/classes/service` directory.

       java -jar wsa.jar -assemble
           -appName hello
           -serviceName HelloService
           -interfaceName oracle.demo.hello.HelloInterface
           -className oracle.demo.hello.HelloImpl
           -input ./build/classes/service
           -output build
           -ear dist/hello.ear
           -uri HelloService
           -targetNamespace http://hello.demo.oracle

   The output of this command is an EAR file that contains the contents of a WAR file that can be deployed to an OC4J instance. The `dist` directory contains the J2EE Web services-compliant application EAR file, `hello.ear`. For more information on the required and optional arguments to `assemble`, see "assemble".

3. Deploy the service and bind the application.

   Deploy EAR files in the standard manner into a running instance of OC4J. For more information on deploying EAR files, see the Oracle Containers for J2EE Deployment Guide. The following is a sample deployment command:

       java -jar <OC4J_HOME>/j2ee/home/admin_client.jar deployer:oc4j:localhost:port <user> <password>
                   -deploy
                   -file dist/hello.ear
                   -deploymentName hello
                   -bindWebApp default-web-site

   The following list describes the variables used in this code example.

   - `<OC4J_Home>`—The directory containing the OC4J installation.

   - `<user>`—The user name for the OC4J instance. The user name is assigned at installation time

   - `<password>`—The password for the OC4J instance. The password is assigned at installation time

   - `default-web-site`—The Web site to which the application will be bound. This is usually `default-web-site`. To configure Web sites, see the `server.xml` file in `<OC4J_HOME>/j2ee/home/config`.

4. (Optional) Check that deployment succeeded. OracleAS Web Services provides a Web Service Home Page for each deployed Web service. See "Using the Web Services Home Page" for information on accessing and using the Web service home page.

5. Generate the client-side code:

   - For the J2SE environment, generate stubs (client proxies) for a J2SE Web service client by running the WebServicesAssembler tool with the `genProxy` command. For more information on generating and assembling client-side code for the J2SE environment, see Chapter 14, "Assembling a J2SE Web Service Client".

   - For the J2EE environment, generate a Service Endpoint Interface and a mapping file for a J2EE Web service client by running the WebServicesAssembler tool with the `genInterface` command. For more information on generating and assembling client-side code, see Chapter 13, "Assembling a J2EE Web Service Client".

   For example, the following command generates stubs that can be used for a J2SE client:

       java -jar wsa.jar -genProxy
                         -output build/src/client/
                         -wsdl http://localhost:8888/hello/HelloService?WSDL
                         -packageName oracle.demo.hello

   This command generates the client proxies and stores them in the directory `build/src/client`. The client application uses the stub to invoke operations on a remote service. For more information on the required and optional arguments to `genProxy`, see "genProxy".

6. Write the client application.

7. Compile and run the client.

   List the appropriate JARs on the classpath before compiling the client. Table A-2, "Classpath Components for a Client Using a Client-Side Proxy" lists all of the JAR files that can possibly be used on the client classpath. As an alternative to listing individual JARs, you can include the client-side JAR, `wsclient_extended.jar` on the client classpath. This JAR file contains all the classes necessary to compile and run a Web service client. The classes are from the individual JAR files listed in Table A-2. See "Setting the Web Service Proxy Client Classpath" for more information on `wsclient_extended.jar` and the client classpath.

#### Ant Tasks for Generating a Stateless Web Service

The current release provides Ant tasks for Web services development. The following code samples show how the WebServicesAssembler commands in the preceding examples can be rewritten as Ant tasks.

For more information on Ant tasks for WebServicesAssembler commands, see Chapter 17, "Using WebServicesAssembler".

For the `assemble` command, here is an example Ant task. In this example, `build/classes/client` is the directory where client classes (stubs) will be generated.

    <oracle:assemble appName="hello"
            serviceName="HelloService"
            input="./build/classes/service"
            output="build"
            ear="dist/hello.ear"
            targetNamespace="http://hello.demo.oracle"
            >
                <oracle:porttype
                    interfaceName="oracle.demo.hello.HelloInterface"
                    className="oracle.demo.hello.HelloImpl">
                    <oracle:port uri="HelloService" />
                </oracle:porttype>
                <oracle:classpath>
                    <pathelement location="build/classes/client"/>
                </oracle:classpath>
    </oracle:assemble>

For the `genProxy` command, here is a sample Ant task. The client proxies will be stored in the directory `build/src/client`.

    <oracle:genProxy  wsdl="http://localhost:8888/hello/HelloService?WSDL"
               output="build/src/client"
               packageName="oracle.demo.hello"
    />

## Writing Java Class-Based Web Services

To use JAX-RPC to create a Web service with Java files, you must provide a public interface that defines the remote methods that you want to expose as a service. The interface definition must also extend `java.rmi.Remote`, and its methods must throw a `java.rmi.RemoteException` object. The interface must also reside in a package.

You can also use the public interface to list the signatures for the public methods, or public methods with supported data types, that you want to make available to the Web service. That is, you can employ the interface to filter the methods that you want to expose.

The implementation of the interface must satisfy other requirements:

- The class must contain a default public constructor.

- The class methods must implement the methods of the Service Endpoint Interface.

- Class methods must not be final.

- For stateful Web services, the class must implement `java.io.Serializable`.

- The class must reside in a package.

- All methods in the interface must throw `java.rmi.RemoteException`. In addition, methods can declare other, specific exceptions. These must extend `java.lang.Exception` directly or indirectly but must not be a `RuntimeException`.Method parameters and return types must be JAX-RPC supported Java types. "Mapping Java Types to XML and WSDL Types" in the Oracle Application Server Advanced Web Services Developer's Guide provides a list of supported Java types.Holder classes can be used as method parameters. These holder classes are either generated or derived from the `javax.xml.rpc.holders` package.The implementation class must not include public final static declarations.A service endpoint interface must not include a remote reference (a class that implements `RemoteInterface`) as either a parameter or a return type. A Java array or JAX-RPC value type must not include a remote reference as a contained element.

For a description of all of the requirements on the interface, see the Enterprise Web Services 1.1 specification at the following Web address: `http://www.jcp.org/aboutJava/communityprocess/final/jsr109/index.html`

When a Web service client makes a service request, OC4J runs the corresponding method in that class. There are very few restrictions on what actions the Web service can perform. At a minimum, the Web services generate some data that is sent to the client or perform an action specified by a Web service request.

The following sections illustrate how to write stateless Web services based on Java classes. For information on writing stateful Web services based on Java classes, see "Exposing Java Classes as a Stateful Web Service".

### Writing Stateless Web Services

OracleAS Web Services supports stateless implementations for Java classes running as Web services. For a stateless Java implementation, OracleAS Web Services creates multiple instances of the Java class in a pool; any one of the instances can be used to service a request. After servicing the request, the object is returned to the pool for use by a subsequent request.

Developing a stateless Java Web service consists of the following steps:

- Defining a Java Interface

- Defining a Java Class

#### Defining a Java Interface

Example 6-1 displays the `HelloInterface.java` interface for the stateless Web service. To comply with the JAX-RPC 1.1 specification, the interface must reside in a package. It must also extend `java.rmi.Remote`, and its methods must throw a `java.rmi.RemoteException` object.

Example 6-1 Defining an Interface for a Stateless Web Service

    package oracle.demo.hello;

    import java.rmi.RemoteException;
    import java.rmi.Remote;

    public interface HelloInterface extends Remote {
        public String sayHello(String name) throws RemoteException;
    }

#### Defining a Java Class

Create a Java class by implementing the methods in the interface that you want to expose as a Web service. A Java class for a Web service usually defines one or more public methods. To comply with the JAX-RPC 1.1 specification, the implementation class must reside in a package. It must also import `java.rmi.Remote` and `java.rmi.RemoteException`.

Example 6-2 displays the public class, `HelloImpl`. This class defines a public method, `sayHello`, that returns the string `"Hello` name`!"` where name is an input value.

Example 6-2 Defining a Public Class for a Stateless Web Service

    package oracle.demo.hello;

    import java.rmi.RemoteException;
    import java.rmi.Remote;

    public class HelloImpl {
         public HelloImpl() {
       }
       public String sayHello(String name) {
         return ("Hello " + name + "!");
       }
    }

Notice that Java class Web service implementations must include a public constructor that takes no arguments.

When an error occurs while running a method on the Java class, it throws a `RemoteException`. In response to the exception, OracleAS Web Services returns a Web service (SOAP) fault. Use standard J2EE and OC4J administration facilities to view errors for a Web service that uses Java classes for its implementation.

When you create a Java class containing methods that implement a Web service, the methods, parameters, and return values must use supported types or nonstandard types supported by OracleAS Web Services. For a list of the supported data types, see the JAX-RPC 1.1 specification available from the following Web site:

`http://java.sun.com/webservices/jaxrpc/index.jsp`

"Mapping Java Types to XML and WSDL Types" in the Oracle Application Server Advanced Web Services Developer's Guide and Table 4-1 provides lists of supported data types and supported nonstandard types.

If methods, parameters, and return values use unsupported types, then you must handle them in either of the following ways.

- Use the interface class to limit the exposed methods to only those using JAX-RPC supported types and the supported non-standard types.

- Use the custom serializer to map unsupported types. For more information on working with unsupported types, see "Custom Serialization of Java Value Types" in the Oracle Application Server Advanced Web Services Developer's Guide.

## Exposing Java Classes as a Stateful Web Service

OC4J supports stateful Web services based on Java classes. The Java object that implements the service persists for the duration of the HTTP session. To maintain state, these services contain Oracle-proprietary extensions. Because of these extensions, you should not consider stateful OracleAS Web Services to be interoperable unless the service provider makes available scopes with the same semantics.

The stateful Web services supported by OracleAS Web Services is HTTP-based. It works only for SOAP/HTTP endpoints and does not work for SOAP/JMS endpoints.

### Prerequisites

The prerequisites for generating a stateful Web service from Java classes are identical to those described for a stateless Web service. For a description of the information and files you must provide, see "Prerequisites".

### How to Assemble a Stateful Web Service

The following instructions describe how to use WebServicesAssembler to create a stateful Web service from a Java class. The Java object that implements the service persists for the duration of the HTTP session.

1. Provide the Java class that you want to expose as a Web service and its interface.

2. Generate the service artifacts by running the WebServicesAssembler with the `assemble` command. For example:

       java -jar wsa.jar -assemble
           -appName counter
           -serviceName counterService
           -interfaceName oracle.demo.count.CounterInterface
           -className oracle.demo.count.CounterImpl
           -input build/classes/service
           -output build
           -ear dist/counter.ear
           -recoverable true
           -timeout 30
           -uri counterService

   Note the `timeout` argument on the command line. In addition to indicating the number of seconds an HTTP session should last before it times out, it also implicitly sets the `session` argument to `true`. When `session` is `true`, the service instance is stored in an HTTP session. The `recoverable` argument indicates that this stateful application is distributable. For more information on the required and optional arguments to `assemble`, see "assemble".

   This command generates all the files required to create a deployable archive. The output `build` directory contains separate directories for the EAR file and the Java classes. The `dist` directory contains the J2EE Web services-compliant application EAR file, `counter.ear`.

3. Deploy the service and bind the application.

   Deploy the EAR file in the standard manner into a running instance of OC4J. For more information on deploying EAR files, see the Oracle Containers for J2EE Deployment Guide. The following is a sample deployment command.

       java -jar <OC4J_HOME>/j2ee/home/admin_client.jar deployer:oc4j:localhost:port <user> <password>
                  -deploy
                  -file dist/counter.ear
                  -deploymentName counter
                  -bindWebApp default-web-site

   The following list describes the parameters used in this code example.

   - `<OC4J_HOME>`—The directory containing the OC4J installation.

   - `<user>`—the user name for the OC4J instance. The user name is assigned at installation time.

   - `<password>`—the password for the OC4J instance. The password is assigned at installation time.

   - `default-web-site`— the Web site to which the application will be bound. This is usually `default-web-site`. To configure Web sites, see the `server.xml` file in `<``OC4J_HOME``>/j2ee/home/config`.

4. (Optional) Check that deployment succeeded. OracleAS Web Services provides a Web Service Home Page for each deployed Web service. See "Using the Web Services Home Page" for information on accessing and using the Web service home page.

5. Generate the client code:

   - For the J2SE environment, generate stubs (client proxies) for a J2SE Web service client by running the WebServicesAssembler tool with the `genProxy` command. For more information on generating and assembling client-side code for the J2SE environment, see Chapter 14, "Assembling a J2SE Web Service Client".

   - For the J2EE environment, generate a Service Endpoint Interface and a mapping file for a J2EE Web service client by running the WebServicesAssembler tool with the `genInterface` command. For more information on generating and assembling client-side code, see Chapter 13, "Assembling a J2EE Web Service Client".

   For example, the following command generates client proxies (stubs) that can be used for a J2SE client:

       java -jar wsa.jar -genProxy
                         -output build/src/client/
                         -wsdl http://localhost:8888/counter/counterService?WSDL
                         -packageName oracle.demo.count

   This command generates the client proxies and stores them in the directory `build/src/client`. The client application uses the stub to invoke operations on a remote service. For more information on the required and optional arguments to `genProxy`, see "genProxy".

   Note: On systems such as Unix or Linux, the URL might need to be quoted (" ") on the command line.

6. Write the client application.

   Ensure that the client participates in the session by setting the `SESSION_MAINTAIN_PROPERTY` runtime property (`javax.xml.rpc.session.maintain`) to `true` either on the stub, the DII call, or the endpoint client instance.

   Instead of setting this property directly, OracleAS Web Services provides a helpful wrapper class with a `setMaintainSession(boolean)` method. Set this method to `true` to maintain sessions. The wrapper takes care of setting the property inside of the client. For example, in the client code, enter:

       CounterServicePortClient c = new CounterServicePortClient();
       //sets Maintain Session to true, as the endpoint is stateful.c.setMaintainSession(true);

7. Compile and run the client.

   List the appropriate JARs on the classpath before compiling the client. Table A-2, "Classpath Components for a Client Using a Client-Side Proxy" lists all of the JAR files that can possibly be used on the client classpath. As an alternative to listing individual JARs, you can include the client-side JAR, `wsclient_extended.jar` on the client classpath. This JAR file contains all the classes necessary to compile and run a Web service client. The classes are from the individual JAR files listed in Table A-2. See "Setting the Web Service Proxy Client Classpath" for more information on `wsclient_extended.jar` and the client classpath.

#### Ant Tasks for Generating a Stateful Web Service

The current release provides Ant tasks for Web service development. The following code samples show how the WebServicesAssembler commands in the preceding examples can be rewritten as Ant tasks.

For the `assemble` command, here is an example Ant task. In this example, `${wsdemo.common.class.path}` represents the classpath.

    <oracle:assemble appName="counter"
                serviceName="counterService"
                input="build/classes/service"
                output="build"
                ear="dist/service.ear"
                recoverable="true"
                timeout="30        "
            >
            <oracle:porttype
                interfaceName="oracle.demo.count.CounterInterface"
                className="oracle.demo.count.CounterImpl">
                <oracle:port uri="counterService" />
            </oracle:porttype>
            <oracle:classpath>
                <pathelement path="${wsdemo.common.class.path}"/>
                <pathelement location="build/classes/client"/>
            </oracle:classpath>
        </oracle:assemble>

For the `genProxy` command, here is an example Ant task.

    <oracle:genProxy wsdl="http://stadp54.us.oracle.com:8888/counter/counter?WSDL"
        output="build/src/client"
        packageName="oracle.demo.count"/>

### Writing Stateful Web Services

Java implementations for a stateful Web service must meet the same requirements as implementations for a stateless service. "Writing Java Class-Based Web Services", describes these requirements.

In addition, OC4J supports the `call`, `session`, and `endpoint` scope for a stateful Java implementation:

- `call`—The class instance is created for each call. The instance is garbage collected after each call. The value of the callScope argument determines whether the class instance is created for each call.

- `session`—The class instance is stored in an HTTP session. This applies only for HTTP transport. Session timeout can be tuned by the `timeout` argument. The value of the session argument determines whether the class instance is stored in an HTTP session.

- `endpoint`—The service endpoint implementation class instance is a singleton instance for each endpoint. This is the default scope.

Developing a stateful Java Web service consists of the following steps:

- Defining a Java Interface

- Defining a Java Class

#### Defining a Java Interface

Example 6-3 displays the `CountInterface.java` interface for the stateful Web service. This example also shows that the service class does not have to implement the Service Endpoint Interface directly. To comply with the JAX-RPC 1.1 specification, the interface must reside in a package. It must also extend `java.rmi.Remote` and its methods must throw a `java.rmi.RemoteException` object.

Example 6-3 Defining an Interface for a Stateful Web Service

    package oracle.demo.count;

    import java.rmi.RemoteException;
    import java.rmi.Remote;

    public interface CounterInterface extends Remote {
        // gets the current counter value
        public int getCurrentCounter() throws RemoteException;
    }

#### Defining a Java Class

Create a Java class by implementing the methods in the interface that you want to expose as a Web service. A Java class for a Web service usually defines one or more public methods. To comply with the JAX-RPC 1.1 specification, the implementation class must reside in a package. It must also import `java.rmi.Remote` and `java.rmi.RemoteException`.

Example 6-4 displays the public class, `CounterImpl`. The class initializes the count and defines the public method, `getCurrentCounter`.

Example 6-4 Defining a Public Class for a Stateful Web Service

    package oracle.demo.count;

    import java.rmi.RemoteException;
    import java.rmi.Remote;

    public class CounterImpl implements java.io.Serializable {
        private int counter = 0;

        public CounterImpl() {
        }

      public int getCurrentCounter() {
          System.out.println("Current counter value is: " + (++counter));
          return (counter);
       }
    }

## Packaging and Deploying Web Services

The packaging of Web services that expose Java classes is described in "Packaging for a Web Service Based on Java Classes".

For a detailed description of Web module deployment, see the Oracle Containers for J2EE Deployment Guide.

## Tool Support for Exposing Java Classes as Web Services

With Oracle JDeveloper, you can create, modify, and deploy J2EE-compliant Java class files as Web services. When you create Java classes in JDeveloper, you use the modeling tools and wizards. The wizards can perform the following tasks.

- Import or create Java classes and interfaces in a project.

- Package and deploy the Java classes exposed as Web services.

For more information on using JDeveloper to create Java classes and expose them as Web services, see the JDeveloper on-line help.

## Limitations

See "Assembling Web Services from Java Classes".

## Additional Information

For more information on:

- using the Home Page to test Web service deployment, see Chapter 12, "Testing Web Service Deployment".

- building a J2EE client, see Chapter 13, "Assembling a J2EE Web Service Client".

- building a J2SE client, see Chapter 14, "Assembling a J2SE Web Service Client".

- JAX-RPC handlers, see Chapter 15, "Understanding JAX-RPC Handlers".

- using the WebServicesAssembler tool to assemble Web services, see Chapter 17, "Using WebServicesAssembler".

- packaging and deploying Web services, see Chapter 18, "Packaging and Deploying Web Services".

- JAR files that are needed to assemble a client, see Appendix A, "Web Service Client APIs and JARs".

- Web services interoperability, see "Ensuring Interoperable Web Services" in the Oracle Application Server Advanced Web Services Developer's Guide.

- using quality of service features in Web service clients, see "Managing Web Service" in the Oracle Application Server Advanced Web Services Developer's Guide.

- adding security to a Web service, see the Oracle Application Server Web Services Security Guide.

- adding reliability to a Web service, see "Ensuring Web Service Reliability" in the Oracle Application Server Advanced Web Services Developer's Guide.

- adding an auditing and logging configuration to a Web service, see "Auditing and Logging Messages" in the Oracle Application Server Advanced Web Services Developer's Guide.

- processing nonstandard data types, see "Custom Serialization of Java Value Types" in the Oracle Application Server Advanced Web Services Developer's Guide.

- the JAX-RPC mapping file, see "JAX-RPC Mapping File Descriptor" in the Oracle Application Server Advanced Web Services Developer's Guide.

- data types supported by OracleAS Web Services, see "Mapping Java Types to XML and WSDL Types" in the Oracle Application Server Advanced Web Services Developer's Guide.

- JDeveloper tool support for Web service development, see the JDeveloper on-line help.