J2EE从零开始之实体EJB

发表于:2007-04-29来源:作者:点击数: 标签:实体ejb开始j2ee
实体EJB用在处理客户端请求大量、并发的情况,它在实现业务逻辑的同时,作为 数据库 的一个缓冲。在服务量大的情况下,减轻数据库的负担,提高业务处理能力。本章介绍实体EJB、两种持久性管理方法、编程模型和实例 开发 过程。 5.1 实体EJB编程模型 1.实体EJ

实体EJB用在处理客户端请求大量、并发的情况,它在实现业务逻辑的同时,作为数据库的一个缓冲。在服务量大的情况下,减轻数据库的负担,提高业务处理能力。本章介绍实体EJB、两种持久性管理方法、编程模型和实例开发过程。

5.1 实体EJB编程模型

  1.实体EJB

  实体EJB封装了业务逻辑实现,并且可以供多个客户使用。除了实现业务逻辑外,实体EJB的属性用来代表商业过程中处理的永久性数据。一个简单的实体Bean可以定义成代表数据库表的一个记录,也就是每一个实体对象代表 一条具体的记录。更复杂的实体Bean可以代表数据库表间关联视图。

  2.实体EJB的持久性

  持久性是实体EJB的一个重要概念。

  
         图5-1 EJB客户端视图

  和会话Bean的编程模型一样,实体EJB的客户端视图也是由主接口和远程接口组成。主接口实现类负责实体对象的创建和查询,远程接口实现类负责逻辑方法的调用。

  3.定位一个会话Bean主接口

  客户端使用JNDI定位一个实体Bean主接口。例如,Account实体Bean的主接口可使用以下代码进行查找:
   Context initialContext = new InitialContext();
   AccountHome accountHome = (AccountHome)
   javax.rmi.PortableRemoteObject.narrow(initialContext.lookup("java:comp/env/ejb/accounts"),
   AccountHome.class);
   一个客户端的JNDI命名空间可以配置起来包含网络上在不同机器上的、不同EJB容器中的EJB的主接口。而EJB容器的实际位置对使用企业Bean的客户端来说是透明的。

  4.实体Bean主接口

  部署在容器中实体Bean的主接口的实现是由容器提供的。并且,容器确保客户端能够通过JNDI访问到部署在容顺中的每个实体Bean的主接口。实现实体Bean主接口的对象是EJBHome。
   通过实体Bean主接口,客户端可以进行如下操作:
   ·创建新的实体对象。
   ·查找存在的实体对象。
   ·删除实体对象。
   ·执行主逻辑方法。
   ·获取主接口的句柄。
   主句柄能被序列化,并且能被写入存储设备中。然后,句柄可以在另一个不同的JVM中,从固定存储器中反序列化,获取主接口的引用。
   实体Bean主接口必须扩展javax.ejb.EJB主接口,并遵循Java语言远程接口规范。

  5.create方法

  实体Bean主接口可以定义多个create方法,每种方法都能创建一个实体对象。create方法的参数一般用来初始化实体对象的状态。每种create方法名的前缀是“create”。
   create方法的返回类型是实体bean的远程接口。每个create方法都要定义抛出两个异常java.rmi.RemoteException和javax.ejb.CreateExcention。也可以包含其它的引用级异常。例如:下面主接口定义中演示了三个create方法:

  public Interface AccountHome extends javax.ejb.EJBHome{
    public Account create(String firstName,String lastName,double initialBalance)
     throws RemoteException,CreateException;
    public Account create(String accountNumber,double initialBalance)
     throws RemoteException,CreateException,LowInitialBalanceException;
    public Account createLargeAccount(String firstname,String lastname,
     double initialBalance)
     throws RemoteException,CreateException;
    ...
   }
   下面代码演示客户端程序如何创建一个新的实体对象:
   AccountHome accountHome =...;
   Account account = accountHome.create("John","Smith",500.00);

  6.finder方法

  实体Bean主接口可以定义一个或多个finder方法,每个方法定义一种查询一个实体EJB和多个EJB对象的方法。
   finder方法必须以“find”为前缀,如findLargeAccounts(...),参数由实体Bean的来定位请求的实体对象。finder方法的返回值必须是实体Bean的远程接口,或者是实现实体Bean远程接口对象的集合。定义finder方法的异常有java.rmi.RemoteException和javax.ejb.FinderException。
   每个实体Bean的主接口包含一个findByPrimaryKey(primaryKey)方法。它允许客户端使用主键定位一个实体对象,它的名字总是findByPrimaryKey,只有一个参数,这个参数具有和实体Bean主键相同的类型,返回类型是实体Bean的远程接口。每个实体Bean有惟一的findByPrimaryKey(primaryKey)方法,该方法不能被重载,其实现必须确保实体对象存在。下面代码片断演示findByPrimaryKey方法:
   public Interface AccountHome extends javax.ejb.EJBHome{
    ...
    public Account findByPrimaryKey(String AccountNumber)
    throws RemoteException,FinderException;
   }
   下面代码片断演示客户端如何使用findByPrimaryKey方法:
   AccountHome=...;
   Account account = account 主findByPrimaryKey("100-3450-3333");

  7.remove方法

  javax.ejb.EJBHome接口定义了允许客户端删除实体对象的方法:
   public Interface EJBHome extends Remote{
    void remove(Handle handle) throws RemoteException,RemoveException;
    void remove(Object primaryKey) throws RemoteException,RemoveException;
   }
   实体对象删除后,客户端访问实体对象会产生java.rmi.NoSuchObjectException异常。

  8.Home方法

  实体Bean的主接口可以定义一个或多个主方法。主方法是不特定于某个实体Bean实例业务逻辑方法。主方法的名字必须以“create”、“ind”或“remove”作为开关。主方法的参数被实体Bean的实现类使用,不依赖于某个特定的实体Bean实例。方法的参数和返回值必须是RMI-IIOP的合法类型。
   主方法的定义必须招聘java.rmi.RemoteException异常。也可以包括其它引用级异常。
   下面代码片断演示两个方法:
   public Interface EmployeeHome extends javax.ejb.EJBHome{
    ...
    public float livingIndex(String state,float Salary)
     throws RemoteExcetption;
    public void addBonus(float company_share_index)
     throws RemoteException,ShareIndexOutOfRangeException;
    ...
   }

  9.主键和对象标识

  每个实体对象有一个惟一的标识。如果两个实体对象有相同的主键,则它们是同一的。EJB架构允许主键是任何合法类型的类。
   拥有实体对象远程接口引用的客户端可以通过getPrimaryKey()方法获取主键标识。和引用联系的对象标识在被引用期间不会改变。
   客户端可以测试两个实体对象是否指向同一个实体对象,用isIdentical(EJBObject)方法。也可以采用equals方法比较它们的主键。
   下面代码片断演示使用isIdentical方法测试指向同一个实体对象的两个对象引用:
   Account acc1 = ...;
   Account acc2 = ...;
   if (acc1.isIdentical(acc2)){
     //acc和acc2是同一个实体对象
   }else{
     //acc1和acc2是不同一个实体对象
   }
   如果客户端知道实体对象的主键,则调用实体Bean主接口的findByPrimaryKey(key)方法,可以获得实体对象的的引用。
   注意,比较两个引用是否指向同一个实体对象,不能使用Object.equals(Object obj)方法,只能使用isIdentical方法。

  10.实体Bean的远程接口

  客户端通过实体Bean的远程接口访问实体对象。实体Bean的远程接口必须扩展javax.ejb.EJBObject接口。远程接口定义客户端使用的逻辑方法。
   下面代码片断演示实体Bean远程接口的定义:
   public Interface Account extends javax.ejb.EJBObject{
    void debit(double amount)
     throws java.rmi.RemoteException,InsufficientBalanceException;
    void credit(double amount)
     throws java.rmi.RemoteException;
    double getBalance()
     throws java.rmi.RemoteException;
   }
   javax.ejb.EJBObject接口定义允许客户端使用实体对象引用进行,如下操作:
   ·获取实体对象的主接口。
   ·删除实体对象。
   ·获取实体对象句柄。
   ·获取实对象主键。
   容器实现javax.ejb.EJBObject接口中定义的方法,而业务方法以EJB的形式,以代理的方式被调用。
   注意 实体对象没有把javax.ejb.EnterpriseBean中定义的方法暴露给客户端,这些方法是被容器调用的。

  11.实体Bean的句柄

  实体对象的句柄是在网络上标识实体的,拥有实体对象的远程接口客户端可以通过调用getHandle()方法获取实体对象句柄,该句柄类继承java.io.Serializable,所以客户端可以序列化句柄。客户端可以在另一个进程和消息系统中,反序列化该句柄,以重新获得实体对象的引用。
   客户端代码必须使用javax.rmi.PortableRemoteObject.narrow(...)方法来把getEJBObject()方法的结果转换成实体Bean远程接口类型。
   下面代码片断演示了句柄的使用:
   //客户端获取account实体句柄,并保存
   ObjectOutputStream stream = ...;
   Account account = ...;
   Handle bandle = account.getHandle();
   stream.writeObject(handle);
   //客户端可以从存储设备中读取句柄,使用句柄获取
   //account实体对象的引用
   ObjectInputStream stream = ...;
   Handle handle=(Handle)stream.readObject(handle);
   Account account = (Account)javax.rmi.PortableRemoteObject.narrow(
   handle.getEJBObject(),Account.class);
   account.debit(100.00);

  12.实体主句柄

  EJB规范允许客户端获取主接口的句柄。客户端把实体Bean的主接口引用以句柄的方式存到存储设备中,然后可以重新获取。当客户端不知道主接口的JNDI名,又想使用主接口,这是个解决的办法。
   主接口的句柄必须实现javax.ejb.HomeHandle接口。
   客户端代码必须使用java.rmi.PortableRemoteObject.narrow(...)方法来把getEJBHome()方法的结果转化成主接口类型。

