EJBs and Web Applications

EJBs have two important but distinct characteristics:

  • They are distributed components.

  • They provide access to the services of the EJB container.

These topics will be considered more extensively in the next chapter, but in the context of Web applications, the second characteristic is the most attractive. One type of EJB is particularly alluring: container-managed persistent entity beans. Because the EJB container automatically takes care of storing and retrieving a CMP bean's data, CMP beans can completely free a developer from having to write database access code.

EJBs, and particularly CMP entity beans, bear a superficial resemblance to standard JavaBeans; after obtaining a bean (using a few mysterious lines of code), we use getter and setter methods to obtain and change the information in it. The container takes care of the rest.

The benefit of having database access taken care of automatically by using CMP entity beans comes at a significant cost. This cost includes:

  • Increased overhead of configuring and administering the EJB container

  • Decreased performance

  • Increased complexity of developing and deploying the application

Most of these costs are incurred because EJB is principally a technology for building distributed components. The mechanism for invoking an object method remotely introduces several layers of indirection between a call from an application to an EJB. Although some significant optimizations can be made, this is true even when EJBs are actually local and use a local interface instead of the remote interface.

Some of the development costs can be mitigated to a degree by using an IDE, such as Oracle JDeveloper. Wizards in JDeveloper allow you to create and deploy a CMP bean, based either on an existing database table or a table that it creates for you, almost effortlessly. It can be argued, however, that this is a pretty extreme way to avoid writing database access code, especially if you look behind the scenes and see what's really going on and how many class files are generated to implement a single entity bean.

Although you will need to consider carefully whether CMP beans are appropriate for a production application, you may nonetheless find that using an automated tool to generate an EJB from an existing table can be a convenient way to prototype code.

Creating a Container-Managed Persistent Entity Bean Using JDeveloper

In this section, we will extend the Web application we began earlier in this chapter by using an EJB to obtain the track information for a selected CD. Normally, we wouldn't mix data access techniques; this is just a demonstration for comparing the different techniques.

Starting JDeveloper

Because JDeveloper does not provide an installation program, it is not available from the start menu or an icon on your desktop. Instead, after downloading and unzipping JDeveloper, you will need to locate the jdev\bin directory and run the executable jdevw.exe manually. You can do this at a DOS prompt by navigating to it using the Windows Explorer or by selecting Run from the Start menu. If you've installed JDeveloper in a directory c:\JDeveloper, the full path would be

 c:\JDeveloper\jdev\bin\jdevw.exe 

A more convenient alternative to starting JDeveloper manually is to create a shortcut for JDeveloper on your desktop. Do this by right-clicking on an empty area of your desktop, selecting New | Shortcut, and entering the full path and filename for jdevw.exe (or press Browse and locate it that way). You can then start JDeveloper by double clicking on this shortcut.

Create a Workspace and Project

After JDeveloper starts, the System Navigator will appear in the top left pane of the main window. To create a workspace and project for developing the EJB:

  • Right-click on the root entry, Workspaces.

  • Click on New Workspace.

  • In the dialog box that appears, change the last part of the directory name to ejbExamples. (The full path, if JDeveloper were installed in c:\JDeveloper, would be c:\JDeveloper\jdev\mywork\ejbExamples). Change the filename to ejbExamples.jws. Leave the box labeled "Add a New Empty Project" checked. Press OK.

  • In the next dialog box, change the last part of the directory name to CDBean. Change the filename to CDBean.jpr. Press OK.

Create a Connection to the Database

We will be creating an EJB based on an existing table, the CD_COLLECTION table. To enable JDeveloper to connect to the database and locate this table, we will need to ensure that JDeveloper has a working database connection. At the bottom of the System Navigator tree:

  • Locate and right-click on Connections.

  • From the popup menu, select New Database Connection.

  • On the next box, Welcome to the Connection Wizard, press Next.

  • Enter the database name as the name of the connection, for example, Osiris. Ensure that Connection Type is Oracle (JDBC). Press Next.

  • Enter username and password, leave Role empty, and check the Deploy Password box. Press Next.

  • Verify the entries for Driver, Hostname, and JDBC Port. These should be "thin", "localhost" (or the machine name), and "1521."

  • Enter the SID for the database, for example, OSIRIS. Press Next.

  • In the next box, press the Test Connection button. This should display "Success!" in the Status box. If it does not, press Back, review your entries, and verify that they agree with your database settings. You may also want to verify independently that the database is running by connecting using SQL*Plus.

  • Once the test is successful, press Finish.

