Using RPC-Style Web Services with J2EE

Web Services provide functionality to the Internet, and are seen as the wave of the future. In this article, Martin Bond explains how to use Web Services protocols to join J2EE application components with any other software that supports those protocols. This excerpt is from Chapter (Day) 20, from Teach Yourself J2EE in 21 Days, second edition, by Martin Bond, et. al. (Sams, 2003, ISBN: 0672325586)

bondAs you saw yesterday, there are many ways of integrating existing and third-party applications and components with J2EE applications. However, the plethora of integration mechanisms has long been an issue. It would be better if there were a more consistent way of integrating applications. Additionally, expectations have increased around the capability to integrate applications that span organizations—particularly across the common communication medium of the Internet. Web Services provide a flexible and powerful integration mechanism that can be used to expose existing functionality and components to other organizations or new applications. Today and tomorrow, you will see how you can use Web Service protocols to build bridges between J2EE application components and any other platforms, applications, or components that support those Web Service protocols.

Web Services are seen by many as the next wave of the Internet revolution. The vision is of a Web as rich with functionality as the current Web is with information. The challenge is to expose this functionality in a consistent and usable way.

Today, you learn about

  • The concepts underlying Web Services and how Web Services fit with J2EE

  • Implementing RPC-style Web Service clients and servers

  • Exposing session EJBs as Web Services

First, you need to understand why you would use Web Services.

The aim of the last two days was to describe how to use J2EE technologies to implement and access a Web Service. This chapter will give an overview of how Web Service interactions work and will show how you can use JAX-RPC to generate and consume SOAP messages based on a WSDL interface.


Note - Before proceeding further, please be aware that the subject of Web Services is in itself very large, and there are many books dedicated to this popular topic. Today and tomorrow are intended to give you a start into using Web Services in Java and with J2EE technologies. However, it is not possible to answer every question or pursue every topic. If you would like to find out more about Java and Web Services after you have read through the material in this book, try the following URLs:


This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Web Service Overview}

This first section provides the underlying information and concepts required to successfully implement Web Services. Before employing Web Services, you should understand which problems they are designed to solve and the motivation behind them. This should ensure that you apply Web Services in appropriate places in your application.

What Is a Web Service?

A Web Service is essentially an application component that can be accessed using Web protocols and data encoding mechanisms—primarily HTTP and XML. In some cases, this is a third-party service hosted remotely. A Web Service differs from a traditional component in several ways, not only in the protocols used to access it. Under the component model, a currency conversion component could bring with it a file containing a fixed set of currency conversion rates that must be updated regularly. However, it would be up to you (the component user) to ensure that this information is updated. On the other hand, a Web Service is (or should be) a “living” entity, such that it brings with it any data and “back-end” functionality it requires. Unlike the component, a currency conversion Web Service takes responsibility for any updating of data or functionality. Your application simply uses the conversion service and leaves the details of obtaining the latest data and subsidiary services to those who implement and host the service.

Similarly, a Web Service can represent a courier service or a credit-card processing service. Again, you do not need to concern yourself with how the service is implemented, simply the results of using the service. Many types of Web Services are appearing that provide a sliding scale of functionality from low-level infrastructure to high-level business services.

Applications can be built from services in a similar way to building applications from components. You will combine standard services (such as credit-card authorization) with custom code to create your desired application.

As a software developer, you might write Web Services for others to use. In this case you would

  1. Decide what functionality you wish to expose as a service.

  2. Implement the service being offered.

  3. Describe the service being offered.

  4. Publish the description.

  5. Inform direct consumers of your Web Service that it is available (or wait for them to discover it).

Alternatively, you may use Web Services as part of your application as follows:

  1. Discover an interesting service.

  2. Retrieve the description.

  3. Plug it into your application.

  4. Use the service as the application executes.

This all sounds very easy, but you need a ubiquitous framework for Web Services to stop this from sliding into chaos. The key factor in delivering such a framework is the widespread agreement to use common, Web-based protocols. In the first instance, this comes down to the use of the Simple Object Access Protocol (SOAP), under which XML-encoded messages are sent over some form of transport mechanism—usually HTTP. SOAP is the way in which Web Services communicate. Other protocols are also required to deliver the full framework, and you will encounter these protocols over the course of the next two days.

Why Use Web Services?

Web Services bring similar advantages to the use of components. Using a service allows you to take advantage of another organization’s expertise in, say, credit-card processing, without you having to become a specialist in it yourself. The service model enables you to use the most powerful and up-to-date functionality by connecting to a remote running service.

Although a service-based approach to application development is not a new concept, it has traditionally presented difficult challenges:

  • Interoperability between different distribution mechanisms, such as CORBA, RMI, and DCOM.

  • Application integration, including legacy systems, cross-vendor, and cross-version.

  • Web-based business requires cross-organization development and high flexibility to accommodate a rapid rate of change, and safe operation through company firewalls.

Web Services can provide a consistent, cross-organization, cross-vendor framework that will speed up the integration of applications and application components. By selecting existing, widely-used standards, the Web Service framework removes many barriers to integration that existed when using other frameworks. The Web Service model is language- and platform-neutral, so developers anywhere can potentially build and consume Web Services.

Probably the most important factor of all is that all the major application, platform, and technology vendors have adopted the Web Service concept and the associated protocols. This means that Web Services will form a large part of application development over the next few years.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Web Service Technologies and Protocols}

The following are some of the more important protocols, technologies, and standards in Web Services:

  • The Simple Object Access Protocol (SOAP)—Combines XML and Multipurpose Internet Mail Extensions (MIME) to create an extensible packaging format. The SOAP envelope can be used to contain either RPC-style or message-style (document-centric) service invocations. A SOAP message can be carried over many transport mechanisms, including HTTP, SMTP, and traditional messaging transports. Although SOAP began its life outside the World Wide Web Consortium (W3C), ongoing work on SOAP can be found at http://www.w3.org/2002/ws/. This includes the latest working drafts of the 1.2 specifications, as well as a link to the version 1.1 specification.

  • The Web Services Description Language (WSDL)—It is an XML vocabulary used to describe Web Services. It defines operations, data types, and binding information. The WSDL specification can be found at http://www.w3.org/TR/wsdl.

  • Universal Description, Discovery, and Integration (UDDI)—Provides a model for organizing, registering, and accessing information about Web Services. The UDDI specifications can be found at http://www.uddi.org/.

  • The Web Service Flow Language (WSFL) and Web Service Collaboration Language (WSCL)—These are concerned with describing the workflow between services so that their relationships can be encapsulated as part of an application. The description of interactions between Web Services is also described as choreography. More information on WSFL can be found at http://xml.coverpages.org/wsfl.html. A W3C working group on choreography has been formed and can be monitored at http://www.w3.org/2002/ws/chor/.

  • Electronic Business XML (ebXML)—Provides a framework for e-commerce that includes the inter-application workflow and the description and discovery of services. It uses SOAP as its transport mechanism but does not directly use WSDL, UDDI, or WSFL. ebXML is a joint initiative between OASIS and the United Nations CEFACT group. The set of ebXML specifications can be found at http://www.ebXML.org/.

Web Service Architecture

The idealized interaction between a Web Service–based application and the Web Service itself is shown in Figure 20.1. The overall interaction is very similar to the way that a J2EE client uses an EJB. When a Web Service is created, information about its interface and location are stored in a registry. The Web Service consumer can then retrieve this information and use it to invoke the Web Service.

bond

Figure 20.1
Interaction between Web Service, registry, and service consumer.

Some of this consumer/service interaction takes place at design and development time. The interface and service contract information can be registered, regardless of whether the service is active. This information is required by the application builder to create code that uses the Web Service in his application. At runtime, the application can look up the precise location of the Web Service to locate it, very much like a traditional RPC mechanism, such as RMI.

There are several variations on this interaction. A Web Service can be used entirely dynamically in that the service description is discovered and invoked dynamically. Alternatively, the location information discovered at design time as part of the service description can be bound into the client application so that it has no need of the registry at runtime. Indeed, the information about the Web Service might not even be registered in any form of registry. The creator of a Web Service can easily provide service descriptions to potential clients by attaching the necessary WSDL documents to an email message.

Similarly, the way in which an application interacts with a Web Service depends on the service. Some services might provide an RPC-style interface based on request/response operations. In this case, the interface to the Web Service will look like a traditional Remote Procedure Call (RPC) interface as found in Java’s RMI. The interaction of an RPC-style Web Service and its clients still uses SOAP messages “under the covers” but it provides a more familiar model for developers to work with. Conversely, other services might work in a message-oriented style by exchanging XML-based documents. In either case, the interaction can be synchronous or asynchronous. There is nothing to stop a Web Service implementation from offering out its services in all four combinations (synchronous RPC-style, asynchronous RPC-style, synchronous message-oriented, and asynchronous message-oriented).

Service developers will define an interface for their services using a description mechanism such as WSDL. This can be based on an existing service implementation, or the service can be developed after the interface is defined.

Application developers will take the service description and write code based on this. In many cases, a client-side proxy will be created for the services and the application will interact with this proxy. However, the precise details of this are left to the client-side developer.

The service implementations will take a variety of forms. On the server-side, an adapter and router will be required to accept inbound SOAP messages and dispatch them to the appropriate service implementation. This performs the role of the Object Request Broker (ORB) in CORBA and RMI or the Service Control Manager (SCM) under DCOM.

The services being invoked can be of varying granularity. You can use Web Service mechanisms to expose fine-grained services, such as currency conversion. However, Web Service protocols are much more suited to exposing coarse-grained services. In some cases these services can represent a whole application, such as an ERP system.

Although much about the Web Service paradigm will seem familiar to you, the use of Web Services, especially third-party Web Services, does bring some extra considerations for developers:

  • The fact that the service is hosted elsewhere will impact testing, security, availability, and scalability. Service-Level Agreements (SLAs) will need to be defined for all services used.

  • The providers of an external service will have to be paid somehow. There will be associated authentication requirements so that use of the service can be tracked by the providers.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Web Services for J2EE}

With the advent of J2EE 1.4, Web Services are now an integral part of J2EE. This section examines at a high level how Web Services fit with the J2EE model and how they can be used with J2EE components.

J2EE Web Service Architecture

J2EE can can be both a provider and consumer of Web Services. Figure 20.2 shows the overall architecture, with business logic being provided by EJBs (although other classes could be used). The functionality offered by the business components will be described by a WSDL document (or similar), and this can then be used to build clients that use this functionality.

bond

Figure 20.2
Overall J2EE Web Service architecture.

SOAP RPC calls will be handled by a router component based around a servlet. This will dispatch calls to the associated EJB or other component. The router that handles document-centric SOAP messages will also be servlet based. In either case, the precise nature of the servlet will depend on the type of underlying transport over which the messages are sent.

The J2EE business components may themselves use other Web Services to help them deliver business functionality. In this case, the components will take advantage of the client-side Web Service APIs to call out to these Web Services.

The Web Service runtime will consist of a variety of filters, providers, and helpers that will be used in combination with the routing servlets and basic, low-level APIs. These helpers will deliver additional value on top of the basic APIs, such as ebXML quality of service guarantees.