5.2 实体对象的生命周期

  实体对象在创建后,有一个标识。客户端使用实体Bean的主接口创建实体对象。创建成功后,客户端获取这个新创建的实体对象的引用。
   实体对象可以通过create方法以外的其他方式创建(如直接插入数据库一条记录),它仍可以通过finder方法访问。同时,实体对象可以不使用remove()方法,而是直接删除(如直接删除数据库一条记录)。

  

  客户端可以通过多种方式获取一个实体对象的远程接口引用:
   ·在方法调用中,引用作为参数传递过来。
   ·使用实体Bean主接口中定义的finder方法找到实体对象。
   ·从实体对象句柄中获取引用。
   拥有实体对象远程接口引用的客户端能做下面的事:
   ·通过远程接口调用实体对象的业务逻辑方法。
   ·获取主接口的引用。
   ·把引用作为参数或作为远程方法调用的返回值。
   ·获取实体对象的主键。
   ·获取实体对象的句柄。
   ·删除实体对象。
   使用不存在实体对象的引用是无效的。调用不存在的实体对象引用的方法会抛出异常java.rmi.NoSuchObjectException。
   多个客户端可以同时访问实体对象。事务处理把每个客户端分离开。

5.3 容器管理持久性实体EJB

5.3.1实例说明

  本示例演示容器管理持久性实体EJB实例的开发过程,内容包括:
   (1)实体EJB主接口、远程接口定义和实现类编写;
   (2)EJB说明文件和部署文件的编写;
   (3)EJB属性与数据表字段映射文件的编写:
   (4)如何定义连接池;
   (5)如何编译EJB程序;
   (6)测试EJB程序。
   示例文件包括:
   AccountHome.java,Account.java,AccountBean.java,ProcessingErrorException.java,Client.java,ejb-jar.xml,weblogic-cmp-rdbms-jar.xml,weblogic-ejb-jar.xml。

