Chapter 22:Container -Managed Persistence
-551 -
* @author: Andrew Yang
* @version: 1.0
*/
package java_database.YachtEBean;
import java.rmi.*;
import java.util.*;
import javax.ejb.*;
public interface YachtHome extends EJBHome {
public Yacht create(String yachtName, String builder, String
engineType,
int capacity, int maxVelocity)
throws CreateException, RemoteException;
public Yacht findByPrimaryKey(String yachtName)
throws FinderException, RemoteException;
public Collection findAllYachts()
throws FinderException, RemoteException;
public Collection findYachtsCapacityMoreThan(int minCapacity)
throws FinderException, RemoteException;
}
Listing 22-2: Remote interface of YachtEJB
/** YachtEJB Remote Interface. CMP is used.
* @author: Andrew Yang
* @version: 1.0
*/
package java_database.YachtEBean;
public-instance variables. Instead, they are identified through specialized getters and setters that
you must write.
For example, you have to write getYachtName, setBuilder, and so on in the YachtEJB
implementation class. What is intriguing is that these methods are declared as abstract and are
implemented automatically by the EJB container during the deployment phase. That makes the
implementation class also abstract; thus, no instance can be instantiated directly for the implementation
class. The EJB container uses the information you provide in the deployment descriptor to automatically
generate a concrete class with all the database-access implementations. The objects of these
container-generated, concrete classes are used at runtime for clients' invocation. The implementation
class of the example YachtEJB is shown in Listing 22-3.
Listing 22-3: Implementation class of YachtEJB
/** YachtEJB Implementation Class. CMP is used.
* @author: Andrew Yang
* @version: 1.0
*/
package java_database.YachtEBean;
import java.rmi.*;
import java.util.*;
import java.sql.*;
import javax.ejb.*;
import javax.naming.*;
import common.*;
import YachtSessionSFBean.*;
public abstract class YachtBean implements EntityBean {
private EntityContext context;
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
public String ejbCreate(String yachtName, String builder, String
engineType,
int capacity, int maxVelocity)
throws CreateException {
// You have to call accessor methods here.
setYachtName(yachtName);
setBuilder(builder);
setEngineType(engineType);
setCapacity(capacity);
setMaxVelocity(maxVelocity);
// If int values passed in are zero, pull the value from the constant
file.
if(capacity <= 0) { setCapacity(YachtConstants.CAPACITY); }
if(maxVelocity <= 0) { setMaxVelocity(YachtConstants.MAX_VELOCITY); }
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-554 -
// Always return null
return null;
}
public void ejbPostCreate(String yachtName, String builder, String
engineType,
int capacity, int maxVelocity) {
// nothing to code
}
// Business Methods
public YachtSession createYachtSession() {
Do not use a text editor to write a deployment descriptor. Use the deployment tool
provided by your application server.
Listing 22-4: Deployment descriptor for YachtEJB
# First DD File – J2EE Standard
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-555-
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise
JavaBeans 2.0//EN"
"
<ejb-jar>
<enterprise-beans>
<entity>
<ejb-name>YachtEJB</ejb-name>
<home>YachtEBean.YachtHome</home>
<remote>YachtEBean.Yacht</remote>
<ejb-class>YachtEBean.YachtBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>YachtBean</abstract-schema-name>
<primkey-field>yachtName</primkey-field>
<cmp-field><field-name>builder</field-name></cmp-field>
<cmp-field><field-name>engineType</field-name></cmp-field>
<cmp-field><field-name>capacity</field-name></cmp-field>
<cmp-field><field-name>maxVelocity</field-name></cmp-field>
<ejb-ref>
<description>The YachtEJB does a lookup for YachtSession
<description>The group of users allowed to access
YachtEJBs.</description>
<role-name>ValidYachtClubUsers</role-name>
</security-role>
<container-transaction>
<method>
<ejb-name>YachtEJB</ejb-name>
<method-intf>Remote</method-intf>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
# Second DD File – Weblogic Specific
<!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 6.0.0
EJB//EN'
'
<weblogic-ejb-jar>
<weblogic-enterprise-bean>
<ejb-name>YachtEJB</ejb-name>
<entity-descriptor>
<entity-cache>
<max-beans-in-cache>150</max-beans-in-cache>
</entity-cache>
<persistence>
<persistence-type>
<type-identifier>WebLogic_CMP_RDBMS</type-identifier>
<type-version>6.0</type-version>
<weblogic-rdbms-jar>
<weblogic-rdbms-bean>
<ejb-name>YachtEJB</ejb-name>
<data-source-name>yachtClub-datasource</data-source-name>
<table-name>yacht</table-name>
<field-map>
<cmp-field>yachtName</cmp-field>
<dbms-column>yacht_name</dbms-column>
</field-map>
<field-map>
<cmp-field>builder</cmp-field>
<dbms-column>builder</dbms-column>
</field-map>
<field-map>
<cmp-field>engineType</cmp-field>
<dbms-column>engine_type</dbms-column>
</field-map>
<field-map>
<cmp-field>capacity</cmp-field>
<dbms-column>capacity</dbms-column>
</field-map>
<field-map>
<cmp-field>maxVelocity</cmp-field>
<dbms-column>max_velocity</dbms-column>
</field-map>
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-558-
</weblogic-rdbms-bean>
</weblogic-rdbms-jar>
<dbms-column>yacht_name</dbms-column>
</field-map>
<field-map>
<cmp-field>builder</cmp-field>
<dbms-column>builder</dbms-column>
</field-map>
… …
Such information tells the EJB container to implement the access calls for these persistent fields. Based
on the deployment information, the EJB container determines the approperate JDBC implementations
(that is, the SQL calls) for the persistent fields and keeps a CMP bean's persistent field synchronized
with the state of the database record it represents. After the concrete classes are generated during the
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-559 -
deployment phase, the life cycle of these CMP bean instances are same as that of BMP instances
discussed in the previous Chapter 21.
For each create method defined in the home interface, you need to write a corresponding ejbCreate
method. As a bean developer, your job is to assign the persistent fields with their initial values by calling
the setters. You may find something weird by looking at the implementation shown in Listing 21-3.
Although the return type is supposed to be the primary key, the ejbCreate method actually returns
null at the end of the code. This is required by EJB specification. The rationale is that this method will
only be called by the EJB container and that the container always knows exactly what the primary key is
for each EJB.
Note
For a BMP bean, you must write code for the ejbRemove method. For a CMP bean,
since the database-access logic is implemented by the EJB container, you typically do
not need to write any code.
In the code shown in Listing 22-3, you do not see even the empty implementation of any finder
method defined in the home interface. How does the EJB container generate the implementation for
Coded by developers
Select Methods (??) Handled by EJB container None
Return type of ejbCreate
method
null Primary key
With CM entity bean, no database code is needed. The database access functionality is specified by
EJB developers or application assemblers in description descriptor in EJB Query language that is
discussed next.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-560-
EJB Query Language
The EJB Query Language (EJB QL) is used to define query methods (for example, finder and
select methods) for CMP entity beans. EJB QL, which is based on SQL-92, can be compiled
automatically by the EJB container to a target language, such as SQL, of a database or other types of
persistent stores. This makes CMP entity beans more portable and much easier to deploy.
An EJB QL query has these three clauses:
§ SELECT
§ FROM
§ WHERE
The SELECT and FROM clauses are required, but the WHERE clause is optional. Here is the high-level
BNF syntax of an EJB QL query:
EJB QL :: = select_clause from_clause [where_clause]
The SELECT clause defines the types of the objects or values that the query returns. A return type is a
remote interface, a local interface, or a persistent field.
The FROM clause defines the scope of the query by declaring one or more identification variables, which
may be referenced in the SELECT and WHERE clauses. An identification variable represents one of the
following elements:
§ The abstract schema name of an entity bean
The parameter_1 is passed into the statement at runtime.
In addition to finder methods, you can use EJB QL to do any number of querying activities. EJB QL
allows you to do simple queries; compound queries; queries that invoke the persistent fields of more
than one EJB; queries that use finder methods on other EJBs; and queries that use persistent fields
accessible through a relationship to other EJBs. In other words, EJB QL is a very powerful tool.
However, it has also the following restrictions:
§ Comments are not allowed.
§ Date and time values are in milliseconds and use Java long data type. A date or time literal
should be an integer literal. To generate a millisecond value, you may use the
java.util.Calendar class.
§ Currently, CMP does not support inheritance. For this reason, two entity beans of different types
cannot be compared.
Note
This section covers only the simplified syntax of EJB QL. The full syntax is beyond the
scope of this book. Interested readers can find a detailed description on EJB QL in
many EJB books.
By now you have learnt how to develop and deploy CMP EJBs. Let us move on to run the example
application.
Running the Example Application
Remember the yacht club application discussed first in Chapter 20? It is uses by a yacht club to
manage its yacht-cruise operation. As a treat, the club offers its member free yacht cruises. The
business process includes the following:
§ Operating the yacht — such as starting, stoping, speeding up and slowing down
§ Checking the status of the yacht — such as current velocity, maximum velocity, current passenger
on board, and so on
§ Picking up club members if there is enough room
§ Dropping off passengers
Over the last three chapters, you have built these three EJBs:
String builder = request.getParameter("Builder");
if (builder == null) {
builder = "Unknown";
}
String engineType = request.getParameter("EngineType");
if (engineType == null) {
engineType = "Unknown";
}
int capacity = 0;
int maxVelocity = 0;
try {
capacity = Integer.parseInt(request.getParameter("Capacity"));
} catch (Exception e) {
capacity = 10;
}
try {
maxVelocity = Integer.parseInt(request.getParameter("MaxVelocity"));
} catch (Exception e) {
maxVelocity = 25;
}
// finally create the Yacht
try {
Yacht yacht = (Yacht) home.create(yachtName, builder, engineType,
capacity,
maxVelocity);
} catch (CreateException e) {
log("CreateException caught while trying to create a new yacht." +
e, out);
}
}
(String)yacht.getPrimaryKey() %>&Action=View>View
Session</a></td>
<td width="25%"><a href=YachtManager.jsp?DestroyYacht=<%=
(String)yacht.getPrimaryKey() %>>Destroy</a></td></tr>
<%
}
%>
</table>
<%
}
%>
<FORM action=YachtManager.jsp>
<b>Create a New Yacht:</b><BR>
<table>
<tr><td>Yacht Name:</td>
<td><INPUT TYPE=TEXT NAME=YachtName></td>
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-564-
<td>Builder:</td>
<td><INPUT TYPE=TEXT NAME=Builder></td></tr>
<tr><td>Engine Type:</td>
<td><INPUT TYPE=TEXT NAME=EngineType></td>
<td>Capacity:</td>
<td><INPUT TYPE=TEXT NAME=Capacity></td></tr>
<tr><td>Maximum Velocity:</td>
<td><INPUT TYPE=TEXT NAME=MaxVelocity></td>
<td></td>
<td>><INPUT TYPE=SUBMIT NAME="CreateNewYacht"
"Destroy," the corresponding yacht is removed from the database. When adding a new yacht, you need
to provide the five persistent attributes of the yacht, namely, yacht name, its builder, the engine type,
capacity, and maximum velocity. An output screen for running this JSP client is illustrated in Figure 22-1.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-565-
Figure 22-1: Output of ManageYacht client
By clicking the hyperlink marked "View Session," you should be able to view the session associated
with this yacht (that is, whether it is in an active cruise operation, the current status such as velocity and
passenger list, and so on). From the code in Listing 22-5, you can see that clicking the View Session
hyperlink sends a request to another JSP client: YachtSessionjManager. jsp, as shown here:
<a href=YachtSessionManager.jsp?YachtPK=<%= (String)yacht.getPrimaryKey() %>
&Action=View>View Session</a>
The code for YachtSessionjManager.jsp is not provided here, and I do it on purpose. By now you
should be able to write your own client to use these EJBs to meet your own needs. You have learned all
the skills you need to access these EJBs from your own client. Do this as an exercise!
Your yacht-session-management client should allow a user to check whether a cruise session is active.
If no active session is associated with the yacht the user has selected, the user should be prompt to
create a session. Once a cruise session is created (or retrieved), the user should be able to operate the
cruising yacht. That means the user is able to start, stop, accelerate and decelerate the yacht, check the
yacht status, drop off passengers, pick up members, and so on.
Because only members can come on board, you do need the help of MemberEJB to implement the
preceding functionality. You can write a JSP client, a Swing client, or a stand-along client. If you decide
to use the JSP client, you may be able to take advantage of the functionality provided by the
HttpSession interface. For example, once a YachtSessionEJB instance session is created, you can
save it to HttpSession as follows:
session.setAttribute(yachtPrimaryKey, theYachtSession);
When a user wants to view the YachtSessionEJB instance for a specific yacht, you just need to
retrieve it as follows:
simple and complex relationships by introducing the container-managed relationship through the
relationship fields.
Relationship Field
A relationship field is like a foreign key in a database table — it identifies a related bean. Like a
persistent field, a relationship field is virtual and is defined in the enterprise-bean class with access
methods. But unlike a persistent field, a relationship field does not represent the bean's state. For
example, each yacht has an engine. Assume an EngineEJB is developed; it has a one-to-one
relationship with the YachtEJB you have written. To model YachtEJB's relationship to EngineEJB, it
has a relationship field: engine. In the deployment descriptor, you specify this relationship as follows:
<ejb-relation>
<ejb-relation-name>Yacht-Engine</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>Yacht-Has-Engine</ejb-relationship-role-
name>
<multiplicity>one</multiplicity>
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-567-
<role-source>
<ejb-name>YachtEJB</ejb-name>
</role-source>
<cmr-field>
<cmr-field-name>engine</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>Engine-In-Yacht</ejb-relationship-role-
name>
<multiplicity>one</multiplicity>
<role-source>
example, in college, each course has many students, and every student may take several courses.
Therefore, in an enrollment application, CourseEJB and StudentEJB have a many-to-many
relationship.
The direction of a relationship may be either bidirectional or unidirectional. In a bidirectional relationship,
each entity bean has a relationship field that refers to the other bean. Through the relationship field, an
entity bean's code can access its related object. If an entity bean has a relative field, we often say that it
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 22:Container -Managed Persistence
-568-
"knows" about its related object. For example, if CourseEJB knows which StudentEJB instances it
has and, at the same time, StudentEJB knows which CourseEJB it is associated with, they have a
bidirectional relationship.
In a unidirectional relationship, only one entity bean has a relationship field that refers to the other. Look
at the snipet of the deployment descriptor given on the previous page; YachtEJB has a relationship
field that identifies EngineEJB, but EngineEJB does not have a relationship field for YachtEJB. In
other words, YachtEJB knows about EngineEJB, but EngineEJB doesn't know which YachtEJB
instances refer to it.
EJB QL queries often navigate across relationships. The direction of a relationship determines whether
a query can navigate from one bean to another. For example, a query can navigate from YachtEJB to
EngineEJB but cannot navigate in the opposite direction. For CourseEJB and StudentEJB, a query
can navigate in both directions, since these two beans have a bidirectional relationship.
Access to Relationship Field
During development, you implement the relationship fields in a similar way to persistent fields. They are
defined in the deployment descriptor, and they have their getters and setters defined in the bean-
implementation class. They can even be exposed in the remote interface. By following a strict syntax for
authoring relationship fields in the bean-implementation class and in the deployment descriptor, the EJB
container is able to implement the relationship automatically behind the scene.
The rules for writing relationship-field accessor methods in a bean-implementation class are listed
here:
§ Both getters and setters for every relationship field must exist in the implementation class.
Collection. This tells the EJB container that you really need to get the whole list and that it is not the
container's responsibility to ensure good performance.
The ejbPostCreate method in Listing 22-3 is empty. However, if there are any relationship fields, you
must put these fields' initialization code in this method. Although all the persistent fields must be set in
the ejbCreate method, it is important to not set any relationship fields in the ejbCreate methods.
When ejbCreate is called, the bean has not yet been inserted into the underlying database. When
calling a setter method, the other EJB in the relationship also tries to update its references in the
related fields. This is not possible, since the EJB that is having ejbCreate method invoked has not yet
been created. You should initialize the relationship fields in the ejbPostCreate method.
Thus, if the YachtEJB is related to EngineEJB, the ejbPostCreate method may look like this:
public void ejbPostCreate(String yachtName, String builder, String
engineType,
int capacity, int maxVelocity, Engine engine) {
// initialize relationship field
setEngine(null);
}
In summary, implement relationships differently for BMP entity beans and CMP entity beans. With BMP,
the code you write implements the relationships. But with CMP, the EJB container takes care of the
relationships for you. Most information of the relationships is given in the deployment descriptor. A bean
developer needs to write very little code for the simple abstract getters and setters and some
initialization in the ejbPostCreate method. All these features make the CMP entity bean more
appealing because they are easier to develop and more flexible.
Summary
In this chapter, you learn how CMP entity beans handle the data persistence and object relationship.
Specifically, you learned:
§ The differences between CMP and BMP
§ How to achieve persistence through persistent fields
§ How to handle entity relationship through relationship fields
§ How to specify database access in EJB query language
databases, file systems, and so on)
§ Simplifying secure and scalable applications by providing developers with a Java-centric
mechanism for working with persistent data
Although lower-level abstractions for interacting with databases are still useful, the goal of JDO is to
reduce the need for explicit code for SQL and transaction handling in common business applications.
In addition to shielding the Java developers from the details of the underlying methods for providing
persistence, JDO acts as a standard layer between the application program and any back-end data
stores, whether it be a relational database, an XML database, a legacy application, a file system, or
flash RAM. Applications using the JDO interface can automatically plug in any data store that provides a
JDO implementation. This generally provides portability and increases the longevity of code.
JDO has come a long way to get here. It originated from Java Specification Request (JSR-012),
proposed in 1999. After three years of lengthy Java community process, it was finally approved as an
official specification in March 2002. In the meantime, many other requested specifications have become
standards, and the JDO work force has been dealing with the fact that JDO is able to be integrated into
the frameworks provided by these related specifications (mostly notably J2EE). Indeed, servlets and
session EJBs can directly manipulate JDO persistent instances instead of dealing with the underlying
data stores. Entity EJBs with bean-managed persistence can delegate business logic and persistence
management to JDO classes instead of forcing the developers writing all SQL commands in the
implementation classes. Integration of JDO with J2EE is discussed later in this chapter. First let us see
what makes JDO different from other data persistence mechanisms.
What Makes JDO an Unique Persistence Mechanism
In most cases, instances of Java classes reside in the memory of the running application. They are
destroyed when the program terminates. However, it is often desirable for the objects to persist even
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.