Tools and Technologies

A number of JSRs in the Java Community Process (JCP) have defined the Web Service APIs and architecture used by J2EE. These include the following:

  • JSR101, the Java APIs for XML-based RPC (JAX-RPC)—JAX-RPC provides APIs for invoking RPC-based Web Services over SOAP. It defines how interactions should take place and provides the basis for automated tools to produce stubs and skeletons. It also specifies type mapping and marshalling requirements between Java and XML Schema types.

  • JSR067, the Java APIs for XML Messaging (JAXM), and the SOAP with Attachments API for Java (SAAJ)—These APIs are used to create document-centric SOAP messages that can be exchanged either synchronously or asynchronously. Vendors can provide messaging profiles on top of this that offer value-added services, such as ebXML.

  • JSR093, the Java API for XML Registries (JAXR)—JAXR defines a two-tier API for accessing registry information stored in XML format. This is targeted at Web Service-related registries, such as UDDI registries and ebXML registry/repositories, as well as other generic XML registries.

  • JSR109, Implementing Enterprise Web Services—JSR109 does not define any Java APIs. Instead, it defines how J2EE implementations should work with JAX-RPC, SAAJ, JAXM, and JAXR. This includes everything from the schema for XML-based configuration files to the overall programming model envisioned.

All these JSRs have now reached their first release, but work is still ongoing to extend and maintain the capabilities defined in them. The contents and status of these JSRs are available through the JCP Web site at http://www.jcp.org/.

The role that each of these APIs plays in the J2EE Web Service architecture is shown in Figure 20.3. All these APIs are included in J2EE 1.4 (as defined in JSR151) and form part of the J2EE Reference Implementation (RI).

bond

Figure 20.3
J2EE Web Service APIs.

As well as implementations of J2EE 1.4, there are various other sources of Java-based Web Service functionality:

  • The Apache Software Foundation provides the Axis toolkit for the creation and use of SOAP-based Web Services that can be deployed in most servlet containers. Axis implements the JAX-RPC and SAAJ APIs and continues to track updates to the associated JSRs as well as the progress of SOAP 1.2. The predecessor to Axis was Apache’s SOAP toolkit 2.2. The Axis toolkit can be found at http://xml.apache.org/axis.

  • For several years, IBM has delivered its its Web Services Toolkit (WSTK) through their Alphaworks developer site. This toolkit has subsequently evolved into the Emerging Technologies Toolkit (ETTK). The ETTK provides a set of tools and APIs on which to build Web Services. The ETTK conforms to the relevant JSRs but also acts as a platform for early delivery of new Web Service APIs such as security and routing. The ETTK integrates with the Apache Tomcat servlet engine and IBM’s WebSphere application server. IBM’s ETTK and can be found at http://www.alphaworks.ibm.com/tech/ettk.

  • The reference implementations of the individual APIs are available as part of the Java Web Services Developer Pack (JWSDP), along with other Java APIs for the manipulation of XML. The JWSDP can be found at http://java.sun.com/webservices.

If you want to investigate or use Web Service functionality in your applications, the appropriate choice will depend on the style and robustness you require.

Integrating Web Services with J2EE

Most development projects involve using or adapting existing functionality. Projects based on Web Services will be no different. In fact, a project can be specifically focused at exposing existing functionality to clients in the form of Web Services. So, how do you expose existing J2EE functionality as Web Services?

For a traditional J2EE application, business logic is contained in EJBs or plain old Java objects (POJOs). This functionality is usually made available to client applications through servlets and JSPs. If the clients are Web browsers, these Web components will generate and consume HTML. Similarly, if the clients are mobile applications, the Web components may generate and consume Wireless Markup Language (WML). However, these WML Web components share the same business logic—they just provide a different front end or channel for it. Web Service clients are no different in that respect from HTML or WML clients. The SOAP router servlet, together with helper classes, acts as a server-side wrapper for the business logic, delivering it to Web Service clients. This situation is shown in Figure 20.4.

bond

Figure 20.4
Web Services are just another channel through which to access business functionality.

The other type of J2EE component in which application logic can be held is a servlet or JSP. You may ask how you would wrap this functionality for use as a Web Service. Well, the issue here is that many of the Web components in question are already acting as channels to some form of client (as shown in Figure 20.4). Consequently, wrapping them makes no sense. What you should do is create a replacement for such a Web component that is targeted at Web Service clients rather than Web browsers. If your Web components are well designed, you should be able to reuse the JavaBeans, servlet filters, and POJO helper classes as part of your Web Service implementation.

Creating a Web Service with JAX-RPC

As discussed earlier, the JAX-RPC specification defines how Web Service clients written in Java can make RPC-style calls on Web Services and how Web Services can be written in Java to receive such calls. The Implementing Enterprise Web Services specification defined in JSR109 describes how such Web Services and Web Service clients can be used as part of a J2EE application. Although it is possible to use other transport mechanisms and interaction styles, the main focus of JAX-RPC is for making synchronous calls on top of the SOAP transport. Hence, the remainder of today will focus on building clients and servers that take part in this type of exchange.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=RPC-Oriented Web Services}

Remote Procedure Calls (RPCs) made over Web-based protocols are essentially no different from those made over other protocols, such as IIOP, DCOM, or JRMP. The calls are usually synchronous (in other words, the client waits for the method to return before continuing). Zero or more parameters of varying types are passed into the call to provide information to process, and zero or more return values are generated to deliver the outputs of the remote method to the client. The remote method calls are delivered to some form of dispatcher at the remote server that determines which method should be called and arranges for the smooth flow of parameters and return values.

For RPC-style operation, SOAP implementations conform to the preceding description. The difference with SOAP (and other Web-based RPC mechanisms, such as XML-RPC) is that it uses standard, general-purpose transports, such as HTTP, together with a text-based method call description in XML. All the parameters and return values are encoded in XML as part of the SOAP body, while information about the service and method to call are provided in the transport header and possibly the SOAP header. When sent over HTTP, the SOAP header and body are wrapped in another XML document—the SOAP envelope—and this envelope forms the body of an HTTP POST request.

An HTTP-based SOAP message will be delivered to a SOAP router that takes the form of an HTTP servlet (for a Java implementation). The SOAP router will examine the HTTP and SOAP header information and decide how it should forward the message body. This will involve instantiating or calling a particular component or class that will receive the message. The SOAP router, or its helper classes, will also perform the conversion of the XML-based parameters into Java objects and primitives that can be passed as part of the service invocation. Figure 20.5 shows the operation of such a SOAP router. Note that the description of the Web Service is used by both the client and server to help determine the correct mapping between Java and XML for method calls and parameter types.

This is all good, but why go to this effort? Why not use an existing RPC mechanism, such as RMI, or just use HTTP itself?

The justification for not using RMI or CORBA to integrate applications relates to commonality and security. There are at least three different distributed object protocols (CORBA, RMI, and DCOM), each of which has its adherents. The use of HTTP and XML provides a common protocol that is not tied to any vendor. Also, the traditional RPC protocols listed have great difficulty in penetrating most firewalls (not surprising, given their capability to invoke random functionality). However, HTTP (and SMTP) has general right of access through most firewalls, which makes it easier to integrate applications across organizational boundaries (after the security questions are sorted out).

bond

Figure 20.5
A Java-based SOAP router.


Caution - From a developer’s perspective, one of SOAP’s greatest assets is its capability to penetrate firewalls. However, from an administrator’s point of view, this presents the same types of problem as traditional RPC, namely the capability to target a random function call at an exposed server. Although the principle of SOAP is only a small step up from the invocation of server-side functionality such as CGI, great care should be taken to ensure adequate security when exposing Web Services. The overall security story for Web Services is still a work in progress.


Although raw HTTP is a good transport, it was created to exchange simple HTML messages. This does not provide the sophistication required for a distributed invocation environment. The use of a defined XML message format brings structure to this environment and allows for the interoperability of Web Service clients and servers from different vendors—something that escaped CORBA until comparatively recently.

So, Web Service protocols have some large advantages over traditional RPC protocols. However, you need to be careful about where you apply Web Service protocols. Such protocols are primarily intended for the integration of coarse-grained components or application functionality. As mentioned earlier, this might be exposed at the same system boundary as an HTML interface on the same functionality. Internally, the system might use RMI CORBA or DCOM to distribute functionality across several tiers. This is fine; there is no need to replace all distribution mechanisms with Web Service protocols. Web Service interfaces should usually be exposed only at the system boundary, not within the system itself.

Now that you understand the architecture and motivation for RPC-style Web Services, you can create a Java-based Web Service client and server.

The JAX-RPC API

JAX-RPC defines a set of classes, interfaces, principles, and mechanisms for making SOAP-based RPC calls. The main parts are

  • Type conversion between Java types and XML types—For simple types, such as strings and primitive types, very little work is required. More effort is required from either the tools or the developer when mapping more complex types between Java and XML.

  • Mapping between SOAP operations defined in WSDL and Java remote method calls—Essentially, WSDL interfaces are represented in Java by Remote interfaces.

  • The server environment and how calls are received and directed—The receiving Java class has access to particular information about the SOAP call provided through a service context. The lifecycle of a servlet-based service is defined.

  • A client- and server-side SOAP message handler mechanism similar in concept to servlet filters.

  • Client programming model describing the relationship between interfaces and stubs, and how these are obtained in different environments such as J2SE and J2EE.

The essential principle is that JAX-RPC tries to make the development of SOAP-based clients and servers fairly simple and intuitive for Java developers. To start your journey through Web Services, the first example is a simple, servlet-based JAX-RPC service and a standalone client for it.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Creating a Simple Service}


Note - All the examples in the rest of this chapter refer to the J2EE Reference Implementation. However, the information required and the techniques used are common across all implementations of JAX-RPC. Basically, the tools might change but the artifacts and information you have to provide as a developer don’t.


The initial service is servlet-based and will just pass strings back and forth to exchange greetings. After you are comfortable with this simple service, we will move on to look at how to provide a Web Service
front-end for a session EJB.

Files and Tools

In common with other J2EE components, a J2EE-based Web Service implementation consists of multiple parts:

  • A reference to the implementation of the functionality to be exposed by the Web Service, which can point to simple Java classes bundled with the component or which can refer to one
    or more EJBs

  • Code that maps between the exposed functionality and the container—for example, skeletons (or ties) and serializers

  • A WSDL definition of the interface implemented by the service

  • Configuration files that tell the J2EE implementation more about how the service should be deployed and the services it requires from its container

A Web Service client has similar code and configuration files but does not carry an interface definition or service implementation information.

All the configuration files are encoded in XML. Some of them are reasonably simple and can easily be created by hand. Other files,
such as the WSDL interface definition, are far more complex and will typically be generated by tools. The stubs and skeletons required will also be automatically generated. To generate the stubs, skeletons,
and WSDL interface definition, we will use the wscompile tool provided
as part of the J2EE Reference Implementation.

Defining the Interface and Implementation

