The WebSphere Web Services Enablement Process


The following diagram illustrates the process steps identified by JSR-109 that are performed when using WAS to enable an EJB to be a web service:

click to expand

These steps are described in the following sections, followed by a detailed example using the Plants-By-WebSphere Catalog EJB.

Select an Implementation Bean

JSR-109 specifies the requirements for selecting an implementation bean. First of all, it must have methods suitable to be mapped to a Service Endpoint Interface, as described in the next step. Next, it must be a stateless implementation, either a stateless session EJB, or a JavaBean without client-specific state. This is because any implementation object might be selected to process a request from any client. If client-specific state is required, a client identifier must be passed as a parameter of the web service operation.

For an EJB, the selected methods must not have a transaction attribute of mandatory. This is because there is no established standard for web services transactions at this time.

For a JavaBean in the web container:

  • It must have a public default constructor

  • The exposed methods must be public

  • It must not save client-specific state between method calls

  • It must be a public, non-final, non-abstract class

  • It must not define a finalize() method

    Important

    A word of caution – while WebSphere makes it easy to expose an existing bean as a web service, it may not be appropriate to do so.

As with any software design creating an appropriate interface for clients is one of the most difficult tasks, it may be better to design a new customer interface tailored to Internet requirements from scratch, and then write a new fa ade bean to implement it by delegating operations to your business logic. As we work through enabling the Plants-By-WebSphere Catalog EJB later in this chapter, we'll discuss some of these considerations.

Create the Service Endpoint Interface

To enable a bean as a web service, we must first create a Java interface containing just those methods of the bean we want to expose as a web service. This interface is called the Service Endpoint Interface. It is similar to the EJB remote interface, and like the EJB remote interface, must follow certain conventions specified by JAX-RPC:

  • The interface must extend the java.rmi.Remote.

  • Each method must throw a java.rmi.RemoteException.

  • All method parameters and return types, including inherited methods must be JAX-RPC-supported Java types, as listed in section 5.1 of the JAX-RPC specification. Probably the biggest restriction is that object references are not permitted unless they are to serializable JavaBeans containing conforming fields.

  • The interface should not contain constant (public static final) declarations.

  • The implementation bean, while required to contain methods whose signatures match those in the Service Endpoint Interface, is not required to implement the Service Endpoint Interface.

For an EJB, it is easiest to create the Service Endpoint Interface by copying the remote interface and removing the methods, fields, and parent classes that don't conform to the above requirements.

Generate the WSDL

Every JAX-RPC implementation, including WebSphere, has tooling that reads a Service Endpoint Interface and generates a corresponding WSDL file, following the rules established in JAX-RPC. WebSphere version 5.0 uses the Java2WSDL command-line tool for this task.

Create Deployment Descriptor Templates

WebSphere's WSDL2Java command-line tool, in addition to other things, will generate templates for the required deployment descriptors from a WSDL document. These templates are automatically filled with deployment information from the WSDL, leaving only a couple of items to be supplied by the developer. The deployment descriptors required by JSR-109 are a webservices.xml file and a mapping file that records the mapping between Java names and XML names. An ibm-webservices-bnd.xml file is also generated that supports WebSphere-specific functionality such as security configuration.

Complete the Deployment Descriptors

Fill in either the ejb-link or servlet-link value of the service-impl-bean element to link the service to the EJB or JavaBean that implements the service.

Assemble the Module

Add the following files to the J2EE module to enable it for web services:

  • The Service Endpoint Interface class

  • The WSDL file

  • The deployment descriptors, webservices.xml, the JAX-RPC mapping descriptor, and the optional ibm-webservices-bnd.xml.

Assemble the EAR

Replace the updated module in the EAR.

Enable the Application

If your application contains EJBs, the initial release of WAS version 5.0 requires that the endptEnabler command be run on the application to add the HTTP endpoint for the service. This is accomplished by adding a WAR module that configures the web services router servlet. This servlet accepts, demarshals, and dispatches web services requests. This step will be part of deployment in the updated release of WAS version 5.0.

Deploy the Application

The application can be deployed from either the admin console, as shown in Chapter 6, or using the wsadmin scripting interface, as described in the WebSphere online help. During deployment, you supply information for the location (URL) of the published service, and choose whether you want the updated WSDL file to be published to the file system. The deployment step fills in the service location element in the WSDL file with the actual location of the service.

Distribute the Application Service Description

The deployed WSDL file is all your customers need to use your service.

Enabling the Catalog EJB as a Web Service

Now let's work through these steps in more detail to provide access to the Plants-By-WebSphere Catalog EJB as a web service. The Catalog EJB was chosen because it is a stateless session bean and is a realistic example of a business function that would be enabled as a web service. The StoreItem bean that represents items in the Catalog provides an opportunity to show a complexType.

Working with the Sample Code in WebSphere Studio

The following sections showing how to enable the Plants-By-WebSphere sample using WebSphere Studio to edit files and assemble the enablement artifacts into the EAR. For the initial release, some steps require command-line tools to be run outside of Studio.

Important

If you are using the initial release of WAS then you will need to install the Web Services Technology Preview before proceeding. You can either download this from DeveloperWorks or it is included on one of the CDs that comes with this book. Follow the instructions to install it.