5.3.2编写源文件

  1.编写主接口程序
  编辑文件AccountHome.java并保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。AccountHome.java源文件如下:

  //AccountHome.java
   //定义本接口在包examples.ejb.basic.containerManaged中
   package examples.ejb.basic.containerManaged;
   //本接口用到的其他类
   //javax.ejb.*中定义了实现EJBean的接口。
   import javax.ejb.CreateException;
   import javax.ejb.EJBHome;
   import javax.ejb.FinderException;
   import java.rmi.RemoteException;
   import java.util.Enumeration;

  /**
   * 这是AccontBean的主接口定义,这个接口是被EJB容器产生的类AccontBeanC实现的。
   * 在这里只需定义EJB创建的方法,这些方法要和EJBean中的"ejbCreate"方法对应。
   */

  //EJBean主接口必须继承javax.ejb.EJBHome接口
   public interface AccountHome extends EJBHome {

   /**
    * 这个方法和"AccountBean.java"中定义的的Bean的"ejbCreate"方法相对应
    * 这两个方法的参数应该相同。当客户端调用"TraderHome.create()"方法时,EJB容器
    * 会找到EJBean的实例,并调用它的"ejbCreate()"方法。
    * 对容器管理的ejb,ejbCreate方法返回为null,而bean管理的ejb,返回的是主键类。
    * @参数 accountID String 账号ID
    * @参数 initialBalance double 初始化结算值
    * @参数 type String 账号类型
    * @返回 Account 远程对象
    * @异常 javax.ejb.CreateException
    * 创建bean错误时抛出的异常
    * @异常 RemoteException 当系统通讯发生故障时抛出
    * @参看 examples.ejb.basic.containerManaged.AccountBean
    */
    public Account create(String accountId, double initialBalance, String type)
    throws CreateException, RemoteException;

   /**
    * 根据主键对象,返回账号对象
    *
    * @参数 primaryKey 主键
    * @返回 Account 账号
    * @异常 javax.ejb.FinderException
    * 访问数据库错误抛出的异常
    * @异常 RemoteException 当系统通讯发生故障时抛出
    * @参看 examples.ejb.basic.containerManaged.AccountBean
    */
    public Account findByPrimaryKey(String primaryKey)
    throws FinderException, RemoteException;
 
    /**
    * 找到所有结算值等于balanceEqual的账号
    *
    * @返回 Account 账号
    * @参数 double balanceEqual,给定的结算值
    * @异常 javax.ejb.FinderException
    * 访问数据库错误抛出的异常
    * @异常 RemoteException 当系统通讯发生故障时抛出
    * @参看 examples.ejb.basic.containerManaged.AccountBean
    */
    public Account findAccount(double balanceEqual)
    throws FinderException, RemoteException;

   /**
    * 找到所有结算值大于balanceGreaterThan的账号
    *
    * @返回 Enumeration 所有账号枚举
    * @参数 double balanceGreaterThan,给定的结算值
    * @异常 javax.ejb.FinderException
    * 访问数据库错误抛出的异常
    * @异常 RemoteException 当系统通讯发生故障时抛出
    * @参看 examples.ejb.basic.containerManaged.AccountBean
    */
    public Enumeration findBigAccounts(double balanceGreaterThan)
    throws FinderException, RemoteException;

   /**
    * 找到所有类型为'null'的EJBeans。
    *
    * @返回 Enumeration 所有账号枚举
    * @异常 javax.ejb.FinderException
    * 访问数据库错误抛出的异常
    * @异常 RemoteException 当系统通讯发生故障时抛出
    * @参看 examples.ejb.basic.containerManaged.AccountBean
    */
    public Enumeration findNullAccounts()
    throws FinderException, RemoteException;

  }

  2.编写远程接口程序

  编辑文件Account.java并保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。Account.java源文件如下:

  //Account.java
   //定义本接口在包examples.ejb.basic.containerManaged中
   package examples.ejb.basic.containerManaged;
   //本接口用到的其他类
   //javax.ejb.*中定义了实现EJBean的接口。
   import java.rmi.RemoteException;
   import javax.ejb.*;

  /**
   * 这是AccontBean的远程接口定义。远程接口中定义了客户端能远程调用EJBean的方法。这些方法除了
   * 要抛出异常java.rmi.RemoteException之外,和EJBean中的定义是一致的。但并不是EJBean来实
   * 现这个接口,而是由容器自动产生的类AccontBeanE实现的。
   */
   //这个接口必须继承javax.ejb.EJBObject接口
   public interface Account extends EJBObject {

   /**
    * 远程方法:存入一定数目的金额
    *
    * @参数 amount 存入金额的数量
    * @返回 double 操作实际结果
    * @异常 RemoteException 当系统通讯发生故障时抛出
    */
    public double deposit(double amount)
    throws RemoteException;

   /**
    * 远程方法:提取一定数目的金额
    *
    * @参数 amount 提取金额的数量
    * @返回 double 操作实际结果
    * @异常 RemoteException 当系统通讯发生故障时抛出
    * @异常 ProcessingErrorException
    * 购买操作出错时抛出的异常
    */
    public double withdraw(double amount)
    throws ProcessingErrorException, RemoteException;

   /**
    * 远程方法:结算
    * @返回 double 结算值
    * @异常 RemoteException 当系统通讯发生故障时抛出
    */
    public double balance()
    throws RemoteException;

   /**
    * 返回账号类型
    *
    * @返回 String 账号类型
    * @异常 RemoteException 当系统通讯发生故障时抛出
    */
    public String accountType()
    throws RemoteException;

  }

  3.编写实现类程序

  编辑文件AccountBean.java并保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。AccountBean.java源文件如下:

  //AccountBean.java
   //定义本接口在包examples.ejb.basic.containerManaged中
   package examples.ejb.basic.containerManaged;
   //本类用到的其他类。javax.ejb.*是开发EJB应用需要的类库。javax.naming.*是实现JNDI服务需要的类库。
   import java.io.Serializable;
   import java.util.Enumeration;
   import java.util.Vector;

  import javax.ejb.CreateException;
   import javax.ejb.DuplicateKeyException;
   import javax.ejb.EJBException;
   import javax.ejb.EntityBean;
   import javax.ejb.EntityContext;
   import javax.ejb.FinderException;
   import javax.ejb.NoSuchEntityException;
   import javax.ejb.ObjectNotFoundException;
   import javax.ejb.RemoveException;
   import javax.naming.InitialContext;
   import javax.naming.NamingException;
   import javax.sql.DataSource;

  /**
   * AccountBean是实体EJB,它演示了:
   * 容器管理的JDBC持续性管理和事务管理;
   * 在这个文件中的代码并没有直接访问数据库;
   * 用户定义的异常;
   * 使用isModified方法,这个方法改变容器管理的字段,通过设置isDirty
   */
   //这个类是实体Bean,必须实现接口 EntityBean
   public class AccountBean implements EntityBean {
    //设置是否打印控制台
    final static boolean VERBOSE = true;
    //声明实体上下文变量
    private EntityContext ctx;
    //声明实体EJB属性变量
    public String accountId; // 这也是主键类
    public double balance;
    public String accountType;
    private transient boolean isDirty; // 决定bean是否谢数据库的标志

   /**
    * 为EJBean设置实体EJB上下文
    *
    * @参数 ctx EntityContext
    */
    public void setEntityContext(EntityContext ctx) {
     log("setEntityContext called (" + id() + ")");
     this.ctx = ctx;
    }

   /**
    * 取消实体上下文设置
    *
    */
    public void unsetEntityContext() {
     log("AccountBean.unsetEntityContext (" + id() + ")");
     this.ctx = null;
    }

   /**
    * 返回EJBean是否被改变
    *
    * 这个方法必须为public 以使被容器调用
    *
    * @返回 boolean isDirty
    */
    public boolean isModified() {
     log("isModified(): isDirty = " + (isDirty ? "true" : "false"));
     return isDirty;
    }

   /**
    * 设置EJBean的改变标志
    *
    * @参数 flag 改变标志
    */
    public void setModified(boolean flag) {
     isDirty = flag;
     log("setModified(): " + id() + (String) (flag ? ": requires saving"
      : ": saving not required"));
    }

   /**
    * 返回标识这个EJBean的主键
    *
    * @返回 String 标志
    */
    private String id() {
     return "" + System.identityHashCode(this) + ", PK = " +
     (String) ((ctx == null) ? "nullctx"
     : ((ctx.getPrimaryKey() == null ?
     "null" : ctx.getPrimaryKey().toString()))) +
     "; isDirty = " + isDirty;
    }

   /**
    * 这是本类必须实现的方法,在本例中没有用到
    *
    */
    public void ejbActivate() {
     log("AccountBean.ejbActivate (" + id() + ")");
    }

   /**
    * 这是本类必须实现的方法,在本例中没有用到
    *
    */
    public void ejbPassivate() {
     log("AccountBean.ejbPassivate (" + id() + ")");
    }

   /**
    * 这是本类必须实现的方法,在本例中没有用到
    *
    */
    public void ejbLoad() {
     log("AccountBean.ejbLoad (" + id() + ")");
    }

   /**
    * 设置EJBean的改变标记为false
    *
    */
    public void ejbStore() {
     log("AccountBean.ejbStore (" + id() + ")");

    setModified(false);
    }

   /**
    * 这是本类必须实现的方法,在本例中没有用到
    *
    */
    public void ejbRemove()
    throws RemoveException
    {
     log("AccountBean.ejbRemove (" + id() + ")");
    }
    /**
    * 这个方法和"AccountBean.java"中定义的的Bean的"ejbCreate"方法相对应
    * 这两个方法的参数应该相同。当客户端调用"TraderHome.create()"方法时,EJB容器
    * 会找到EJBean的实例,并调用它的"ejbCreate()"方法。
    * 对容器管理的ejb,ejbCreate方法返回为null,而bean管理的ejb,返回的是主键类。
    * @参数 accountID String 账号ID
    * @参数 initialBalance double 初始化结算值
    * @参数 type String 账号类型
    * @异常 javax.ejb.CreateException
    * 创建bean错误时抛出的异常
    * @参看 examples.ejb.basic.containerManaged.AccountHome
    */
    public String ejbCreate(String accountId, double initialBalance, String type)
    throws CreateException
    {
     log("AccountBean.ejbCreate( id = " + System.identityHashCode(this) + ", PK = " +
     accountId + ", " + "initial balance = $ " + initialBalance + ")");
     this.accountId = accountId;
     this.balance = initialBalance;
     this.accountType = type;
     return null; // See 9.4.2 of the EJB 1.1 specification
    }

   /**
    * 这是本类必须实现的方法,在本例中没有用到
    */
    public void ejbPostCreate(String accountId, double initialBalance, String type)
    {
     log("AccountBean.ejbPostCreate (" + id() + ")");
    }

   // 应用程序定义的方法

   /**
    * 存入一定金额
    *
    * @参数 amount double 数量
    * @返回 double 结算
    */
    public double deposit(double amount)
    {
     log("AccountBean.deposit: Depositing $" + amount + " into '" + accountId + "'");
     //业务逻辑计算
     balance += amount;
     //设置改变标记
     setModified(true);
     return balance;
    }

   /**
    * 提取一定数量的金额
    *
    * @参数 amount double 数量
    * @返回 double 结算
    * @exception ProcessingErrorException
    * 如果提取的数量大于结算值
    */
    public double withdraw(double amount)
    throws ProcessingErrorException
    {
     log("AccountBean.withdraw: Withdrawing $" + amount + " from '" + accountId + "'");
     if (amount > balance) {
      //抛出用户定义异常
      throw new ProcessingErrorException("Request to withdraw $" + amount +
      "; is more than balance $" + balance +
      " in account " + accountId);
     }
     //业务逻辑计算
     balance -= amount;
     //设置改变标记
     setModified(true);
     return balance;
    }
    /**
    * 返回当前的结算
    *
    * @返回 double 结算
    */
    public double balance() {
     log("AccountBean.balance (" + id() + ")");

    return balance;
    }
    /**
    * 返回账号类型
    *
    * @返回 String 账号类型
    */
    public String accountType() {
     log("AccountBean.accountType (" + id() + ")");

    return accountType;
    }
    //控制台输出
    private void log(String s) {
     if (VERBOSE) System.out.println(s);
    }
   }

  4.编写处理异常程序

  用文本编辑器编辑文件ProcessingErrorException.java并将它保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。其源文件如下:

  //ProcessingErrorException.java
   //定义本类在包examples.ejb.basic.containerManaged 中
   package examples.ejb.basic.containerManaged;

  /**
   * 这是用户定义的异常类
   */
   //用户定义的异常类必须继承Exception
   public class ProcessingErrorException extends Exception {

   /**
    * 获取没有字符串参数的异常
    *
    */
    public ProcessingErrorException() {}

   /**
    * 用特定的字符串构造异常
    *
    * @参数 message Exception 消息
    */
    public ProcessingErrorException(String message) {super(message);}
   }

  5.编写客户端测试程序

  编辑文件Client.java并将它保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。其源文件如下:

  //Client.java
   //定义本类在包examples.ejb.basic.containerManaged 中
   package examples.ejb.basic.containerManaged;
   //本类用到的其他类
   import java.rmi.RemoteException;
   import java.util.Enumeration;
   import java.util.Hashtable;
   import java.util.Properties;
   import java.util.Vector;
   //本类用到的EJB类
   import javax.ejb.CreateException;
   import javax.ejb.DuplicateKeyException;
   import javax.ejb.FinderException;
   import javax.ejb.ObjectNotFoundException;
   import javax.ejb.RemoveException;
   //本类用到的名称服务类
   import javax.naming.Context;
   import javax.naming.InitialContext;
   import javax.naming.NamingException;
   import javax.rmi.PortableRemoteObject;
   /**
   * 这个类演示了如何调用一个实体EJB,并进行如下操作:
   * A:创建一个Account远程对象,存入一些钱。然后试图提取超过当前结算的金额。或抛出用户定义的异常,
   * 最后,清除Account远程对象。
   * B:创建一些新的账号,它们有不同的结算值。找到所有计算值大于给定数值的账号。找到结算职为0的账号。
   * 试图查找账号类型为null的账号。最后,删除所有新创立的账号。
   * 这个例子同时演示了怎样在JNDI树查找EJB主接口。
   */
   public class Client {
    //声明变量
    private String url;
    private String accountId;
    private AccountHome home;
    //构造方法
    public Client(String url, String accountId)
    throws NamingException {

    this.url = url;
     this.accountId = accountId;
     //找找主接口,lookupHome是本例自定义方法。
     home = lookupHome();
    }

   /**
    * 在命令行运行这个实例:
    * java examples.ejb.basic.containerManaged.Client "t3://localhost:7001"
    * 参数是可选的
    * @参数 url URL such as "t3://localhost:7001" of Server
    * @参数 accountID String Account ID to test, default "10020"
    */
    public static void main(String[] args) {
     System.out.println("\nBeginning containerManaged.Client...\n");

    String url = "t3://localhost:7001";
     String accountId = "10020";

    // Parse the argument list
     switch(args.length) {
      case 2:
       accountId = args[1];
       // fall through
      case 1:
       url = args[0];
       break;
     }

    Client client = null;

    try {
      //实例化本类
      client = new Client(url, accountId);
     } catch (NamingException ne) {
      //异常处理
      log("Unable to look up the beans home: " + ne.getMessage());
      System.exit(1);
     }

    try {
      //运行实例A
      client.runExamplePartA();
      //运行实例B
      client.runExamplePartB();
     } catch (Exception e) {
      //异常处理
      log("There was an exception while creating and using the Accounts.");
      log("This indicates that there was a problem communicating with the server: "+e);
     }

    System.out.println("\nEnd containerManaged.Client...\n");
    }

   /**
    * 执行实例A
    *


原文转自:http://www.ltesting.net

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
...

热门标签