ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


JSR 109: Web Services Inside of J2EE Apps

by Al Saganich
08/07/2002

Over the last six months, a number of standards have begun to emerge in the areas of Web services' lifecycles, security measures, collaborations, and transactions. JSRs have emerged to begin the process of defining, in a standard way, the different aspects of how Web services might be supported in a J2EE-compliant application server.

JSR 109 specifically discusses local client access to Web services, server lifecycle, and deployment of Web services. JSRs 104, 105, and 106 combine to describe various aspects of Web services security, including APIs for trust services, digital signatures, and encryption. JSRs 156 and 157 define a basis for supporting transactions and collaborations between Web services, including support for 2PC (JTA) and business-style transactions. In this article, we will examine the intent of JSR 109 and examine its impact on Web services implemented in a J2EE environment.

JSR 109: Web Services For J2EE
Current specification status: Version 0.3
(public review version 1.0) dated 15-April-2002.

Introducing JSR 109

Over the past few years, J2EE has emerged as the dominant standard for serving up information on the Web. A large number of standards have evolved, of which Web services is one of the most recent, to place application functionality behind Web front ends. First there were servlets and JSP, as well as stateless session Enterprise Java Beans. Over time, the EJB specification changed and grew to support stateful, then entity, and eventually message-based semantics.

Its only logical to assume the J2EE arena will continue to grow and evolve. JSR 109 is one of the latest specifications to expand J2EE support into new areas. JSR 109 effectively defines how a J2EE application server could be expanded to provide native support for deploying, managing, and accessing Web services in a standard fashion.

Specifically, JSP 109 covers a number of important areas:

Related Reading

Java Web Services
By David A. Chappell, Tyler Jewell

In this article, we will examine various areas of JSP 109 to understand the benefit of each. But as you read this article, please remember that specifications are designed to describe a solution to a problem. Often we look at a technology and think only in terms of what it does, losing sight of the problem it was meant to solve. As we read specifications, we should continue to ask, "What problem does this solve?" A specification should describe a solution to a problem, without being too broad or too narrow in scope.

First and foremost, JSP 109 attempts to define a programming model for implementing Web services so that outwardly, they appear exactly the same to the calling application, regardless of how they were implemented. Because Web services are controlled and defined by many other specifications, JSR 109 cannot require any changes beyond the scope of how a Web service is implemented and deployed in a compliant application server. We'll look at the various aspects of the development and deployment model shortly.

In addition, JSP 109 attempts to define a client-side programming model that mimics other J2EE programming models; developers familiar with "traditional" remote methodologies will be familiar with JSR 109. By "traditional," we mean that JSR 109 defines a client-side programming model that is consistent with other J2EE applications, uses JNDI, etc., to obtain access to a remote interface and then call into the object it references.

Note: A number of members of the voting Web services communities, such as Sun and BEA, have expressed significant reservations with the scope of JSR 109. For a complete review of comments, see the voting page.

Client Programming Model

The purpose of the client-side programming model of JSR 109 is to clearly define how Java applications might access a Web service locally in a manner similar to how EJB access works today. The problem is one of complexity. Other JSRs define mechanisms for accessing Web services not residing locally within an application server; however, such methods add a significant level of programming complexity to client applications. Accessing a Web service from within the application server that defines it should be a straightforward process. The client-side programming model in JSR 109 defines a mechanism for accessing a locally-deployed Web service in a simple and well-understood manner.

Three Models

JSR 109 defines three specific client programming models -- client-managed port access, container-managed port access, and dynamic port access. We will be concentrating on client-managed access, which defines an interface, based on the original WSDL, to the Web service. Using client-managed access, an application requests a port to a specific interface. Container-managed port access acts much like client-managed, except that the container manages calls to the instance directly, and the client requests a generic port that might be used to access multiple different instances.

A Note on Ports

Before we jump into accessing a Web service, we must first understand the concept of ports. A port is effectively an instance of a Web service. A client application accessing a Web service must ask a service interface for access to the service, at which point the application server might either serve up an existing instance or create a new instance to handle the request. Readers familiar with EJB programming will find the client-side programming model for JSR 109 very familiar.

With dynamic port access, no prior knowledge of the WSDL definition is required, and calls are generated on the fly. While significantly more robust, dynamic access to any object hasn't proven to be very useful in real-world applications. In the future -- if or when dynamic programming becomes more prevalent -- such access methods will prove valuable. For the remainder of this article, we will work with the more traditional container-managed port access model, where a definition of the Web service interface is known to the client beforehand. We'll look at client-managed and container-managed port access later.

Step 1: First we obtain an InitialContext as we would in any JNDI client application. (The specifics of JNDI are beyond the scope of this article. Interested readers are directed to the Javasoft JNDI tutorial.) When we examine the Web services deployment, we will understand the specifics of the actual name used to access the Web service; until then, we'll need to take the Web services name on faith. Clearly the application server would need to ensure that the actual Web service was bound into the JNDI tree.

Example 1. Client-managed port access.

00 InitialContent ic = new InitialContext(); 
01 SomeSpecificServiceInterface srv = (SomeSpecificServiceInterface)ic.lookup      
       (java:comp/env/service/SomeSpecificServiceInterface);    
02 ServiceInstance si = (SomeSpecificService)srv.getServiceInstancePort(); 

If we look closely at this snippet, we see a traditional JNDI lookup on line 00. On line 01, we obtain an specific instance of a generic ServiceInterface object interface. All services are required to implement the Services interface, which defines a number of common methods for accessing a service, such as returning specific instances. Anyone familiar with the EJB specification will see the resemblance between a Services interface and an EJB home interface. On line 02, we then obtain an instance of a remote object, which defines the actual method calls on the instance of the object.

Client-managed port access is typically used when a Web services definition is completely known at development time. If for some reason the application server could not return an instance supporting the cast operation on line 01, an exception would be thrown.

Example 2. Container-managed port access.

00 InitialContent ic = new InitialContext();
01 Service srv = (Service)ic.lookup
       (java:comp/env/service/SomeSpecificServiceInterface);
02 ServiceInstance si = (SomeSpecificService)srv.getPort(); 

Example 2 differs only slightly from Example 1. Specifically, on line 01, we now request a generic instance of the object. No interface was specified, so the container is free to return any appropriate available instance that matches the requested JNDI name. Line 02 also differs in that we use a generic getPort() call rather then a specific named get<some port>Port call, as we did in Example 1.

The specification states that container-managed port access might be used when the client only accesses the Service definition for the object. Line 02 then assumes that the client knows about a specific interface that the service might not support. If the container did not understand the requested cast, an exception would be thrown at run time. More likely, the client did not have a complete WSDL definition at build time, and therefore cannot use the get<some port>Port() method, but rather the client would cast the appropriate instance type -- a seemingly more likely possibility.

Server Programming Model

The server programming model is perhaps the most important aspect of JSR 109. The ability to understand how a Web service behaves during the various phases of its lifecycle allows the Web service developer to create services that behave predictably under a variety of conditions. The EJB specification defines the lifecycle for the various EJB types. JSR 109 goes to the next level and extends the EJB model to define how Web services act in a Web services container. JSR 109's treatment of server programming is an attempt to solve the problem of consistency of behavior.

A Quick Background Note

Web applications and EJBs normally execute inside of "containers." A container provides all of the services that the EJB or Web application might require at runtime. Transaction, JNDI, JDBC, and similar services are all provided through the container. Normally, there are two types of containers within an application server -- Web application and EJB containers. Both offer similar services, such as lifecycle management, for the object in question, but differ slightly, based on what service they provide. Web application containers know how to load servlets; EJB containers know how to load EJBs.

Before we get into the specifics of JSP 109, let's understand what is required to support Web services in a J2EE-compliant manner. First and foremost, the implementation of a Web service should be transparent to the client. The fact that a Web service is implemented within an application server in Java should in no way change the client's view of the service behavior. Additionally, we'd like to be able to use our Web service on a variety of application servers. Thus, the programming model should be portable and robust, to support both today's implementations and those of tomorrow.

Of lesser, but still high, importance is seamless integration with existing J2EE services, such as JDBC. We'd like our Web services to be able to take advantage of the advances already available in J2EE in a simple way, without compromising the integrity of the service itself.

With these goals in mind, JSP 109 defines two specific support areas for Web services: stateless session bean and servlets. JSR 109 is disappointing in that message-driven beans are clearly omitted without explanation. Message beans allow for scalable asynchronous messaging, an important aspect of Web services. While the behavior of message beans can be simulated with either a stateless session bean or a servlet, additional coding is required.

Ports are an important concept within Web services, and JSR 109 defines how ports are mapped to services within a J2EE application server. Ports within a Web service are similar in concept to instances in a JVM.

Implementing Web Services With Stateless Session Beans

One of the coolest parts of JSR 109 is that stateless session beans can be used to quickly and easily develop Web services. A complete review of the EJB specification as it applies to stateless session beans is appropriate for those readers with insufficient EJB background. The important aspects of the specification as it applies to Web services are provided here.

Enterprise JavaBeans

Related Reading

Enterprise JavaBeans
By Richard Monson-Haefel

All of the aspects defined above apply to new Web services. What about exposing an existing EJB as a Web service? As long as the EJB follows the rules defined by the specification and doesn't violate the JAX-RPC specification, it may be deployed as an implementation of an existing service. In fact, from the perspective of the EJB container, there is no real difference between the two.

Stateless session beans execute within the context of an EJB container. The container itself controls the lifecycle of a bean, including creating and destroying bean instances. Figure 1 shows the lifecycle of a stateless session EJB. Note that most application servers support a concept of "pooling" or "pre-creating" instances of objects to improve application performance. I've added an additional "conceptual" state representing "pooled."


Figure 1. Stateless Session EJB Lifecycle

