ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button O'Reilly Book Excerpts: Java Servlet & JSP Cookbook

Cooking with Java Servlets & JSP, Part 2

Related Reading

Java Servlet & JSP Cookbook
By Bruce W. Perry

by Bruce W. Perry

Editor's note: Last week we published three sample recipes from O'Reilly's Java Servlets & JSP Cookbook. This week, we conclude this two-part series with a look at recipes from the book that use servlets to access EJBs and to connect to Amazon Web Services.

Recipe 25.8: Accessing an EJB Using the WebLogic JNDI Tree

Problem

You want to access an Enterprise JavaBean (EJB) from a servlet on WebLogic.

Solution

Find out the EJB's JNDI name and use the javax.naming package to get a reference to the EJBObject or remote interface so that you can call the EJB's methods.

Discussion

A servlet accesses an EJB by using a specified JNDI name. The process is therefore transparent to the servlet developer. Any EJBs an application uses comprise the business tier of an application. The servlets and JSPs represent the web tier within the multi-tiered distributed architecture of a typical Java 2 Enterprise Edition (J2EE) application. All you need to know is the JNDI name associated with the EJB in order to use the EJB in your programs.

TIP: Enterprise JavaBeans is a comprehensive topic; however, this recipe is devoted to showing how a servlet can connect to an EJB. The "See Also" segment of this recipe includes several links to EJB and J2EE information and books.

You should be aware of the EJB's business methods, but do not have to be an expert on the javax.ejb package to use the EJB. Example 25-13 shows the source code for a stateless session EJB that is managed by BEA WebLogic 7.0 application server.

TIP: A certain type of EJB, a stateless session bean encapsulates business logic that does not require persistence or the saving of the object's state between method calls. On the other hand, a stateful session bean (such as a shopping cart object), must remember the object's state (such as the value of various instance variables) between method calls, as part of a conversation with the EJB client.

Example 25-13 provides a java.util.Map that links U.S. state names with their postal abbreviations. The session bean includes one business method, getAbbreviation( ), which receives a state name as a parameter and returns its postal abbreviation.

Example 25-13. The stateless session EJB

package com.jspservletcookbook;

import javax.ejb.*;

import java.util.Map;
import java.util.HashMap;

public class AbbrevBean implements SessionBean{

