★ wanayoo — archive 1999 http://developer.java.sun.com/developer/onlineTraining/J2EE/Intro/entity.htmlNouvelle recherche | Portail wanayoo
Java Technology Home Page
A-Z Index

Java Developer Connection(SM)
Online Training

Downloads, APIs, Documentation
Java Developer Connection
Tutorials, Tech Articles, Training
Online Support
Community Discussion
News & Events from Everywhere
Products from Everywhere
How Java Technology is Used Worldwide
 
Training Index

Writing Enterprise Applications
Lesson 2: A Simple Entity Bean

[J2EE TECH CENTER] [<<BACK] [CONTENTS] [NEXT>>]

This lesson expands the Lesson 1 example to use an entity Bean. The BonusServlet calls on the entity Bean to save the social security number and bonus information to and retrieve it from a database table. This database access functionality adds the third and final tier to the thin-client, multitiered example started in Lesson 1.

The J2EE Reference Implementation comes with Cloudscape database, and you need no additional setup to your environment for the entity Bean to access it. In fact in this example, you do not write any SQL or JDBC TM code to create the database table or perform any database access operations. The table is created and the SQL code generated with the Deployer tool during assembly and deployment.

Lesson 2 Zip file


Create the Entity Bean

An entity Bean represents persistent data stored in one row of a database table. When an entity Bean is created, the data is written to the appropriate database table row, and if the data in an entity Bean is updated, the data in the appropriate database table row is also updated. The database table creation and row updates all occur without your writing any SQL or JDBCTM code.

Entity Bean data is persistent because it survives crashes. If a crash occurs while the data in an entity Bean is being updated, the entity Bean data is automatically restored to the state of the last committed database transaction. If the crash occurs in the middle of a database transaction, the transaction is backed out to prevent a partial commit from corrupting the data.

BonusHome

The main difference between the CalcHome session Bean code and the BonusHome entity Bean code shown below is the addition of the findByPrimaryKey finder method. This method takes the primary key as a parameter, which is a social security number. The primary key is used to retrieve the table row with a primary key value that corresponds to the social security number passed to this method.

The create method takes the bonus value and primary key as parameters. When BonusServlet instantiates the home interface and calls its create method, the container creates a BonusBean instance and calls its ejbCreate method. The BonusHome.create and BonusBean.ejbCreate methodsmust have the same signatures, so the bonus and primary key values are passed from the home interface to the entity Bean by way of the entity Bean's container. If a row for a given primary key (social security) number already exists, a java.sql.RemoteException is thrown that is handled in the BonusServlet client code.

package Beans;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.FinderException;
import javax.ejb.EJBHome;

public interface BonusHome extends EJBHome {
  public Bonus create(double bonus, String socsec)
        throws CreateException, RemoteException;
  public Bonus findByPrimaryKey(String socsec)
        throws FinderException, RemoteException;
}

Bonus

After the home interface is created, the container creates the remote interface and entity Bean. The Bonus interface declares the getBonus and getSocSec methods so the servlet can retrieve data from the entity Bean.
package Beans;

import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface Bonus extends EJBObject {
  public double getBonus() throws RemoteException;
  public String getSocSec() throws RemoteException;
}

BonusBean

BonusBean is a container managed entity Bean. This means the container handles data persistence and transaction management without your writing code to transfer data between the entity Bean and the database or define transaction boundaries.

If for some reason you want the entity Bean to manage its own persistence or transactions, you would provide implementations for some of the empty methods shown in the BonusBean code below. The following links take you to documents that describe Bean-managed persistence and transactions, and a later lesson in this tutorial will cover Bean-managed transactions.

  • Chapter 3 of the Writing Advanced Applications tutorial.

  • Chapter 4 of the Enterprise JavaBeansTM Developer's Guide.
When BonusServlet calls BonusHome.create, the container calls the BonusBean.setEntityContext method. The EntityContext instance passed to the setEntityContext method has methods that let the Bean return a reference to itself or get its primary key.

Next, the container calls the ejbCreate method. The ejbCreate method assigns data to the Bean's instance variables, and then the container writes that data to the database.

The ejbPostCreate method is called after the ejbCreate method and performs any processing needed after the Bean is created. This simple example does no post-create processing.

