CMP实体bean实战开发
一个容器管理持续的实体bean允许容器处理一些或者它的全部数据访问逻辑。用容器管理的持续,你需要把实体bean类的一些域公开出来,好让容器在代表bean执行数据库操作时可以设置这些域。
在容器管理持续化的情况下,entity bean类的代码必须满足以下条件。首先,类必须定义为public。此外,这个类还必须实现以下内容:
1.EntityBean接口
2.零个或多个ejbCreate方法及ejbPostCreate方法
3.对应于持续化及关联字段的定义它的get方法及set方法
4.home方法
5.business方法
entity bean类不能实现以下方法:
1、finder方法
2、finalize方法
一个访问方法的命名以get或set开始,后面是首字母大写的持续化及关联字段。例如,对salary字段的访问 方法是getSalary和setSalary。
本示例描述一个简单的CMP 实体bean使用实例,构建一个简单的产品查询应用,实例中包括的3个主要 文件:
Product.java-------远程接口文件
ProductHome.java--------本地接口文件
ProductBean.java--------Bean文件
Product.java内容如下
import javax.ejb.*;
import java.rmi.RemoteException;/**
定义了企业bean的公开商务方法.
客户端通过远程接口和企业bean交互
*/
public interface Product extends EJBObject {// 实体bean域的获得器和设置器方法public String getName() throws RemoteException;
public void setName(String name) throws RemoteException;
public String getDescription() throws RemoteException;
public void setDescription(String description) throws RemoteException;
public double getBasePrice() throws RemoteException;
public void setBasePrice(double price) throws RemoteException;
public String getProductID() throws RemoteException;
}ProductHome.java内容如下
import javax.ejb.*;
import java.rmi.RemoteException;
import java.util.Enumeration;
public interface ProductHome extends EJBHome {
/*
这个方法创建EJB对象
请注意本地接口返回一个EJB对象,而Bean却没有返回值。这是因为EJB容器负责生成这个EJB对象,而Bean负责初始化。
@参数productID :产品号 (唯一)
@参数name:产品名t
@参数description :产品的描述
@参数basePrice Base:产品的基础价格
@返回新创建的EJB对象
*/
public Product create(String productID, String name, String description, double basePrice) throws CreateException, RemoteException;public Product findByPrimaryKey(String productID) throws FinderException, RemoteException;
//定位器方法,容器负责实现。
}Productbean.java文件内容如下
import java.sql.*;
import javax.naming.*;
import javax.ejb.*;
import java.util.*;
import java.rmi.RemoteException;
/**
容器管理持续性,一个产品的持续内容包括ID#,name,description和 baseprice 
*/
public class ProductBean implements EntityBean {protected EntityContext ctx;//容器管理的状态域必须定义成public类型
public String productID; // 主键
public String name;
public String description;
public double basePrice;public ProductBean() {
System.out.println("New Product Entity Bean Java Object created by EJB Container.");
}
public String getName() throws RemoteException {
System.out.println("getName() called.");
return name;
}public void setName(String name) throws RemoteException {
System.out.println("getName() called.");
this.name = name;
}public String getDescription() throws RemoteException {
System.out.println("getDescription() called.");
return description;
}public void setDescription(String description) throws RemoteException {
System.out.println("setDescription() called.");
this.description = description;
}public double getBasePrice() throws RemoteException {
System.out.println("getBasePrice() called.");
return basePrice;
}public void setBasePrice(double price) throws RemoteException {
System.out.println("setBasePrice() called.");
this.basePrice = price;
}public String getProductID() {
System.out.println("getProductID() called.");
return productID;
}// EJB必需的方法
// 由容器调用,执行时可获得需要的资源
public void ejbActivate() throws RemoteException {
System.out.println("ejbActivate() called.");
}/**
* EJB 容器在它从数据库中移除实体bean前调用这个方法。它和客户端调用home.Remove()方法相对应。
*/
public void ejbRemove() throws RemoteException {
System.out.println("ejbRemove() called.");
}public void ejbPassivate() throws RemoteException {
System.out.println("ejbPassivate () called.");
}public void ejbLoad() throws RemoteException {
System.out.println("ejbLoad() called.");
}public void ejbStore() throws RemoteException {
System.out.println("ejbStore() called.");
}public void setEntityContext(EntityContext ctx) throws RemoteException {
System.out.println("setEntityContext called");
this.ctx = ctx;
}public void unsetEntityContext() throws RemoteException {
System.out.println("unsetEntityContext called");
this.ctx = null; 
}public String ejbCreate(String productID, String name, String description, double basePrice) throws CreateException, RemoteException {
System.out.println("ejbCreate(" + productID + ", " + name + ", " + description + ", " + basePrice + ") called");this.productID = productID;
this.name = name;
this.description = description;
this.basePrice = basePrice;
return null;
}public void ejbPostCreate(String productID, String name, String description, double basePrice) throws RemoteException {
System.out.println("ejbPostCreate() called");
}
// 因为是容器管理的持续性,不需要定义finder方法。
}
将以上3个文件编译成class文件得到Product.class ProductBean.class ProductHome.class
部署BEAN文件
准备工作:启动j2ee服务器j2ee -verbose;启动cloudscape数据库服务器cloudscape -start。
1. 打开部署工具deploytool,新建一个applicaton命名为Product,display name 也使用Product
2. 给新建的application添加一个EnterPrise Bean,以下操作取默认值。3.添加建立的三个 class文件(Product.Class ProductHome.Class 和 ProductBean.Class)4.下一步选择 bean类型Entity bean 设置Enterprise bean Class 
ProductBean,Enterprise bean name 为ProductBean,display name 默认。
5.设置remote home interface 为ProductHome,remote interface 为Product
6.下一步操作如下,选取定义的状态域。将Primary key class 修改为java.lang.String。
设置Primary key field name为productID。7.下面的按next跳过,最后单击finish按钮完成实体Bean 的创建过程.
8.选中创建的ProductBean 在右侧的工作栏中点击Entity设置Deployment Setting.
选中Database Setting ,Database jndi name ---jdbc/cloudscape
user name :scott,password :tiger.
9.生成默认得sql语句
10.下面可以部署了点击deploy,设置jndi name。11.点击finish完成部署
12.使用客户端测试刚部署的CMP实体bean。
客户端Client.java
import javax.ejb.*;
import javax.naming.*;
import java.rmi.*;
import java.util.Enumeration;
import java.util.Properties;
public class Client {
public static void main(String[] args) { 
ProductHome home = null; 
try { Properties props=System.getProperties();
Context ctx=new InitialContext(props);
home = (ProductHome) ctx.lookup("ProductHome");
//创建几个产品EJB对象
home.create("123-456-7891", "P5-400", "400 Mhz Pentium", 300);
home.create("123-456-7892", "P5-450", "450 Mhz Pentium", 400);
home.create("123-456-7893", "SD-64", "64 MB SDRAM", 50);
home.create("123-456-7894", "SD-128", "128 MB SDRAM", 100);
home.create("123-456-7895", "SD-256", "256 MB SDRAM", 200);
//查找一件产品,打印出产品名
Product pk=home.findByPrimaryKey("123-456-7891");
System.out.println(pk.getName());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
13.客户端执行java Client返回结果如下:P5-400
14.注:假设你的JAVA_HOME,J2EE_HOME,classpath和path路径已经正确设置。如果出现问题请检查你的路径是否正确。
本实例在j2dk1.3.1 ,j2sdkee1.3.1和 cloudscape4.06环境下通过。

解决方案 »

  1.   

    I got some initial ideas for this, only for your reference.
    In your requirement, I understand:
    1. Each business type got the similar structure, I mean, the fields. so there will be some common fields shared by ALL the business types.And I understand the argument on the DataBase Design is:
    1. Performance
    2. WorkloadFor performance:
    If you handled the EJB with large set of fields, it really would influence the performance though you could tune it in Weblogic 7.0, that is why your EJB designer thinks that the EJB will be broken down into multi fine-grained sub EJBs. However, the latter will also introduce the performance issues as your EJB Container will manage many fine-grained sub EJBs rather than one EJB. Further it might introduce the transaction 'dead-lock' as each transaction will span each fine-grained sub EJBs rather than the one EJB.So, based on this, I think that the performance issue here is NOT the main point.For workload:
    For the workload, I think that both options from your EJB designer and DBA make no difference, the reason is quite simple, for EJB designer, all the work will be done in the Session Bean, while for DBA, all the work will be done in each sub EJB. The workload is there, and the difference of EJB designer and DBA is WHERE to do it.For some requirement, I think the following needs sepecial attentions:
    1. Is it possible to abstract the base object for ALL the business types?
    2. When one business type got some change during the development, how to minimize the impact?
    3. When one NEW business type comes in during the development, how to minimize the impact?
    4. How to abstract the EJB tier to provide the common business interface to the client? 
    5. As there might be complex query which could not be supported by EJB-QL, how do you provide the room for BMP in case the EJB-QL could not support such a complex query?Based on those 5 points, I come up with the following:
    1. Use EJB inheritance and Polymorphism, though it is NOT natural to use this feature in EJB, but in your case, I think it is perfect.
    The perso-code is below:Bean class
    ---------------
    public abstract class BaseBusinessTypeBean implements EntityBean {
    //define the common abstract fields
    public abstract String commonField1;
    public abstract String commonField2;
    //define the ejbCreate method
    public pkClass ejbCreate(String commonField1, String commonField2 ) throws CreateException {
      setCommonField1(commonField1);
      setCommonField2(commonField2);
      return null;
     
    }
    }
    public abstract class BusinessType1Bean extends BaseBusinessType {
    //define its own type fields
    public abstract String ownField;
    //define the ejbCreate method
    public pkClass ejbCreate(String commonField1, String commonField2, String ownField) throws CreateException {
     super.ejbCreate(commonField1, commonField2);
     setOwnField(ownField);
    }
    }Local interface
    ---------------
    public interface BaseBusinessType extends EJBLocalObject {
    //just getter/setter of the abstract fields
    //and common business methods
    }public interface BusinessType1 extends BaseBusinessType {
    //Only add the business methods from BusinessType1
    }Local Home Interfaces
    ---------------
    public interface BaseBusinessTypeHome extends EJBLocalHome {
    public BaseBusinessType findByPrimaryKey(String commonField1) throws FinderException;
    public BaseBusinessType create(String commonField1, String commonField2) throws CreateException;
    }
    public interface BusinessType1Home extends EJBLocalHome{
    public BusinessType1 findByPrimaryKey(String commonField1) throws FinderException;
    public BusinessType1 create(String commonField1, String commonField2, String ownField) throws CreateException;
    }2. Database
    There are several ways to mapping the EJB inheritance and polymorphism in Database. The following is just one of them:
    use one table for all the business type EJBs.
    the table structure will be like:
    String commonField1
    String commonField2
    ..
    Stirng ownField1
    ..
    String BusinessType(In this field, you coud define different business types in your application);This database mapping is quite straightforward, and it will be flexible if you will use the BMP to do some complex query.Also, it you want to add new fields and new business type, just manipulate one table:
    1. If you want to change/add/delete the common fields, then all the EJB no matter base or sub extened class has to be modified, so to avoid this risk, just make sure that all the common fields will be frozen and I think you could decide on this.
    2. If you want to change/add/delete the fields in each extended business type, just change that business type, it will not influence all the others.
    3. If you want to add new business type, all the others will not be changed.3. The common business interface
    You might use Factory pattern or something like that to provide the common business interface to decouple the EJB tier and client, it will be like this:public final class businessInterface {
    public addRecode(int businessType, RecordVO recordVO) {}
    }