    private SessionContext context;
    private Map abbrevMap;
    
    
  public AbbrevBean( ){ //the bean's no-arguments constructor
    
      //A Map containing the names of states and abbreviations
      abbrevMap = new HashMap( );
    
      abbrevMap.put("ALABAMA","AL");
      abbrevMap.put("ALASKA","AK");
      abbrevMap.put("AMERICAN SAMOA","AS");
      abbrevMap.put("ARIZONA","AZ");
      abbrevMap.put("ARKANSAS","AR");
      abbrevMap.put("CALIFORNIA","CA");
      abbrevMap.put("COLORADO","CO");
      abbrevMap.put("CONNECTICUTT","CT");
    
      abbrevMap.put("DELAWARE","DE");
      abbrevMap.put("DISTRICT OF COLUMBIA","DC");
      abbrevMap.put("FEDERATED STATES OF MICRONESIA","FM");
      abbrevMap.put("FLORIDA","FL");
      abbrevMap.put("GEORGIA","GA");
      abbrevMap.put("GUAM","GU");
      abbrevMap.put("HAWAII","HI");
      abbrevMap.put("IDAHO","ID");
    
      abbrevMap.put("ILLINOIS","IL");
      abbrevMap.put("INDIANA","IN");
      abbrevMap.put("IOWA","IA");
      abbrevMap.put("KANSAS","KS");
      abbrevMap.put("KENTUCKY","KY");
      abbrevMap.put("LOUISIANA","LA");

      abbrevMap.put("MAINE","ME");
      abbrevMap.put("MARSHALL ISLANDS","MH");
      abbrevMap.put("MARYLAND","MD");
      abbrevMap.put("MASSACHUSETTS","MA");
      abbrevMap.put("MICHIGAN","MI");
      abbrevMap.put("MINNESOTA","MN");
    
      abbrevMap.put("MISSISSIPPI","MS");
      abbrevMap.put("MISSOURI","MO");
      abbrevMap.put("MONTANA","MT");
      abbrevMap.put("NEBRASKA","NE");
      abbrevMap.put("NEVADA","NV");
      abbrevMap.put("NEW HAMPSHIRE","NH");
    
      abbrevMap.put("NEW JERSEY","NJ");
      abbrevMap.put("NEW MEXICO","NM");
      abbrevMap.put("NEW YORK","NY");
      abbrevMap.put("NORTH CAROLINA","NC");
      abbrevMap.put("NORTH DAKOTA","ND");
      abbrevMap.put("NORTHERN MARIANA ISLANDS","MP");
    
      abbrevMap.put("OKLAHOMA","OK");
      abbrevMap.put("OREGON","OR");
      abbrevMap.put("PALAU","PW");
      abbrevMap.put("PENNSYLVANIA","PA");
      abbrevMap.put("PUERTO RICO","PR");
      abbrevMap.put("RHODE ISLAND","RI");
      abbrevMap.put("SOUTH CAROLINA","SC");
      abbrevMap.put("SOUTH DAKOTA","SD");
    
      abbrevMap.put("TENNESSEE","TN");
      abbrevMap.put("TEXAS","TX");
      abbrevMap.put("UTAH","UT");
      abbrevMap.put("VERMONT","VT");
      abbrevMap.put("VIRGIN ISLANDS","VI");
      abbrevMap.put("VIRGINIA","VA");
      abbrevMap.put("WASHINGTON","WA");
      abbrevMap.put("WEST VIRGINIA","WV");
      abbrevMap.put("WISCONSIN","WI");
      abbrevMap.put("WYOMING","WY");
 
  }//constructor
    
  public void setSessionContext(SessionContext ctx) throws 
    EJBException {
      context = ctx;
  }//setSessionContext

  public Map getAbbrevMap( ){
      return abbrevMap;
  }
    
  //The bean's business method
  public String getAbbreviation(String state){
      return (String) abbrevMap.get(state);
  }
    
  //javax.ejb.SessionBean method; it has to be implemented in a session 
  //bean, but is not relevant to Stateless session beans.
  public void ejbActivate( ){}

  //javax.ejb.SessionBean method; it has to be implemented in a Session 
  //bean, but is not relevant to stateless session beans.
  public void ejbPassivate( ){}

  //javax.ejb.SessionBean method;
  public void ejbRemove( ) {}

}

Example 25-13 could easily be implemented as an ordinary Java helper or utility class. However, I show a simple example of an EJB so that the recipe can focus on how a servlet connects to these objects.

EJBs have a deployment descriptor, similar to the web.xml file that web applications use. The EJB deployment descriptor must be named ejb-jar.xml. When you package the EJB(s) before they are deployed on an application server, include this deployment descriptor as part of the archive. The ejb-jar.xml file describes the related EJB component(s); the application server uses this descriptive information in order to properly deploy the EJB.

For example, the ejb-jar.xml file in Example 25-14 specifies the type of EJB (e.g., stateless session bean) and the fully qualified class names of its related Java classes, such as its remote interface.

Example 25-14. The ejb-jar.xml file

<?xml version="1.0"?>

  <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.
  //DTD Enterprise JavaBeans 2.0//EN"
  "http://java.sun.com/dtd/ejb-jar_2_0.dtd"
   >

<ejb-jar>
  <enterprise-beans>
    <session>
      <ejb-name>AbbreviationEjb</ejb-name>
      <home>com.jspservletcookbook.AbbrevHome</home>
      <remote>com.jspservletcookbook.Abbrev</remote>
      <local-home>com.jspservletcookbook.AbbrevLocalHome</local-home>
      <local>com.jspservletcookbook.AbbrevLocal</local>
      <ejb-class>com.jspservletcookbook.AbbrevBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>