As with RMI, a remote interface definition is central to the use of JAX-RPC. This interface is either written by a developer and then used to generate a WSDL file, or the Java interface is generated from a pre-provided WSDL file. In the examples we look at today, the WSDL file is generated from the Java interface definition. The Java interface definition must extend java.rmi.Remote and all methods must be declared as throwing java.rmi.RemoteException. The simple Web Service is based around a simple Java Remote interface, Greeting, containing a single method called sayHelloTo(). The sayHelloTo() method takes a single String parameter—the name of the person to greet—and returns the resultant greeting. The Greeting interface is shown in Listing 20.1.

Listing 20.1 Interface for the Greeting Service (Greeting.java)

package wsexamples;

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

public interface Greeting extends Remote
{
  public String sayHelloTo(String name) throws RemoteException;
}

The sayHelloTo() method is the Web Service equivalent of the “Hello World!” program used as a first step in learning programming languages such as C and Java. In Web Service terms, the method is simple because it takes a single parameter and returns a single value. These values are both strings, and strings are easily marshaled between the on-the-wire XML representation used by SOAP and the internal java.lang.String type.

The Greeting interface is implemented by the GreetingImplementation
class. The sayHelloTo() method simply appends the name passed in
onto a suitable greeting and passes back the resultant string. The GreetingImplementation class is shown in Listing 20.2.

Listing 20.2 Implementation of the Greeting Service (GreetingImplementation.java)

package wsexamples;

public class GreetingImplementation implements Greeting
{
  public String sayHelloTo(String name)
  {
    return “Hi there ” + name;
  }
}

As you can see, there is nothing special about the
GreetingImplementation class. If you did not know that Greeting was
a Remote interface, the rest of the class gives you no indication. As stated earlier, this first example will be a servlet-based Web Service. However, there is no servlet definition in the interface or implementation. As the creation of a servlet to implement a given interface is something of a predictable task, all this can be automated. Think of the implementation class as being like the bean class in an EJB—it will get surrounded by “scaffolding” as it is deployed and configured. This “scaffolding” consists of the fixed infrastructure provided by J2EE, such as the SOAP routing servlet discussed earlier, and some files specifically generated for your service, such as the
Web Service stub and skeleton files.

Web Service Compiler Configuration File

When you created EJBs earlier, you had to include various configuration files to tell the container about the EJB and its requirements. The same principle applies for a JAX-RPC Web Service. Somehow, a variety of artifacts must be created that describe the service for potential clients and help to integrate the service with its container. In the J2EE Reference Implementation, the main tool for this is wscompile. The wscompile tool can generate WSDL, server-side scaffolding, and client-side scaffolding. For the time being, you will concentrate on the WSDL and server-side scaffolding.

wscompile requires a variety of information about the artifacts you need to create. You define this information in an XML-encoded configuration file. The root element is configuration and its sole attribute indicates that the file conforms to the RI’s JAX-RPC schema:

<configuration xmlns=”http://java.sun.com/xml/ns/jax-rpc/ri/config”>

Within this root element you will typically define one of two child elements:

  • service—Contains information to help generate a WSDL file
    based on a Remote interface

  • wsdl—Defines information about a Web Service definition
    from which a Remote interface is to be generated

The element you require will depend on whether you are starting from a Java interface definition or starting from WSDL. In this case, you will start from the code and generate the WSDL. Although this is convenient as a learning exercise, it is not the best practice to follow when creating industrial-strength Web Services. Some of the reasons for this are discussed in the section “Starting from WSDL” later today.

In this case, because you are generating a WSDL file from a Remote interface, you need a service element within the root. The attributes of this element define the following:

  • The name of the service (name) that is to be defined in the WSDL description.

  • The target namespace (targetNamespace) within which the service’s messages and message parts are to be defined.

  • The namespace (typeNamespace) within which the service’s data types are to be defined.

  • The package into which generated Java artifacts are to be placed (packageName). Because you are only defining a WSDL document at the moment, this is not used, but it must still be provided; otherwise, wscompile will fail.

The resultant element will look something like this:

<service name=”GreetingService”
     targetNamespace=”urn:J2EE21Examples” 
     typeNamespace=”urn:J2EE21ExamplesTypes” 
     packageName=”wsexamples”
>

Each service element can contain one or more interface elements. The interface element describes a Web Service endpoint that is exposed as part of the service. The name attribute defines the name of the Java interface that implements the methods to be exposed. This should be set to the fully qualified name of the interface you created earlier (you can also specify the name of the implementation, or servant, class using the servantName attribute although this does not affect the generation of the WSDL):

<interface name=”wsexamples.Greeting” servantName=
“wsexamples.GreetingImplementation”/>

Listing 20.3 shows a full wscompile configuration file that will generate the WSDL for the simple Greeting interface shown earlier.

Listing 20.3 wscompile Web Service Configuration File (config-service.xml)

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration 
 xmlns=”http://java.sun.com/xml/ns/jax-rpc/ri/config”>
 <service 
   name=”GreetingService” 
   targetNamespace=”urn:J2EE21Examples”
   typeNamespace=”urn:J2EE21ExamplesTypes”
   packageName=”wsexamples”>
   <interface name=”wsexamples.Greeting” servantName=
“wsexamples.GreetingImplementation”/> </service> </configuration>

You define which artifacts you want wscompile to generate using command-line options. Once you have created the configuration file shown in Listing 20.3, you can use wscompile to generate the WSDL description and mapping file for the Greeting service.

Under Microsoft Windows:

wscompile -define -classpath %CLASSPATH%;classes -nd wsgenerated –mapping
ws
generatedmapping.xml wsconfig-service.xml

Under Unix:

wscompile -define -classpath $CLASSPATH:classes -nd ws/generated –mapping
ws/
generated/mapping.xml ws/config-service.xml

The line shown assumes that the compiled classes for Greeting and GreetingImplementation reside in the classes subdirectory and that the configuration file is in the ws subdirectory. The –define flag indicates that you want just the service definition at the moment (no server or client artifacts), the –nd flag indicates that the resultant WSDL file should be placed in the ws/generated subdirectory, and the –mapping flag indicates where the generated mapping file is to be saved.

The code for all of today’s examples is on the Web site that accompanies this book. You will find them in the examples directory for Day 20. With the code supplied on the accompanying Web site, you can use the following Ant command to build the supplied Greeting service, which includes the creation of the WSDL and the mapping file:

asant build

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=The WSDL File}

The WSDL file generated by wscompile is shown in Listing 20.4. It is worth taking a few moments to study this information because it provides a good insight into the way that Web Services work.

Listing 20.4 Generated GreetingService WSDL (GreetingService.wsdl)

<?xml version=”1.0″ encoding=”UTF-8″?>

<definitions name=”GreetingService”
       targetNamespace=”urn:J2EE21Examples”
       xmlns:tns=”urn:J2EE21Examples” 
       xmlns=”http://schemas.xmlsoap.org/wsdl/” 
       xmlns:xsd=”http://www.w3.org/2001/XMLSchema” 
       xmlns:soap=”http://schemas.xmlsoap.org/wsdl/soap/”>
  <types/>
  <message name=”Greeting_sayHelloTo”>
    <part name=”String_1″ type=”xsd:string”/>
  </message>
  <message name=”Greeting_sayHelloToResponse”>
    <part name=”result” type=”xsd:string”/>
  </message>
  <portType name=”Greeting”>
    <operation name=”sayHelloTo” parameterOrder=”String_1″>
      <input message=”tns:Greeting_sayHelloTo”/>
      <output message=”tns:Greeting_sayHelloToResponse”/>
    </operation>
  </portType>
  <binding name=”GreetingBinding” type=”tns:Greeting”>
    <soap:binding transport=http://schemas.xmlsoap.org/soap/http
style
=”rpc”/> <operation name=”sayHelloTo”> <soap:operation soapAction=”"/> <input> <soap:body encodingStyle=”http://schemas.xmlsoap.org/soap/
encoding/” use=”encoded” namespace=”urn:J2EE21Examples”/> </input> <output> <soap:body encodingStyle=”http://schemas.xmlsoap.org/soap/
encoding/” use=”encoded” namespace=”urn:J2EE21Examples”/> </output> </operation> </binding> <service name=”GreetingService”> <port name=”GreetingPort” binding=”tns:GreetingBinding”> <soap:address location=”REPLACE_WITH_ACTUAL_URL”/> </port> </service> </definitions>

The document consists of the following sections:

  • The XML prolog (<?xml …?>) and root element(definitions)—The namespace declarations on the root element show that the operations defined here belong in the namespace
    urn:J2EE21Examples and that this namespace is also represented by the tns prefix. The default namespace declaration indicates that all unqualified elements and attributes come from the W3C’s WSDL definitions. The xsd prefix denotes types from the
    W3C XML Schema definition, whereas the soap prefix denotes types from the SOAP schema.

  • The types section—There are no complex types in the Greeting interface, so all the type definitions required come from the XML Schema. Hence, the types element is empty.

  • WSDL message definitions—These define two matched messages: a request and a response. The request (Greeting_sayHelloTo) takes a single string parameter, and the response (Greeting_sayHelloToResponse) also returns a single string.

  • WSDL portType definitions—A portType is the equivalent of an interface definition. It contains one or more operation definitions, which in turn are built from the message definitions in the document. In this case, there is a single operation defined in the Greeting called sayHelloTo. This consists of the two messages, Greeting_sayHelloToRequest and Greeting_sayHelloToResponse, seen earlier.

  • The binding element—Called GreetingBinding, it indicates that clients can access the Greeting port type through the SOAP protocol. Now that you have an interface (portType), you can define the protocols over which that interface can be accessed. The WSDL operation is mapped to a SOAP operation with input and output soap:body elements defined to map the request and response.

  • Within this WSDL binding, a SOAP binding (soap:binding)
    is defined
    —Because SOAP can work with a variety of underlying transports and it can work in an RPC-centric or
    document-centric way, the attributes on the
    soap:binding indicate that it is an RPC-style binding that uses HTTP.

  • Finally, an instance of the service is defined in the WSDL service element—A WSDL service contains a list of WSDL port elements. Each port element defines a specific instance of a server that conforms to one of the WSDL binding elements
    defined earlier.

  • Again, in the case of the simple Greeting service, the service element (named GreetingService) contains a single WSDL port called GreetingPort. This specifies that a server conforming to the GreetingBinding can be found at the SOAP address defined by the location attribute.

This is a very simple WSDL document defining a very simple service. WSDL documents are typically far longer and more complex. Because
of this, WSDL is largely intended for manipulation by tools and applications.

By examining the WSDL document, you can see how the information defined in the wscompile configuration file forms part of the WSDL. The targetNamespace and tns prefix in the WSDL are associated with the targetNamespace defined in the configuration file. The name of the WSDL service comes from the name attribute of the service element in the configuration file. The WSDL port is formed by appending the string “Port” to the name of the interface defined as a child of the service element in the configuration file.

