Turn EJB components into Web services

Build and deploy an EJB component as a Web service with JAX-RPC

The evolution of Web-related technologies has changed the way applications in an organization communicate with customer and partner applications. Like every popular technology, Web services came like a wave and have assimilated deeply into IT organizations. Having revolutionized the IT world, Web services are here to stay. Thus, to compete in the market space, certain parts of your enterprise applications must be exposed as Web services.

The wide acceptance of Web services by companies has changed the way applications are designed, and Java developers must adapt to a service-oriented architecture. If you develop applications using J2EE, you are probably in the best position to adapt to a service-oriented architecture and expose your application as a Web service. Most J2EE application servers, such as Oracle Application Server 10g and BEA WebLogic, provide support for building and deploying Web services applications. However, J2EE 1.4 standardized building and deploying Web services applications with Java API for XML-based Remote Procedure Call (JAX-RPC).

JAX-RPC enables developers to write Web services applications by using Java classes and EJB (Enterprise JavaBeans) components. Numerous business applications have been written to EJB to encapsulate business logic in the middle tier. If you use EJB in your enterprise applications, you can easily expose them as Web services without redeveloping the business logic. This article discusses how you can build and deploy an EJB component as a Web service by using JAX-RPC and provides some guidelines for using EJB components as Web services.

What is JAX-RPC?

Before we dive into the details of developing an EJB Web service, let's quickly examine JAX-RPC. JAX-RPC, defined under Java Specification Request 101 in the Java Community Process, provides the Java API for building and accessing Web services. It can be seen as the heart and soul of building and deploying Web services with J2EE. JAX-RPC provides a simple, robust platform for building Web services applications by hiding from the application developer the complexity of mapping between XML types and Java types and the lower-level details of handling XML and SOAP (Simple Object Access Protocol) messages. It introduces a method call paradigm by providing two programming models: a server-side model, for developing Web services endpoints using Java classes or stateless EJB components, and a client-side model, for building Java clients that access Web services as local objects. JAX-RPC 1.1 mandates use of SOAP 1.1 and interoperability with other Web services built with other technologies such as Microsoft .Net. Several J2EE 1.4-compliant application servers, such as Oracle Application Server Containers for J2EE (OC4J) 10.0.3, Sun ONE (Open Network Environment) Application Server, and IBM Websphere V6, support JAX-RPC.

Developing and deploying an EJB Web service

EJB components, by design, are meant for distributed computing and are hence well suited for exposure as Web services. EJB supports declarative transactions and security, and these benefits can also be leveraged if you decide to use EJB components as Web services. J2EE 1.4 allows exposing only stateless session beans as Web services with JAX-RPC.

By their nature, SOAP and Web services are stateless, and hence stateless session beans are an ideal choice for exposing as Web services. Stateless session beans are used for business operations such as checking someone's credit, charging a bank account, or placing an order, and these operations are a perfect fit for exposure as Web services. You can use a stateless session Web service to accomplish any of these business operations by accessing a persistence layer such as CMP (container-managed persistence) entity beans or an O/R (object/relational) framework such as TopLink, or sending a message to a JMS (Java Message Service) queue that activates an MDB (message-driven bean) to process the business rule.

Guidelines for development

If you use a Session Fa�ade design pattern in your J2EE applications, it will prove easier for you to expose your business process as a Web service. However, exposing all session beans in your application as Web services is not a good idea and will pose a management nightmare. A session bean that implements a business activity and will be used by another remote application is an ideal candidate for exposure as a Web service. The session fa�ade must be coarse-grained, not fine-grained. For example, an ideal choice for an EJB Web service is an EJB component that has methods for completing an order or charging a credit card, not an EJB component that just provides access to an entity bean's getter and setter methods. You must remember that Web services are invoked with SOAP, that you should avoid exposing an EJB component as a Web service if it may involve a long-running business transaction, and that you should also avoid calling that bean from a Web application.

Developing an EJB Web service

If you already have a stateless session bean, you can easily expose it as a Web service. You must perform the following tasks to expose your EJB component as a Web service:

  • Create a Web service endpoint for the stateless EJB component. Change the EJB deployment descriptor, ejb-jar.xml, to define the endpoint.
  • Create a Web services definition, using the WSDL (Web Services Description Language) and Web services deployment descriptors such as webservices.xml.
  • Package your EJB component in an ejb-jar with the descriptors and WSDL, and deploy it into your application server of choice.

