5.4 Bean管理持久性实体EJB

  Bean管理持久性的EJB要求开发者维护EJB和数据库的映射关系,在Bean实现类的编写中,由开发者指定对数据库的操作。
  示例文件包括:AccountHome.java,Account.java,AccountBean.java,ProcessingErrorException.java,Client.java,Servlet.java,ejb-jar.xml,weblogic-ejb-jar.xml。

5.4.1 编写源文件

  1.编写主接口程序

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

//AccountHome.java
//定义本接口在包examples.ejb.basic.beanManaged 中
package examples.ejb.basic.beanManaged;
//本类用到的其他类。javax.ejb.*是开发EJB应用需要的类库。javax.naming.*是实现JNDI服务需要的类库。
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()"方法。
* @参数 accountID String 账号ID
* @参数 initialBalance double 初始化结算值
* @返回 Account 远程对象
* @异常 javax.ejb.CreateException
* 创建bean错误时抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
* @参看 examples.ejb.basic.beanManaged.AccountBean
*/
public Account create(String accountId, double initialBalance)
throws CreateException, RemoteException;

/**
* 根据主键对象,返回账号对象
*
* @参数 primaryKey 主键
* @返回 Account 账号
* @异常 javax.ejb.FinderException
* 访问数据库错误抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
* @参看 examples.ejb.basic.beanManaged.AccountBean
*/
public Account findByPrimaryKey(String primaryKey)
throws FinderException, RemoteException;

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

  2.编写远程接口程序

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

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