Create the CMP Entity Bean

We will use a wizard to create the EJB. As you will see, we need only to indicate the type of bean, CMP based on a table, and identify the table. JDeveloper will do the rest. In the System Navigator:

  • Right-click on the project name, CDBean.jpr.

  • Select New… from the popup menu.

  • In the box that appears, select Enterprise JavaBeans from the left side, then select Container-managed Entity Beans from Tables. Press OK.

  • In the next box, for JDBC Connection, select the connection you created for the database in the last step, e.g., Osiris.

  • In the list of tables that appears in the Available Tables list, locate the CD_COLLECTION table. (You can enter CD in the Table Name Pattern box to find it more quickly.) Highlight CD_COLLECTION and press the single right arrowhead to select it. Press Next.

  • Accept the defaults in the next box and press Finish.

Test the Entity Bean Using the Embedded OC4J

JDeveloper can automatically create a sample application to test the EJB. We'll first test it using the OC4J container embedded in the JDeveloper IDE. First, start the bean:

  • Right-click on the Cd_collection bean.

  • Select Run Cd_collection.

The log window will show that the embedded OC4J server has been started and that the bean has been deployed. Next, we'll create a test application.

  • Right-click on the Cd_collection bean.

  • Select Create Sample Java Client.

  • Ensure that the button labeled Connect to OC4J Embedded in JDeveloper is selected and press OK.

This will create a small class that will include a main() method to exercise the Cd_collection bean. To run the sample application:

  • Right-click on Cd_collectionClient.java.

  • Select Run Cd_collectionClient.java

The output, listing all the records in the CD_COLLECTION table, will display in the log window.

Create a Connection for the Standalone OC4J Instance

To test the application and bean on an application server in this case, on a standalone instance of OC4J we first need to create a connection for the application server:

  • Right-click on the Connections, select New Application Server Connection.

  • Press Next on the welcome screen.

  • Enter a name for the connection, such as OC4J.

  • Accept the default of Oracle9i Application Server and press Next.

  • Leave username admin. For the password, enter the admin password (if OC4J was set up as described earlier in this chapter, this will be adminpwd), and check the box labeled Deploy Password. Press Next.

  • In the next box, accept the default settings and press Next.

  • In the next box, press Test Connection. If you do not get the "Success!" message, use the Back button to review your settings.

  • Once the test is successful, press Finish.

Deploying the EJB

The first step in deploying an EJB is to create a deployment profile that establishes some basic settings:

  • Right-click on the CDBean project, CDBean.jpr.

  • Select New.

  • In the box that appears, select Deployment Profiles on the left side, then select EJB Jar File - J2EE EJB Module on the right. Press OK.

  • Change the filename of the deployment profile to CDBean.deploy in the next box and press Save.

  • In the next box, accept the default filenames for the .jar file, the .ear file, and the Enterprise Application Name. Press OK.

Once we've created the deployment profile, we can deploy the bean as follows:

  • Right click on the newly created deployment profile, CDBean.deploy.

  • Select Deploy to => OC4J.

  • The log window will show the progress of the deployment, including the creation of the .jar and .ear files, as well as invocation of the OC4J admin tool. Eventually, it will indicate that Deployment is finished.

Testing the EJB on the Standalone OC4J Server

To test the EJB on the standalone server, we can generate another test application:

  • Right-click on the Cd_collection bean.

  • In the box that appears, select Connect to Remote App Server. Ensure that the J2EE application name is CDBean and that the Oracle9i AS Connection name is OC4J. Press OK.

This creates a new client application, Cd_collectionClient1.java. Locate this under the CDBean project in the System Navigator.

  • Right-click on Cd_collection1.java.

  • Select Run Cd_collection1.java from the popup menu.

This sample application should produce the same results as the first one, listing all the records in the CD_COLLECTION table. In the next section, we'll use some of the code produced to access the EJB from our Servlet/JSP application.

Using a CMP Entity Bean in a Web Application