The rest of the empty methods are callback methods called by the container to notify the Bean that some event is about to occur. You would provide behavior for some of these methods if you are using Bean-managed persistence, and others if you need to provide Bean-specific cleanup or initialization operations. These cleanup and initialization operations take place at specific times during the Bean's lifecycle, and the container notifies the Bean and calls the applicable method at the appropriate time. Here is a brief description of the empty methods:

  • The ejbPassivate and ejbActivate methods are called by the container before the container swaps the Bean in and out of storage. This process is similar to the virtual-memory concept of swapping a memory page between memory and disk.

  • The container calls the ejbRemove method if the home interface has a corresponding remove method that gets called by the client.

  • The ejbLoad and ejbStore methods are called by the container before the container synchronizes the Bean's state with the underlying database.
The getBonus and getSocSec methods are called by clients to retrieve data stored in the instance variables. This example has no setXXX methods, but if it did, clients would call them to change the data in the Bean's instance variables. Any changes to the instance variables result in an update to the table row in the underlying database.
package Beans;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;

public class BonusBean implements EntityBean {
  public double bonus;
  public String socsec;
  private EntityContext ctx;

  public double getBonus() {
        return this.bonus;
  }
  public String getSocSec() {
        return this.socsec;
  }

  public String ejbCreate(double bonus, 
		String socsec) 
		throws CreateException{
  //Called by container after setEntityContext 
    this.socsec=socsec;
    this.bonus=bonus;
    return null;
  }

  public void ejbPostCreate(double bonus,
                String socsec) {
  //Called by container after ejbCreate
  }

//These next methods are callback methods that
//are called by the container to notify the
//Bean some event is about to occur

  public void ejbActivate() {
  //Called by container before Bean 
  //swapped into memory 
  }

  public void ejbPassivate() {
  //Called by container before 
  //Bean swapped into storage 
  }

  public void ejbRemove() throws RemoteException {
  //Called by container before 
  //data removed from database
  }

  public void ejbLoad() {
  //Called by container to 
  //refresh entity Bean's state
  }

  public void ejbStore() {
  //Called by container to save 
  //Bean's state to database
  }

  public void setEntityContext(EntityContext ctx){
  //Called by container to set Bean context
  }

  public void unsetEntityContext(){
  //Called by container to unset Bean context
  }
}

Change the Servlet

The
BonusServlet program is very similar to the Lesson 1 version with changes in the init and doGet methods. The init method for this lesson looks up both the CalcBean session Bean, and the BonusBean entity Bean.
public void init(ServletConfig config) 
		throws ServletException{
  try {
     InitialContext ctx = new InitialContext();
     Object objref = ctx.lookup("bonus");
     Object objref2 = ctx.lookup("calcs");
     homebonus=(BonusHome)PortableRemoteObject.narrow(
		objref, BonusHome.class);
        homecalc=(CalcHome)PortableRemoteObject.narrow(
		objref2, CalcHome.class);
   } catch (Exception NamingException) {
     NamingException.printStackTrace();
   }
}
The try statement in the doGet method creates the CalcBean and BonusBean home interfaces. After calling calBonus to calculate the bonus, the BonusHome.create method is called to create an entity Bean instance and a corresponding row in the underlying database table. After creating the table, the BonusHome.findByPrimaryKey method is called to retrieve the same record by its primary key (social security number). Next, an HTML page is returned to the browser showing the data originally passed in, the calculated bonus, and the data retrieved from the database table row.

The catch statement catches and handles duplicate primary key values (social security numbers). The underlying database table cannot have two rows with the same primary key, so if you pass in the same social security number, the servlet catches and handles the error before trying to create the entity Bean. In the event of a duplicate key, the servlet returns an HTML page the original data passed in, the calculated bonus, and a duplicate key error message.

try {
//Calculate bonus
    double bonus = 100.00;
    theCalculation = homecalc.create();
    calc = theCalculation.calcBonus(multiplier, bonus);
    try {
//Create row in table
      theBonus = homebonus.create(calc, socsec);
      record = homebonus.findByPrimaryKey(socsec);
//Display data
      out.println("<H1>Bonus Calculation</H1>");
      out.println("<P>Soc Sec passed in: " + 
		theBonus.getSocSec() + "<P>");
      out.println("<P>Multiplier passed in: " + 
		multiplier + "<P>");
      out.println("<P>Bonus Amount calculated: " + 
		theBonus.getBonus() + "<P>");
      out.println("<P>Soc Sec retrieved: " + 
		record.getSocSec() + "<P>");
      out.println("<P>Bonus Amount retrieved: " + 
		record.getBonus() + "<P>");
      out.println("</BODY></HTML>");
//Catch duplicate key error
//Remote Exception is thrown by BonusHome
    } catch (java.rmi.RemoteException e) {
      String message = e.getMessage();
//Display data
      out.println("<H1>Bonus Calculation</H1>");
      out.println("<P>Soc Sec passed in: " + 
		socsec + "<P>");
      out.println("<P>Multiplier passed in: " + 
		multiplier + "<P>");
      out.println("<P>Bonus Amount calculated: " + 
		calc + "<P>");
      out.println("<P>" + message + "<P>");
      out.println("</BODY></HTML>");
    }
  } catch (Exception CreateException) {
    CreateException.printStackTrace();
  }
}