/**
* 这是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;
}

  3.编写实现类程序

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

//AccountBean.java
//定义本接口在包examples.ejb.basic.beanManaged
package examples.ejb.basic.beanManaged;
//本类用到的其他类。javax.ejb.*是开发EJB应用需要的类库。javax.naming.*是实现JNDI服务需要的类库
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
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.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

/**
* AccountBean是实体EJB,它演示了:
* EJBean管理的JDBC持续性管理和事务管理;
* 在这个文件中的代码直接访问数据库;
*/
//这个类是实体Bean,必须实现接口 EntityBean
public class AccountBean implements EntityBean {
//设置是否打印控制台
final static private boolean VERBOSE = true;
//声明实体上下文变量
private EntityContext ctx;
private String accountId; // 这也是主键类
private double balance;
/**
* 为EJBean设置实体EJB上下文
*
* @参数 ctx EntityContext
*/
public void setEntityContext(EntityContext ctx) {
log("setEntityContext called");
this.ctx = ctx;
}

/**
* 取消实体上下文设置
*
*/
public void unsetEntityContext() {
log("unsetEntityContext (" + id() + ")");
this.ctx = null;
}
/**
* 这是本类必须实现的方法,在本例中没有用到
*
*/
public void ejbActivate() {
log("ejbActivate (" + id() + ")");
}

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

/**
* 从数据库中加载EJB
*
* @异常 javax.ejb.NoSuchEntityException
* 如果在数据库中没有找到Bean
* @异常 javax.ejb.EJBException
* 通讯或系统错误
*/
public void ejbLoad() {
log("ejbLoad: (" + id() + ")");
//声明数据库连接对象
Connection con = null;
//声明SQL命令预处理对象
PreparedStatement ps = null;
//找到账号主键
accountId = (String) ctx.getPrimaryKey();

try {
//获取数据库连接
con = getConnection();
//设置SQL命令,读取记录
ps = con.prepareStatement("select bal from ejbAccounts where id = ?");
//设置SQL命令
ps.setString(1, accountId);
//执行SQL
ps.executeQuery();
//获取SQL结果
ResultSet rs = ps.getResultSet();
if (rs.next()) {
//取得数据
balance = rs.getDouble(1);
} else {
String error = "ejbLoad: AccountBean (" + accountId + ") not found";
log(error);
throw new NoSuchEntityException (error);
}
} catch (SQLException sqe) {
//数据库异常处理
log("SQLException: " + sqe);
throw new EJBException(sqe);
} finally {
cleanup(con, ps);
}
}

/**
* 数据库中存入EJBean
*
* @异常 javax.ejb.NoSuchEntityException
* 如果在数据库中没有找到Bean
* @异常 javax.ejb.EJBException
* 通讯或系统错误
*/
public void ejbStore() {
log("ejbStore (" + id() + ")");
//声明数据库连接对象
Connection con = null;
//声明SQL命令预处理对象
PreparedStatement ps = null;

try {
//获取数据库连接
con = getConnection();
//设置SQL命令,更新数据库
ps = con.prepareStatement("update ejbAccounts set bal = ? where id = ?");
//设置SQL命令
ps.setDouble(1, balance);
ps.setString(2, accountId);
//执行SQL
if (!(ps.executeUpdate() > 0)) {
String error = "ejbStore: AccountBean (" + accountId + ") not updated";
log(error);
throw new NoSuchEntityException (error);
}
} catch(SQLException sqe) {
///数据库次操作异常处理
log("SQLException: " + sqe);
throw new EJBException (sqe);
} finally {
cleanup(con, ps);
}
}


/**
* 这个方法和"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错误时抛出的异常
*/
public String ejbCreate(String accountId, double initialBalance)
throws CreateException
{
//日志信息
log("AccountBean.ejbCreate( id = accountId" + ", " + "initial balance = $ " + initialBalance + ")");
this.accountId = accountId;
this.balance = initialBalance;
//声明数据库连接
Connection con = null;
PreparedStatement ps = null;

try {
//获取数据库连接
con = getConnection();
//执行sql语句,插入记录
ps = con.prepareStatement("insert into ejbAccounts (id, bal) values (?, ?)");
ps.setString(1, accountId);
ps.setDouble(2, balance);
if (ps.executeUpdate() != 1) {
String error = "JDBC did not create any row";
log(error);
throw new CreateException (error);
}

return accountId;
} catch (SQLException sqe) {
//异常处理
try {
//查找主键
ejbFindByPrimaryKey(accountId);
} catch(ObjectNotFoundException onfe) {
String error = "SQLException: " + sqe;
log(error);
throw new CreateException (error);
}
String error = "An Account already exists in the database with Primary Key " + accountId;
log(error);
throw new DuplicateKeyException(error);
} finally {
cleanup(con, ps);
}
}

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

/**
* 从数据库中删除EJBean
*
* @异常 javax.ejb.NoSuchEntityException
* 如果数据库中没找到这个ejb
* @异常 javax.ejb.EJBException
* 通信错误抛出的异常
*/
public void ejbRemove() {
log("ejbRemove (" + id() + ")");
//声明数据库连接
Connection con = null;
PreparedStatement ps = null;

try {
//获取连接
con = getConnection();
//获取主键
accountId = (String) ctx.getPrimaryKey();
//执行SQL语句,删除记录
ps = con.prepareStatement("delete from ejbAccounts where id = ?");
ps.setString(1, accountId);
if (!(ps.executeUpdate() > 0)) {
String error = "AccountBean (" + accountId + " not found";
log(error);
throw new NoSuchEntityException (error);
}
} catch (SQLException sqe) {
//异常处理
log("SQLException: " + sqe);
throw new EJBException (sqe);
} finally {
//清除
cleanup(con, ps);
}
}

/**
* 给定主键查找EJBean
*
* @参数 pk String 主键
* @返回 String 主键
* @异常 javax.ejb.ObjectNotFoundException
* EJBean没发现抛出的异常
* @异常 javax.ejb.EJBException
* if there is a communications or systems failure
*/
public String ejbFindByPrimaryKey(String pk)
throws ObjectNotFoundException
{
log("ejbFindByPrimaryKey (" + pk + ")");
//声明数据库连接
Connection con = null;
PreparedStatement ps = null;

try {
//获取连接
con = getConnection();
//查询主键对应的记录
ps = con.prepareStatement("select bal from ejbAccounts where id = ?");
ps.setString(1, pk);
ps.executeQuery();
//获取结果集
ResultSet rs = ps.getResultSet();
if (rs.next()) {
balance = rs.getDouble(1);
} else {
//没有发现这个主键值的ejb
String error = "ejbFindByPrimaryKey: AccountBean (" + pk + ") not found";
log(error);
//抛出异常
throw new ObjectNotFoundException (error);
}
} catch (SQLException sqe) {
//异常处理
log("SQLException: " + sqe);
throw new EJBException (sqe);
} finally {
//清除
cleanup(con, ps);
}

log("ejbFindByPrimaryKey (" + pk + ") found");
return pk;
}

/**
* 查找所有结算大于给定值的EJBeans
* 返回主键枚举
*
* @参数 balanceGreaterThan double Test Amount
* @返回 主键枚举
* @异常 javax.ejb.EJBException
* 通信错误抛出的异常
*/
public Enumeration ejbFindBigAccounts(double balanceGreaterThan) {
log("ejbFindBigAccounts (balance > " + balanceGreaterThan + ")");
//声明数据库连接
Connection con = null;
PreparedStatement ps = null;

try {
//获取连接
con = getConnection();
ps = con.prepareStatement("select id from ejbAccounts where bal > ?");
ps.setDouble(1, balanceGreaterThan);
ps.executeQuery();
//获取结果集
ResultSet rs = ps.getResultSet();
Vector v = new Vector();
String pk;
while (rs.next()) {
pk = rs.getString(1);
v.addElement(pk);
}
//返回枚举
return v.elements();
} catch (SQLException sqe) {
//异常处理
log("SQLException: " + sqe);
throw new EJBException (sqe);
} finally {
//清除
cleanup(con, ps);
}
}

/**
* 存入一定数量
*
* @参数 amount double Amount
* @返回 double 结算
*/
public double deposit(double amount) {
log("Depositing $" + amount + " into '" + accountId + "'");
balance += amount;
return balance;
}

/**
* 提取
*
* @参数 amount double 数量
* @返回 double 结算
* @异常 ProcessingErrorException
* 如果数量大于结算
*/
public double withdraw(double amount)
throws ProcessingErrorException
{
log("Withdrawing $" + amount + " from '" + accountId + "'");
if (amount > balance) {
String error = "Request to withdraw $" + amount +
" more than balance " + balance + " in account " + accountId;
log(error);
throw new ProcessingErrorException(error);
}

balance -= amount;
return balance;
}

/**
* 返回当前结算值
*
* @返回 double 结算
*/
public double balance() {
return balance;
}

/**
* 从连接池中获取当前连接
*
* @返回 连接
* @异常 javax.ejb.EJBException
* 通信错误
*/
private Connection getConnection()
throws SQLException
{
//声明初始化上下文
InitialContext initCtx = null;
try {
initCtx = new InitialContext();
//查找数据源
DataSource ds = (javax.sql.DataSource)
initCtx.lookup("java:comp/env/jdbc/demoPool");
//返回数据源连接
return ds.getConnection();
} catch(NamingException ne) {
//有异常
log("UNABLE to get a connection from demoPool!");
log("Please make sure that you have setup the connection pool properly");
throw new EJBException(ne);
} finally {
try {
if(initCtx != null) initCtx.close();
} catch(NamingException ne) {
log("Error closing context: " + ne);
throw new EJBException(ne);
}
}
}

// 也可以使用WebLogic的日志服务
private void log(String s) {
if (VERBOSE) System.out.println(s);
}

// 返回这个beans的id
private String id() {
return "PK = " + (String) ctx.getPrimaryKey();
}
//清除
private void cleanup(Connection con, PreparedStatement ps) {
try {
if (ps != null) ps.close();
} catch (Exception e) {
log("Error closing PreparedStatement: "+e);
throw new EJBException (e);
}

try {
if (con != null) con.close();
} catch (Exception e) {
log("Error closing Connection: " + e);
throw new EJBException (e);

}
}
}

  4.编写处理异常程序

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

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