One thing to note about the generated WSDL is that it is not complete. All the relevant type definitions are there (none in this case, but you will see more later), as are the definitions of the operations and their parameters and the protocol bindings. However, in the SOAP address associated with the port element, there is no endpoint address (the location is set to “REPLACE WITH ACTUAL URL”). This is not surprising because this WSDL has been generated from a class on the disk and wscompile has no way of knowing where this service will be deployed. Part of the deployment process will involve filling out this WSDL endpoint information so that the WSDL can be employed by a Web Service client.

The Mapping File

The mapping file—mapping.xml—provides a link between information in the WSDL document and the Java code supplied to support the service defined. There is a 1-1 relationship between mapping files and WSDL documents, and there are other constraints on the WSDL to assist the mapping, such as there being only one service description in a WSDL file. A full list of these restrictions and a detailed description of the mapping file (termed the “JAX-RPC Mapping Deployment Descriptor”) can be found in section 7.3 of the document Web Services for J2EE document that was produced by JSR109.

Thankfully, the mapping file for our simple Greeting service is itself simple. It starts with a standard prolog and the root element java-wsdl-mapping:

<?xml version=”1.0″ encoding=”UTF-8″?>
<java-wsdl-mapping version=”1.1″ 
          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”>

Within the root, you define package-mapping elements that map the namespaces using the WSDL to Java packages in which you define your classes. For the simple service, you just need to indicate that the service defined in the WSDL document under the target namespace of urn:J2EE21Examples is associated with the code defined in the Java package wsexamples:

<package-mapping>
  <package-type>wsexamples</package-type>
  <namespaceURI>urn:J2EE21Examples</namespaceURI>
</package-mapping>

The remainder of the mapping file defines how the WSDL service, port and binding relate to the parts of the Java Greeting interface defined earlier. The full mapping file is shown in Listing 20.5.

Listing 20.5 Mapping File for the Simple Greeting Service
(mapping.xml)

java-wsdl-mapping version=”1.1″
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”>
<package-mapping>
<package-type>wsexamples</package-type>
<namespaceURI>urn:J2EE21ExamplesTypes</namespaceURI>
</package-mapping>
<package-mapping>
<package-type>wsexamples</package-type>
<namespaceURI>urn:J2EE21Examples</namespaceURI>
</package-mapping>
<service-interface-mapping>
<service-interface>wsexamples.GreetingService
</service-interface>
<wsdl-service-name xmlns:serviceNS=”urn:J2EE21Examples”
>serviceNS:GreetingService</

wsdl-service-name>
  <port-mapping>
   <port-name>GreetingPort</port-name>
   <java-port-name>GreetingPort</java-port-name>
  </port-mapping>
 </service-interface-mapping>
 <service-endpoint-interface-mapping>
  <service-endpoint-interface>wsexamples.Greeting
</service-endpoint-interface> <wsdl-port-type xmlns:portTypeNS=”urn:J2EE21Examples”>portTypeNS:
Greeting
</wsdl-port-type> <wsdl-binding xmlns:bindingNS=”urn:J2EE21Examples”>bindingNS:
GreetingBinding
</wsdl-binding> <service-endpoint-method-mapping> <java-method-name>sayHelloTo</java-method-name> <wsdl-operation>sayHelloTo</wsdl-operation> <method-param-parts-mapping> <param-position>0</param-position> <param-type>java.lang.String</param-type> <wsdl-message-mapping> <wsdl-message xmlns:wsdlMsgNS=”urn:J2EE21Examples”>wsdlMsgNS:
Greeting_sayHelloTo</
wsdl-message>
     <wsdl-message-part-name>String_1</wsdl-message-part-name>
     <parameter-mode>IN</parameter-mode>
    </wsdl-message-mapping>
   </method-param-parts-mapping>
   <wsdl-return-value-mapping>
    <method-return-value>java.lang.String</method-return-value>
    <wsdl-message xmlns:wsdlMsgNS=”urn:J2EE21Examples”>
wsdlMsgNS:Greeting_sayHelloToResponse</
wsdl-message>
    <wsdl-message-part-name>result</wsdl-message-part-name>
   </wsdl-return-value-mapping>
  </service-endpoint-method-mapping>
 </service-endpoint-interface-mapping>
</java-wsdl-mapping>

Packaging and Deploying the Simple Web Service Using J2EE RI deploytool

This section shows how to deploy the simple Web Service to the J2EE RI. You will get the most out of this if you actually perform these steps (but if you’re on a train or plane, just read the text and make do).

As usual, start up the PointBase database server and J2EE RI server before starting deploytool.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Creating the Web Service WAR}

You will package up the Web Service in a WAR file, so choose File, New, Web Component to create a new one. Click Next to skip the introduction screen and move onto the WAR file creation screen. You will be creating a New Stand-Alone WAR Module so ensure that this option is selected. Next, under WAR Naming, browse to a location in which you wish to save your WAR file and provide “wsgreeting” as the File Name.

Now you can populate your WAR with the files you saw earlier. Under the Contents section, click the Edit button to display the Edit Contents of wsgreeting screen. Browse to find the class files (Greeting.class and GreetingImplementation.class), the WSDL file (GreetingService.wsdl – created in folder build/generated), and the mapping file (mapping.xml – created in folder build/generated). Add each of these files to the contents as shown in Figure 20.6 and click OK.

bond

Figure 20.6
Populating the Web Service WAR with class and configuration files.

Your WAR file settings should look similar to those in Figure 20.7.

bond

Figure 20.7
The settings for the Web Service WAR file.

Click Next to move on to the Choose Component Type screen and select Web Services Endpoint. Click Next to move onto the Choose Service screen. Under the Service Definition, the WSDL File drop-down list should offer you the GreetingService.wsdl file and the Mapping File drop-down list should offer you the mapping.xml file. Select these two files so that your screen looks like that in Figure 20.8. You will see that the service name has been picked up from the WSDL file.

bond

Figure 20.8
Selecting the WSDL and mapping files.

Now click Next to move onto the Component General Properties window. Select wsexamples.GreetingImplementation as your Service Endpoint Implementation (this will be offered from the drop-down list). Again, the fields will be populated based on the information in the file.

Click Next to move on to the Web Service Endpoint screen. Select wsexamples.Greeting as your Service Endpoint Interface. In the WSDL Port section, set the Namespace to be urn:J2EE21Examples and ensure that the Local Part becomes GreetingPort as shown in Figure 20.9.

bond

Figure 20.9
Configuring the Web Service Endpoint.

That completes the initial configuration, so click Next followed by Finish. You should be presented with a deploytool screen that looks like Figure 20.10.

bond

Figure 20.10
Web Service WAR in deploytool.

Configuring the WAR and Component

There are three final bits of Sun-specific configuration that are needed to complete the Web Service WAR. First, select the General tab of the wsgreeting WAR file (as shown in Figure 20.10). Set the Context Root field to /wsgreeting.

Now select the GreetingImplementation component in the left-hand pane. Select the Aliases tab and Add an alias of /GreetingService as shown in Figure 20.11.

Finally, select the Endpoint tab and change the Endpoint Address at the bottom of the tab to be GreetingService. You should now save your WAR file and you are ready to deploy your service.

During this process, deploytool has generated several new files for you:

  • The web.xml file—This contains the servlet definition for your
    Web Service. One part of this defines a servlet and indicates that wsexamples.GreetingImplementation is the servlet class. Obviously, the GreetingImplementation class you saw earlier is not a servlet, but this is indicative of more Web Service scaffolding. As the Web component is marked as a Web Service, the container to which it is deployed will hook it up to a SOAP router servlet during deployment. The other part of the file is the alias you added mapping /GreetingService to the GreetingImplementation servlet:
    <servlet>
      <display-name>GreetingImplementation</display-name>
      <servlet-name>GreetingImplementation</servlet-name>
      <servlet-class>wsexamples.GreetingImplementation
    </servlet-class> </servlet> <servlet-mapping> <servlet-name>GreetingImplementation</servlet-name> <url-pattern>/GreetingService</url-pattern> </servlet-mapping>
  • The sun-web.xml file—This contains the sun-specific configuration performed toward the end of the configuration. This includes the setting of the context root and the mapping of the Web Service endpoint information (the names of the service and port) to the servlet used to implement the service:
    <sun-web-app>
     <context-root>/wsgreeting</context-root>
     <servlet>
      <servlet-name>GreetingImplementation</servlet-name>
      <webservice-endpoint>
       <port-component-name>Greeting</port-component-name>
       <endpoint-address-uri>GreetingService
    </endpoint-address-uri> </webservice-endpoint> </servlet> </sun-web-app>
  • The webservices.xml file— This file is described in the JSR109 document as the “Web Services Deployment Descriptor” and is described in the next section.

bond

Figure 20.11
Adding an alias for the Web Service.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=The Web Services Deployment Descriptor}

The Web Services Deployment Descriptor contains a list of the Web Services being deployed and the ports each one of them contains. The root element is webservices, which contains one or more webservice-description elements. Within the webservice-description element there is some information about the overall service, such as the name of the service, the associated WSDL file, and which mapping deployment descriptor should be used for this particular Web Service:

<webservice-description-name>GreetingService
</webservice-description-name> <wsdl-file>WEB-INF/wsdl/GreetingService.wsdl</wsdl-file> <jaxrpc-mapping-file>mapping.xml</jaxrpc-mapping-file>

Each webservice-description element contains one port-component element for each port in the service. For your simple Greeting service, there is just a single port you can call GreetingPort. This suggested name is intentionally different from the name used in the WSDL document to help you differentiate it:

<port-component>
  <display-name>Greeting</display-name>
  <port-component-name>Greeting</port-component-name>
  …
</port-component>

The wsdl-port element below the port-component element defines the associated port name from the WSDL you generated earlier—GreetingPort—and the namespace in which it is defined—urn:J2EE21Examples:

<wsdl-port xmlns:wsdl-port_ns__=”urn:J2EE21Examples”>wsdl-port_ns__
:GreetingPort</wsdl-port>

The service-endpoint-interface element within the port-component defines the Java interface associated with this port. In your case, this is the fully qualified name of the interface you are supplying in the WAR file:

<service-endpoint-interface>wsexamples.Greeting
</service-endpoint-interface>

The other useful bit of information in the port-component is the link to the implementation. The service-impl-bean in this case defines a link to the GreetingImplementation defined in the web.xml file:

<service-impl-bean>
  <servlet-link>GreetingImplementation</servlet-link>
</service-impl-bean>

Deploying the Service

Now you can deploy the service. Select the wsgreeting WAR in the left-hand pane of deploytool and then select Tools, Deploy from the menus. Provide your administrator user name and password if prompted and ensure that the message “Operation Completed Successfully” is displayed on the Distribute Module screen.

During this deployment, all of the server-side scaffolding, such as the server-side skeletons, will be generated by the container into which you are deploying. Note that there is no need in this case to ask for a client JAR file because you will contact the service over SOAP. The only thing needed to create the artifacts used by the client is the WSDL description (after all, the Greeting Web Service could be implemented in Microsoft .NET if it was developed by someone else).

You can now access the simple Web Service at the URL http://localhost/wsgreeting/GreetingService. Putting this URL directly into a browser will not have much effect as browsers issue HTTP GET commands while Web Services generally use HTTP POST. However, you can test that your service is there by asking it for its WSDL description. To do this, add “?WSDL” onto the end of the URL and type it into your browser:

http://localhost/wsgreeting/GreetingService?WSDL 

This will return the deployed WSDL file as shown in Figure 20.12.

bond

Figure 20.12
Querying the Web Service for its WSDL.

The WSDL document is identical to the one in the Web Service WAR, but it now contains the location information for the deployed service (remember that the original WSDL had its location set to REPLACE WITH ACTUAL URL):

…
<service name=”GreetingService”>
 <port name=”GreetingPort” binding=”tns:GreetingBinding”>
  <soap:address xmlns:wsdl=http://schemas.xmlsoap.org/wsdl/
   location=”http://localhost:8000/wsgreeting/GreetingService”/>
 </port>
</service>
…

In the next section, you will use this WSDL file to generate stubs through which a client application can contact the Web Service.

Consuming the Simple Greeting Service

To use your Web Service you need a client. For the purposes of this exercise, this client will be a standard Java class with a main method. However, it could also be a J2EE component such as a JSP or EJB. The differences with such clients are discussed later.

To call the Web Service from a client, you could use low-level APIs to create and send SOAP messages. However, one of the main intentions of JAX-RPC is to provide the developer with a familiar development model. Hence, you will again use the tools to create a stub (or proxy) that represents the service for the client. The stub exposes Java methods that match the SOAP operations supported by the server. The client application can simply call these Java methods to invoke the functionality of the service. The J2EE RI tool used is again wscompile. You can use wscompile to take the WSDL description of the deployed service and create client-side stubs through which to invoke the service.

In this case the configuration file needs client-focused information provided in a wscompile configuration file similar to the one used earlier to generate the WSDL in the section “Web Service Compiler Configuration File.” The file still has a root element of configuration, but in place of the service element you use a wsdl element. The packageName attribute of the wsdl element indicates that the generated Java classes and interfaces should reside in the package client. The location attribute specifies that the WSDL file to use should be retrieved from the deployed service. This means that it contains the correct endpoint location information for the service you deployed. The client configuration file is shown in Listing 20.6.

Listing 20.6 wscompile Client Configuration File (config-client.xml)

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration xmlns=”http://java.sun.com/xml/ns/jax-rpc/ri/config”>
  <wsdl
location=http://localhost:8000/wsgreeting/GreetingService?WSDL
packageName=”client”/> </configuration>


Note - Do not use the original WSDL file without the location information when creating your client. Stubs generated from WSDL that do not contain a valid endpoint will fail at runtime unless one is set programmatically. This is a more flexible mechanism, but it makes them more complicated to use. Dynamic endpoint allocation is fine later, but for the time being we will be working with the endpoint URL encoded in the WSDL.


When you call wscompile, you should ask it to generate the client scaffolding you need (-gen:client). If you are working in a development environment that does not provide code completion based on introspection, you should also specify the –keep option so that the .java files are still around for inspection:

wscompile –gen:client -d classes –keep –s build/generatedproxy ws/
config-client.xml

The client-side scaffolding shares many files with the server-side scaffolding, including any complex types, serializers, and a serializer registry to map types to serializers. However, the following client-specific artifacts are also generated:

  • Greeting interface—This is generated from the WSDL port description. It is almost identical to the remote Java Greeting interface from which the WSDL was generated.

  • GreetingService interface—This defines a single method getGreetingPort() that returns a client-side proxy for the service implementing the Greeting interface.

  • GreetingService_Impl class—This is a factory class that represents the Web Service as a whole. You can obtain client-side proxies from instances of this class. For your simple service, this will just serve client-side proxies that implement the Greeting interface.

  • Greeting_Stub class—This is the client-side proxy itself that implements the client-side Java Greeting interface generated from the WSDL.

You can build a Web Service client using these generated classes. To use these classes, you should either import the namespace in which they were generated (client derived from the client configuration file as shown in Listing 20.6) or place your client class in the same namespace:

package client;

You can create your client code in a simple main() method. Don’t forget that all these method calls can generate RemoteExceptions, so be sure to place them all inside a try/catch block. The first thing to do is instantiate the factory that represents the Web Service:

GreetingService serviceProxy = new GreetingService_Impl();

From this service proxy, you can then obtain an interface proxy:

Greeting interfaceProxy = serviceProxy.getGreetingPort();

As the interface proxy implements the client-side Greeting interface, you can call the sayHelloTo() method on this, passing the name of the person to greet:

String response = interfaceProxy.sayHelloTo(“Fred”);

This call will trigger a SOAP request to the simple Greeting Web Service. The service will prepend the message you defined in your implementation and return the result. The full code for a sample simple Web Service client is shown in Listing 20.7.

Listing 20.7 Client for Simple Web Service (GreetingClient.java)

package client;

public class GreetingClient
{
  public static void main(String[] args)
  {
    try
    {
      GreetingService serviceProxy = new GreetingService_Impl();

      Greeting interfaceProxy = serviceProxy.getGreetingPort();

      String response = interfaceProxy.sayHelloTo(“Fred”);
      System.out.println(“Response from greeting service was: ” 
+ response); } catch (Exception ex) { ex.printStackTrace(); } } }

You compile and run your client as you would any other Java application, but ensure that the generated client-side classes are on your classpath. To generate the client-side scaffolding, compile the pre-provided client class and run it, use the following Ant directive:

asant run

This will communicate with the web service you deployed earlier. You should see the following message:

Response from greeting service was: Hi there Fred

So, now you have created, deployed, and invoked a simple Web Service under J2EE using JAX-RPC.

One final question before moving on from here is how to re-target this Web Service client at a different endpoint. By default, the stub uses the endpoint URL encoded into the WSDL document. As you move from development into test, staging, and live environments, the URL of the endpoint will probably change. However, you do not necessarily want to regenerate your proxies at every stage. Instead, you can set the endpoint for the stub to use as follows (in this example “ELEPHANT” is the name of the host on which the service is deployed):

javax.xml.rpc.Stub stub = (javax.xml.rpc.Stub)interfaceProxy;
stub._setProperty(ENDPOINT_ADDRESS_PROPERTY, 
         “http://ELEPHANT:8000/wsgreeting/DIFFERENT_NAME”);

You can then define the endpoint address as a property that can be picked up by the running program.


Caution - When re-targeting a proxy at a different endpoint, you should ensure that the endpoint supports the same port type—even down to the name of each part of each message. Some services may be forgiving on this (that is, the names could differ and it will still accept the operation invocation), but others are not.


This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Building More Robust Web Services}

The service you have created so far is fairly simplistic. When you come to create real Web Services, you will need to consider additional issues such as lifecycle and scalability. You will also approach certain tasks in a different way.

Starting from WSDL

When a system is designed, the designers will create UML diagrams (or the like) to represent the system entities and interactions between them. Tools can then generate programming artifacts, such as Java classes and interfaces based on this information. If the system will be based on Web Services, such artifacts will include WSDL descriptions of the required services. You, as a Java developer, will then be presented with a WSDL description that requires a Java implementation. The creation of WSDL independently from code is generally a better approach than starting from code and generating WSDL for reasons discussed in the sidebar “Always Start from the WSDL.”


Always Start from the WSDL - One of the reasons for the popularity of WSDL and SOAP as mechanisms for defining and implementing Web Services is that they are relatively simple. A benefit of this simplicity is that they provide a low barrier to entry for any platform or programming language that wants to join the Web Service party. However, despite their simplicity, WSDL and SOAP documents are not very friendly for humans. The sheer volume of information contained in a nontrivial interface definition and the amount of prior protocol knowledge required to fully grasp the meaning of some of the elements and attributes mean that you would not want to use WSDL documents or SOAP packets as bedtime reading.


It is good practice in any partitioned application to clearly define the interfaces between components. This is especially true of distributed applications. For this reason, most distribution mechanisms encourage developers to start by defining their distributed interface. In the case of RMI, this interface is defined in Java, whereas in other environments, such as CORBA and DCOM, the interface is defined in a language-neutral Interface Definition Language (IDL). This makes sense as RMI is mostly concerned with Java-to-Java communication, whereas CORBA and DCOM are both independent of any particular programming language. The use of IDL enables cross-language interoperation, which can be somewhat trickier if you start with RMI.

WSDL is largely another form of IDL. It allows you to define your interfaces, their protocol bindings, and the location at which the service is deployed. However, WSDL documents, like IDL documents, are somewhat inaccessible for the average developer. There is a lot of detail to learn, and it is tricky to edit raw WSDL. Because of this, most Web Service toolkits and products (including Apache Axis, Microsoft Visual Studio .NET, and the J2EE RI) provide the capability of generating a WSDL document from a language artifact, such as a Java interface definition or an ASP.NET ASMX page. The principle here is that you can just write things in the language with which you are familiar and have them exposed as a Web Service. You do not have to write any WSDL to allow a Web Service client to consume your Web Service implementation. This has many similarities to the way that a CORBA client can consume an RMI interface using a CORBA IDL interface generated with the –idl option to rmic.

Although interface generation makes an otherwise potentially awkward task a lot easier, there is a fundamental flaw in this approach, which is this:

WSDL, like IDL, was never intended to represent rich object-oriented interfaces.

The implication of this will become clear later, as you define a rich remote interface with parameters and return values consisting of encapsulated objects and collections of objects. When such an interface is translated into WSDL, the result is a far simpler description containing structures and arrays. This means that a lot of information about the behavior that you have associated with your data is lost at the Web Service interface.

When you have a rich environment at each end of the conversation, rich artifacts, such as instances of developer-defined classes, can be passed with little, if any, effort. However, if you do not know what environment is at the far end, you lose the ability to do this. If your Web Service client is a Perl application, how would it deal with your complex objects? Hence, WSDL and SOAP must cater to the lowest-common-denominator in order to provide a low barrier of entry for platforms and languages.

When a WSDL generation tool attempts to convert a developer-defined Java class into WSDL, it must cut some corners to make it fit in the data-centric typing system used by WSDL. This means that data becomes “raw”—effectively just data structures and arrays of data structures. The structure and relationships of such a description in many ways reflects quirks of the language from which it was generated. This can make it quite unwieldy when imported into a different language. The alternative is to define a pair of custom serializers and deserializers that will map your language artifact into a richer on-the-wire representation. However, this means that the sender or receiver at the other end must also know about your format and have a matching serializer/deserializer pair for their platform. Neither of these scenarios is particularly helpful.

In summary, the best approach is to start by defining the interface—in this case in WSDL. You can then use the Web Service toolkits to generate language artifacts from the WSDL. This will always provide a fairly “clean” structure as you are going from a simpler type system (data only) into a more complex one (data + behavior). If you then choose to provide custom serialization to turn the simple types into complex types, you are quite at liberty to do so. However, it is very much your own decision and does not force an unwieldy description on the other end of the conversation. It is well worth investigating tools that simplify the creation of WSDL documents—for example xmlspy—(see http://www. xmlspy.com) as these will take away the pain associated with writing WSDL by hand.

Rather than having to work out manually what sort of Java class would match that WSDL description, the J2EE RI (in common with other J2EE implementations) provides a tool to perform the mapping of the SOAP operations and XML Schema types in the WSDL document into Java artifacts. The wscompile tool can produce server-side skeletons from the WSDL document in the same way that it creates client-side stubs. One of these server-side artifacts will be a Java Remote interface that reflects the definitions from the WSDL file. You can then implement this interface (as you did previously) and package your service for deployment. The implementation still implements the Remote interface; the only difference is that this is the generated one. The build sequence is also slightly different in that you will need to run wscompile before building your Web Service implementation class rather than afterward as you did before. The rest of the configuration files would be almost identical to those for the basic greeting service.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Exposing EJBs Through Web Service Protocols}