Compile

First, compile the entity Bean and servlet. Refer to Lesson 1 for path and classpath settings, and information on where to place the source files.

Compile the Entity Bean

Unix:
  #!/bin/sh
  cd /home/monicap/J2EE
  J2EE_HOME=/export/home/monicap/J2EE/j2sdkee-beta
  CPATH=.:$J2EE_HOME/lib/j2ee.jar
  javac -d . -classpath "$CPATH" Beans/BonusBean.java
                Beans/BonusHome.java Beans/Bonus.java

Windows:
  cd \home\monicap\J2EE
  set J2EE_HOME=\export\home\monicap\J2EE\j2sdkee-beta
  set CPATH=.;%J2EE_HOME%\lib\j2ee.jar
  javac -d . -classpath %CPATH% Beans/BonusBean.java
                Beans/BonusHome.java Beans/Bonus.java

Compile the Servlet

Unix:
  cd /home/monicap/J2EE/ClientCode
  J2EE_HOME=/export/home/monicap/J2EE/j2sdkee-beta
  CPATH=.:$J2EE_HOME/lib/j2ee.jar:/export/home/monicap/J2EE:
        /export/home/monicap/J2EE/Beans
  javac -d . -classpath "$CPATH" BonusServlet.java

Windows:
  cd \home\monicap\J2EE\ClientCode
  J2EE_HOME=\export\home\monicap\J2EE\j2sdkee-beta
  CPATH=.;%J2EE_HOME%\lib\j2ee.jar:\export\home\monicap\J2EE:
        \export\home\monicap\J2EE/Beans
  javac -d . -classpath %CPATH% BonusServlet.java

Start the Platform and Tools

To run this example, you need to start the J2EE server, the Deployer tool, and Cloudscape database. In different windows, type the following commands:
  j2ee -verbose
  deploytool
  cloudscape -start
If that does not work, type this from the J2EE directory:
Unix:
  j2sdkee-beta/bin/j2ee -verbose
  j2sdkee-beta/bin/deploytool
  j2sdkee-beta/bin/cloudscape -start

Windows:
  j2sdkee-beta\bin\j2ee -verbose
  j2sdkee-beta\bin\deploytool
  j2sdkee-beta\bin\cloudscape -start

Assemble and Deploy

Before you can redeploy the J2EE application with the changes for this lesson, you have to uninstall the Lesson 1 J2EE application. You can do this any time before you deploy, but just to make sure you do not forget, do it now.

Uninstall the Application

At the bottom of the Deployer tool is a window listing BonusApp with an Uninstall button to the right. Click Uninstall.

Delete and Create New WAR File

The web archive (WAR) file contains BonusServlet and bonus.html. Because you have changed BonusServlet, you have to delete the WAR file from the application, recreate it with the new BonusServlet, and add the new WAR file back to the J2EE application.

Click the BonusApp application in the Local Applications window so you can see its application components. Select BonusWar so it is highlighted.

At the top of the Deployer tool, there is an Edit menu. Select Delete.

Now, go through the steps to create the WAR file. These steps are outlined in Lesson 1 and summarized below:

  • Select Application.New Web Component from the menus at the top.

  • Step 1 of 15: Read and Click Next

  • Step 2 of 15: Specify the ClientCode directory, Click Add, and select BonusServlet.class in the top window and bonus.html in the bottom window.

  • Step 3 of 15: Name the WAR file Bonus.war with a display name of BonusWar.

  • Skip Step 4, 5, 6, 7, and 8 of 15.

  • Step 9 of 15: Make sure Describe a servlet is selected.

  • Step 10 of 15: Make the servlet class and display name BonusServlet.

  • Skip Step 11, 12, and 13 of 15.

  • Step 14 of 15: Create the WAR now.

  • Step 15 of 15: Read and click Done.

  • Add the WAR now.

  • In the Inspecting window, select Web Context and specify BonusRoot.

Create EJB JAR for Entity Bean

The steps to creating the EJB JAR for the entity Bean are very similar to the steps for the session Bean covered in Lesson 1. There are a few differences, however, and those differences are explained here.