</ejb-jar>

The package that contains this EJB, and with which the EJB is deployed on the application server, is a JAR file named myejb.jar (just a name I concocted; you do not have to use the same name).

Since this stateless session bean is deployed on BEA WebLogic Server, the JAR file must include a vendor-specific deployment descriptor named weblogic-ejb-jar.xml. This deployment descriptor gives the deployer the opportunity to configure several aspects of how the EJB is deployed on WebLogic, such as the JNDI names of its home and local home interfaces.

TIP: The "home" object is an implementation of the "home" interface, and the "local home" object is an implmentation of the local home interface. These objects are "factories" for EJB objects, which delegate the business-method calls to the EJB deployed in the server. A factory is a Java class that generates objects of a different kind of Java class. In this recipe's case, the client uses JNDI to get a reference to the home object, which creates an EJB object. The servlet (client) then calls the EJB object's getAbbreviation( ) method; the EJB object is a remote object or "stub" that delegates this method call to the original EJB stored on the server.

You will encounter the home object's JNDI name in the servlet depicted later on in this recipe.

TIP: When you deploy an EJB on WebLogic using the Administration Console, WebLogic automatically binds the home and local home objects within the WebLogic JNDI tree, using the names specified by the weblogic-ejb-jar.xml deployment descriptor.

Example 25-15 shows the weblogic-ejb-jar.xml deployment descriptor for our stateless session bean.

Example 25-15. The weblogic-ejb-jar.xml file

<!DOCTYPE weblogic-ejb-jar PUBLIC 
  '-//BEA Systems, Inc.//DTD WebLogic 7.0.0 EJB//EN' 
  'http://www.bea.com/servers/wls700/dtd/weblogic-ejb-jar.dtd'>

<weblogic-ejb-jar>
  <weblogic-enterprise-bean>
    <ejb-name>AbbreviationEjb</ejb-name>
    <stateless-session-descriptor>
        <pool>
            <initial-beans-in-free-pool>1</initial-beans-in-free-pool>
        </pool>
    </stateless-session-descriptor>
    <jndi-name>AbbrevHome</jndi-name>
    <local-jndi-name>AbbrevLocalHome</local-jndi-name>
  </weblogic-enterprise-bean>
</weblogic-ejb-jar>

An EJB module is a complicated package that includes bean classes, remote interfaces, and two different deployment descriptors. Example 25-16 shows the contents of the myejb.jar file. I use the jar tvf myejb.jar. command in a command-line window to display the contents of the specified JAR file (it works in both Unix and Windows).

Example 25-16. The contents of the ejb-jar.xml file

H:\book\cookbook\code\chap27\src\ejbs\ejbjar>jar tvf myejb.jar

    META-INF/
    META-INF/MANIFEST.MF
    com/
    com/jspservletcookbook/
    com/jspservletcookbook/Abbrev.class
    com/jspservletcookbook/AbbrevBean.class
    com/jspservletcookbook/AbbrevHome.class
    com/jspservletcookbook/AbbrevLocal.class
    com/jspservletcookbook/AbbrevLocalHome.class
 
    META-INF/ejb-jar.xml
    META-INF/weblogic-ejb-jar.xml

In Example 25-16, the session bean is AbbrevBean.class, the remote interface is Abbrev.class, and the home object (the factory for EJB objects that implement the Abbrev interface) is AbbrevHome.class.

