This material is from the book JBuilder Developer’s Guide , written by Saleem Siddiqui, Michael Landy, and Jeff Swisher, published by Sams Publishing.
© Copyright Sams Publishing. All rights reserved.
Using entity beans is a practice that many users of application servers
do not want to venture into. Part of this is due to the lack of understanding;
the other part is due to the lack of capabilities in earlier versions
of the EJB specification. As we look at entity beans, keep in mind two
important considerations when designing the architecture:
-
Using local interfaces versus remote interfaces
-
Container managed persistence versus bean managed persistence
Use the Local Interface
When accessing data remotely, the result of the data has to be moved
from one location to another, thus, data has to be serialized. This
process of serialization is expensive. In other words, the latency of
serializing data, sending it over the wire, and rematerializing the
data on the client can be time consuming. With the introduction of EJB
2.0 specification, the capability to call and communicate to an entity
bean with a local interface was defined.
Inspiration
The inspiration of local interfaces is specifically to address the
performance issues related to serializing data. With the use of session
façades or the use of value objects, the need for network ubiquity
and serializing data has become less important. Without the need for
serialized data, an alternative was needed. This alternative is to pass
data by reference rather than value. In other words, instead of copying/
serializing the data, a reference to the data is passed.
Inner Workings
The inner workings of this change in the design are rather simple.
If the entity bean runs within the same process, you can access the
entity bean using its local interface and pass all data by reference
rather than value. There is a drawback to using this method of communication:
You lose the concept of network ubiquity. In other words, the client
needs to know the location of the bean you want to use, but you gain
what was lost in higher performance throughput.
Use CMP Before BMP
When I first started to use J2EE servers, the idea of letting the container
manage all the persistence for me seemed unsettling. So I found myself
developing persistence code. The process was neither desirable nor ultimately
a good, efficient process for developing large-scale applications. I
was developing huge portions of code that did nothing other than save,
read, and remove instances of data. They were virtually identical except
for the details of the SQL statements and member attributes.
Inspiration
With the changes in the EJB specification from 1.1 to 2.0, container
managed persistence became all the more important and powerful. Without
these necessary changes to the specifications, many developers found
that most uses of CMP were limited to simple persistence.
Inner Workings
Container managed persistence supports most of the persistence requirements
that any enterprise application needs. Using the container for accomplishing
these tasks is not only quicker to develop, but the performance is usually
better. If those two reasons are not enough, container managed persistence
is by far the most portable of the components within the J2EE architecture.
In Practice
The ChalkTalk application needs the capability to read and save data
to the database structure. We have read and written data to the database
using JDBC; now it is time to accomplish the same task using entity
beans. The process of building the beans is rather simple; most of our
work will be executed in the session facade.
Building the Persistence Layer
The creation of the persistence layer using JBuilder depends on the
appropriate data structure being completed. In Chapter 15, "Database
Connectivity," we created the necessary data store for our application.
We will now create the entity beans to manage this persistence. The
following steps are used to build the necessary entity beans:
-
Import a schema from our data source in the EJB module containing
our session beans. This is accomplished by right-clicking on the
data source node when we are in the EJB Designer and selecting Import
Schema from Datasource. -
Set the following database parameters:
-
Driver: com.borland.datastore.jdbc.DataStoreDriver
-
URL: jdbc:borland:dslocal:C:JBDGdbChalkTalk.jds
-
Username: leave blank
-
Password: leave blank
-
Right-click on each table and create a CMP 2.0 entity bean for
each table. For example, right click on the table Room and create
a CMP 2.0 bean. -
Define relationships.
Configuring an Entity Bean
Typically each entity bean that has been created requires more finder
methods than just a findByPrimaryKey. Our Room entity
bean is a perfect example.
-
Right-click on our Room entity bean. Add a finder method.
-
Configure the following properties for the finder method:
-
Name: findAll
-
Return type: java.util.Collection
-
Input parameters: leave empty
-
Home interfaces: Local Home
-
Query: SELECT OBJECT(o) FROM RoomSchema AS o
-
Compile and save.
Creating an EJB Connection Factory
This factory supplies caching to both local and remote interfaces.
Although this connection factory differentiates between local and remote
interfaces, you have the capability to make this interface ubiquitous.
The following steps build your EJB connection factory:
-
Create a new class within your project, calling it EJBConnectionFactory.
-
Move the newly created class to the package com.sams.chalktalk.beans.
-
Add the following code to implement the connection to both local
and remote beans in addition to placing them into a cache when the
connection has been established: -
Compile and save your project.
package com.sams.chalktalk.beans; import javax.naming.*; import java.util.*; import javax.ejb.*; class EJBHomeFactory { private static EJBHomeFactory instance = null; private Context initialContext; private Map ejbHomes; private EJBHomeFactory() throws NamingException { initialContext = new InitialContext(); ejbHomes = Collections.synchronizedMap(new HashMap()); } public static EJBHomeFactory getInstance() throws NamingException { if(instance == null) { instance = new EJBHomeFactory(); } return instance; } public EJBLocalHome lookupByLocalEJBReference(String ejbReferenceComponent) throws NamingException { java.lang.Object home = ejbHomes.get(ejbReferenceComponent); if(home == null) { home = initialContext.lookup("java:comp/env/ejb/" + ejbReferenceComponent); ejbHomes.put(ejbReferenceComponent, home); } return (EJBLocalHome) home; } public EJBHome lookupByRemoteEJBReference(String ejbReferenceComponent, Class homeClass) throws NamingException { java.lang.Object home = ejbHomes.get(ejbReferenceComponent); if(home == null) { java.lang.Object obj = initialContext.lookup("java:comp/env/ejb/" + ejbReferenceComponent); home = javax.rmi.PortableRemoteObject.narrow(obj, homeClass); ejbHomes.put(ejbReferenceComponent, home); } return (EJBHome) home; } }
Creating a Manager Bean
A manager bean surfaces the business logic and ultimately interfaces
to the persistence utilizing the entity beans. These manager beans will
then be attached to the session facade to consolidate the middle-tier
access. The following steps are required to create one of the manager
beans:
-
Create a new class, naming the class RoomManager and placing
the new class in the package com.sams.chalktalk.beans. -
The following code surfaces the required business logic. The requirements
of the manager class are used to implement all the appropriate business
logic, such as checking to make sure that a room has a capacity.
package com.sams.chalktalk.beans; import javax.naming.*; import javax.ejb.*; import java.util.*; class RoomManager { //Add a home factory for caching the home interfaces private EJBHomeFactory homeFactory; private static RoomManager instance = null; //Use the RoomValueFactory to create private RoomValueFactory roomValueFactory; private RoomManager() throws NamingException { homeFactory = EJBHomeFactory.getInstance(); } public static RoomManager getInstance() throws NamingException { if(instance == null) { instance = new RoomManager(); } return instance; } public String createRoom(RoomValue roomValue) throws FinderException, NamingException { try { RoomHome roomHome = (RoomHome) homeFactory.lookupByLocalEJBReference("Room"); Room room = roomHome.create(roomValue.getLocation(),roomValue. getCapacity(),roomValue.getName(),roomValue.getKey()); return room.getName(); } catch(Exception e) { throw new EJBException(e); } } public void updateRoom(RoomValue roomValue) throws FinderException, NamingException { try { Room room = roomValueFactory.findRoom(roomValue.getKey()); room.setCapacity(roomValue.getCapacity()); } catch(Exception e) { throw new EJBException(e); } } public void removeRoom(Short key) throws FinderException, NamingException { try { Room room = roomValueFactory.findRoom(key); room.remove(); } catch(Exception e) { throw new EJBException(e); } } public void removeAllRooms() throws FinderException, NamingException { try { Collection rooms = roomValueFactory.findAllRooms(); Iterator iterator = rooms.iterator(); Room room = null; while(iterator.hasNext()) { room = (Room) iterator.next(); room.remove(); } } catch(Exception e) { throw new EJBException(e); } } }
Attaching the Session Facade
Our session facade wraps multiple manager beans together into one session
bean. In other words, we will access all functionality for our ChalkTalk
system utilizing this one session bean. The following steps are required
to attach the facade to our manager bean:
-
Define a private member for each type of bean manager you want
to use. For example, the following code defines one for our RoomManager: -
Create an instance of our manager bean within ejbCreate().
The following demonstrates the implementation using our RoomManager: -
Attach the manager bean call to be called from the corresponding
session bean method. If the client calls the createRoom
method of the session bean, it then needs to pass the information
to the manager class. The following code demonstrates such an implementation: -
Compile and save your project.
private RoomManager roomManager;
public void ejbCreate() throws CreateException { try { roomManager = RoomManager.getInstance(); } catch (NamingException ex) { //pass exception to the container throw new EJBException(ex); }
public void createRoom(RoomValue room) { try { roomManager.createRoom(room); } catch (Exception ex) { throw new EJBException(ex); } }
Testing the Implementation
It is time to test the client we created. The easiest way to test the
session facade is to build a client dedicated to testing the interface.
The following steps build a test client to exercise this facade:
-
Select File, New from the JBuilder menu.
-
Within the Object Gallery, under the Enterprise tab, select the
EJB Test Client. -
Specify the following parameters to build our test client:
-
EJB name: ChalkTalkFacade
-
Package: com.sams.chalktalk.client
-
Class name: ChalkTalkFacadeTestClient
-
Generate Method for Testing Remote Interface Calls with Arguments:
Checked -
Generate Logging Messages: Checked
-
Generate Main Functions: Checked
-
Generate Header Comments: Checked
-
Add the following code to the main method to test your
session bean interface: -
Save, compile, and run your test application.
//create a Remote interface client.create(); //Add a room client.addRoom(new RoomData(5,"Small Room",5,"2nd Floor")); //Add with invalid capacity client.addRoom(new RoomData(3,"Error Room",0,"3rd Floor"));
Summary
Using entity beans is a question for design, experience, need, and
implemented technology. Entity beans are designed to handle all the
persistence requirements for most enterprise applications. Entity beans,
like session beans, are designed to be distributed objects with the
following characteristics:
-
Entity beans provide persistence.
-
Entity beans are transactional.
-
Entity beans are multiuser.
-
Entity beans are long-lived.
-
Entity beans survive the life of the container.
The introduction of more advanced container managed persistence and
the other important features added to the EJB specification has made
building and ultimately managing an application much more efficient.
Reflections
-
Should I use container managed or bean managed persistence?
-
Should I design for use with local or remote interfaces?
-
Should entity beans be used to encapsulate nontraditional data
access?
About the Authors
Saleem Siddiqui is a technical architect and trainer with Dunn Solutions Group. He is also a Sun Certified Developer and a Borland Certified JBuilder Instructor. At Dunn, he provides consulting services and business application development.
Michael Landy is Director of Business Applications for Dunn Solutions Group directing the strategic solutions for clients.
Jeff Swisher is a technical manager for the Dunn Solutions Group business applications. He works as a programmer, trainer, architect, and instructional designer. He is a Sun Certified Java Developer and a Borland Certified Instructor in JBuilder.
Source of this material
This material is from Chapter 23: Developing Entity Beans from the book JBuilder Developer’s Guide (ISBN: 0-672-32427-X) written by Saleem Siddiqui, Michael Landy, and Jeff Swisher, published by Sams Publishing. |
To access the full Table of Contents for the book.
Other Chapters from Sams Publishing:
The Java Database Control in BEA Weblogic