There are several ways that a CMP entity bean can be incorporated into a Web application.

  • JSP Scriptlets: It's possible to include code to access it directly in a JSP, but it takes a lot of code and, as discussed earlier, it's not good practice to include a lot of code in a JSP.

  • JSP Custom tags: A slightly better way to use EJBs in a JSP application is to write a set of custom tags that allow the JSP to use the EJB; this would be a good choice if the application was primarily JSP-based and most Java code was already implemented using a custom tag library.

  • Servlets/Java classes/JavaBeans: Because it takes a fair amount of Java code to use an EJB, it's generally best to use a more sophisticated method than just JSP or JSP and custom tags. As discussed earlier, the MVC design pattern, using JSP for presentation, servlets, and helper classes as the controller and EJBs (or EJBs and JavaBeans) as the model has advantages in terms of flexibility and maintainability.

Of these alternatives, the third is clearly the most appropriate for our CD Web application.

In the example so far, we've created one JavaBean, a heavyweight one that has the logic in it to access the database and populate itself. Similarly here, we could create a heavyweight JavaBean that calls the EJB and populates itself. In a real application, we would want to be consistent in our choice. Here, to provide variety in the examples, we'll use a lightweight JavaBean. The controller class will call the EJB and populate the JavaBean before forwarding the request to a JSP, which will display the information contained in the JavaBean.

The CDInfoController

The CDInfoController class contains the logic for obtaining a CMP bean containing the CD information we want. First are the imports, some constants, and instance variables.

 import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import mypackage1.Cd_collection; import mypackage1.Cd_collectionHome; import mypackage1.Cd_collectionPK; import java.util.Collection; import java.util.Iterator; import java.lang.Long; public class CDInfoController extends HttpController {   private static final String CD_SELECTED  = "CDSELECTED";   private static final String ARTIST_NAME  = "ARTISTNAME";   private static final String CD_BEAN  = "CDBean";   private static final String JSP_PAGE = "/CDInfo.jsp";   private static final String ERROR_PAGE = "/NotFound.jsp";   private String artistName;   private long cdid;   public void dispatch(HttpServletRequest request,                        HttpServletResponse response,                        ServletContext servletContext)    throws ServletException, IOException   {     Cd_collection cdBean = null;     CDInfoBean cdinfo = new CDInfoBean();     parseCDSelected(request); 

The literal constants are the names of the JPS files and the names of the attributes that we use to communicate with them. We also instantiate the Java-Bean (CDInfoBean not shown here) that we will use to store the CD information.

The variables artistName and cdid are the information that we need to obtain from the attribute that was set when the user pressed the Submit button for a particular CD. Remember that these two values were concatenated into a single string and set as the NAME attribute of a session parameter because of limitations in the way an HTML Submit button is implemented in certain browsers.

The logic for obtaining information from the CDSELECTED attribute is not straightforward because we don't know the precise name of the attribute. We only know that it begins with CDSELECTED, as in the following example:

 CDSELECTED=112;ARTISTNAME=Richard Thompson 

The helper method, parseCDSelected(), looks through the session's attributes, locates this string and parses it, and sets the class's cdid and artistName variables. We interrupt the presentation of the dispatch() method to present the code for this helper method.

 void parseCDSelected(HttpServletRequest request) {   Enumeration paramNames = request.getParameterNames();   while(paramNames.hasMoreElements())   {     String paramName = (String) paramNames.nextElement();     System.out.println("-- " + paramName);     if(paramName.startsWith(CD_SELECTED))     {       StringTokenizer st= new StringTokenizer(paramName, ";=", true);       if(st.countTokens()>=7)       {         if(    st.nextToken().equals(CD_SELECTED)             && st.nextToken().equals("="))         {           cdid=Long.parseLong(st.nextToken().trim());         }         if(   st.nextToken().equals(";")            && st.nextToken().equals(ARTIST_NAME)            && st.nextToken().equals("=")           )         {            artistName=st.nextToken().trim();         }       }     }   } } 

Note that this method is fairly strict in enforcing the format of the attributes; this is useful for debugging purposes. Normally, it would be sufficient simply to ensure that the right number of tokens are present and retrieve the desired ones, throwing the rest away.

Calling the EJB

To use an EJB, we need to obtain two objects:

  • The home object. This object serves as an EJB factory and manages the life cycle of the EJB object.

  • The EJB object. This is the object that we interact with in the same way we would with a standard JavaBean. It's different from a JavaBean, in that it is actually only a stub that delegates our calls to the real bean implementation.

To find the home object, we use JNDI, the Java API for naming and directory services. The following code, lifted straight out of the sample client application Cd_collection1.java that JDeveloper created for us, sets a number of parameters to obtain an initial context for the JNDI search. (It uses a hashtable that it builds dynamically, but this is equivalent to using a properties file, which is what we would do in a production environment.) The code then uses JNDI to obtain the home object for our EJB, Cd_collection. Here, we are once again looking at the code for the dispatch() method:

 try {   // source from sample application code   Hashtable env = new Hashtable();   env.put(Context.INITIAL_CONTEXT_FACTORY,    "com.evermind.server.rmi.RMIInitialContextFactory");   env.put(Context.SECURITY_PRINCIPAL, "admin");   env.put(Context.SECURITY_CREDENTIALS, "adminpwd");   env.put(Context.PROVIDER_URL, "ormi://noizmaker/CDBean");   Context ctx = new InitialContext(env);   Cd_collectionHome cd_collectionHome =       (Cd_collectionHome)ctx.lookup("Cd_collection");   // end source from sample code 

Once we have the home object, we can obtain our EJB object by using the CDID and the findByPrimaryKey() finder method that obtains the corresponding bean. To do this, we need to create a primary key. In theory, we can use a Java wrapper class as the primary key (and need to use a custom Java class only if it is something more complex, such as a combination of columns) but JDeveloper by default creates a custom primary key class. In this case, it wraps the long value representing the CDID. To use the primary key class it has created, Cd_collectionPK(), we instantiate it by calling its constructor, which takes a long value. We then use this key and call the finder method that obtains the corresponding bean.

 Cd_collectionPK pk = new Cd_collectionPK(cdid); cd_collection = cd_collectionHome.findByPrimaryKey(pk); 

We can now use this bean by calling its getter and setter methods. Here, we only use it to obtain information to populate a JavaBean, CDBeanInfo:

     // fill JavaBean     cdinfo.setAlbumTitle(cdBean.getAlbum_title());     cdinfo.setReleaseDate(cdBean.getRelease_date());     cdinfo.setLabel(cdBean.getLabel());     cdinfo.setArtistID(cdBean.getArtist_id());     cdinfo.setCDID(cdBean.getCd_id());  } catch(Exception e) {   System.out.println("Caught: " + e); } 

Once we've successfully put the information in a JavaBean, we can set this bean and the artist's name as request attributes. We then obtain and call a request dispatcher; note that we call an error page instead of the regular JSP if we are unable to obtain the CD information.

 RequestDispatcher dispatcher=null; if(cd_collection!=null) {   request.setAttribute(ARTIST_NAME, artistName);           request.setAttribute(CD_BEAN, cdinfo);   dispatcher = servletContext.getRequestDispatcher(JSP_PAGE); } else {   dispatcher = servletContext.getRequestDispatcher(ERROR_PAGE); } dispatcher.forward(request, response); 

This is the JSP file for displaying the CD information:

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE>CD Info</TITLE> </HEAD> <BODY> <H2>CD Info:</H2> <jsp:useBean    scope="request" /> Album title: <%= CDBean.getAlbumTitle() %><BR> Artist name: <%= request.getAttribute("ARTISTNAME") %> <BR> Label: <%= CDBean.getLabel() %><BR> Release date: <%= CDBean.getReleaseDate() %><BR> <FORM ACTION="/servlet/MusicServlet" METHOD="POST"> <INPUT TYPE="SUBMIT" NAME="PROCEED" VALUE="Continue"> <INPUT TYPE="HIDDEN" NAME="REQUESTPAGE" VALUE="STARTPAGE"> </FORM> </BODY> </HTML> 

Add the CDInfoController.java and CDInfoBean.java files to the default-web-app\WEB-INF\classes directory and the JSP file to the default-web-app directory, and run the MusicResults application again. This time, when we select a CD, the information for the selected CD will appear in the new CD Info page.



Java Oracle Database Development
Java Oracle Database Development
ISBN: 0130462187
EAN: 2147483647
Year: 2002
Pages: 71

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net