/**
* 这是用户定义的异常类
*/
//用户定义的异常类必须继承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\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:

//Client.java
//定义本类在包examples.ejb.basic.beanManaged 中
package examples.ejb.basic.beanManaged;
//本类用到的其他类
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
//本类用到的EJB类
import javax.ejb.CreateException;
import javax.ejb.EJBException;
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,并进行如下操作:
*/

public class Client {
//声明变量
private String url;

private AccountHome home;
//构造方法
public Client(String url)
throws NamingException
{

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

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

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

// 解析命令行参数
if (args.length != 1) {
System.out.println("Usage: java examples.ejb.basic.beanManaged.Client t3://hostname:port");
return;
} else {
url = args[0];
}


Client client = null;

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

try {
//运行实例
client.example();

} 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 beanManaged.Client...\n");
}
/**
* 执行实例
*
*/
public void example()
throws CreateException, RemoteException, FinderException,
RemoveException
{

int numBeans = 20;
//声明并创建账号数组
Account [] accounts = new Account [numBeans];

// 创建20个账号
for (int i=0; i<numBeans; i++) {
accounts [i] = findOrCreateAccount("ID: "+i, i * 1000);
}

// 打印账号结算
for (int i=0; i<numBeans; i++) {
log("Account: :"+accounts[i].getPrimaryKey()+
" has a balance of "+accounts[i].balance());
}

// 查找所有结算大于5000的账号
findBigAccounts(5000.0);

// 清除所有账号

log("Removing beans...");
for (int i=0; i<numBeans; i++) {
accounts[i].remove();
}
}


/**
* 列出所有结算大于给定值的账号
* 这个finder方法演示返回枚举账号
*/
private void findBigAccounts(double balanceGreaterThan)
throws RemoteException, FinderException
{
log("\nQuerying for accounts with a balance greater than " +
balanceGreaterThan + "...");
//调用主接口创建账号方法findBigAccounts,返回账号枚举
Enumeration enum = home.findBigAccounts(balanceGreaterThan);

if(! enum.hasMoreElements()) {
log("No accounts were found!");
}

while (enum.hasMoreElements()) {
//创建远程对象
Account bigAccount= (Account) PortableRemoteObject.narrow(enum.nextElement(),
Account.class);

log("Account " + bigAccount.getPrimaryKey() +
"; balance is $" + bigAccount.balance());
}
}

/**
* 如果对应id的账号以存在,则返回这个id,否则创建它
*/
private Account findOrCreateAccount(String id, double balance)
throws CreateException, RemoteException, FinderException
{
try {
log("Trying to find account with id: "+id);
return (Account) PortableRemoteObject.narrow(home.findByPrimaryKey(id),
Account.class);
} catch (ObjectNotFoundException onfe) {
// 账号不存在,创建它
return (Account) PortableRemoteObject.narrow(home.create(id, balance),
Account.class);
}
}


/**
* 给定id和结算创建一个新的账号
*/
private Account createAccount(String id, double balance)
throws CreateException, RemoteException
{
log("Creating account " + id + " with a balance of " +
balance + "...");
//创建远程账号对象
Account ac = (Account) PortableRemoteObject.narrow(home.create(id, balance),
Account.class);
log("Account " + id + " successfully created");

return ac;
}

/**
* 使用JNDI查找bean的主接口
*/
private AccountHome lookupHome()
throws NamingException
{
Context ctx = getInitialContext();

try {
//查找主接口
Object home = ctx.lookup("beanManaged.AccountHome");
return (AccountHome) PortableRemoteObject.narrow(home, AccountHome.class);

} catch (NamingException ne) {
//异常处理
log("The client was unable to lookup the EJBHome. Please make sure " +
"that you have deployed the ejb with the JNDI name " +
"beanManaged.AccountHome on the WebLogic server at "+url);

throw ne;
}
}

/**
* 获取初始化上下文
*/
private Context getInitialContext() throws NamingException {

try {
// 设置属性对象
Properties h = new Properties();
h.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
h.put(Context.PROVIDER_URL, url);
return new InitialContext(h);
} catch (NamingException ne) {
//异常处理
log("We were unable to get a connection to the WebLogic server at "+url);
log("Please make sure that the server is running.");
throw ne;
}
}
//控制台输出
private static void log(String s) {
System.out.println(s);
}
}

  6.客户端程序

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