Finally, Example 25-17 shows the servlet that uses the session bean from Example 25-13. The code is self-explanatory. The important thing to remember is that the servlet receivese a reference to the AbbrevHome object from the WebLogic JNDI tree. Then the servlet, in its doGet( ) method, calls the AbbrevHome object's create( ) method to get an instance of the session bean's remote interface (in this example, it's an Abbrev type ).

Example 25-17. A servlet that accesses the EJB on WebLogic using JNDI

package com.jspservletcookbook;    

import java.io.IOException;  
import java.io.PrintWriter;   

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;  

import javax.rmi.PortableRemoteObject;

import javax.servlet.*;
import javax.servlet.http.*;

public class WebJndiServlet extends HttpServlet {

  public void doGet(HttpServletRequest request, 
    HttpServletResponse response)
    throws ServletException, java.io.IOException {
    
      //The request parameter looks like 'state=Massachusetts'
      String state = request.getParameter("state");
      Context env = null;
      Abbrev abbrev = null;
      AbbrevHome home = null;
        
      try{
            
          env = (Context) new InitialContext( );
           
          //Look up the home or factory object on the WebLogic JNDI tree  
          Object localH  = env.lookup("AbbrevHome");
             
          //This method call is necessary for EJB code that uses a 
          //technology called RMI-IIOP
          home = (AbbrevHome) PortableRemoteObject.narrow(localH,
              AbbrevHome.class);
             
          //close the InitialContext
          env.close( );
             
          if (home == null)
              throw new ServletException(
              "AbbrevHome is an unknown JNDI object");
             
          //Get the remote interface by calling the home object's create( ) 
          //method
          abbrev = (Abbrev) PortableRemoteObject.narrow(home.create( ),
              Abbrev.class);
             
      } catch (NamingException ne) { 
          try{ env.close( );} catch (NamingException nex) { }
          throw new ServletException(ne);
      } catch (javax.ejb.CreateException ce) { 
             throw new ServletException(ce);
      }
    
    
      //set the MIME type of the response, "text/html"
      response.setContentType("text/html");
    
      java.io.PrintWriter out = response.getWriter( );
    
      out.println("<html><head>");
    
      out.println("<title>State abbreviations</title></head><body>");
      out.println("<h2>Here is the state's abbreviation</h2>");
    
      //Call the EJBObject's getAbbreviation( ) method; the EJBObject  
      //delegates this method call to the session bean. Put the request 
      //parameter in all upper-case, because this is how the session bean's 
      //java.util.Map stores the state names, which are the Map's keys

      if (state != null)
          out.println( abbrev.getAbbreviation(state.toUpperCase( )) );
        
          try{
              //The servlet is through with the EJBObject; call its remove( ) 
          //method
          abbrev.remove( );
          } catch (javax.ejb.RemoveException re){}
   
      out.println("</body></html>");

     }//doGet
     
  public void doPost(HttpServletRequest request, 
    HttpServletResponse response)
    throws ServletException, java.io.IOException {
       
         doGet(request, response);
    
  }//doPost
    
}//WebJndiServlet

The value of the abbreviation for a state such as "Oregon" is ultimately retrieved on the server side by calling the session bean's getAbbreviation( ) method. Figure 25-8 shows a web browser window after a user has requested the servlet. The URL looks something like http://localhost:7001/webjndi?state=Oregon. The URL pattern /webjndi is mapped in web.xml to the servlet of Example 25-17.

Figure 25-8
Figure 25-8. An EJB-accessing servlet's web browser display

See Also

Recipe 25.4 on configuring a JNDI object with WebLogic; Recipe 25.6 on accessing a JNDI object with a servlet on WebLogic; Chapter 2 on deploying web components with WebLogic; a web link for the javax.ejb API: http://java.sun.com/j2ee/1.4/docs/api/javax/ejb/package-summary.html; the documentation page for WebLogic Server 7.0: http://edocs.bea.com/wls/docs70/index.html; a link to J2EE tutorials, including an Enterprise JavaBean tutorial: http://java.sun.com/j2ee/tutorial/index.html; Enterprise JavaBeans, Third Edition (O'Reilly); J2EE Design Patterns (O'Reilly).

Pages: 1, 2

Next Pagearrow