In addition, in order to deploy web services-enabled J2EE applications you will need a stand alone installation of WebSphere Application Server. In other words, you cannot use the unit test environment that is part of WSAD.

Creating the PlantsByWebSphereCatalog Service Endpoint Interface

The first step is to create a Service Endpoint Interface that represents the customer's view of the service. The first decision is to determine the name for the Service Endpoint Interface class. The Java2WSDL command derives the names of the WSDL portType and service from the Service Endpoint Interface name. Knowing this, let's pick PlantsByWebSphereCatalog as a name that will be meaningful to a customer when they receive the generated WSDL file.

The next step is to fill in the contents of the PlantsByWebSphereCatalog interface. When you have an existing EJB that provides the business logic for the web service, it is logical to use the EJB remote interface as a template, since it is already a Java interface and the methods already throw java.rmi.RemoteException.

Let's start by copying the Catalog.java remote interface to PlantsByWebSphereCatalog.java.

Using Studio locate Catalog.java in the PlantsByWebSphereEJB project, right-click on it, and select Copy then Paste it into the same package.

The Name Conflict panel appears to permit you to rename the copied class. Enter PlantsByWebSphereCatalog as the new name:

click to expand

Double-click on the new class to open it in the Java editor:

click to expand

Look at the overall structure of the interface:

package com.ibm.pbw.ejb; import java.rmi.RemoteException; import java.util.Vector; /**  * Remote interface for Catalog stateless session bean.  */ public interface PlantsByWebSphereCatalog extends javax.ejb.EJBObject { … }

To be compliant with JAX-RPC, the interface must extend java.rmi.Remote. Although javax.ejb.EBJObject extends java.rmi.Remote, it (the EJBObject) introduces methods that have parameters of type java.lang.Object, which is not permitted by JAX-RPC. Therefore, the interface declaration needs to be changed to extend java.rmi.Remote:

 public interface PlantsByWebSphereCatalog extends java.rmi.Remote 

Expand the PlantsByWebSphereCatalog class to display the methods:

click to expand

These methods should be reviewed first for suitability as web service operations, and then for whether the parameter types are supported by JAX-RPC.

From examining this interface, it is apparent that it serves a number of different client roles:

  • A shopping customer who browses the contents of the catalog

  • A purchasing agent who adds and updates item information

  • A supplier who queries the current inventory of each item, ships new inventory, and then updates item quantities and costs

Since the latter two roles raise security issues, and we want our enabled catalog to be accessible to everyone, let's eliminate the catalog modification methods from the Service Endpoint Interface and make it read-only.

Delete the unwanted modification methods by holding the Ctrl key down and clicking on all the set methods, as well as addItem(), and deleteItem(). After selecting, press Delete and confirm the deletion:

click to expand

That leaves the following methods:

  • StoreItem getItem(String id) throws RemoteException;

  • byte[] getItemImageBytes(String id) throws RemoteException;

  • float getItemPrice(String id) throws RemoteException;

  • StoreItem[] getItems() throws RemoteException;

  • StoreItem[] getItemsByCategory(int category) throws RemoteException;

  • StoreItem[] getItemsLikeName(String name) throws RemoteException;

    Note

    Note that you can define additional Service Endpoint Interfaces for the Catalog EJB that satisfy the requirements of the other client roles. The same EJB can implement multiple web services.

The next thing to examine is the StoreItem class. Since it is a return type from a web service call, it needs to be represented in XML. JAX-RPC section 5.4 defines the conventions a Java class needs to follow in order to be mapped to XML. To summarize, these conventions are:

  • The class must have a public default constructor.

  • The class must not implement (directly or indirectly) the java.rmi.Remote interface. The java.rmi.Remote interface marks an object as able to be referenced by a remote client. Because there is currently no notion of a remote object reference in WSDL, any object passed to or from a Web service must be passed by value. This means that the actual data in the object must be transmitted (serialized) with the invocation.

  • The class may implement any other Java interface or extend another Java class.

  • The Java type of every public field must be a supported JAX-RPC type. Only public fields are transmitted in XML.

  • The class may contain methods or static, transient, non-public fields, but they are not mapped to XML.

  • The Java class for a JAX-RPC value type may be a JavaBeans class, having non-public fields and public get and set methods to access each bean property. In this case, each property must be a supported JAX-RPC type.

  • The class may, but is not required to, extend java.io.Serializable as long as it meets the above requirements.

Examination of the StoreItem class shows that it follows the JavaBeans pattern, and that all bean properties (String, int, boolean, and float) are supported JAX-RPC types. Let's take a quick look at the properties accessors in StoreItem:

  • public String getId();

  • public String getName();

  • public String getHeading();

  • public String getDescr();

  • public String getPkginfo();

  • public String getImage();

  • public float getPrice();

  • public float getCost();

  • public int getQuantity();

  • public int getCategory();

Notice the bean properties include information you might prefer that your customers not have, such as your cost for the item. This illustrates the importance of designing the Service Endpoint Interface as carefully as you would any other publicly exposed interface. If Plants-By-WebSphere were a real enterprise, your development department would likely be designing a PublicStoreItem, and either adding methods to retrieve PublicStoreItems to the CatalogBean EJB, or, more likely, implementing a PublicCatalogBean fa ade EJB to mediate between the public requests and your internal data.

The methods in the fa ade EJB would retrieve StoreItems from the catalog and repackage them as PublicStoreItems for public consumption:

public PublicStoreItem getItem(String id) {    Catalog c = ... //reference to Catalog EJB    StoreItem s = c.getItem(id);    if (s.isPublic())       return new PublicStoreItem(s.getID(), s.getName(), s.getDescription(),                                   s.getImage(), s.getPrice());    else

After the editing is complete, the PlantsByWebSphereCatalog Service Endpoint Interface looks like this:

 package com.ibm.pbw.ejb; import java.rmi.RemoteException;
public interface PlantsByWebSphereCatalog extends java.rmi.Remote { /** * Get all inventory items. * @return array of all StoreItems. */ public StoreItem[] getItems() throws RemoteException; /** * Get all inventory items for the given category. * @param category Category of items desired. * @return array of StoreItems in the specified category. */ public StoreItem[] getItemsByCategory(int category) throws RemoteException; /** * Get inventory items that contain a given String within their names. * @param name String to search names for. * @return array of StoreItems matching name. */ public StoreItem[] getItemsLikeName(String name) throws RemoteException; /** * Get the Inventory item for the given ID. * @param inventoryID - ID of the Inventory item desired. * @return StoreItem */ public StoreItem getItem(String inventoryID) throws RemoteException;

/**
* Get the Inventory item's price. * @param inventoryID - ID of the Inventory item desired. * @return the inventory item's price. */ float StoreItem getItemPrice(String inventoryID) throws RemoteException; /** * Get the image for the inventory item. * @param inventoryID The id of the inventory item wanted. * @return byte array containing the image. */ public byte[] getItemImageBytes(String inventoryID) throws RemoteException; }

Create PlantsByWebSphereCatalog.wsdl

The next step is to convert the PlantsByWebSphereCatalog Service Endpoint Interface into a WSDL document. To do this, we need to get set up to run the Java2WSDL command-line tool. The Java2WSDL command creates a WSDL document from the Service Endpoint Interface class.

Open a command shell, and change directory to the workspace for the PlantsByWebSphereEJB\ejbModule directory in Studio's workspace directory.

After installing the Technology Preview, the command-line tools are in the WebSphere Application Server bin directory. Add the bin directory to your PATH environment variable.

Add j2ee.jar in the WebSphere Application Server lib directory and the current directory (".") to your classpath environment variable. Since the Java2WSDL command takes a Java class as an option, it requires that classpath be set up the same as is required to compile the class with the javac command.

Now we can run the Java2WSDL command to generate PlantsByWebSphereCatalog.wsdl:

 Java2WSDL -implClass com.ibm.pbw.ejb.CatalogBean com.ibm.pbw.ejb. PlantsByWebSphereCatalog WSWS3006W: Warning: The -location was not set, the value "file:undefined_location" is used instead.

The –implClass option is used to supply additional information to Java2WSDL to permit the Java parameter names to be used as the WSDL part names. Since the Java2WSDL command reads the compiled class file instead of the Java source file for the Service Endpoint Interface, it can't determine the names of the parameters of the Service Endpoint Interface methods. Without the –implClass option, the PlantsByWebSphereCatalog.wsdl file would contain WSDL parts named in0, in1, and so on. This naming scheme isn't helpful to customers that use the WSDL.

The compiled Service Endpoint Interface class doesn't contain parameter names, even when compiled for debug. However, Java classes, when compiled for debug, do contain parameter names. You use a Java class that implements methods having the same signature as those in the Service Endpoint Interface to supply the missing parameter name information. Note that implClass doesn't have to implement the Service Endpoint Interface, it's sufficient to have methods with matching signatures.

In this example, CatalogBean is the class that implements the methods of the Service Endpoint Interface. By default, Studio will compile CatalogBean with debug information. If it doesn't, verify that the Add variable attributes to generated class files preference is enabled on the Java compiler settings panel available by selecting Window | Preferences | Java | Compiler | Classfile Generation.

At this point, you have a choice. The following sections examine the internals of the WSDL file you just created. If you'd prefer to continue with the development steps right away, skip this section for now.

Examining the Service Description

Up until now, you've heard a lot about WSDL, but haven't actually looked inside a WSDL document. Since we've just created one for the PlantsByWebSphereCatalog service, now's the perfect time to see what it contains.

You can view the generated PlantsByWebSphereCatalog.wsdl file in Studio by following these steps.

Switch to the XML Perspective by selecting Window | Open Perspective | XML.

Navigate to the ejbModule directory that you created the WSDL file in.

Right-click on the ejbModule directory and select Refresh. The PlantsByWebSphereCatalog.wsdl file should appear under ejbModule.

Double-click on PlantsByWebSphereCatalog.wsdl to display the contents of the file:

click to expand

To browse the WSDL file, you can switch between the Design view and Source view by clicking the tabs at the bottom of the XML Editor pane.

Namespace Declarations

A WSDL document contains a set of definitions. The header of a WSDL document declares the XML namespaces that are available for use in the remainder of the document:

<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions      targetNamespace="http://ejb.pbw.ibm.com"      xmlns="http://schemas.xmlsoap.org/wsdl/"      xmlns:apachesoap="http://xml.apache.org/xml-soap"      xmlns:intf=http://ejb.pbw.ibm.com     xmlns:impl="http://ejb.pbw.ibm.com"      xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"      xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"      xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"      xmlns:xsd="http://www.w3.org/2001/XMLSchema"> … </wsdl:definitions>

The targetNamespace, http://ejb.pbw.ibm.com, is derived from the package name of the Service Endpoint Interface by Java2WSDL. JAX-RPC does not specify a mapping between Java package names and XML namespaces, but it does require a one-to-one mapping between them.

The table below identifies the meaning of each namespace:

Namespace Prefix

Meaning

default

Namespace for WSDL 1.1 framework

wsdl

Namespace for WSDL 1.1 framework

apachesoap

Namespace for XML types defined by Apache implementations

intf

Namespace for elements derived from the Service Endpoint Interface

impl

Namespace for elements in <wsdl:service> derived from the Service Endpoint Interface

soapenc

SOAP 1.1 encoding namespace

wsdlsoap

Namespace for WSDL 1.1 SOAP binding

xsd

Namespace for XML Schema 2001

These namespace definitions appear in the WSDL document unconditionally, regardless of whether names in these namespaces are actually used in the document.

Service Interface Definition

As shown in the diagram earlier, the service interface portion of the WSDL document defines the interface to the service with four distinct sections:

  • wsdl:portType
    The abstract interface defining the operations that can be invoked on the interface

  • wsdl:message
    Defines the data flowing into and out of each operation in the wsdl:portType

  • wsdl:type
    Defines the types used in the messages

  • wsdl:binding
    Defines the concrete encoding for each operation in the wsdl:portType

The Service Endpoint Interface of the PlantsByWebSphereCatalog is mapped to a portType. Each Java method in the Service Endpoint Interface is mapped to an operation in the portType.

Let's compare and contrast the Java language definition of the getItem() method with the corresponding WSDL operation. First, the WSDL portType:

<wsdl:portType name="PlantsByWebSphereCatalog"> ... <wsdl:operation name="getItem" parameterOrder="inventoryID">   <wsdl:input message="intf:getItemRequest" name="getItemRequest" />    <wsdl:output message="intf:getItemResponse" name="getItemResponse" />  </wsdl:operation> … </wsdl:portType>

Then the corresponding Java method:

public StoreItem getItem(String inventoryID) throws RemoteException;

Both the Java interface and wsdl:portType have the same name and both have a rendering of the methods and operations available on the interface.

The Java method signature contains specific types, StoreItem and String, as you would expect with a programming language. On the other hand, the WSDL interface refers to parameters as a wsdl:input message named getItemRequest() and return types as a wsdl:output message named getItemResponse(). The input and output message definitions shown below describe the data transferred to and from the method.

Let's look at the wsdl:message definitions for the getItem() method:

   <wsdl:message name="getItemRequest">       <wsdl:part name="inventoryID" type="xsd:string" />     </wsdl:message>    <wsdl:message name="getItemResponse">       <wsdl:part name="getItemReturn" type="intf:StoreItem" />     </wsdl:message>

Comparing the arguments and result of the Java interface to these wsdl:messages, you can see that each parameter on the Java interface is mapped to a wsdl:part in a wsdl:message. Each wsdl:part has a type that is based on the JAX-RPC mapping between Java types and XML.

For more complex or application-specific types, such as the StoreItem bean, the wsdl:part type is a reference to a type definition elsewhere. For this sample, the intf:StoreItem is defined in the wsdl:types section as complex types, as shown below:

<wsdl:types>   <schema      targetNamespace="http://ejb.pbw.ibm.com"      xmlns="http://www.w3.org/2001/XMLSchema">    <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>    <complexType name="StoreItem">     <sequence>      <element name="name" nillable="true" type="xsd:string"/>      <element name="category" type="xsd:int"/>      <element name="cost" type="xsd:float"/>      <element name="public" type="xsd:boolean"/>      <element name="image" nillable="true" type="xsd:string"/>      <element name="quantity" type="xsd:int"/>      <element name="price" type="xsd:float"/>      <element name="notes" nillable="true" type="xsd:string"/>      <element name="ID" nillable="true" type="xsd:string"/>      <element name="pkginfo" nillable="true" type="xsd:string"/>      <element name="description" nillable="true" type="xsd:string"/>      <element name="heading" nillable="true" type="xsd:string"/>     </sequence>    </complexType>    <element name="StoreItem" nillable="true" type="impl:StoreItem"/>   </schema> 

Note the import of the SOAP encoding namespace. This appears unconditionally to support the use of SOAP 1.1 "section 5" encodings, even though none are used in this complexType. The SOAP encodings are extensions to the standard XML Schema types and support features like sparse arrays and multiple references to a value.

Finally, let's examine a portion of the PlantsByWebSphereCatalogSoapBinding:

<wsdl:binding name="PlantsByWebSphereCatalogSoapBinding" type="intf:PlantsByWebSphereCatalog">       <wsdlsoap:binding style="rpc"                 transport="http://schemas.xmlsoap.org/soap/http"/>

This binding declares a type of intf:PlantsByWebSphereCatalog which as we have already seen is a wsdl:portType. That tells us that this binding is providing a concrete encoding for the PlantsByWebSphereCatalog interface. The type= keyword on the wsdl:binding element describes the wsdl:portType that a binding references.

The next XML fragment in the binding, wsdlsoap:binding, is a WSDL extension element. It is used to further refine the semantics of the invocation of the operations on the interface. In this case, the wsdlsoap elements define information needed to transport the message parts in a SOAP 1.1 envelope on an HTTP transport. The binding style attribute has two choices: rpc or document. Using rpc specifies that each parameter or result will be passed as a separate element in the SOAP message. The alternative style is document style binding. Document style passes the parameters bundled into one or more XML elements.

The Java2WSDL tool has a -style option that lets you specify which style of WSDL to generate from the Service Endpoint Interface. Finally, notice that the header of the binding also contains the definition of the transport over which the Web service invocation will flow. In this sample, it is SOAP over HTTP. Other bindings such as SOAP/JMS are permitted in WSDL, but they are not defined by JAX-RPC.

<wsdl:operation name="getItem">   <wsdlsoap:operation soapAction="" />        <wsdl:input name="getItemRequest">          <wsdlsoap:body                    encodingStyle=http://schemas.xmlsoap.org/soap/encoding/                    namespace="http://ejb.pbw.ibm.com" use="encoded" /> 

The next element, wsdl:operation, defines which of the operations in the portType are being bound. The wsdlsoap:operation child element provides the binding for the operation to the SOAP protocol. The soapAction attribute is required for client use of SOAP over HTTP bindings. It denotes a value for the SOAPAction HTTP header field. The messages for the operation appear in the wsdl:input and wsdl:output elements. For each message, a wsdlsoap:body element defines how to encode the message parts for transmission.

      ...       </wsdl:input>       <wsdl:output name="getItemResponse">           wsdlsoap:body                    encodingStyle=http://schemas.xmlsoap.org/soap/encoding/                    namespace="http://ejb.pbw.ibm.com" use="encoded" />        </wsdl:output> </wsdl:operation> ... </wsdl:binding>

Note the encodingStyle= attribute on the wsdlsoap:body element. There are two ways to encode the message parts when using the SOAP binding. One is encoded, using the SOAP 1.1 "section 5" encoding (named after the section of the SOAP 1.1 specification that defines it), as indicated by the URL http://schemas.xmlsoap.org/soap/encoding/. The second encoding style is literal. Knowing the XML schema type for a value may not be sufficient to actually encode it into XML for transmission. A concrete encoding must also be specified to indicate how values are to be encoded and decoded. When the encodingStyle is literal, the parts are transmitted as an XML document.

However, when literal encoding is used to transmit data structures, information may be lost. The primary feature of the encoded encodingStyle is the ability to transmit graphs of objects, maintaining their relationship to one another. This feature is also known as multi-ref. For example, if you have an array containing 10 string references, each pointing to the same String object, literal encoding would transmit the contents of the string 10 times, while encoded encoding would transmit the string value for the first array element, and then for the last nine, transmit references to the first value. In this way, the receiver can reconstruct the same object graph as was sent.

There are four possible combinations of the style and encodingStyle attributes, but (fortunately), only two are commonly used, rpc/encoded for programmatic interfaces that pass individual parameters and maintain their relationships, and doc/literal for exchanging XML documents as messages. The default encoding for WebSphere and JAX-RPC is rpc/encoded, but the industry, prompted by WS-I.org (the Web Services Interoperability consortium founded by IBM and Microsoft), has excluded encoded and recommends doc/literal or rpc/literal.

Contrasting this binding with the wsdl:portType PlantsByWebSphereCatalog reveals one of the greatest strengths of WSDL. Notice how each part of the PlantsByWebSphereCatalog wsdl:portType is repeated in the binding definition and then augmented with WSDL extensions describing the specifics of how to encode each part of the invocation. This enables the binding to precisely describe the encoding to be used when invoking any operation on a given wsdl:portType. More importantly it also enables the web service definition to contain more than one binding for a given portType, because the specifics of how to invoke the service have been separated from what the service interface looks like.

Throughout each section of the WSDL document you can also see use of the wsdl:soap extensions, which in our sample indicate the use of SOAP. The port uses the:

<wsdlsoap:address location=/>

extension to declare where an implementation of the web service can be found, and the PlantsByWebSphereCatalogSOAPBinding uses the wsdlsoap:binding, wsdlsoap:operation, and wsdlsoap:body extensions to declare that the binding to the web service is going to use SOAP.

Service Implementation Definition

Next let's examine the service implementation section of the service description:

<wsdl:service name="PlantsByWebSphereCatalogService">     <wsdl:port binding="intf:PlantsByWebSphereCatalogSoapBinding           name="PlantsByWebSphereCatalog">           <wsdlsoap:address                      location="http://myhost/PlantsByWebSphereCatalog/                               services/PlantsByWebSphereCatalog"/>     </wsdl:port> </wsdl:service>

Here you can see that this web service is called PlantsByWebSphereCatalogService. It has only one port, called PlantsByWebSphereCatalog. This port refers to the PlantsByWebSphereCatalogSoapBinding binding that is defined elsewhere in the document. Note that the location of the service implementation is provided by the location URL in the wsdlsoap:address element. By combining the target service location and a concrete encoding into a port, we can see how WSDL can be used to enable multi-protocol access to the web service. If there were two bindings defined for this service, there would be two ports defined. Each port provides a separate and distinct access path to the target service, where the access path is defined by the protocol and encoding specified in the binding and the target location specified in the address.

The address location is normally set during deployment of the web service, since that's the time a service implementation is bound to a specific URL. You can also specify the location on the Java2WSDL command line using the -location argument. Since no location was specified when the Java2WSDL command was run earlier, if you view the generated WSDL document, you will see that the location was set to a default location, "file:undefined_location".

Configuring the Web Service

So far, we've selected an implementation EJB, created a Service Endpoint Interface for it that defines the Web services interface for the EJB, and created a WSDL document from the Service Endpoint Interface that describes the service.

The next step is to create and configure the deployment descriptors used by JSR-109 and WebSphere to inform WebSphere that incoming web service requests are to be accepted on a certain URL and routed to the EJB for processing.

Create Deployment Descriptor Templates

Return to the command window and environment you set up in the section titled Create PlantsByWebSphereCatalog.wsdl above.

Run the WSDL2Java command to generate the templates for the deployment descriptors:

 WSDL2Java -META-INF-Only -server-side EJB -verbose PlantsByWebSphereCatalog.wsdl Parsing XML file:  PlantsByWebSphereCatalog.wsdl Generating META-INF\webservicesclient.xml Generating META-INF\ibm-webservicesclient-bnd.xml Generating META-INF\webservices.xml Generating META-INF\ibm-webservices-bnd.xml Generating META-INF\PlantsByWebSphereCatalog_mapping.xml

The -META-INF-Only option tells WSDL2Java to generate just deployment descriptors, and not any Java classes. The -server-side EJB option indicates that the deployment descriptors should enable an EJB (as opposed to a JavaBean) as a web service. The -verbose option displays the names of the generated files.

Notice that the files were generated into a META-INF subdirectory, as required by JSR-109 for your EJB JAR. If the current directory isn't the root of the JAR hierarchy, you can change WSDL2Java's output directory with the -output option. Also, if you were generating deployment descriptor templates for a JavaBean, they would be placed in a WEB-INF subdirectory instead of the META-INF subdirectory.

This command generated the following files:

  • webservicesclient.xml – required by JSR-109.

  • PlantsByWebSphereCatalog_mapping.xml – required by JSR-109. This descriptor contains detailed information about the mapping between Java and XML being used.

  • ibm-webservices-bnd.xml – optional for WebSphere, this file contains WebSphere-specific deployment binding information, such as the security configuration for the service.

  • webservicesclient.xml – not needed for a web services implementation, but required by JSR-109 for a J2EE application client using the web service in a client container.

  • ibm-webservicesclient-bnd.xml – not needed for a web services implementation, optional for an application client to configure WebSphere-specific deployment binding information.

When enabling a WebSphere Application Server component to be a web service, you can delete the generated client deployment descriptor templates. To do so, return to Studio and switch to the XML perspective by selecting Window | Open Perspective | XML.

Navigate to the META-INF directory of the ejbModule.

Right-click on the META-INF directory and select Refresh. The deployment descriptors listed above appear in the Navigator pane:

Delete the two files: ibm-webservicesclient-bnd.xml and webservicesclient.xml.

You've now created the server-side deployment descriptor templates.

Configure the Deployment Descriptors

Until WSAD is updated to handle the JSR-109 deployment descriptors, you'll have to configure them by hand. This is easier than it sounds. The mapping deployment descriptor records the transformations made by the Java2WSDL and WSDL2Java tools when mapping between Java and XML, and requires no configuration. For the curious, the generated PlantsByWebSphereCatalog_mapping.xml file contains:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE java-wsdl-mapping PUBLIC "-//IBM Corporation, Inc.// DTD J2EE JAX-RPC mapping 1.0//EN" "http://www.ibm.com/webservices/dtd/j2ee_jaxrpc_mapping_1_0.dtd"> <java-wsdl-mapping>   <package-mapping>     <package-type>com.ibm.pbw.ejb</package-type>     <namespaceURI>http://ejb.pbw.ibm.com</namespaceURI>   </package-mapping> </java-wsdl-mapping>

This mapping file specifies that the Java package com.ibm.pbw.ejb corresponds with the XML namespace http://ejb.pbw.ibm.com, something that you've probably already guessed from examining the WSDL file.

Note

A note on standards compliance – the initial Tech Preview version of the WebSphere version 5.0 web services only supports describing package to namespace mapping. JSR-109 requires that a number of other mapping items be represented that will be supported in the WebSphere version 5.0 update.

Configuring the webservices.xml file is almost as easy as configuring the mapping file. The generated template is:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE webservices PUBLIC "-//IBM Corporation, Inc.// DTD J2EE Web services 1.0//EN" "http://www.ibm.com/webservices/dtd/j2ee_web_services_1_0.dtd"> <webservices>   <webservice-description>     <webservice-description-name>         PlantsByWebSphereCatalogService     </webservice-description-name>     <wsdl-file>META-INF/PlantsByWebSphereCatalog.wsdl</wsdl-file>     <jaxrpc-mapping-file>         META-INF/PlantsByWebSphereCatalog_mapping.xml     </jaxrpc-mapping-file>     <port-component>       <port-component-name>PlantsByWebSphereCatalog</port-component-name>       <wsdl-port>         <namespaceURI>http://pbw.ibm.com</namespaceURI>         <localpart>PlantsByWebSphereCatalog</localpart>       </wsdl-port>       <service-endpoint-interface>         com.ibm.pbw.PlantsByWebSphereCatalog       </service-endpoint-interface>       <service-impl-bean>         <ejb-link>           ??SET THIS TO ejb-name ELEMENT OF ejb-jar.xml??         </ejb-link>       </service-impl-bean>     </port-component>   </webservice-description> </webservices>

The string "??SET THIS...??" is all you have to fill in to configure webservices.xml. Copy this value from the ejb-name element in the ejb-jar.xml file that's already in the META-INF directory of the Plants-By-WebSphere EJB JAR:

<ejb-name>Catalog</ejb-name>

Filling in the ejb-link in webservices.xml with this name tells the application server that calls on the web services are to be routed to the Catalog EJB, and that the Catalog EJB implements methods having the same signature as those of the Service Endpoint Interface.

The completed <ejb-link> element is:

 <ejb-link>Catalog</ejb-link> 

To configure webservices.xml in Studio, double-click on webservices.xml in the Navigator to open it in the edit pane. If Studio reports an error on the header, you can safely ignore it. This may occur because the initial version of Studio version 5.0 isn't aware of the JSR-109 deployment descriptors.

Select the Design tab at the bottom of the edit pane, then open the descriptor until you see the ejb-link element:

click to expand

Replace the ejb-link element value with Catalog. Save your changes.

You have now finished configuring the web services deployment descriptors. There are some other interesting elements in webservices.xml. They are summarized in the following table:

Element

Description

webservice-description-name

The J2EE name for the service. Remember that a service can contain multiple ports.

wsdl-file

The relative path of the WSDL file in the module.

jaxrpc-mapping-file

The relative path of the mapping file in the module.

port-component-name

The J2EE name for the port.

wsdl-port

The name of the port in the WSDL file that's being implemented.

service-endpoint-interface

The Java Service Endpoint Interface class that corresponds to the wsdl:portType of the wsdl:port.

ejb-link

The EJB that implements this port.

Assemble the EJB JAR and Update the Application EAR

JSR-109 states that the developer is responsible for assembling the web services enablement files into the EJB JAR that contains the EJB, PlantsByWebSphereEJB.jar. Correspondingly the following files should be added to PlantsByWebSphereEJB.jar:

  • META-INF\webservices.xml

  • META-INF\PlantsByWebSphereCatalog_mapping.xml

  • META-INF\PlantsByWebSphereCatalog.wsdl

  • META-INF\ibm-webservices-bnd.xml

The class file for the PlantsByWebSphereCatalog Service Endpoint Interface at the relative path corresponding to its Java package.

To assemble the application using Studio, move the WSDL file to the META-INF directory, right-click on PlantsByWebSphereCatalog.wsdl in the Navigator pane and select Move.

From the Folder Selection panel, select the META-INF subdirectory and click OK.

Export the assembled EAR by selecting File | Export | EAR file. Click Next to display the EAR Export panel:

click to expand

Select the PlantsByWebSphereEAR project under the What Resources do you want to export? field.

Enter the EAR file name in the Where do you want to export resources to? field.

Click Export source files if you wish to have the Java files included in the archive.

Press Finish to create the exported EAR file.

Enable the Web Services Endpoint Listener

For WAS version 5.0 Web Services Technology Preview, an additional step is required to process the web services-enabled EAR file before it is deployed. This step will not be required after the version 5.0 update. This step is to run the endptEnabler command to add a servlet configuration to the EAR so that incoming SOAP requests on HTTP are routed to the EJB.

The SOAP runtime in WAS version 5.0 includes a servlet that can be configured to listen for incoming web services requests and route them to the appropriate EJB. The endptEnabler command adds a WAR file to the EAR file containing only a web.xml deployment descriptor that configures the router servlet appropriately. The Technology Preview install places the endptEnabler command in the bin subdirectory of the WAS installation directory. endptEnabler is an interactive tool run from the command line:

 endptEnabler IBM WebSphere Application Server Release 5 Web services Enterprise Archive Enabler Tool. Copyright IBM Corp., 1997-2002 Please enter the name of your ear file: PlantsByWebSphere.ear *** Backing up EAR file to: PlantsByWebSphere.ear~ JSR 109 enabled EJB Jar file at name PlantsByWebSphereEJB.jar Please enter a file name for your endpoint [PlantsByWebSphereEJB.war]: Please enter a context root for your endpoint [/PlantsByWebSphereEJB]: PBW 

The boldfaced text above is entered by the developer. For each JAR file containing webservices.xml, you are prompted for two pieces of information: the name of the WAR file to be added to the EAR, and the name of the context root (part of the URL) that will be used to access the service. The complete URL to access the service is:

http://host[:port]/context-root/services/port-component-name 

The context-root is specified when running the endptEnabler. The port-component-name is specified in webservices.xml. The services component of the URL is constant, as specified by JSR-109. Since the port-component-name is PlantsByWebSphereCatalog, let's simplify the context root by changing the default to PBW.

The endptEnabler makes two changes to the EAR file. First, it updates application.xml to add the new web module (WAR file):

 <module >   <web>     <web-uri>PlantsByWebSphereEJB.war</web-uri>     <context-root>/PBW</context-root>   </web> </module> 

Here you can see the context-root being set as specified and being associated with the new WAR file.

The second change is to add the WAR file to the EAR. The primary content of the WAR is the web.xml deployment descriptor:

 <web-app >   <display-name>WebSphere Web service</display-name>     <servlet >       <servlet-name>WSRouterServlet</servlet-name>       <display-name>Web services Router Servlet</display-name>       <servlet-class>           com.ibm.ws.webservices.axis.ws.transport.http.WASWebAxisServlet       </servlet-class>     </servlet>       ...       <servlet-mapping >         <servlet-name>WSRouterServlet</servlet-name>         <url-pattern>/services/*</url-pattern>       </servlet-mapping> </web-app> 

The url-pattern says whenever the URL contains PBW/services/, it will be directed to the WSRouterServlet. The WSRouterServlet has the ability to examine the port-component information in the webservices.xml file in PlantsByWebSphereEJB.jar, and route the request to the correct EJB. Putting all this together, the following URL will route your SOAP request to the Catalog EJB:

http://localhost:9080/PBW/services/PlantsByWebSphereCatalog

The context root and port-component-names are automatically included in the SOAP location field in the WSDL port when the application is deployed.

Deploying the Web Services-Enabled Application

Important

If you are using the Web Services Technology Preview, deploying and running a JSR-109 compliant web services application requires the stand-alone WebSphere Application Server version 5.0 with the Web Services Technology Preview installed.

When you deploy a WebSphere Application that has been enabled for web services, two extra deployment tasks request information.

Begin deployment by opening the Administration Console and uninstalling the Plants-By-WebSphere application if it's already installed. Then choose Install New Application as shown below and enter the path to the web services-enabled PlantsByWebSphere.ear:

click to expand

Press Next and proceed as usual for deploying an EJB, as described earlier in Chapter 6.

The first deployment task associated with deploying a web service is the Publish the WSDL file task.

Important

If you're using the initial version of WebSphere Application Server 5.0, you won't see this task unless the Web services Technology Preview has been installed.

click to expand

When a web service-enabled module is deployed, the WSDL files in the module are always updated with the location URL for the service and stored in the WebSphere Application Server's configuration directory for that module. If you specify a directory name in the Publish the WSDL file task, the updated WSDL files are also copied to the specified directory in a directory structure representing the modules and services being deployed. You will normally want to specify this directory to obtain WSDL that can be given to your customers to use to access the service. Note that the directory specified must already exist. Specify an existing directory and press Next.

The Get the name of the Server that hosts the web service deployment task appears:

click to expand

This task prompts for the protocol, host, and port for the location URL to access the web service. The default values are suitable for accessing the server where the EAR file is deployed. If you use an HTTP server such as IHS, an edge server, or other means of accepting and redirecting HTTP requests, you should change the host and port to match the HTTP server.

Finish deployment as usual.

After deployment is finished, the PlantsByWebSphere directory contains the following directory structure and files:

  • PlantsByWebSphere – the directory you specified to publish to

  • PlantsByWebSphere – the application name

  • PlantsByWebSphereEJB.jar – the module file name

  • PlantsByWebSphereCatalogService – web service description name (from webservices.xml)

  • PlantsByWebSphereCatalog.wsdl – the WSDL file for the service

If you look inside the published PlantsByWebSphereCatalog.wsdl file you'll find:

<wsdlsoap:address location=http://myhost:9080/PBW/services/PlantsByWebSphereCatalog />

You can now give this WSDL document to your customers to use in creating clients to access your service. If you want to publish the WSDL to a UDDI registry, WebSphere Studio Application Developer includes wizards to publish a WSDL file to UDDI.

Restart the server to activate the PlantsByWebSphereCatalog web service.

Verifying the Web Service Deployment

After you've deployed the PlantsByWebSphereCatalog web service into the application server and restarted, how can you verify the deployment? Let's try typing that URL into a browser and seeing what happens:

click to expand

The Apache AXIS-based runtime in the application server has intercepted the HTTP request to the URL, recognized that it doesn't contain a SOAP request, and responded with an acknowledgment message showing that the service is alive.

Now append ?wsdl to the URL. Does the result look familiar?

click to expand

The WSDL for the Catalog service has been published to this specific URL. You can just give this URL to your customers to access the WSDL for your service, instead of giving them the entire WSDL document.

Summary of Business Logic Enablement for Web services

To summarize what you've accomplished so far, we have:

  • Created a Java Service Endpoint Interface representing the Web service

  • Created a WSDL file describing the Java service

  • Created deployment descriptors describing how to map the service implementation to an EJB

  • Assembled and deployed the application

  • Published the WSDL (customers can use this WSDL to develop their own clients on any vendor's platform to access your service)




Professional IBM WebSphere 5. 0 Applicationa Server
Professional IBM WebSphere 5. 0 Applicationa Server
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 135

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net