Let's take a simple stateless session bean example, TimeServiceBean, and walk through each of these steps. You can download a fully functional example of the EJB Web service this article discusses from the Oracle Technology Network.

Your EJB component's Web service endpoint should implement the java.rmi.Remote interface, and every method exposed in the endpoint interface must throw java.rmi.RemoteException. The following code is the Web service endpoint for an EJB component called TimeService:

package time; 
import java.rmi.RemoteException;
import java.rmi.Remote; 
public interface TimeService extends Remote
{
public String getDateTime (String name) throws RemoteException;

If you just want your EJB component exposed as a Web service, you do not need to build other interfaces. But you can use the same component directly from a J2EE application or as a Web service, and the J2EE container will use the same bean pool for both uses.

The TimeService Web service interface exposes a getDateTime() method, accepts java.lang.String as a parameter, and returns java.lang.String as a return type. You can use only primitives and classes that are JAX-RPC value types as parameters or return types for the EJB methods defined in the Web service endpoint interface. Some examples of JAX-RPC value types are nonprimitives such as java.lang.String or java.lang.Double and Java mappings of Mime (Multipurpose Internet Mail Extensions) types such as java.awt.Image or javax.xml.transform.Source. User-specific Java types may also be used if the user provides a serializer for those types. Most vendors provide a custom serialization registration framework.

For exposing the Web service endpoint interface, an entry is required in ejb-jar.xml. For example, we have the following entry for our TimeService Web service:

<session>
<display-name>TimeServiceEJB</display-name>
<ejb-name>TimeServiceEJB</ejb-name>
<service-endpoint>time.TimeService</service-endpoint> 
<ejb-class>time.TimeServiceBean</ejb-class>
<session-type>Stateless</session-type>
...
</session>

The most important things for the Web service are the WSDL and the Web services deployment descriptor webservices.xml file. The WSDL describes the Web service and is the contract to which the Web service guarantees it will conform.

Following is the WSDL for the TimeService Web service:

<?xml version="1.0" encoding="UTF-8"?> 
<definitions name="MyTimeService" targetNamespace="urn:oracle-ws" xmlns:tns="urn:oracle-ws" 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="TimeService_getDateTime">
<part name="String_1" type="xsd:string"/></message>
<message name="TimeService_getDateTimeResponse">
<part name="result" type="xsd:string"/></message>
<portType name="TimeService">
<operation name="getDateTime" parameterOrder="String_1">
<input message="tns:TimeService_getDateTime"/>
<output message="tns:TimeService_getDateTimeResponse"/></operation></portType>
<binding name="TimeServiceBinding" type="tns:TimeService">
<operation name="getDateTime">
<input>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:oracle-ws"/></input>
<output>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:oracle-ws"/></output>
<soap:operation soapAction=""/></operation>
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/></binding>
<service name="MyTimeService">
<port name="TimeServicePort" binding="tns:TimeServiceBinding"><soap:address location="REPLACE_WITH_ACTUAL_URL"/></port> 
</service>
</definitions>

If you look carefully, you will find that the WSDL has a complete description of the TimeService EJB Web service, including the port, operations, and message types. There is no difference in the WSDL between an EJB Web service and another Web service.

As we discussed earlier, deployment of an EJB Web service in J2EE requires a standard compliant deployment descriptor named webservices.xml (shown below) in META-INF in the ejb-jar file. This descriptor specifies the set of Web service descriptions for deployment into the J2EE application server and their dependencies on container resources and services:

<description>A Web service to serve current Time</description> 
<webservice-description>
<webservice-description-name>TimeServiceEJB</webservice-description-name>
<wsdl-file>META-INF/MyTimeService.wsdl</wsdl-file>
<jaxrpc-mapping-file>META-INF/mapping.xml</jaxrpc-mapping-file>
<port-component>
<description>port component description</description>
<port-component-name>TimeServicePort</port-component-name>
<wsdl-port xmlns:ns="urn:oracle-ws">ns:TimeServicePort</wsdl-port> 
<service-endpoint-interface>time.TimeService</service-endpoint-interface>
<service-impl-bean>
<ejb-link>TimeServiceEJB</ejb-link>
</service-impl-bean>
</port-component> 
</webservice-description>

If you look at the webservices.xml file, you will see that it specifies the location of the WSDL; mapping.xml, which contains Java-to-WSDL mapping; and the service endpoint interface for the TimeService EJB component.

Several implementation-specific references such as the context root and endpoint addresses cannot be specified in the Web services deployment descriptor and must be specified in the vendor-specific deployment descriptor, because most of these references are specific to a particular J2EE server vendor. For example, if you use OC4J, you will need to package an oracle-webservices.xml file in the ejb-jar to define these properties. For our TimeService EJB component, the contents of the oracle-webservices.xml are as follows:

<oracle-webservices>
<context-root>/ejbws</context-root>
<webservice-description name="TimeServiceEJB">
<port-component name="TimeServicePort">
<endpoint-address-uri>/timeport</endpoint-address-uri>
</port-component>
</webservice-description>
</oracle-webservices>

The context-port and endpoint-address-uri imply that the Web service's endpoint can be reached via http://<hostname>:<port>/ejbws/timeport.

A tool provided with the application server usually generates WSDL, webservices.xml, and vendor-specific deployment descriptors such as oracle-webservices.xml. For example, if you use the J2EE Reference Implementation, you can use the wscompile tool to generate the WSDL and the Web services deployment descriptors. However, you can use an IDE that makes Web services development much easier and your development cycle much faster. You can avoid several mundane tasks such as creating the endpoint interface, the WSDL, and the deployment descriptors and instead focus on creating business logic. IDEs provide wizards for creating the Web service endpoints and for generating the WSDL and the deployment descriptors.

The J2EE 1.4 Blueprint application Java Adventure Builder 1.0.1 provides a nice design pattern and guideline for building a Web services application using J2EE and can be used as a reference application.

Invoke a Web service

An EJB Web service does not differ from any other Web service and can be invoked by a client written in Java, .Net, or any other programming language. A detailed discussion of Web service clients reaches beyond this article's scope, but let's examine how a Web service can be invoked from either a standalone Java program or a J2EE application module such as a servlet or an EJB component.

The client for the EJB Web service can be any of the following types: static stub, dynamic proxy, or Dynamic Invocation Interface (DII). The code example includes a static stub client.

If you use a static stub client, which is commonly used, you must use the JAX-RPC compiler to generate the client-side artifacts for accessing the Web service. The JAX-RPC compiler reads the WSDL document and generates the endpoint interface and the Stub class, which can be used to invoke the Web service as a local object. The Stub class converts each method invocation into SOAP messages that are sent to the Web service endpoint and also translates the reply messages into return values for the methods being invoked.

So the client code for accessing the EJB Web service may look like the code below. If you examine the code, you will find that the client depends on the generated Stub for the Web service.

import javax.xml.rpc.Stub;
import time.*;
public class TimeClient
{
   public static void main(String[] args)
   {
      String inputParam = "Debu Panda";
      if(args.length !=0)
      inputParam = args[0];
            
      try {
        
         Stub stub = createProxy();
         TimeService time = (TimeService)stub;
         System.out.println("Invoking the webservice end-point for the Stateless EJB deployed in OC4J");
         System.out.println(time.getDateTime(inputParam));
         System.out.println("Good Bye !!");     
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }    
     private static Stub createProxy() {
        // MyTimeService_Impl is implementation-specific to the J2EE vendor
        return (Stub)(new MyTimeService_Impl().getTimeServicePort());
    }
}

However, JAX-RPC makes it simpler for J2EE developers to use Web services from any type of J2EE component—that is, application clients, Web clients, or EJB components can invoke a Web service. (Note: You can find sample code for accessing Web services for different types of clients from the Oracle Technology Network.) You can define a service-ref element in the deployment descriptor for your component. For example, if you access the TimeService Web service from an EJB component, ejb-jar.xml may contain the following:

<service-ref>
   