The types of application functionality exposed through Web Service protocols will be many and varied. The variety of such applications will match, if not exceed, the variety of browser-based applications found on the Web. This means that Web Service applications will have a variety of requirements for such systemic qualities as scalability, availability, performance, and so on. Essentially, Web Service applications are just like any other application. Because of their requirements for scalability and availability, the functionality behind many Java-based Web Services will be implemented using EJBs. What is needed then is a simple way to expose this functionality while keeping overhead to the minimum.

EJBs as Web Service Facades

On Day 18, the role of the facade pattern was discussed as a way of reducing network traffic and creating a simpler, coarse-grained interface from a set of fine-grained interfaces. The use of a Session Facade providing coarse-grained access to entity EJBs has been particularly successful.

As Web Services are intended to be a coarse-grained interface to underlying functionality, the Facade pattern also applies at a Web Service boundary. Indeed, an overarching Session Facade may contain the coarse-grained representation of the business logic implemented by combinations of entity and session EJBs in the application. This overarching Session Facade is ideal to be exposed using Web Service protocols—indeed it may have been created for just such a purpose.

You will now examine an example that uses a stateless session EJB as a Façade for some of the agency functionality from the case study. The façade will provide a list of jobs available at a given location. The stateless session bean will call on underlying entity beans to retrieve the required data. The client will be a standalone Java client just as for the servlet-based Web Service implementation.

Defining the Interface and Implementation

JAX-RPC allows you to expose a stateless session bean so that it can be accessed through Web Service protocols. In developer terms, the main difference between an EJB exposed through JAX-RPC and one exposed through RMI is that you do not provide the same interface files. For an RMI-based EJB, you will provide a home interface and an EJB business interface that extends javax.ejb.EJBObject or javax.ejb.EJBLocalObject. An EJB developed to be exposed as a Web Service does not have a home interface. The relationship between the client and server is different and the client delegates all lookup of services to the proxy as you saw in the GreetingClient class earlier. Similarly, the business interface is defined slightly differently to reflect the different relationship. While the interface for a Web Service EJB is still a Remote interface, it must directly extend java.rmi.Remote rather than one of the EJBObject variants.


Note - As it stands, you cannot use the same interface definition for the EJB Remote interface and the Web Service using the tools provided with the J2EE RI (wscompile will generate an error if your Web Service interface extends javax.ejb.EJBObject rather than java.rmi.Remote). This can be seen as a good thing, as it might tempt people to always specify the EJB remote interface as a Web Service interface for the associated EJB. You should not just automatically expose all stateless session EJBs as Web Services. However, if you have a well-crafted, coarse-grained facade implemented as a stateless session EJB, there is no reason you should not expose this as a Web Service.


Listing 20.8 shows an interface that can be used to expose an EJB method that lists the job vacancies registered with the job agency at a particular location. You can see that the interface extends Remote and the findJobsAtLocation() method is labeled as throwing RemoteException. The interface defines a single method that takes a location as a string and returns a string array of job information. Nothing much indicates that this interface is part of an EJB.

Listing 20.8 A Web Service Interface for Agency Functionality (Service.java)

package agency;

import java.rmi.*;

public interface Service extends Remote
{
  public String[] findJobsAtLocation(String location) throws 
RemoteException; }

The implementation, on the other hand, looks like a typical session EJB as shown in listing 20.9. Examination of the code reveals that it has the usual lifecycle methods for a stateless session bean and retrieves the local resources it needs in its setSessionContext() method. The only resource it uses is a reference to the home interface of the entity Job EJB.

The bean implements the single business method—findJobsAtLocation()—defined on the Service interface. The implementation of this method uses the findByLocation method on the JobHome interface which returns a list of the jobs at the given location. The method creates a Job EJB instance for each job in the list and calls the getCustomer() and getRef() methods on its JobLocal interface. The strings created from the job information are stored in an array to be returned to the caller.

Listing 20.9 An Enterprise Bean to Underpin a Web Service (ServiceBean.java)

package agency;

import java.util.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.* ;

import data.*;

public class ServiceBean implements SessionBean
{
  private JobLocalHome jobHome;

  public String[] findJobsAtLocation(String location)
  {
    String[] jobs = null;
    try
    {
      Collection col = jobHome.findByLocation(location);
      jobs = new String[col.size()];
      Iterator it=col.iterator();
      for (int i=0; i < jobs.length; ++i)
    {
          JobLocal job = (JobLocal)it.next();
          jobs[i] = job.getCustomer() + “/” + job.getRef();
      }
    }
    catch (Exception ex)
    {
      // In response to any error just return null
      jobs = null;
    }
    return jobs;
  }
  
  // EJB methods start here


  public void ejbCreate () throws CreateException {}

  public void ejbActivate(){}

  public void ejbPassivate(){}

  public void ejbRemove(){}

  private SessionContext ctx;

  public void setSessionContext(SessionContext ctx)
  {
    this.ctx = ctx;
    InitialContext ic = null;
    try
    {
      ic = new InitialContext();     
      jobHome = (JobLocalHome)ic.lookup(“java:comp/env/ejb/JobLocal”);
    }
    catch (NamingException ex)
    {
      error(“Error looking up java:comp/env/ejb/JobLocal”,ex);
      return;
    }
  }
  
  private void error (String msg, Exception ex)
  {
    String s = “ServiceBean: “+msg + “n” + ex;
    System.out.println(s);
    throw new EJBException(s,ex);
  }
}

The only real difference between this bean implementation and any other stateless session bean is that exceptions are treated differently. When it is exposed through a native RMI interface, the bean implementor can assume that the caller has some way of dealing with any exceptions thrown by the bean, so any errors can be raised as exceptions. However, in Web Service terms, you are less certain how an exception will appear to a client and so it is safer to adopt a less Java-specific stance. In this case, an error is indicated by a null return value. The handling of errors and exceptions in Web Services is discussed later in the section “Web Service Errors and Exceptions.”

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Web Service Compiler Configuration File}

As with the servlet-based Web Service, you will need to provide additional information in addition to the standard J2EE deployment descriptor for this type of component. In the J2EE Reference Implementation, you again use wscompile to generate this information. The configuration file used to generate the artifacts for the agency Service bean, shown in listing 20.10, is almost identical to that for the servlet-based Web Service, as shown in Listing 20.3 (only the names have changed).

Listing 20.10 wscompile Web Service Configuration File (config-service.xml)

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration 
 xmlns=”http://java.sun.com/xml/ns/jax-rpc/ri/config”>
 <service 
   name=”AgencyService” 
   targetNamespace=”urn:J2EE21Agency” 
   typeNamespace=”urn:J2EE21AgencyTypes” 
   packageName=”agency”>
   <interface name=”agency.Service”/>
 </service>
</configuration>

The wscompile command line is identical to that for the servlet-based Web Service, and the same files will be produced, namely the WSDL description and the mapping.xml file.

As before, the sample code is on the Web site that accompanies this book. As it forms the basis of the exercise, you will find this example in the exercise directory for Day 20. With the code supplied on the accompanying Web site, you can use the following Ant command to build the supplied agency Web Service, which includes the creation of the WSDL and the mapping file:

asant build

The WSDL File

As the interface is different from the greeting service defined earlier, the WSDL generated will also be different. As the findJobsAtLocation() method returns something other than a simple type, a complex type is defined in the types section of the WSDL description:

<types>
  <schema targetNamespace=”urn:J2EE21AgencyTypes”
      xmlns:tns=”urn:J2EE21AgencyTypes”
      xmlns:soap11-enc=”http://schemas.xmlsoap.org/soap/encoding/”
      xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
      xmlns:wsdl=”http://schemas.xmlsoap.org/wsdl/”
      xmlns=”http://www.w3.org/2001/XMLSchema”>
    <import namespace=”http://schemas.xmlsoap.org/soap/encoding/”/>
    <complexType name=”ArrayOfstring”>
      <complexContent>
        <restriction base=”soap11-enc:Array”>
          <attribute ref=”soap11-enc:arrayType” wsdl:arrayType=”string[]“/>
        </restriction>
      </complexContent>
    </complexType>
  </schema>
</types>

Without going into too much detail, the new type—ArrayOfString— is defined to be an unbounded array of the simple string type. This new type is defined in the scope of the urn:J2EE21Agency namespace specified for types in the wscompile configuration file. This ArrayOfString type can then be used later in the WSDL document to define the return type of the findJobsAtLocation operation:

<message name=”Service_findJobsAtLocationResponse”>
  <part name=”result” type=”ns2:ArrayOfstring”/>
</message>

As you can see, the findJobsAtLocation response is defined to contain an ArrayOfString, which is scoped to namespace ns2 (ns2 is defined to be urn:J2EE21Types in the overall definitions element). Other than this, the WSDL document is very similar to the greeting service WSDL described earlier.

The Mapping File

As you would expect, the mapping file is also very similar to that for the greeting service. It contains nothing specific to the service being implemented by an EJB and simply reflects the changes in the interface, such as the use of the array of strings as a return type:

<java-wsdl-mapping version=”1.1″ …>
  <service-endpoint-interface-mapping>
  …
    <service-endpoint-method-mapping>
    …
      <wsdl-return-value-mapping>
        <method-return-value>java.lang.String[]</method-return-value>
        <wsdl-message xmlns:wsdlMsgNS=”urn:J2EE21Agency”>
          wsdlMsgNS:Service_findJobsAtLocationResponse
        </wsdl-message>
        <wsdl-message-part-name>result</wsdl-message-part-name>
      </wsdl-return-value-mapping>
    </service-endpoint-interface-mapping>
  …
  </service-endpoint-method-mapping>
  …
</java-wsdl-mapping>

Packaging and Deploying the Agency Web Service Using J2EE RI deploytool

This section shows how to deploy the simple Web Service to the J2EE RI. As noted before, you will need to start up the PointBase database server and J2EE RI server before starting deploytool.

Creating the Agency EAR

By choosing File, Open, load up the Day20/exercise/j2ee-ri/agency.ear enterprise application archive. This defines a single group of Entity beans called Entity which will be used by the Web Service session bean. Highlight the Agency application in the explorer on the left side of the deploytool GUI and its contents will be shown on the right side, as shown in Figure 20.13.

bond

Figure 20.13
Partially built Agency case study EAR.

You will package up the Web Service in an EJB-JAR file, so choose File, New, Enterprise Bean to create a new one. Click Next to skip the introduction screen and move onto the EJB-JAR file screen. You will be creating your New JAR Module in the Application called agency, so ensure that this option is selected. Next, under JAR Naming, enter “agency-session-ejb” as the File Name.