//Servlet.java

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

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import weblogic.html.BreakElement;
import weblogic.html.HeadingElement;
import weblogic.html.ServletPage;
import weblogic.html.StringElement;

/**
* 这个servlet和Client类类似
* 这个servlet必须在web.xml文件中注册
* 使用url http://localhost:7001/examplesWebApp/beanManaged调用这个servlet
*/
public class Servlet extends HttpServlet {

static String accountId = "10020";

/**
* 查找beanManaged主接口
* 创建beans并调用远程接口中定义的方法
*
* @参数 req HttpServletRequest
* @参数 res HttpServletResponse
* @异常 java.io.IOException
* 如果IO错误
*/
public void service(HttpServletRequest req, HttpServletResponse res)
throws IOException
{
//设置文档类型
res.setContentType("text/html");
OutputStream out = res.getOutputStream();
String title = "EJBean Bean-managed Persistence Servlet";
//ServletPage实例
ServletPage sp = new ServletPage(title);
//编辑html元素
sp.getBody()
.addElement(new HeadingElement(title, 1));
printElement("", sp);

// 获取参数
// "http://localhost:7001/beanManaged?user=foobar&password=FooBarNone"
//用户名
String user = req.getParameter("user");
//密码
String password = req.getParameter("password");

if(user!=null && password!=null){
printElement("Using user <b>" + user
+ "</b> and password <b> " + password + "</b>", sp);
printElement("", sp);
} else {
printElement("No user and password credentials", sp);
printElement("", sp);
}

double amount = 100;
double balance = 3000;
Vector v = new Vector();

try {
// 获取上下文
Context ctx = getInitialContext();
//查找主接口
AccountHome home = (AccountHome) ctx.lookup("beanManaged.AccountHome");

// 查找Account或创建它
Account ac = null;
try {
printElement("Looking up account " + accountId + "...", sp);
ac = (Account) home.findByPrimaryKey(accountId);
}
catch (Exception ee) {
//异常处理
printElement("Did not find " + accountId, sp);
}

if (ac == null) {
printElement("Account " + accountId +
" being created; opening balance is $" + balance, sp);
//创建远程对象
ac = home.create(accountId, balance);
}
else {
printElement("Account " + accountId + " found; balance is $" + ac.balance(), sp);
}
printElement("", sp);

// A部分: 存入和提取大于当前结算的金额,会抛出用户定义的异常

printElement("Part A: Depositing $" + amount, sp);
//存入
balance = ac.deposit(amount);
printElement("Current balance is $" + balance, sp);
printElement("", sp);

amount = balance + 10;
try {
printElement("Withdrawing amount greater than current balance. Expecting an exception...", sp);
//提取
balance = ac.withdraw(amount);
printElement("Error: expected an exception.", sp);
}
catch (ProcessingErrorException pe) {
//用户定义的异常
printElement("Received expected Processing Error:<br>" + pe, sp);
}
printElement("", sp);

// B部分: 创建一些新的用户,并给定不同的初始结算
// 查找结算大于给定值的所有账号
// 最后,删除所有新的账号

int numAccounts = 5;
printElement("Part B: Creating " + numAccounts + " new accounts...", sp);
long now = System.currentTimeMillis();
for (int i = 0; i < numAccounts; i++) {
String id = "" + now + i; // 唯一的账号id
balance = i*100; // 初始结算
v.addElement(home.create(id, balance));
printElement("Created account: " + id +
"; balance is $" + balance, sp);
}
printElement("", sp);

if (v.size() == numAccounts) {
printElement("" + numAccounts + " accounts successfully created", sp);
}
else {
printElement("Error: Only " + v.size() +
" accounts were created successfully", sp);
}
printElement("", sp);

double balanceGreaterThan = 200;
printElement("Querying for accounts with a balance greater than " +
balanceGreaterThan + "...", sp);
//调用主接口的方法
Enumeration e = home.findBigAccounts(balanceGreaterThan);
if (e != null) {
while (e.hasMoreElements()) {
//每个账号
Account bigAccount= (Account) e.nextElement();
//打印每个账号的主键
printElement("Account " + bigAccount.getPrimaryKey() +
"; balance is $" + bigAccount.balance(), sp);
Thread.sleep(1000);
}
}
printElement("", sp);

printElement("Removing accounts just created...", sp);
//清除所有账号
for (int i = 0; i < numAccounts; i++) {
String id = "" + now + i;
((Account)(v.elementAt(i))).remove();
printElement("Removed account: " +id, sp);
}
printElement("", sp);

// 捕获异常
}
catch (ProcessingErrorException pe) {
printElement("Unexpected Processing Error: " + pe, sp);
}
catch (Exception e) {
//其它异常
printElement(":::::::::::::: Unexpected Error :::::::::::::::::", sp);
e.printStackTrace();
}
finally {
printElement("End beanManaged.Servlet...", sp);
}

sp.output(out);
out.flush();
}

/**
* 基本的servlet信息
*/
public String getServletInfo() {
return "EJBean Servlet";
}

/**
* 打印一个bean的HTML信息
*/
static private void printAccount(Account account, ServletPage sp)
throws RemoteException, IOException {
printElement("Account " + account.getPrimaryKey() +
"; balance is $" + account.balance(), sp);
}

/**
* 打印消息给浏览器
*/
static private void printElement(String message, ServletPage sp)
throws IOException {
sp.getBody()
.addElement(new BreakElement())
.addElement(new StringElement(message));
}

/**
* 获取当前用户、密码和url的初始化上下文。
*
* @return 上下文
* @异常 java.lang.Exception if there is
* an error in getting the Context
*/
static public Context getInitialContext() throws Exception {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
return new InitialContext(p);
}
}

  7.编写ejb描述文件

  编辑文件ejb-jar.Xml并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:

<?xml version="1.0"?>

<!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN' 'http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd'>

<ejb-jar>
<enterprise-beans>
<entity>
<ejb-name>beanManaged</ejb-name>
<home>examples.ejb.basic.beanManaged.AccountHome</home>
<remote>examples.ejb.basic.beanManaged.Account</remote>
<ejb-class>examples.ejb.basic.beanManaged.AccountBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>

<resource-ref>
<res-ref-name>jdbc/demoPool</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

</entity>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>beanManaged</ejb-name>
<method-intf>Remote</method-intf>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

  8.编写ejb部署文件

  编辑文件weblogic-ejb-jar.xml并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:

<?xml version="1.0"?>

<!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 5.1.0 EJB//EN' 'http://www.bea.com/servers/wls510/dtd/weblogic-ejb-jar.dtd'>

<weblogic-ejb-jar>
<weblogic-enterprise-bean>
<ejb-name>beanManaged</ejb-name>
<caching-descriptor>
<max-beans-in-cache>100</max-beans-in-cache>
</caching-descriptor>
<reference-descriptor>

<resource-description>
<res-ref-name>
jdbc/demoPool
</res-ref-name>
<jndi-name>
examples-dataSource-demoPool
</jndi-name>
</resource-description>

</reference-descriptor>

<jndi-name>beanManaged.AccountHome</jndi-name>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>

5.4.2 编译

  (1)打开命令窗口,进入C:\work\src\examples\ejb\basic\beanManaged目录。
  (2)运行设置环境变量命令脚本setEnv.cmd:
   c:\work\src\examples\ejb\basic\beanManaed>c:\work\setEnv
  setEnv.cmd在附带光盘的work目录下,可以直接把它拷贝到C:\work\目录。
  (3)运行编译脚本build.cmd:
   c:\work\src\examples\ejb\basic\beanManaed>bukld
  其中build.cmd代码如下:

@REM Copyright (c) 2000 BEA Systems, Inc. All Rights Reserved.
@REM You must set your environment by running the setExamplesEnv shell script
@REM prior to executing this script.

@REM Create the build directory, and copy the deployment descriptors into it
mkdir build build\META-INF
copy *.xml build\META-INF

@REM Compile EJB classes into the build directory (jar preparation)
javac -d build Account.java AccountHome.java ProcessingErrorException.java AccountBean.java

@REM Make a EJB jar file, including XML deployment descriptors
cd build
jar cv0f std_ejb_basic_beanManaged.jar META-INF examples
cd ..

@REM Run EJBC on jar file
java -classpath %WL_HOME%/lib/weblogic_sp.jar;%WL_HOME%/lib/weblogic.jar weblogic.ejbc -compiler javac build\std_ejb_basic_beanManaged.jar %WL_HOME%\config\%DOMAIN_NAME%\applications\ejb_basic_beanManaged.jar

@REM Compile servlets and EJB interfaces into WEB-INF/classes directory of the Examples Web App
@REM This ensures that the EJB can be accessed by JSPs and servlets of the Examples Web App
javac -d %EX_WEBAPP_CLASSES% Servlet.java Account.java AccountHome.java ProcessingErrorException.java

@REM Compile EJB interfaces & client app into the clientclasses directory
javac -d %CLIENT_CLASSES% Account.java AccountHome.java ProcessingErrorException.java Client.java

5.4.3 定义数据源

  本示例使用数据源examples-dataSource-demoPool和连接池demoPool。前面已经定义了连接池demoPool,本节演示如何通过系统管理工具Console定义连接池demoPool的数据源。
  (1)启动WebLogic服务
  (2)启动系统管理控制台程序console(在浏览器URL中输入http://127.0.0.1:7001/console/,回车)。
  (3)点出console控制台左面板的Services/JDBC/Data Sources,如图5-8所示。
  (4)接下来是一个主要的步骤,点击控制台右面板的“Create a new JDBC ConnectionPool...”,创建新的连接池。进入图5-9的操作界面。定义新数据源名称“Name:”为“examples-dataSource-demoPool”,定义连接池名称“Pool Name:”为“demoPool”,然后点击“Create”创建。
  (5)下面有一个重要的步骤,那就是创建完数据源后,还要把它部署到系统管理的服务器myserve中点击图5-9的Targets页,在Available栏中选中myserver,点击向右的箭头,点击“Apply”。如图6-10所示。

  1.修改启动脚本

  本示例使用WebLogic Server 6.0自带的小型关系数据库cloudscape。因此在WebLogic Server启动的时候,要对启动脚本文件startWebLogic.cmd进行修改。如果还没有修改,则参见上一个实例。

  2.配置Servlet

  本示例客户端测试程序除了Client.java之外,还提供了一个Servlet程序,它和Client具有一样的功能,以Servlet应用的方式使用。使用Sevlet前要进行注册。Servlet程序的注册信息都放在web.xml文件中。
  要注册Servlet首先要编辑C:\bea\wlserver6.0\config\mydomain\applications\DefaultWebApp_myserver\WEB-INF路径下的web.xml文件。

  <?xml version="1.0" ?>
  <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 1.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
  <web-app>
   ...
   <!--chapter 6 -->

   <servlet>
    <servlet-name>beanManaged</servlet-name>
    <servlet-class>examples.ejb.basic.beanManaged.Servlet</servlet-class>
   </servlet>
   <servlet-mapping>
    <servlet-name>beanManaged</servlet-name>
    <url-pattern>/beanManaged*</url-pattern>
   </servlet-mapping>
   ...
  </web-app>
  其中虚线表示在web.xml中注册的其它Servlets。
  编辑完web.xml要重新启动服务器以使其生效。

  3.运行测试

  (1)测试Client
  运行测试程序。继续使用前几个步骤使用的命令窗口,执行:
    C:\work\src\examples\ejb\basic\beanManaged>java
    examples.ejb.basic.beanManaged.Client t3://127.0.0.1:7001/
  观察命令窗口的运行情况,如图5-11所示。

  (2)测试Servlet
  打开浏览器,在地址栏中输入http://127.0.0.1:7001/beanManage,回车。会出现如图5-12所示的页面。