          <service-ref-name>service/TimeService</service-ref-name>
          <service-interface>time.TimeService</service-interface>
          <wsdl-file>META-INF/MyTimeService.wsdl</wsdl-file>
           <service-qname>urn:oracle-ws</service-qname>
      </service-ref>

To enable your application to find the Web service, you must specify the Web service's location in your vendor deployment descriptor. For example, if you use OC4J to look up the Web service from your EJB component, orion-ejb-jar.xml should have the following contents to look up the component:

<service-ref-mapping name="service/TimeService"> 
   <port-info>
      <wsdl-port namespaceURI="urn:TimeService" localpart="TimeServicePort"/> 
      <stub-property>
         <name>javax.xml.rpc.service.endpoint.address</name>
         <value>http://localhost:8888/ejbws/timeport</value>
      </stub-property>                
    </port-info> 
</service-ref-mapping>

If you use a static stub, you must generate these classes and the package with your application prior to deployment in your server. You can make a JNDI (Java Naming and Directory Interface) lookup as follows to use a Web service:

InitialContext ctx= new InitialContext();
MyTimeService ts = (MyTimeService)ctx.lookup("java:comp/env/service/MyTimeService");
TimeService time = ts.getTimeServicePort();
String timeDate = time.getDateTime("Debu Panda")

EJB Web service and SOAP message handlers

For J2EE developers, SOAP message handlers are analogous to servlet filters. The J2EE container invokes message handlers automatically to either pre- or post-process a SOAP message, independent of actual SOAP message processing. For example, an encryption handler can be invoked when a client sends a message with confidential information such as a Social Security Number or a credit card number. In the same way servlet filters are chained, several handlers can work in a chained fashion; for example, one handler encrypts the message and another digitally signs it. The message handlers are configured in webservices.xml. You can use a message handler with an EJB Web service. No specific changes are required for EJB to use a message handler, and the message handler classes are packaged in the ejb-jar. If you use message handlers in the Web services client and your EJB component or Web module is a client of a Web service that requires a message handler, you must use the service-ref element in your module's deployment descriptor.

Interoperability

Heterogeneous systems and software are a reality in today's computing environment, and Web services are an effective technology for integrating these heterogeneous systems. Interoperability of Web services built with a heterogeneous technology such as J2EE becomes simple if you build Web services that conform to Basic Profile 1.0 of the Web Services-Interoperability Organization (WS-I). J2EE Web services using JAX-RPC require Basic Profile 1.0. So if Web services interoperability is important to you, you must conform to Basic Profile 1.0 when building EJB Web services.

Best practices

Here are a few best practices for developing an EJB Web service:

  • Avoid overusing Web services in your applications. Examine whether you really need to expose your EJB as a Web service.
  • Use a coarse-grained session façade that encapsulates your business logic to be used as a Web service. Avoid exposing all your application's session beans as Web services.
  • Examine properly whether you need either RPC-style or document-style Web services. RPC-style Web services are more efficient than document-style Web services. On the contrary, document style is more flexible because you can use schema.
  • Make sure you design your Web service so that it creates minimal network traffic.
  • Avoid maintaining any kind of state information in your EJB components that you expose as Web services.
  • Use JAX-RPC data types as the method parameters for your Web service to give it interoperability with heterogeneous Web services. Avoid types such as Collection, HashMap, and Lists as parameters for your Web service if interoperability is important for your application.
  • Many of the conventional best practices for J2EE applications (Web applications) are also relevant to EJB Web services. For example, avoid exposing an EJB component that involves long-running transactions as a Web service.
  • Weigh your security requirements against performance, because security comes with a higher cost. The performance costs of end-to-end security are high.

Conclusion

This article has presented the steps for exposing an EJB component as a Web service by using JAX-RPC and has provided some guidelines. You can start building your EJB Web service by using these guidelines with J2EE 1.4-compliant containers such as OC4J 10.0.3 Developer Preview or IBM Websphere V6.

I would like to thank Anirban Chatterjee and Lenny Phan of the OC4J development team for providing the sample code and reviewing the article.

Debu Pandais a principal product manager of the Oracle Application Server development team, where he focuses his efforts on the EJB container and transaction manager. He has more than 13 years of experience in the IT industry, has published articles in several magazines, and has presented at many technology conferences such as JavaOne and OracleWorld. His J2EE-focused Weblog can be found at http://radio.weblogs.com/0135826/.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies