Chapter 31. Exercises for Chapter 15

Exercise 15.1: Web Services and EJB 2.1

In this exercise, you will learn how to use JAX-RPC’s client and server-side programming model with EJB 2.1. You will expose a stateless session bean as a web service. You will also investigate how to connect to and invoke on an existing web service from within EJB code. The stateless session bean that is exposed models the TravelAgentEndpoint in Chapter 15 of the EJB book. The supporting code for the rest of this exercise is borrowed from the exercises for Chapter 11 (Workbook 8). This exercise also introduces another stateless session bean that acts as a JAX-RPC client to the TravelAgentEndpoint EJB.

Initialize Your Environment

Perform the following steps:

  1. Open a command prompt or shell terminal and change to the ex15_1 directory created by the extraction process.

  2. Set the JAVA_HOME and JBOSS_HOME environment variables to point to where your JDK and JBoss 4.0 are installed. Examples:

    Windows:C:workbookex15_1> set JAVA_HOME=C:jdk1.4.2 C:workbookex15_1> set JBOSS_HOME=C:jboss-4.0
    Unix:$ export JAVA_HOME=/usr/local/jdk1.4.2 $ export JBOSS_HOME=/usr/local/jboss-4.0
  3. Add ant to your execution path. Ant is the build utility.

    Windows:C:workbookex15_1> set PATH=..antin;%PATH%
    Unix:$ export PATH=../ant/bin:$PATH

Clean the Database

You need to clean and refresh the database. To do this, first shutdown JBoss if you have it running and then run the ant clean.db.

Build and Deploy Example Programs

JBoss implements web services integration using the Apache Axis project http://ws.apache.org/axis/. One of the more annoying things about web services and EJB is creating a WSDL document based on a Service Endpoint interface. To alleviate this work, Axis has a nice tool called Java2WSDL that allows you to automatically generate a WSDL document based on a plain Java interface. If you examine the build.xml file, you can see an ant target devoted to invoking this utility.

build.xml

  <target name="wsdl" depends="compile">
    <java classname="org.apache.axis.wsdl.Java2WSDL" fork="yes" dir=".">
      <classpath refid="classpath"/>
      <arg value="-lhttp://localhost:8080/ws4ee/services/TravelAgentService"/>
       <arg value="-uLITERAL"/>
       <arg value="-sTravelAgentEndpoint"/>
      <arg value="-o${src.resources}/META-INF/travelagent.wsdl"/>
      <arg value="com.titan.webservice.TravelAgentEndpoint"/>
    </java>
    <copy file="${src.resources}/META-INF/travelagent.wsdl" todir="${src.resources}/client/META-INF/" />
  </target>

The -l switch tells Java2WSDL the default service location URL that will be used by a client connection. The -uLITERAL switch tells Axis to generate WSDL with RPC/Literal messaging. No one takes the default RPC/Encoded messaging seriously anymore as it doesn’t interoperate very well. The -o switch just specifies where the WSDL file should be generated. The class name of the Service Endpoint Interface (it can be any Java interface) must be specified as an argument and must also be within the classpath.

In this exercise there are two EJB jar files. One is titan.jar, which contains TravelAgentEndpoint and other supporting EJBs; the other is titan-client.jar, which contains the EJB that will be connecting to TravelAgentEndpoint as a JAX-RPC client. Both of these jars require the travelagent.wsdl file to do their things.

To do the build, perform the following steps:

  1. Generate the WSDL documents:

    $ ant wsdl
  2. Compile and deploy the ejb jars:

$ ant ejbjar

You will see titan.jar and titan-client.jar built, copied to the JBoss deploy directory, and redeployed by the application server.

So where’s the JAX-RPC stub generation? The spirit of JBoss has always been to avoid any precompilation step. If you have run any of the other examples in this book, you will have seen that there is not any stub generation for EJBs either. At deployment time, JBoss automatically generates dynamic proxies to handle all web service communication both with clients and services.

Examine the Server Model

To illustrate how to expose a stateless session bean, the TravelAgentEJB from Exercise 4.2 has been extended. This first thing to be done was to define a Service Endpoint interface the web service will implement. This interface is defined in src/main/com/titan/travelagent.

TravelAgentEndpoint.java

package com.titan.webservice;

public interface TravelAgentEndpoint extends java.rmi.Remote {
   String makeReservation(int cruiseId, int cabinId, 
                          int customerId, double price)
           throws java.rmi.RemoteException;
}

This interface is taken directly from Chapter 15 of the EJB book. Next, you have to define all the deployment descriptors. These files reside in src/resources/META-INF.

ejb-jar.xml

<session>
  <description>
     A Web Service reservation service
  </description>
  <ejb-name>TravelAgentEjbEndpoint</ejb-name>
  <service-endpoint>
     com.titan.webservice.TravelAgentEndpoint
  </service-endpoint>
  <ejb-class>
     com.titan.webservice.TravelAgentBean
  </ejb-class>
  <session-type>Stateless</session-type>
  <transaction-type>Container</transaction-type>
  <ejb-ref>
...

This XML is taken directly from Chapter 15 of the EJB book and added to the definition of the other supporting EJBs.

travelagent_mapping.xml

<java-wsdl-mapping
  xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
               http://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd"
  version="1.1">
  <package-mapping>
    <package-type>com.titan.webservice</package-type>
    <namespaceURI>
        http://webservice.titan.com/TravelAgentEndpoint
    </namespaceURI>
  </package-mapping>
</java-wsdl-mapping>

The endpoint we are exposing follows the guidelines for a simple mapping file. The namespaceURI element is a little different from Chapter 15 of the EJB book because it should match the generated WSDL document.

webservices.xml

<webservices
   xmlns="http://java.sun.com/xml/ns/j2ee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:titan="http://www.titan.com/TravelAgent"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                 http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd"
                     version="1.1">

<webservice-description>
   <webservice-description-name>
      TravelAgentService
   </webservice-description-name>
   <wsdl-file>META-INF/travelagent.wsdl</wsdl-file>
   <jaxrpc-mapping-file>
      META-INF/travelagent_mapping.xml
   </jaxrpc-mapping-file>
   <port-component>
      <port-component-name>TravelAgentEndpoint</port-component-name>
      <wsdl-port>titan:TravelAgentEndpoint</wsdl-port>
      <service-endpoint-interface>
          com.titan.webservice.TravelAgentEndpoint
      </service-endpoint-interface>
      <service-impl-bean>
          <ejb-link>TravelAgentEjbEndpoint</ejb-link>
      </service-impl-bean>
   </port-component>
 </webservice-description>
</webservices>

This is a standard webservices.xml descriptor. It links the WSDL file, mapping file, Service Endpoint interface, and TravelAgentEndpoint EJB all together. The important part of this file as it pertains to Jboss is the <webservice-description-name>. JBoss binds all deployed web services under the /ws4ee/services/<webservice-description-name> URL. For this example, it would be under /ws4ee/services/TravelAgentEndpoint. You can also view all endpoints by going to the base URL /ws4ee/services (Figure 31-1).

Listing the deployed services

Figure 31-1. Listing the deployed services

Examine the Client Model

TravelAgentClientEJB is a stateless session bean that illustrates how to invoke a web service from within EJB code. It simply exposes the same interface as TravelAgentEndpoint EJB and implements it by delegating to the TravelAgentEndpoint interface, invoking over the wire via a SOAP invocation.

TravelAgentClientBean.java

public String makeReservation(int cruiseId, int cabinId, 
                              int customerId, double price)
           throws java.rmi.RemoteException {
   try {
      javax.naming.Context jndiContext = new InitialContext( );
      Object obj =
           jndiContext.lookup("java:comp/env/service/TravelAgent");

      javax.xml.rpc.Service svc = (javax.xml.rpc.Service) obj;
      TravelAgentEndpoint endpoint = (TravelAgentEndpoint)
                             svc.getPort(TravelAgentEndpoint.class);

      return endpoint.makeReservation(cruiseId, cabinId, 
                                      customerId, price);

   } catch (Exception e) {
      e.printStackTrace( );
      throw new EJBException("failed");
   }
}

Since the spirit of JBoss is to avoid stub generation, the preferred method for clients is the Dynamic Proxy API as JBoss will automatically set up all proxies at deploy time. TravelAgentClientBean.makeReservation is an example of this. A generic proxy is registered for the service reference and you can get a proxy to any endpoint interface you want by passing in a Java Class parameter to the getPort method.

ejb-jar.xml

<session>
  <ejb-name>TravelAgentClientEJB</ejb-name>
...
     <service-ref>
          <service-ref-name>service/TravelAgent</service-ref-name>
          <service-interface>
              javax.xml.rpc.Service
          </service-interface>
          <wsdl-file>META-INF/travelagent.wsdl</wsdl-file>
          <jaxrpc-mapping-file>
              META-INF/travelagent_mapping.xml
          </jaxrpc-mapping-file>
     </service-ref>
  </session>

The <service-ref> element is standard. One thing to note is that the <service-qname> element can be left out if the WSDL file contains only one service definition. The other deployment descriptors are the same descriptors as in the server model.

travelagent.wsdl

<wsdl:service name="TravelAgentEndpointService">
   <wsdl:port name="TravelAgentEndpoint"
        binding="impl: TravelAgentEndpointSoapBinding">

      <wsdlsoap:address location="http://localhost:8080/ws4ee/services/
                     TravelAgentService"/>

   </wsdl:port>
</wsdl:service>

The address location in the TravelAgentEJB.wsdl file is the URL used by the Dynamic Proxy created in the listCabins method.

Run the Client Application

The client application is made up of two clients. The first client initializes the entity beans and database tables that are needed for this exercise.

C:workbookex15_1>ant createdb
Buildfile: build.xml

prepare:

compile:

createdb:
  [java] Calling TravelAgentBean to create sample data..
  [java] All customers have been removed
  [java] All cabins have been removed
  [java] All ships have been removed
  [java] All cruises have been removed
  [java] All reservations have been removed
  [java] Customer with ID 1 created (Burke Bill)
  [java] added credit card: 4300000000000000 for Bill
  [java] Customer with ID 2 created (Labourey Sacha)
  [java] Created ship with ID 101...
  [java] Created ship with ID 102...
  [java] Created cabins on Ship A with IDs 100-109
  [java] Created cabins on Ship B with IDs 200-209
  [java] Created Alaska Cruise with ID 0 on ShipA
  [java] Created Norwegian Fjords Cruise with ID 1 on ShipA
  [java] Created Bermuda or Bust Cruise with ID 2 on ShipA
  [java] Created Indian Sea Cruise with ID 3 on ShipB
  [java] Created Australian Highlights Cruise with ID 4 on ShipB
  [java] Created Three-Hour Cruise with ID 5 on ShipB
  [java] Made reservation for Customer 1 on Cruise 0 for Cabin 103
  [java] Made reservation for Customer 1 on Cruise 5 for Cabin 208
  [java] Made reservation for Customer 2 on Cruise 1 for Cabin 105
  [java] Made reservation for Customer 2 on Cruise 5 for Cabin 202
  [java] Creating database table...

The second client is a MakeReservation script that can be run from the command line. There is a script provided for both Unix and Windows. The arguments for the script are a cruise ID, cabin ID, a customer ID, and finally a price for the reservation. You can pull three of the arguments from the output of run.createdb:

C:workbookex15_1>MakeReservation 1 106 1 5000.00
Buildfile: build.xml

prepare:

compile:

ejbjar:

run.client:
     [java] reservation 5 completed.

Here we are, back at the dock, our “EJB on JBoss” cruise complete! We really hope you’ve enjoyed the voyage and that we’ll soon meet you on JBoss’s forums for some more exciting adventures.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.107.193