EJB Design Patterns5(0分)

  • 主题发起人 主题发起人 VRGL
  • 开始时间 开始时间
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)?null:(Integer)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.
 
读了后,感觉爽
 
就像我们在设计模式4中看到的, Entity Bean的实现大小被缩减到在ejbCreate(), getData()
and setData()方法中的仅仅几行,不管CMP字段的数目.
下一步是建模公司和雇员的Entity Beans,这个有点繁琐而且建议读者先对borland
公司的<EJB程序员指南>的OR Mapping和高级CMP有所了解.
对这个关系建模根本不需要对结构的代码变化,然而Entity Beans实现类需要一点点
修改来反映两个实体间的关系,鉴于此Deployment Descriptor需要有小的修改.
象以前, Entity Bean从结构继承,下面是公司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;
}
}
下面是雇员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
}
在上面的程序片段中,雇员Entity Bean从雇员结构继承,雇员结构本身有
一个字段comId表示雇员和公司之间的的外键,在所有的前面的设计模式中,
这个字段是CMP的.而在设计模式5中这个字段用在Deployment Descriptor中
un-checking的方法从CMP中去掉.而对公司Entity Bean的远程引用现在是CMP的.
现在的问题是怎么在getData()和SetData()方法中更新公司Entity Bean的引用,
当这些方法只get和set comId(在设计模式上下文中没有被CMP)的值.
简单的说,过程的结构没有变化并且字段comId(不再CMP)在RPC中被拷贝到
Entity Bean和从Entity Bean拷贝出来.需要的是对公司Entity Bean的远程
引用在必须被写入数据库和从数据库读出时更新.我们需要用ejbLoad()和ejbStore()
方法在Entity Bean实现类中为我们完成这项工作.
在雇员Entity Bean中的ejbLoad()方法的代码片段如下:
public void ejbLoad() {
try {
comId=(company ==
null)?null:(Integer)company.getPrimaryKey();
} catch (Exception e) {
//throw some runtime exception (e.g. EJBException)
}
}
以上代码几乎不需要解释.当数据被从数据库中读出(在事务的开始时候),
comId(不是CMP)字段在雇员Entity Bean被set.因此当getData()方法被调用时,
返回的结构将包含正确地comId的值.
在雇员Entity Bean中的ejbStore()方法如下:
public void ejbStore() {
try {
company = (comId ==
null)?null:beanGlossary.getCompanyHome().findByPrimary
Key(comId);
} catch (Exception e) {
//throw some runtime exception (e.g. EJBException)
}
}
ejbStore()在事务结束当数据被写入数据库时被调用.在这种情况下,comId的值
被修改(通过调用setData方法),this必须被写到数据库中.在上面方法中的代码
把comId转化成公司的远程引用.(毕竟comId是公司Entity Bean的主键).
使用空check的原因是数据库不能存空值(表之间的弱引用),并且这些同样需要建模.
任何情况下,用java对基本类型的封装要比使用基本类型自己好,因为他们能
存空值而且易于转换成其他形式.
上面的BeanGlossary类的代码片断容易引起一些混淆.
这实际上是一个捕获EJB的lookup的utility类(一个无状态session bean),
在entity bean和有状态session bean的情况下,Home接口的lookup是被缓冲的.
在无状态session bean的情况下,Remote接口是被缓冲的(作为ejb规范1.1的一部分,
一个SLSB在Home接口中调用的create()是不被优化的).
通过在上面上下文的缓冲,我们意思是第一个请求是被lookup的.随后的调用是得到
已经在对象引用中初始化的home接口或remote接口.
BeanGlossarySB utility类的代码片段如下:
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
}
在设计模式5中,我们没有处理Entity Bean的Home接口.
在雇员Entity Bean的情况下, 会有一个finder元素在
findEmployeesByCompany(Company pCompany)的几行中,
这将会返回雇员远程引用的集合. 在公司Entity Bean 中的Deployment
Descriptor map了在上面定义的finder元素的雇员集合.
这样,在公司Entity Bean中的方法getEmployees()在remote接口中的调用
返回需要的与那家公司相联系的远程引用的雇员的集合.

 
不知是否可以把几个设计模式的模型详细讲解,看半天还是不懂。
谢谢。
 
接受答案了.
 

Similar threads

A
回复
0
查看
992
Andreas Hausladen
A
A
回复
0
查看
943
Andreas Hausladen
A
A
回复
0
查看
619
Andreas Hausladen
A
A
回复
0
查看
819
Andreas Hausladen
A
A
回复
0
查看
478
Andreas Hausladen
A
后退
顶部