Note: In this lesson, the entity Bean is placed in a separate JAR file from the session Bean as an easy way to continue the example from Lesson 1 with the least number of changes.

Because these Beans have related functionality, however, you could bundle and deploy them in the same JAR file. You will see how to bundle related Beans in the same JAR file in Lesson 3.


  • Select Application.New EJB JAR from the menus at the top.

  • Step 1 of 12: Read and click Next.

  • Step 2 of 12: Make sure the directory path points to J2EE.

    Step 3 of 12: Type: Beans.BonusBean, Beans.BonusHome, and Beans.Bonus for the class, home, and remote names. The display name is BonusBean. Click Entity for the Bean type.

  • Step 4 of 12: Select Container managed persistence. In the window below, check bonus and socsec. The primary key class is java.lang.String, and the primary key field name is socsec. Note that the primary key has to be a class type. Primitive types are not valid for primary keys.

  • Skip Step 5, 6, 7, and 8 of 12.

  • Step 9 of 12: Select Transactions managed by the server. In the list below make getBonus and getSocSec required. This means the container starts a new transaction before running these methods. The transaction commits just before the methods end. You can find more information on these transaction settings in Chapter 6 of the Enterprise JavaBeans Developer's Guide.

  • Step 10 of 12: Select Don't add another ejb descriptor.

  • Step 11 of 12: In the Location field, make the JAR file name Bonus.jar, and give it BonusJar for the display name.

  • Add the JAR file to the application now.

  • In the Local Applications window, select BonusApp. In the Inspecting window, select JNDI names, give BonusBean the JNDI name of bonus, and press the Return key.
Before the J2EE application can be deployed, you need to specify deployment settings for the entity Bean and generate the SQL. Here is how to do it:
  • In the Local Applications window, select BonusBean.

  • In the Inspecting window, select Entity, and click the Deployment Settings button to the lower right.

  • In the Deployment Settings window, specify jdbc/Cloudscape (with a capital C on Cloudscape) for the Database JNDI name, make sure the Create table on deploy and Delete table on Deploy boxes are checked, and click Generate SQL now.
  • When the SQL generation completes, select the findByPrimaryKey method in the EJB method box. To the right a SQL statement appears. It should read SELECT "socsec" FROM "BonusBeanTable" WHERE "socsec"=?. The question mark (?) represents the parameter passed to the findByPrimaryKey method.

  • Click OK.

Verify and Deploy the J2EE Application

Normally you would verify the J2EE application before deploying it as was done in Lesson 1. But this Beta release has bugs that cause the verification of a container-managed entity Bean to generate false errors. So, rather than confuse things by verifying the application and getting a lot of errors on the entity Bean that you do not have to worry about, the next step is to deploy the application.
  • Select Tools.Deploy Application from the menus at the top. If you did not uninstall the application first, you are prompted to do it now.

  • Step 1: Click Next.
  • Step 2: JNDI name for CalcBean is calcs and for BonusBean is bonus. If these do not display, type them in.

  • Step 3: Context root is BonusRoot. If this does not display, type it in.

  • Click Deploy.

Run the J2EE Application

The web server runs on port 8000 by default. To open the bonus.html page point your browser to http://localhost:8000/BonusRoot/bonus.html, which is where the deploy tool put the HTML file.

Fill in a social security number and multiplier, and click the Submit button. BonusServlet processes your data and returns an HTML page with the bonus calculation on it.

Bonus Calculation

Soc Sec passed in: 777777777
Multiplier passed in: 25
Bonus Amount calculated: 2500.0
Soc Sec retrieved: 7777777777
Bonus Amount retrieved: 2500.0
If you go back to bonus.html and change the multiplier to 2, but use the same social security number, you see this:
Bonus Calculation

Soc Sec passed in: 777777777
Multiplier passed in: 2
Bonus Amount calculated: 200.0

RemoteException occurred in server thread; nested 
exception is: java.rmi.RemoteException: ERROR in 
database INSERT ; nested exception is: SQL Exception: 
The statement was aborted because it would have caused 
a duplicate key value in a unique or primary key constraint.

[TOP]


[ This page was updated: 12-Jan-2000 ]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Glossary - Applets - Tutorial - Employment - Business & Licensing - Java Store - Java in the Real World
FAQ | Feedback | Map | A-Z Index
For more information on Java technology
and other software from Sun Microsystems, call:
(800) 786-7638
Outside the U.S. and Canada, dial your country's AT&T Direct Access Number first.
Sun Microsystems, Inc.
Copyright © 1995-2000 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.