Enterprise JavaBeansTM
|
Session Beans | Entity Beans |
---|---|
Fields contain conversaton state. | Represents data in a database. |
Handles database access for client. | Shares access for multiple users. |
Life of client is life of Bean. | Persists as long as data in database. |
Can be transaction aware. | Transactional. |
Does not survive server crashes. | Survives server crashes. |
Note:
In the Enterprise Java Beans specification, EJB Server support for session Beans is mandatory. EJB Server Support for entity Beans is currently optional, but becomes mandatory for version 2.0 of the specification.
Simple Example
A high-level view of the simple example application is shown in the diagram. The client application is a servlet that receives data from and sends data to a browser, and interacts with an entity Bean and a session Bean through their home and remote interfaces. The EJB Home Server handles all the low-level details including the database read and write operations.
You do not need to know how an enterprise Bean is implemented to use it; all you need to know are its methods. You might or might not write your own enterprise Beans to use in an application. It is possible and often desirable to use enterprise Beans written by a provider that you assemble into an application.
Deployment tools and an EJB Home Server are essential to running the application code. The deployment tools generate enterprise Bean containers, which are classes that provide an interface to the low-level implementations in a given EJB Server. The server provider can include containers and deployment tools for their server and will typically publish their low-level interfaces so other vendors can develop containers and deployment tools for their server.
The simple example uses the EJB Server created by EJBHome. Visit this site for a free reference implementation that includes the EJB Server and deployment tools for generating containers. The site also provides tutorials to walk you through example programs that come with the download.
Source Code
The source code files for the example are listed below. The example program requires a
database table named bonus
with the following fields:
CREATE TABLE BONUS SOCSEC Integer, BONUS Real, primary key (SOCSEC)
The source code follows naming conventions so the EJB Home Server can find the application classes, containers, and database table. For example with The source for a given enterprise Bean, the enterprise Bean, home interface, and primary key class names use the remote interface name as a prefix.
Other naming conventions are used within the source code and discussed below where they appear. While source file-naming conventions are standard across EJB Server implementations, naming conventions used within the source are specific to the EJB Server or deployment tool you use.
BonusServlet.java
. getBonus
getSocSec
addBonus
create
findByPrimaryKey
int bonus
int socsec
getBonus
getSocSec
addBonus
ejbCreate
BonusPK.java
, primary key with these fields and methods: socsec
BonusPK
Calc.java
, the remote interface with this method: calcBonus
CalcHome.java
, the home interface with this method: create
CalcBean.java
, an enterprise Bean with these public fields and methods: int bonus
int calcBonus
ejbCreate
When the entity and session Beans are deployed, a number of container source and class files are generated with the following prefixes. A container is a set of classes generated by the deployment tool that manages an enterprise Bean's persistence, transactional properties, and security.
The thin-client BonusServlet.java declares variables and parameter values of specific types to locate the database table, create the home interface, and invoke the entity and session Bean methods.
Note:
To keep the code simple, data values that the servlet would normally receive from user input to a browser form is hard coded.
These are the import and declarations statements. The entity Bean remote interface type
is Bonus
and maps to the database table name, which is also Bonus
.
The socsec
and bonus
variables map to the fields in the database
table. Variable names that map to the database table or fields in the database are case
insensitive.
import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.Properties; import javax.naming.*; //location of Bean classes import com.ejbhome.examples.*; public class BonusServlet extends HttpServlet { //Entity Bean home and remote interface variables BonusHome homebonus; Bonus theBonus, rec1; //Session Bean home and remote interface variables CalcHome homecalc; Calc theCalculation; int socsec = 0, retsocsec = 0; int bonus = 0, retbonus = 0;
The EJB Home Server uses the beans.properties
configuration file to map enterprise Beans to the home interfaces for their respective
container classes. Here is how the mapping looks. The container classes are not created
until the Beans are deployed, but you can put the entry into this file before you deploy
because the naming convention is consistent. The values calcs
and bonuses
are used in the next code segment for the enterprise Bean lookup. The values in this file
and the strings used in the code have to match exactly so the EJB Home Server can look up
the enterprise Bean home interface.
calcs=com.ejbhome.examples.EJBHomeCalcHome bonuses=com.ejbhome.examples.EJBHomeBonusHome
Here is the servlet init
method
implementation. The JNDI API
is used to look up the Beans and containers.
public void init(ServletConfig config) throws ServletException{ try{ Properties env = new Properties(); env.put("java.naming.factory.initial", "com.ejbhome.naming.spi.rmi.RMIInitCtxFactory"); Context ctx = new InitialContext(env); //Look up home interfaces and containers //for entity and session beans. //Strings map to settings in the beans.properties file. homebonus = (BonusHome)ctx.lookup("bonuses"); homecalc = (CalcHome)ctx.lookup("calcs"); } catch (Exception NamingException) { NamingException.printStackTrace(); } }
In the next code segement, the socsec
and bonus
variables are initialized with values that would normally come from
user input to a form in the browser. These values are used to create the entity Bean home
interface and two records in the Bonus
table. After each record is created,
its data is retrieved from the database and displayed in the browser. For simplicity, the
code to display the data in the browser is not included in the segment, but here is the
entire source file for the BonusServlet.java servlet.
try{ socsec = 555220000; bonus = 200; for(int i = 1; i <3; i++){ //Use the entity Bean home interface to create a record theBonus="homebonus.create(socsec," bonus); //Get the data from the record and display it in the browser retbonus="theBonus.getBonus();" retsocsec="theBonus.getSocSec();" socsec +="1;" } } catch (Exception CreateException) { CreateException.printStackTrace(); }This next code segment uses the primary key class to retrieve a record from the database, and uses the home interface to retrieve the data in the record fields. For simplicity, the code to display the retrieved data in the browser is not included in the segment, but here is the entire source file for the BonusServlet.java servlet.
try{ //Instantiate a primary key object BonusPK PK = new BonusPK(555220000); //Locate a record with the primary key rec1 = hmebonus.findByPrimaryKey(PK); //Use the entity Bean home interface //to retrieve current bonus value retbonus = rec1.getBonus();
This next code segment creates the session
Bean's home interface, and uses the home interface to call the session Bean's calcBonus
method. The hard-coded values passed to the calcBonus
method would normally
be received by user input to a form in the browser. For simplicity, the code to display
the final bonus in the browser is not included in the segment, but here is the entire
source file for the BonusServlet.java servlet.
//Calculate bonus int base = 100; int perf=5, company=2; theCalculation = homecalc.create(); int calc = theCalculation.calcBonus( base, perf, company); System.out.println(calc); rec1.addBonus(calc); retbonus = rec1.getBonus(); } catch (Exception FinderException) { FinderException.printStackTrace(); }
The thin-client servlet produces the following output. Of course, you need the entity and session Beans compiled and deployed before the application will actually work. The next sections describe the source files for the enterprise Beans and enterprise Bean deployment.
Record 1
Soc Sec: 555220000
Bonus Total: 200
Record 2
Soc Sec: 555220001
Bonus Total: 200
Calculate Bonus for 555220000
Bonus Before: 200
Bonus After: 1200
The example entity Bean represents a row in the Bonus
table. At runtime,
there can be any number of simultaneous entity Bean instantiations to represent different
rows in the table. The thin-client servlet instantiates two entity Beans to create the two
rows in the Bonus
table.
socsec (Primary Key) | bonus |
---|---|
555220000 | 200 |
555220001 | 200 |
However, the thin-client servlet does not work directly with the entity Bean to create
rows or access data, but creates an instance of the home
interface. The home interface extends EJBHome
and has methods that define
how the entity Bean is created and located in its container. It also follows the rules of
the Remote Method Invocation (RMI) API in that the arguments and return types for each
method must be serializable and the methods should throw java.rmi.RemoteException
as one of its exception.
package com.ejbhome.examples; import javax.ejb.*; import java.rmi.*; public interface BonusHome extends EJBHome { Bonus create(int bonus, int socsec) throws CreateException, RemoteException; Bonus findByPrimaryKey(BonusPK socsec) throws FinderException, RemoteException; }
When the home interface is instantiated, the EJB
Home Server also creates the remote interface and enterprise Bean instances. Here is the remote interface. It extends EJBObject
and declares the
BonusBean
methods. It also follows the rules of the RMI API in that the
arguments and return types for each method must be serializable and the methods should
throw java.rmi.RemoteException
as one of its exception.
package com.ejbhome.examples; import javax.ejb.*; import java.rmi.*; public interface Bonus extends EJBObject { int getBonus() throws RemoteException; int getSocSec() throws RemoteException; void addBonus(int bonus ) throws RemoteException; }
The EJBHome server requires a container-managed entity Bean to have a primary key class with a public primary key field (or fields, if using composite primary keys). You can have the container manage an enterprise Bean or write the code to manage the Bean yourself. In this example, both Beans are container-managed, and you should always let the container manage an entity Bean.
Here is the primary key class. The primary key in the Bonus
table is socsec
,
and so socsec
is a public field in this class that is assigned a value when
the class is constructed.
package com.ejbhome.examples; public class BonusPK implements java.io.Serializable { public int socsec; public BonusPK(int socsec) { this.socsec = socsec; } public BonusPK() {} }
Now for a look at the entity
bean source code. It implements EntityBean
and the developer-defined and
interface methods. It should follow the rules of the RMI API in that the arguments and
return types for each method must be serializable and the methods should throw java.rmi.RemoteException
as one of its exception.
package com.ejbhome.examples; import java.rmi.RemoteException; import javax.ejb.*; public class BonusBean implements EntityBean { public int bonus = 0; public int socsec = 0; protected EntityContext ctx; public int getBonus() throws RemoteException { return bonus; } public int getSocSec() throws RemoteException { return socsec; } public void addBonus(int bonus) throws RemoteException { this.bonus += bonus; } public void ejbCreate(int socsec, int bonus) throws CreateException, RemoteException { this.socsec=socsec; this.bonus=bonus; } // Other interface methods public void setEntityContext(javax.ejb.EntityContext ctx) throws RemoteException { this.ctx = ctx; } public void unsetEntityContext() throws RemoteException { ctx = null; } public void ejbRemove() throws RemoteException, RemoveException { } public void ejbActivate() throws RemoteException { } public void ejbPassivate() throws RemoteException { } public void ejbLoad() throws RemoteException { } public void ejbStore() throws RemoteException { } }
The session Bean performs a simple calculation. Its source code is similar to the entity Bean source code with the few differences described here.
The home interface does not have a FindByPrimaryKey
method because no database access is involved. A session Bean could perform database
access, and would then need a FindByPrimaryKey
method, but the simple example
does not need it.
package com.ejbhome.examples; import javax.ejb.*; import java.rmi.*; public interface CalcHome extends EJBHome { Calc create() throws CreateException, RemoteException; }
The remote interface declares the session Bean's one method.
package com.ejbhome.examples; import javax.ejb.*; import java.rmi.*; public interface Calc extends EJBObject { int calcBonus(int base, int perf, int company) throws RemoteException; }
The session Bean
implements SessionBean
and the developer-defined and interface methods.
package com.ejbhome.examples; import java.rmi.RemoteException; import javax.ejb.*; public class CalcBean implements SessionBean throws Remote Exception { public int bonus; protected SessionContext ctx; public int calcBonus(int base, int perf, int company) { int calc = (base*perf*company); this.bonus += calc; return this.bonus; } public void ejbCreate() throws CreateException, RemoteException {} // Other interface methods public void setSessionContext(javax.ejb.SessionContext ctx) throws RemoteException { this.ctx = ctx; } public void ejbRemove() throws RemoteException { } public void ejbActivate() throws RemoteException { } public void ejbPassivate() throws RemoteException { } public void ejbLoad() throws RemoteException { } public void ejbStore() throws RemoteException { } }
The Deployer tool generates these container classes for BonusBean
and CalcBean
.
BonusBean | CalcBean |
---|---|
EJBHomeBonusBean.class EJBHomeBonusBean.java EJBHomeBonusHome.class EJBHomeBonusHome.java EJBHomeBonusHome_Skel.class EJBHomeBonusHome_Skel.java EJBHomeBonusHome_Stub.class EJBHomeBonusHome_Stub.java EJBHomeBonusMetaData.class EJBHomeBonusMetaData.java EJBHomeRemoteBonus.class EJBHomeRemoteBonus.java EJBHomeRemoteBonus_Skel.class EJBHomeRemoteBonus_Skel.java EJBHomeRemoteBonus_Stub.class EJBHomeRemoteBonus_Stub.java | EJBHomeCalcBean.class EJBHomeCalcBean.java EJBHomeCalcHome.class EJBHomeCalcHome.java EJBHomeCalcHome_Skel.class EJBHomeCalcHome_Skel.java EJBHomeCalcHome_Stub.class EJBHomeCalcHome_Stub.java EJBHomeCalcMetaData.class EJBHomeCalcMetaData.java EJBHomeRemoteCalc.class EJBHomeRemoteCalc.java EJBHomeRemoteCalc_Skel.class EJBHomeRemoteCalc_Skel.java EJBHomeRemoteCalc_Stub.class EJBHomeRemoteCalc_Stub.java |
Conclusion
If you want to develop thin-client multitiered applications for the net, Enterprise JavaBeans is the way to go. You can write business applications with reusable and modular enterprise Beans and leave the system-level programming to the underlying architecture. You will not be alone--the Enterprise JavaBeans architecture has been adopted, supported, and put on the product roadmaps of more than 25 companies.
Here are links to additional information on Enterprise JavaBeans.
Monica Pawlan is a staff writer on the JDC team. She has a background in 2D and 3D graphics, security, database products, and loves to explore emerging technologies.
monica.pawlan@eng.sun.com