Beans move between states for a variety of reasons. Understanding why a bean transitions from state to state will help us understand how to develop beans that behave properly.

  1. Transition 1 represents the initial creation of a bean. Normally, the application server will pre-create some number of beans; however, if the pool is completely in use, and there is available memory, a new instance of a bean would normally be created at client-access time. New beans have their init() method called before they can be used, as any one-time initialization can be done at this point.
  2. Transition 2 repesents the transition from a pooled state to a method-ready state. This transition occurs when a pooled instance is allocated to a client, normally during a get<...>Port() call. Again, the reason for the pooled state is to improve startup performance.
  3. Transition 3 is simply "business as usual." An instance of an object is allocated to a client and the client makes one or more method calls.
  4. Transition 4 occurs when an object is specifically released (i.e., by setting the variable to null) or by going out of scope. Depending on the application server, the bean will transition to pooled and be re-initialized, or go directly to the does-not-exist state.
  5. Transition 5 occurs when the bean is actually de-allocated. The destroy() method is called, and the client can then undo anything done during the init() method.

A note on transactions: The Web services of today are not transaction-aware, and any transaction context is suspended before a bean method is evoked. Practically speaking, this means that beans must not specify or require a transaction context, and as such, cannot be marked transaction "Mandatory."

Implementing Web Services With Servlets

There isn't really a significant difference, conceptually, between implementing Web services using EJBs and implementing with servlets. Choosing servlets as the implementation vehicle is really a matter of personal preference. Web services implemented as servlets need to follow the same guidelines as EJB-based implementations. The real difference between the two is the behavior of the underlying implementation. Table 1 shows some of the most obvious differences. It should be noted that these differences are the opinion of the author and not stated in JSR 109.

Table 1: Differences between EJB and servlet implementations

  Servlet EJB
Lifetime Long-lived Normally short-lived, might be
longer with pooling
Startup overhead Can be significant Normally light
Memory footprint Large Small
Container Services support Some Significant
Lifecycle-aware Marginally Very
Transaction Unsupported Must not be required
Must implement javax.servlet.SingleThreadModel javax.ejb.SessionBean
Scales Poorly Well
When you might choose When a small number of long-lived
methods are required. Startup
overhead not an issue.
When a large number of very
short-lived calls are required.

The one area where Servlet and EJB behavior differs significantly is in lifecycle management. As we saw in Figure 1, an EJB is made aware that is has been created via the init() call, and removed via the destroy() call. The servlet specification has no analogous interface; to support similar behavior, JSR 109 defines an additional interface -- java.xml.rpc.server.ServiceLifeCycle -- that provides similar behavior.

Example 3. java.xml.rpc.server.ServiceLifeCycle

package java.xml.rpc.server;
   public interface ServiceLifeCycle {
   void init(Object context) throws ServletException;
   void destroy();
   } 

Deployment

Deployment solves the problem of isolating the aspects of the Web service specific to how it is used from the aspects specific to its implementation. It normally defines both packaging and naming/initialization. The name of the service and what initialization it might require are examples of deployment-specific concerns that the developer might define as required, but the deployer needs to specify in order for the Web service to operate correctly. JSP 109 piggy-backs its deployment onto the deployment of the normal EJB or Web application via a new deployment description, webservices.xml..

As with so much of JSR 109, deployment of a Web service looks very much like an EJB deployment descriptor. Example 4 shows a sample of how a webservices.xml file might look, and contains five main elements.

Example 4 shows how a webservices.xml file might look. It should be noted, however, that this sample was based on the .03 version of the specification, and is subject to change. The code is simple enough (a complete DTD can be found in the specification), but bears some explanation.

Lines 12-16 link the Web service description provided by the WSDL on line 05 to the implementation. Either an EJB or a servlet can be specified as the engine for the Web service, and must be linked back to EJBs or servlets previously defined. Line 11 defines the service interface for obtaining the port for the Web service. Lines 08 and 09 qualify the external name of the Web service, so that any external client might use it.

Example 4. Sample webservices.xml

00 <?xml version="1.0"?>
01 <webservices>
02    <description>My first Web Service using JSP 109</description>
03    <display-name>Sample</display-name>
04    <web-services-description>
05        <wsdl-name>path.to.the.wsdl.representing.the.service</wsdl-name>
06        <port-components>
07           .. various optional elements such as description etc
08           <port-component-name>MyWebService</port-component-name>
09           <port-qname-namespace>qualifying.namespace</port-qname-namespace>
10           <port-qname-localname>name.within.namespace</port-qname-localname>
11           <service-def-interface>com.webservicesareus.webservice.sampleservInt
                      </service-def-interface>
12           <service-impl-bean>
13               <ejb-link>link to a named ejb</ejb-link>
14               or
15               <servlet-link>link to a named servlet</servlet-link>
16           </service-impl-bean>
17        </port-components>
18    </web-services-description>    
19 </webservices>  

JSR 109 is an interesting specification that attempts to define how Web services can be incorporated into an J2EE application server. While there there are some clear questions, such as why MBeans were omitted, the specification does cover the major areas required to define how Web services might be piggy-backed onto existing J2EE applications and within application servers. I'll be watching this JSR closely, along with many of the similar JSPs on security.

Al Saganich is BEA Systems' senior developer and engineer for enterprise Java technologies, focused on Java integration and application with XML and Web services.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.