V
VRGL
Unregistered / Unconfirmed
GUEST, unregistred user!
Design Pattern V
As we saw in Design Pattern IV, the size of the Entity Bean implementation class
was greatly reduced to just a few lines of code in the ejbCreate(), getData()
and setData() methods irrespective of the number of CMP fields.
The next step is to model the relationship between the Company and Employee
Entity Beans. This is slightly complex and it is recommended that the reader first get
acquainted with the Borland? Programmers Guide for EJB? in the section
pertaining to OR (Object Relational) Mapping and Advanced CMP issues.
Modeling the relationship requires absolutely no code change in the Struct. However
the Entity Bean implementation classes will require minor modifications to reflect
the relationship between the two entities, modifications are required in the
Deployment Descriptor regarding this issue.
As before, the Entity Bean inherits from the Struct.
Code snippet for the Company Entity Bean
public class CompanyBean extends CompanyStruct
implements EntityBean {
EntityContext entityContext;
// CMP for all fields in the CompanyStruct
public java.util.Collection employees;
//one-to-many
//rest of the code including getData() and setData()
public java.util.Collection getEmployees() {
return employees;
}
}
Code snippet for the Employee Entity Bean
public class EmployeeBean extends EmployeeStruct
implements EntityBean {
EntityContext entityContext;
//CMP for all fields in EmployeeStruct EXCEPT
//the comId
public Company company;//remote reference to company
In the above code snippet, the Employee Entity Bean inherits from the
EmployeeStruct. The EmployeeStruct itself has a field comId that
represents the foreign key relationship between an Employee and a Company. While
in all previous design patterns, this field was CMP in the Design Pattern V this field
is omitted from CMP by un-checking it in the Deployment Descriptor. Instead, the
remote reference to the Company Entity Bean is CMP now.
Now the problem that arises is how to update the reference to the Company entity
bean in the getData() and setData() methods as these methods get and set
the values for the comId field only, which in this design pattern context is not
container managed. In short, the Struct of course has not changed and field comId
(not CMP anymore) is copied to and from the Entity Bean during RPCs. What is
required is that the remote reference to the Company Entity Bean be updated when
data has to be written to the database or read from the database. We shall use the
ejbLoad() and ejbStore() methods in the Entity Bean implementation class
to perform this action for us.
Code snippet for the ejbLoad() method in the Employee Entity Bean
public void ejbLoad() {
try {
comId=(company ==
null)?nullInteger)company.getPrimaryKey();
} catch (Exception e) {
//throw some runtime exception (e.g. EJBException)
}
}
The above code hardly needs explaining. When data is read from the database (at the
start of a transaction), the comId (not CMP) field in the Employee Entity Bean is
set. Thus when the getData() method is called, the Struct returned will contain
the correct value for the comId field.
Code snippet for the ejbStore() method in the Employee Entity Bean
public void ejbStore() {
try {
company = (comId ==
null)?null:beanGlossary.getCompanyHome().findByPrimary
Key(comId);
} catch (Exception e) {
//throw some runtime exception (e.g. EJBException)
}
}
The ejbStore() is called at the end of the transaction when data is to be written
to the database. In this case, the value comId may have been modified (by a call to
the setData() method) and this has to be written to the database. The code in
the above method converts the comId to the remote reference Company. (After all
comId is the primary key of the Company Entity Bean).
The reason for the null check is that the database could hold null values (weak
references between tables), and these have to be modeled as well. In any case, it is
better to use the Java? wrappers for the basic types instead of the basic types
themselves, because of their ability to hold null values and be easily converted to
other formats.
The BeanGlossary class in the above code snippet might cause some confusion.
This is actually a utility class (a stateless session bean) that caches lookups of EJBs.
In the case of entity beans and stateful session beans, the lookup of the Home
Interface is cached. In the case of stateless session beans, the Remote Interface is
cached (as per the EJB? specification 1.1, the create() called on the Home
Interface of a SLSB is a no-op).
By caching in the above context, we mean that only on the first request is the lookup
done. Subsequent calls to get the home interface or the remote interface return the
already initialized object reference.
Code snippet for the BeanGlossarySB utility class
public class BeanGlossarySB implements SessionBean {
private Context context = null;
public javax.naming.Context getContext() throws
NamingException {
if (context == null)
context = new javax.naming.InitialContext();
return context;
}
// Company
private CompanyHome companyHome = null;
public CompanyHome getCompanyHome() throws
NamingException {
if (companyHome == null)
companyHome = ((CompanyHome)
javax.rmi.PortableRemoteObject.narrow(
getContext().lookup("java:comp/env/ejb/Company"),
CompanyHome.class));
return companyHome;
}
// rest of the EJBs
}
In Design Pattern V we have not dealt with the Home Interfaces of the Entity Bean.
In the case of the Employee Entity bean, there would be a finder element along the
lines of findEmployeesByCompany(Company pCompany). This would
return a Collection of Employee remote references. The Deployment
Descriptor in the Company Entity Bean maps the Collection of Employees
defined to the finder element above.
Thus a call on the Company Entity Bean’s method getEmployees() in the
remote interface returns the required Collection of Employee Remote
References that are associated with that particular company.
As we saw in Design Pattern IV, the size of the Entity Bean implementation class
was greatly reduced to just a few lines of code in the ejbCreate(), getData()
and setData() methods irrespective of the number of CMP fields.
The next step is to model the relationship between the Company and Employee
Entity Beans. This is slightly complex and it is recommended that the reader first get
acquainted with the Borland? Programmers Guide for EJB? in the section
pertaining to OR (Object Relational) Mapping and Advanced CMP issues.
Modeling the relationship requires absolutely no code change in the Struct. However
the Entity Bean implementation classes will require minor modifications to reflect
the relationship between the two entities, modifications are required in the
Deployment Descriptor regarding this issue.
As before, the Entity Bean inherits from the Struct.
Code snippet for the Company Entity Bean
public class CompanyBean extends CompanyStruct
implements EntityBean {
EntityContext entityContext;
// CMP for all fields in the CompanyStruct
public java.util.Collection employees;
//one-to-many
//rest of the code including getData() and setData()
public java.util.Collection getEmployees() {
return employees;
}
}
Code snippet for the Employee Entity Bean
public class EmployeeBean extends EmployeeStruct
implements EntityBean {
EntityContext entityContext;
//CMP for all fields in EmployeeStruct EXCEPT
//the comId
public Company company;//remote reference to company
In the above code snippet, the Employee Entity Bean inherits from the
EmployeeStruct. The EmployeeStruct itself has a field comId that
represents the foreign key relationship between an Employee and a Company. While
in all previous design patterns, this field was CMP in the Design Pattern V this field
is omitted from CMP by un-checking it in the Deployment Descriptor. Instead, the
remote reference to the Company Entity Bean is CMP now.
Now the problem that arises is how to update the reference to the Company entity
bean in the getData() and setData() methods as these methods get and set
the values for the comId field only, which in this design pattern context is not
container managed. In short, the Struct of course has not changed and field comId
(not CMP anymore) is copied to and from the Entity Bean during RPCs. What is
required is that the remote reference to the Company Entity Bean be updated when
data has to be written to the database or read from the database. We shall use the
ejbLoad() and ejbStore() methods in the Entity Bean implementation class
to perform this action for us.
Code snippet for the ejbLoad() method in the Employee Entity Bean
public void ejbLoad() {
try {
comId=(company ==
null)?nullInteger)company.getPrimaryKey();
} catch (Exception e) {
//throw some runtime exception (e.g. EJBException)
}
}
The above code hardly needs explaining. When data is read from the database (at the
start of a transaction), the comId (not CMP) field in the Employee Entity Bean is
set. Thus when the getData() method is called, the Struct returned will contain
the correct value for the comId field.
Code snippet for the ejbStore() method in the Employee Entity Bean
public void ejbStore() {
try {
company = (comId ==
null)?null:beanGlossary.getCompanyHome().findByPrimary
Key(comId);
} catch (Exception e) {
//throw some runtime exception (e.g. EJBException)
}
}
The ejbStore() is called at the end of the transaction when data is to be written
to the database. In this case, the value comId may have been modified (by a call to
the setData() method) and this has to be written to the database. The code in
the above method converts the comId to the remote reference Company. (After all
comId is the primary key of the Company Entity Bean).
The reason for the null check is that the database could hold null values (weak
references between tables), and these have to be modeled as well. In any case, it is
better to use the Java? wrappers for the basic types instead of the basic types
themselves, because of their ability to hold null values and be easily converted to
other formats.
The BeanGlossary class in the above code snippet might cause some confusion.
This is actually a utility class (a stateless session bean) that caches lookups of EJBs.
In the case of entity beans and stateful session beans, the lookup of the Home
Interface is cached. In the case of stateless session beans, the Remote Interface is
cached (as per the EJB? specification 1.1, the create() called on the Home
Interface of a SLSB is a no-op).
By caching in the above context, we mean that only on the first request is the lookup
done. Subsequent calls to get the home interface or the remote interface return the
already initialized object reference.
Code snippet for the BeanGlossarySB utility class
public class BeanGlossarySB implements SessionBean {
private Context context = null;
public javax.naming.Context getContext() throws
NamingException {
if (context == null)
context = new javax.naming.InitialContext();
return context;
}
// Company
private CompanyHome companyHome = null;
public CompanyHome getCompanyHome() throws
NamingException {
if (companyHome == null)
companyHome = ((CompanyHome)
javax.rmi.PortableRemoteObject.narrow(
getContext().lookup("java:comp/env/ejb/Company"),
CompanyHome.class));
return companyHome;
}
// rest of the EJBs
}
In Design Pattern V we have not dealt with the Home Interfaces of the Entity Bean.
In the case of the Employee Entity bean, there would be a finder element along the
lines of findEmployeesByCompany(Company pCompany). This would
return a Collection of Employee remote references. The Deployment
Descriptor in the Company Entity Bean maps the Collection of Employees
defined to the finder element above.
Thus a call on the Company Entity Bean’s method getEmployees() in the
remote interface returns the required Collection of Employee Remote
References that are associated with that particular company.