At the conclusion of his J2EE (Java 2 Platform, Enterprise Edition) Web services presentation at last year's JavaOne, IBM architect Jim Knutson remarked that "every Web service needs a place to be a service." He then suggested that the most ideal place to be a Web service was inside the J2EE infrastructure. A little more than a year later, the final release of J2EE 1.4 is imminent, and its most significant promise is to deliver on the J2EE Web services vision.
The Web service features in J2EE 1.4 address both the server and client sides of Web services. The features extend J2EE to allow existing server-side enterprise Java components to become Web services and specify how a J2EE client container can invoke Web services. The technologies for both aims have existed for a while, and the new J2EE specs rely on those existing APIs for Web services support. The new specs add to the existing technologies a set of interoperability requirements, and a programming and deployment model for Web service integration.
There are two specifications that explicitly outline those added features: Java Specification Request 151, the umbrella JSR for J2EE 1.4, and JSR 109, Web Services for J2EE. At the time of this writing, JSR 109 has reached its final stage in the JCP (Java Community Process), while JSR 151 is in the last voting phase. Additionally, the JCP amended the final release of JSR 101, Java APIs for XML-based Remote Procedure Call (JAX-RPC), to support J2EE 1.4 interoperation requirements.
J2EE 1.3-level application servers can also implement many of the features prescribed by these JSRs. Indeed, many application server vendors have supported various Web service development and deployment features in their existing products for some time now. JSRs 109 and 151 codify some existing practices and describe new mechanisms with the hope of creating a universal J2EE-Web services integration model. Next-generation application servers will likely follow that unified, standardized model.
Following a brief survey of new Web service-related J2EE features, this article reviews the new client and server programming models, including new J2EE deployment and service management roles associated with Web services support.
Web service-related J2EE extensions
Perhaps the most significant, and most consequential, additions to J2EE are the new interoperation requirements. The requirements prescribe support for SOAP (Simple Object Access Protocol) 1.1 in the J2EE presentation layer to facilitate XML message exchange. J2EE 1.4-compliant containers must also support the WS-I (Web Services Interoperability Consortium) Basic Profile. Since XML message exchange in J2EE depends on JAX-RPC, the JAX-RPC specifications now mandate WS-I Basic Profile support as well.
The result is that a J2EE 1.4-based application can be invoked as a Web service, even from applications not written in the Java programming language. While that is an evolutionary step for J2EE, since the platform has long embraced non-Java based systems, it is possibly the most direct way to facilitate interaction with Windows-based technologies that rely on .Net.
A J2EE-based service's client does not have to be aware of how a service is implemented. Rather, that client can use the service by relying entirely on the service's WSDL (Web Services Description Language) definition. (Previous JavaWorld Web Services columns explain how to discover services based on their WSDL definitions, and how to create and use WSDL definitions. See Resources for links.) While the J2EE specs do not spell out the exact mechanics of such interaction, J2EE 1.4's embrace of the WS-I Basic Profile, which Microsoft also claims to follow, will likely make J2EE-.Net interaction common.
To facilitate access to WSDL definitions, J2EE 1.4 adds support for the JAXR (Java API for XML Registries) standard. The JAXR libraries are now a required part of the J2EE application client, EJB (Enterprise JavaBeans), and Web containers (not the applet container, though). Since WS-I Basic Profile mandates support for UDDI (Universal Description, Discovery, and Integration) 2.0, J2EE clients, as well as EJB components and servlets, can interact with public Web service registries. ("Web Services Take Float with JAXR" (JavaWorld, May 2002) offers a tutorial on JAXR.) Figure 1 illustrates the additional Web service-related libraries supported by J2EE 1.4.
Indeed, J2EE takes the view that a Web service is an implementation of one or more interfaces defined by a WSDL document. The operations described in WSDL are first mapped to Java methods following the JAX-RPC specification's WSDL-to-Java mapping rules. Once a Java interface corresponding to a WSDL file is defined, you can implement that interface's methods in one of two ways: as a stateless session bean running in the EJB container or as a Java class running in the J2EE servlet container. Finally, you arrange for the respective container to listen for incoming SOAP requests and map those requests to the respective implementation (EJB or servlet). To process incoming SOAP invocations, J2EE 1.4 mandates the JAX-RPC runtime as an additional J2EE container service.
In keeping with the J2EE architecture, a service implementation's container mediates access to a Web service: if you expose either an EJB component or a servlet as a J2EE Web service, your service's clients can invoke that service only indirectly, via the container. That allows a service implementation to benefit from the container's security, thread management, and even quality-of-service guarantees. In addition, containers let you make important Web service decisions, such as security constraints, at deployment time. Finally, J2EE's container-based model makes Web service deployment portable: you can develop a Java-based Web service using any J2EE tool and expect that service to run in any other compliant container implementation.
A Web service client, on the other hand, remains unaware of a Web service container's presence. Instead, the client sees a port representing a network endpoint instance of a Web service. That endpoint follows the JAX-RPC service endpoint interface (SEI) model and provides an implementation of the service's interface. A client views each J2EE Web service as an SEI and port combination. A single J2EE container can host many such combinations, as Figure 2 illustrates. Each SEI/port combination is an instance of a Web service.
Note that the client in this architecture can be either a J2EE client, running inside the J2EE client container, or a non-J2EE client. Any WS-I Basic Profile-compliant client can use a J2EE Web service, but each client may follow different programming models. The J2EE Web services specification outlines a programming model for clients that run inside the J2EE application client container and another model—the server programming model—for Web service implementations that execute in the EJB or servlet containers.
The J2EE Web service client programming model
The essence of the Web service client programming model is to streamline the use of APIs defined in JSRs 67 (Java APIs for XML Messaging, JAXM), 93 (JAXR), and 101 (JAX-RPC), and to provide a comprehensive framework for using those APIs together in the J2EE client container.
In keeping with the J2EE client programming model, a Web service client is remotable and provides local/remote transparency. The Web service port provider and the container that the port runs in define how a client sees a Web service. The client always accesses the port and is never passed a direct reference to a Web service's implementation. A J2EE Web service client remains unaware of how a port operates and must concern itself only with the methods a port defines. Those methods constitute a Web service's public interface. In addition, a client must consider access to a Web service port as stateless across service invocations. As far as the client is concerned, a port lacks a unique identity—a client has no way of determining if it communicates with identical ports across service invocations.
The client gains access to a port based on the port's service interface. J2EE Web services rely on JAX-RPC to define the relationship between a port and its service interface. JAX-RPC creates that relationship based on WSDL processing rules. Thus, the Web service's WSDL definition ultimately governs the port's behavior. Based on the JAX-RPC definition, the service interface can either be a generic interface directly implementing the
javax.xml.rpc.Service interface, or a "generated service," which is a subtype of that interface. The latter interface type is specific to a Web service's type.
In the J2EE programming model, the client obtains a reference to a Web service's
Service object via a JNDI (Java Naming and Directory Interface) lookup operation. The JNDI lookup occurs by a logical name, or service reference, for the Web service. As with all directory-based resources, a client must declare what resources it needs in its deployment descriptor (more on that later).
The Java Web services specification (JSR 109) recommends that all Web services be subsumed under the JNDI
service subcontext. The client container binds the service interface described by that reference under the
java:comp/env client environment naming context. By declaring a service reference in the client's deployment descriptor, the client container ensures that the referenced service is available in JNDI-aware resources. The following code snippet shows how to obtain a reference to a J2EE-based Web service via JNDI lookup:
InitialContext ctx = new InitialContext(); Service myService = (Service)ctx.lookup("java:comp/env/services/MyWebService");
The above code obtains a generic service object: an object without a specific type. A JAX-RPC-generated service is accessed the same way, this time casting the service to the specific Web service's interface type:
InitialContext ctx = new InitialContext(); MyWebService myService = (MyWebService)ctx.lookup("java:/comp/env/services/MyWebService");
Note that this code assumes that the
MyWebService reference binds to an object that implements the
MyWebService interface. Since service-binding is facilitated at a Web service's deployment time, J2EE tools are expected to ensure that consistency. All J2EE 1.4-compliant application servers must support JNDI-based service lookup.
Once a client obtains a Web service's
Service object, it can use that object to retrieve a
javax.xml.rpc.Call instance that performs the actual service invocation. The client has three options to obtain a
Call: via a stub, a dynamic service proxy, or a DII (Dynamic Invocation Interface). I won't discuss in this article the differences between those methods since, regardless of how a
Call is created, that
Call refers directly back to the service's port—the only object the client must be aware of when invoking the Web service. All J2EE 1.4-compliant containers must support the
Service interface methods, and thus allow a client to gain a reference to a
Call object for a Web service, and to that service's port, via
Note that in contrast to using JAX-RPC outside J2EE, a client should not use the JAX-RPC
ServiceFactory class to obtain a new service. Instead, the client should gain access to the
Service from a JNDI-based source, since reference to a service retrieved from JNDI will have all the settings and configurations necessary to invoke the particular service instance. From a client's viewpoint, that difference is somewhat analogous to how a J2EE client retrieves a JDBC
DataSource via the JNDI interface to access a database, instead of manually configuring a JDBC
Call object in place, the client follows the JAX-RPC semantics of remote procedure calling. For instance, the client might use the
invoke() method on that
Call to interact with the Web service. (For an example of JAX-RPC-style service invocation, see "I Like Your Type: Describe and Invoke Web Services Based on Service Type" (JavaWorld, September 2002).)
The Web service server programming model
A J2EE-based Web service may follow one of two possible implementations: If the service is implemented as a regular Java class, it must conform to the JAX-RPC servlet container's requirements. Or, if the service is defined to execute in the EJB container, then it must follow the programming model required of stateless EJB session beans. Regardless of implementation method, each container provides the Web service implementation with lifecycle support, concurrency management, and a security infrastructure.
The J2EE server container's primary responsibility is to map and dispatch SOAP requests, in the EJB case, to stateless session beans, and, in the servlet container case, to methods in JAX-RPC service endpoint classes. While the JAX-RPC specification defines a programming model for the latter option, the J2EE Web services JSR (JSR 109) outlines an analogous model for stateless EJB session beans.