Now you can populate your EJB-JAR with the files you saw earlier. Under the Contents section, click the Edit button to display the Edit Contents of agency-session-ejb screen. Browse to find the class files (Service.class and ServiceBean.class), the WSDL file (AgencyService.wsdl), and the mapping file (mapping.xml). You will also need to add the interface definitions for the entity beans used that can be found under the folder Day20exerciseclassesdata. Add each of these files to the contents as shown in Figure 20.14 and click OK.

bond

Figure 20.14
Adding class and configuration files to EJB-based Web Service.

Now click Next to move onto the General screen. Select agency.ServiceBean as your Enterprise Bean Class (this will be offered from the drop-down list). Ensure that the Enterprise Bean Type is set to Stateless Session. There is no need to define home, local or remote interfaces for this Web Service bean. So click Next to move to the Configuration Options screen.

Ensure that Expose Bean as Web Service Endpoint is selected and click Next.

On the Choose Service screen in the Service Definition section, select AgencyService.wsdl as your WSDL File and mapping.xml as your mapping file (these will be offered from the drop-down lists). The other fields will be populated based on the information in the files as shown in Figure 20.15.

bond

Figure 20.15
Service definition for EJB-based Web Service.

Click Next to move on to the Web Service Endpoint screen. Select agency.Service as your Service Endpoint Interface. In the WSDL Port section, set the Namespace to be urn:J2EE21Agency and ensure that the Local Part becomes ServicePort. In the Sun-specific Settings section, set the Endpoint Address to be jaxrpc/ServiceBean as shown in Figure 20.16.

bond

Figure 20.16
Endpoint configuration for EJB-based Web Service.

That completes the initial configuration, so click Next followed by Finish. You should be presented with a deploytool screen that looks like Figure 20.17.

bond

Figure 20.17
EJB-based Web Service viewed in deploytool.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Configuring the EJB Component}

To complete the Web Service configuration, highlight the agency-session-ejb in the left-hand pane and select its Web Services tab. Select the AgencyService in the list and in the Sun-specific Setting section, set the WSDL Publish Location to be jaxrpc/ServiceBean?WSDL as shown in Figure 20.18.

To complete the EJB configuration, highlight the ServiceBean itself in the left-hand pane and select the EJB Refs tab. Click Add and add a reference to the JobBean setting the name to ejb/JobLocal, type to Entity, interfaces to Local, and the home and local interface names to data.JobLocalHome and data.JobLocal respectively. This is shown in Figure 20.19. Once this is added, select the reference and change the Sun-specific settings for ejb/JobLocal to data-entity-ejb.jar#JobBean.

bond

Figure 20.18
WSDL location configuration.

bond

Figure 20.19
Adding entity references to the EJB-based Web Service.

During this process, deploytool has generated several new files for you:

  • The ejb-jar.xml file—This contains the EJB definition for your Web Service and looks like a standard stateless session bean deployment descriptor.

  • The sun-ejb-jar.xml file—This contains the Sun-specific configuration performed during the bean configuration. This includes the setting of the endpoint URI and the location from which the WSDL description can be recovered:
    <sun-ejb-jar>
      <enterprise-beans>
        …
        <ejb>
          <ejb-name>ServiceBean</ejb-name>
          <jndi-name>ServiceBean</jndi-name>
          <webservice-endpoint>
            <port-component-name>Service</port-component-name>
            <endpoint-address-uri>jaxrpc/ServiceBean</endpoint-
    address-uri> </webservice-endpoint> </ejb> <webservice-description> <webservice-description-name>AgencyService</
    webservice-description-name> <wsdl-publish-location>jaxrpc/ServiceBean?WSDL</
    wsdl-publish-location> </webservice-description> </enterprise-beans> </sun-ejb-jar>
  • The webservices.xml file— This is described in the next section.

The Web Services Deployment Descriptor

The Web Services Deployment Descriptor for the EJB is similar to that for the servlet-based Web Service, containing the service description and pointers to the WSDL and mapping files. The principal difference is that the port-component points to an EJB rather than a servlet:

<webservices …>
  <webservice-description>
  …
    <port-component>
      <service-impl-bean>
        <ejb-link>ServiceBean</ejb-link>
      </service-impl-bean>
    </port-component>
  </webservice-description>

</webservices>

Deploying the Service

Now you can deploy the service. Select the Agency EAR in the left-hand pane of deploytool and then select Tools, Deploy from the menus. Provide your administrator user name and password if prompted and ensure that the message “Operation Complete Successfully” is displayed on the Distribute Module screen.

As with the servlet-based Web Service, all of the server-side scaffolding required for the Web Service is generated during deployment. There is no client JAR file because you will contact the service over SOAP so the only thing needed to create the artifacts used by the client is the WSDL description.

You can now access the simple Web Service at the URL http://localhost/jaxrpc/ServiceBean and its WSDL is available at http://localhost/jaxrpc/ServiceBean?WSDL.

The WSDL document is identical to the one in the EJB-JAR file, but it now contains the location information for the deployed service:

…
<service name=”AgencyService”>
 <port name=”ServicePort” binding=”tns:ServiceBinding”>
  <soap:address xmlns:wsdl=http://schemas.xmlsoap.org/wsdl/
         location=”http://localhost:8000/jaxrpc/ServiceBean”/>
 </port>
</service>
…

In the next section, you will use this WSDL file to generate stubs through which a client application can contact the Web Service.

Consuming the Simple Greeting Service

As you might expect, the client for a Web Service based on an EJB is very similar to one for a Web Service based on a servlet. The client will need to obtain a stub that represents the PortType of the deployed service. This can be generated by running wscompile against the WSDL file retrieved from the deployed Web Service. The wscompile configuration file (client-config.xml) is almost identical except that it points to a different URL:

<wsdl location=http://localhost:8000/jaxrpc/ServiceBean?WSDL
packageName= “client”/>

The wscompile command line is identical to the one used for the servlet-based Web Service you saw earlier. After you have generated the stubs and factories, you can use them in your client. The client will be similar to the servlet-based Web Service client shown in Listing 20.7, but obviously the types and methods implemented by them will be different. The following client-specific artifacts are generated that can be used in the client:

  • Service interface—This is generated from the WSDL port description. It is almost identical to the remote Java Service interface from which the WSDL was generated.

  • AgencyService interface—This defines a single method getServicePort() that returns a client-side proxy for the Web Service implementing the Service interface.

  • AgencyService_Impl class—This is a factory class that represents the Web Service as a whole. You can obtain client-side proxies from instances of this class. For your simple service, this will just serve client-side proxies that implement the Service interface.

  • Service_Stub class—This is the client-side proxy itself that implements the client-side Java Service interface generated from the WSDL.

A client for the Web Service ServiceBean is shown in Listing 20.11. Again, this shares the namespace of the proxies (client) and catches RemoteExceptions. The client calls the findJobsAtLocation passing in the location string provided on the command line. It then prints out the job information returned from the Web Service.

Listing 20.11 Web Service Client for the ServiceBean

package client;

public class AgencyServiceClient
{
  private static String location = “%”;

  public static void main(String[] args)
  {
    if (args.length == 1)
    {
      location = args[0];
    }
    else if (args.length > 1)
    {
      System.err.println(“Usage: AgencyServiceClient 
[ location ]“); System.exit(1); } try { AgencyService serviceProxy = new AgencyService_Impl(); Service interfaceProxy = serviceProxy.getServicePort(); System.out.println(“Using Location: “+location); System.out.println(“Job list: “); String[] jobs = interfaceProxy.findJobsAtLocation(location); for(int i=0; i<jobs.length; ++i) { System.out.println(jobs[i]); } System.out.println(“nDonen”); } catch (Exception ex) { ex.printStackTrace(); } } }

You compile and run your client as you would any other Java application, but ensure that the generated client-side classes are on your classpath. To generate the client-side scaffolding, compile the pre-provided client class and run it, using the following Ant directive:

asant AgencyServiceClient

This will communicate with the EJB-based web service you deployed earlier. If you enter the location “London,” you should see the following message:

   [java] Using Location: London
   [java] Job list:
   [java] winston/Cigar trimmer

So, now you have created, deployed, and invoked an EJB-based Web Service under J2EE using JAX-RPC.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Other Considerations for Web Services}

So far, the Web Services you have seen have used simple parameters, such as strings and integers and have been free from errors. However, in the real world, most systems will need to pass complex types such as arrays, classes, and data structures and will need to cope with issues such as error handling. During the rest of today, you will look at such issues.

Web Service Errors and Exceptions

The use of Web Service protocols implies that your application is making calls across network boundaries. As such, you must be prepared to handle any network-related errors that occur. As the Web Service interface is based around a Java remote interface, any client code must catch and handle java.rmi.RemoteException. A RemoteException will be generated in response to any unhandled runtime exceptions that occur. Such exceptions are mapped to SOAP fault elements that are included in the body of the response from the server.

You can define domain exceptions—for example, InvalidProductCodeException—on your Web Service remote interfaces. These exceptions are defined in the service WSDL as fault elements. Such fault elements are marshaled back to the client in the SOAP message that forms the response from the server. For a Java client, the exception will be regenerated in its original form and rethrown. The handling of fault elements by non-Java clients will depend on the support for WSDL-defined fault elements in that environment. A Java exception is a complex type, so the JAX-RPC runtime must be able to marshal and unmarshal at least some of its contents (such as its message). Therefore, exceptions must conform to certain rules to be successfully passed. These rules are similar to those for JavaBeans and are defined in section 5 of the JAX-RPC specification (JSR101).

Context and Lifecycle of JAX-RPC Web Services

The servers created so far have been very simple. However, real-world applications require more sophistication. It is important to know about and control the lifetime of your service instances. The service might need to initialize itself when it is created and release resources when it is destroyed. Similarly, it might need to obtain information relating to this call, such as the identity of the caller or message header settings.

The lifecycle and state management of your Web Service implementation will depend on the type of component that underlies it. If you have built a Web Service based on a stateless session EJB, a new bean will be instantiated for each call and it will follow the stateless session EJB lifecycle. If you are using a servlet-based implementation, there is no guarantee that successive calls will use the same instance. In both cases, JSR109 explicitly states that there should be no reliance on state shared across calls. This means that, although JAX-RPC programming looks like traditional RPC programming in which you communicate with a specific object, it does not behave this way. It has much in common with the design and use of stateless session EJBs in that no assumptions about users or their states can be made.

In some Web Service implementations, you can use HTTP cookies to maintain an ongoing conversation between client and server (as used by servlet and JSP session state). However, this is not very helpful because it ties the service implementation to the HTTP protocol. If you want to maintain any form of state in a Web Service, you should explicitly persist that state—probably in a database. You will then need to issue the client with some form of identifier for this state as a return value from the method. Although this can seem clunkier than the use of HTTP-based session state, this “exposed state” is more suited to Web Service interaction. Think of a service that allows you to place and track orders. When placing the order, you will be issued with some form of order identifier. If you need to track the progress of the order, you will submit the order identifier as part of the tracking request. This is the level of granularity at which you should think about Web Service state. It may be hours, or even days, between the placing of the order and the tracking request. You should not expect to keep a session open across this time period, and you should not expect all requests to be made across a particular protocol (HTTP). If this does not sit easily with your design, you are probably not using Web Services at the right level of component granularity and you may be better off using another protocol such as RMI for your client/server communication.

The lifecycle of a stateless session EJB is well documented. It has methods that tell it when it is being readied for use (setSessionContext/ejbCreate) and when it is being discarded (ejbRemove). If you are using a servlet-based Web Service implementation, your class can optionally implement the javax.xml.rpc.server.ServiceLifeCycle interface to receive the same information. This interface defines an init method that passes a context object and a destroy method that perform the same roles as setSessionContext/ejbCreate and ejbRemove, respectively.

The context passed into the ServiceLifeCycle.init method is an implementation of the javax.xml.rpc.server.ServletEndpointContext interface. The primary purpose of this interface is to provide access to the javax.xml.rpc.handler.MessageContext implementation for the current Web Service invocation. The basis of the message context for a SOAP message is extra information contained in the SOAP headers. You can also cast the MessageContext to a javax.xml.rpc.handler.soap.SOAPMessageContext to retrieve the SOAPMessage and the SOAP actor information. The following code fragment shows how you would obtain information from the MessageContext in a servlet-based Web Service:

public void init(Object context)
{
 ServletEndpointContext endpointContext = (ServletEndpointContext)context;
 
 MessageContext messageContext = endpointContext.getMessageContext();

 // Examine Web Service call headers
 String correlationId = (String)(messageContext.getProperty
(“CorrelationId”)); … }

The MessageContext is made available to an enterprise bean through the getMessageContext method that has been added to the javax.ejb.SessionContext interface.

In some cases, you need to perform common processing of incoming messages, maybe message inspection and rejection, or some form of transformation of the message content. If your application design calls for a Front Controller or Intercepting Filter (see Day 18 for details), you would typically use a mechanism such as servlet filters to implement this functionality. The JAX-RPC specification provides a similar message pre- and post-processing mechanism that is independent of the container type called handlers. An in-depth discussion of handlers is beyond the scope of this chapter, but basically you can set up a chain of one or more handlers that will pre-process incoming messages or post-process message responses. The handlers have access to the message itself and the MessageContext, so they can communicate with the Web Service implementation by setting or altering values in the MessageContext.

Mapping Between Java and SOAP/WSDL Types

For simple types, SOAP and WSDL use the representations defined in “XML Schema Part 2: Datatypes” that is part of the W3C XML Schema standard. There is a straight mapping for all Java primitive types except for char. There is also a straight mapping for the Java String class.

If you defined a Web Service with the following (unlikely) method:

public void test(byte byteArg, short shortArg, int intArg, long longArg,
           float floatArg, double doubleArg, 
           boolean boolArg, String stringArg)

this would map into WSDL as follows:

<definitions name=”GreetingService” targetNamespace=”urn:J2EE21Examples”
       xmlns:tns=”urn:J2EE21Examples” 
       xmlns=”http://schemas.xmlsoap.org/wsdl/”
       xmlns:xsd=”http://www.w3.org/2001/XMLSchema” 
       xmlns:soap=”http://schemas.xmlsoap.org/wsdl/soap/”>
 <types/>
 <message name=”Greeting_test”>
  <part name=”byte_1″ type=”xsd:byte”/>
  <part name=”short_2″ type=”xsd:short”/>
  <part name=”int_3″ type=”xsd:int”/>
  <part name=”long_4″ type=”xsd:long”/>
  <part name=”float_5″ type=”xsd:float”/>
  <part name=”double_6″ type=”xsd:double”/>
  <part name=”boolean_7″ type=”xsd:boolean”/>
  <part name=”String_8″ type=”xsd:string”/>
 </message>
 <message name=”Greeting_testResponse”/>
 …
</definitions>

Note that all the arguments are mapped to a type using the xsd prefix, which refers to the http://www.w3.org/2001/XMLSchema namespace. All these mappings are performed without any extra effort on your part, as are String, Date, Calendar, BigInteger, and BigDecimal. Arrays of these built-in types are also supported automatically. Sections 4 and 5 of the JAX-RPC specification (JSR101) define standard mappings between Java and XML types for an implementation of JAX-RPC.


Note - You may notice that the Java type char is missing. This is because there is no direct mapping between a Java char and an XML Schema type. Hence, it is not one of the Java types that is automatically marshaled.


When you start to work with other complex Java types, and arrays of those types, more effort must be put into the representation of these mappings. Consider what is done by RMI when you pass Java objects between a client and server:

  • RMI uses the Java serialization mechanism to convert the contents of the object into a byte stream that can be sent across the network.

  • Both client and server must have a definition for the type being passed (or must be able to get hold of one).

  • The remote interface definition uses standard Java syntax to indicate where objects are used as parameters or return values.

When using complex Java types as part of a Web Service, you must address the same issues. However, there is the added complication that you must do this in a platform- and language-independent way. Therefore, the following is needed to pass complex parameters as part of a Web Service method:

  • Provide a mechanism to marshal and unmarshal the contents of a complex Java type into an XML format that can be used as part of a SOAP message

  • Deliver the marshalling and unmarshalling mechanism on both the client and the server

  • Indicate in the WSDL definition that certain parameters or return values are complex types, and provide a mapping between the complex types and their associated marshalling/unmarshalling code

Consider also the situation where you are provided with WSDL that has been generated from a non-Java Web Service, such as a Web Service implemented using Microsoft .NET components. This may also contain definitions for complex types that must be mapped into Java types to use that Web Service from Java.

Somebody has to do this mapping, and it is not necessarily straightforward. Sometimes it can be done using automated tools, while at other times it may require custom code.

Marshaling Complex Types

A certain amount of complex type mapping is done for you. If your complex types are fairly straightforward, they can be defined according to JavaBeans principles (default constructor, getters and setters, serializable). Such types can be automatically marshaled into and out of XML by a JAX-RPC implementation, so in this case you will not be required to write any additional code to get these types across a Web Service interface.

Web Service design is heavily influenced by two aspects: statelessness and data-only passing. As discussed in the sidebar “Always Start from the WSDL,” a WSDL description defines data that is passed back and forth between clients and servers. There is no way of specifying functionality, so all the on-the-wire types are defined only in terms of their data. This fits well with coarse-grained component design principles where you should not really be handing out combinations of data and functionality but designing your interfaces so that functionality is encapsulated in the component and data is passed in and out. Complex data structures that cross the component boundary then become Data Transfer Objects (DTOs) as discussed on Day 18. In Java terms, a Data Transfer Object should be implemented as a JavaBean.

In some cases, a simple JavaBean style class is not enough to represent the data being manipulated. If you need more control over what is included in the XML messages being exchanged, you can define custom serializers and deserializers to be included as part of your Web Service. You briefly saw some of the automatically generated serializers and deserializers when looking at the structure of the deployed WAR file in the section “Deploying the Service.” A type registry is defined to associate the XML data structures in the message with particular Java types. The appropriate serializer or deserializer is called to marshal data between the two formats.

A complete discussion of complex type mapping is beyond the scope of this book; however, if you are interested, this is covered in sections 15 and 19 of the JAX-RPC specification (JSR101).

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

{mospagebreak title=Summary}

Today, you have seen how Web Service protocols and application styles provide a future route for many application integration projects. Web Services provide a framework for the integration of internal or external applications using HTTP and XML. You have seen that Web Service protocols provide a better solution when exposing functionality for integration than existing RPC or Web mechanisms, and you have explored the Web Service functionality offered in J2EE.

You deployed a servlet-based JAX-RPC Web Service and then called this Web Service through a proxy generated from its WSDL. You deployed an EJB-based JAX-RPC Web Service and used the WSDL generated from it to create a Web Service client. You examined how state and lifecycle are handled for Web Service implementations, and you looked at issues around complex type mapping when marshaling between Java objects and XML data types.

Q&A

  1. SOAP uses HTTP as a transport, so does this mean that it is restricted to synchronous interaction?

  2. Any transport can be used for a SOAP message as long as someone creates a binding for it. SOAP bindings have been defined for SMTP, and such bindings can be created for any other transport mechanism, such as FTP or MQSeries, regardless of whether such mechanisms are synchronous or asynchronous.

    Also, although HTTP is inherently synchronous, you can use it to pass XML documents that consist of business “messages” and that form part of a workflow. If the sender of the message is also capable of receiving such messages, it may receive a response of some form at some future point in time. This uses two synchronous interactions to create asynchronous behavior.

  3. Can I use JAX-RPC to send an XML document rather than performing an XML-based RPC call?

  4. Although it is possible to send an XML document as a parameter to an RPC call using JAX-RPC, document-centric interactions are intended to be serviced by the SOAP with Attachments API for Java (SAAJ) and the Java API for XML Messaging (JAXM). You will encounter SAAJ and JAXM in more detail tomorrow.

  5. What sort of information is contained in a WSDL document?

  6. A WSDL document contains two basic types of information. It contains the interface for the Web Service that consists of type information, message definitions (parameters and return types), operation definitions (methods that can be called), port types (groupings of methods), and bindings that define how port types are carried over different transports. A WSDL file also contains specific location information for a Web Service in the form of ports that provide a specific location for an instance of a port type and service descriptions that define groups of ports.

  7. Why can I only expose stateless session EJBs as Web Services under JAX-RPC and not other types?

  8. Although JAX-RPC provides an RPC-style interface to a Web Service, the whole ethos of Web Services is based around a stateless model of operation. The maintenance of state in traditional RPC terms relies on either an ongoing connection or a protocol-specific token being passed. Neither of these suits the style and granularity of Web Service interaction. All Web Service implementations under JAX-RPC for J2EE are required to be stateless, so only stateless session EJBs match this requirement.

Exercises

Today’s exercise is to extend the JAX-RPC front end for the Agency case study so that a client can find all the applicants at a specific location. In the exercise directory under Day 20 on the accompanying Web site there is a version of the Agency case you have seen in this chapter. Your task is to add to the Service EJB a method that takes the name of a location and returns an array of strings representing the applicants registered at that location.

The provided files consist of the stateless session bean discussed in this chapter (Service) that allows you to list all the jobs at a particular location.

If you need a few pointers, you should:

  1. Update the Service.java and ServiceImplementation.java files in day20/ exercise/src/agency. You can get a list of applications for a location using the findByLocation method on the ApplicantHome interface.

  2. Build the classes using asant build-service.

  3. Open the ear file created in the build folder and add to the Service EJB an ejb reference for the applicant home interface.

  4. Verify and deploy your EAR to your J2EE RI application server (using deploytool or asant deploy-service).

  5. Update the AgencyServiceClient.java file in day20/exercise/src/client to call your new method.

  6. Build the client using asant build-client and then run it with asant run-client.

A complete solution can be found in the agency folder on the Day 20 folder on the accompanying Web site.

This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan