Apache Geronimo 通信基础 —— 开发、部署和测试(下)
消息驱动 bean()
既然您已经实现了 PurchaseOrderEJB,接下来就可以实现 PurchaseOrderMDB 了。与 EJB 不同,MDB 是 JMS 侦听器,侦听 JMS 主题 或队列上的 JMS 消息。根据 EJB 2.1 规范,MDB 不仅限于 JMS 侦听器,而是可实现任意自定义侦听器接口。在本系列的第 3 部分中, 您将再次回顾这一点,并修改 PurchaseOrderMDB,以便使用自定义侦听器接口,将其与 JCA 资源适配器相集成。
在本教程中,您将实现 PurchaseOrderMDB,它侦听 JMS 主题(POTopic)接收到的带有采购请求的 JMS 消息。接收到采购请求消息时 ,它将调用 PurchaseOrderEJB 来创建新采购订单。
实现 PurchaseOrderMDB
不同于实体 bean,MDB 不必实现远程接口或主接口,而是要实现 MessageDrivenBean 和 MessageListener 接口 —— 因而必须实现 onMessage() 方法。清单 9 给出了 PurchaseOrderMDB 的代码片段。
PurchaseOrderMDB 的源文件(.java)可在 $part1.home/src/examples/po/mdb 目录下找到。
清单 9. MDB 源代码
public class PurchaseOrderMDB implements MessageDrivenBean, MessageListener { private MessageDrivenContext ctx = null; public void setMessageDrivenContext(MessageDrivenContext mdCtx) throws EJBException { ctx = mdCtx; } public void onMessage(Message msg) { if (msg instance of ObjectMessage) { Serializable bean = ((ObjectMessage) msg).getObject(); poBean = (PurchaseOrderBean) bean; addPurchaseOrder(poBean); } }// end onMessage
在 PurchaseOrderMDB 的 onMessage() 方法中,您调用了 PurchaseOrderEJB 的 addPurchaseOrder() 方法在数据库表中创建新采购 订单行。
Geronimo 服务器的 JNDI 属性如下:
java.naming.facTory.initial=org.openejb.client.RemoteInitialContextFacToryjava.naming.provider.url=localhost:4201
(4201 是默认端口)
java.naming.security.principal=system(默认用户名)
java.naming.security.credentials=manager(默认口令)
清单 10. 查找实体 bean 并创建采购订单
private void addPurchaseOrder (PurchaseOrderBean poBean) {try {//EJB JNDI Properties for Geronimo ServerHashtable env = new Hashtable();env.put("java.naming.facTory.initial", "org.openejb.client.RemoteInitialContextFacTory");env.put("java.naming.provider.url", "localhost:4201");env.put("java.naming.security.principal", "system");env.put("java.naming.security.credentials", "manager");// create a new InitialContextInitialContext ctx = new InitialContext(env);// Lookup Purchase Order Entity BeanObject o = ctx.lookup("PurchaseOrderEJB");RemotePurchaseOrderHome home =(RemotePurchaseOrderHome) PortableRemoteObject .narrow(o, RemotePurchaseOrderHome.class);// Create a new Purchase OrderRemotePurchaseOrder po = home. create ( poBean.getPurchaseOrderNum(), poBean.getItem(), poBean.getDescription(), poBean.getUnitPrice(), poBean.getQuantity(), poBean.getRequesTorEmail());log.info("Purchase Order Number # :" + po.getPurchaseOrderNum());} catch (Exception e) { e.printStackTrace(); log.severe(""+e);}}}
如 清单 10 所示,为了在数据表中创建一个采购订单行,您在 JNDI 服务器中查找 PurchaseOrderEJB,并调用主接口上的 create() 方法。
定义 MDB 描述符
既然已经实现了 PurchaseOrderMDB,就该在描述符中定义 MDB 了。您不必为 MDB 定义单独的描述符。它们是在与 EJB 相同的描述符 中定义的,也就是 ejb-jar.xml(参见 清单 11)和 openejb-jar.xml(参见 清单 12)。
清单 11. 定义 MDB 的 ejb-jar.xml 代码片段
PurchaseOrderMDBexamples.po.mdb.PurchaseOrderMDBContainerjavax.jms.Topic
在 openejb-jar.xml 中,您定义了 MDB 应侦听的主题/队列 JNDI 名(POTopic)(参见 清单 12)。您还要定义 MDB 在 ejb-ref 部 分中调用的 EJB。
清单 12. 定义 MDB 的 openejb-jar.xml 代码片段
PurchaseOrderMDBgeronimo.server:J2EEApplication=null,J2EEServer=geronimo,JCAResource=geronimo/activemq/1.0/car,j2eeType=JCAResourceAdapter,name=ActiveMQ RA destination POTopic destinationType javax.jms.Topic ejb/PurchaseOrderEJBPurchaseOrderEJB
PurchaseOrderMDB 在 addPurchaseOrder() 方法中调用 PurchaseOrderEJB,因此 EJB 是在 部分中定义的。
Geronimo 服务器配置
既然已经实现了 PurchaseOrderMDB 和 PurchaseOrderEJB,现在就可以配置 Geronimo 服务器以便部署。首先使用 Geronimo 服务器 中的 Derby 为 PurchaseOrderEJB 配置数据库表 PURCHASEORDER。
Geronimo 中不需要任何 JMS 配置,因为 JMS 主题/队列是在部署期间由服务器动态创建的。Geronimo 为 JMS 主题或队列使用 openejb-jar.xml 描述符中的 JNDI 名。
数据库配置
运行 $GERONIMO_HOME/bin/startup.bat 启动您的 Geronimo 服务器。如果您未在系统属性中设置 JAVA_HOME,可在 $GERONIMO_HOME/bin/setjavaenv.bat 中进行设置。为 Geronimo 使用默认用户名 system 和口令 manager。
在 http://localhost:8080/console 处可使用 Geronimo 管理控制台,在左窗格中的 Misc > Embedded DB 菜单下单击 DB Manager。
创建 ExampleDatabase,如 图 3 所示。
图 3. 在 Geronimo 服务器中创建数据库
成功创建了 ExampleDatabase 之后,您将会看到它出现在数据库列表中,如 图 4 所示。
图 4. 数据库创建成功
现在创建表 PURCHASEORDER,方法是在 SQL Command 文本区域中输入 SQL 脚本(参见 清单 13)。务必确保首先在 Use DB 下拉列表 中选中 ExampleDatabase,然后再单击 Run SQL 按钮(参见 图 5)。
清单 13. 创建表的 SQL 脚本
CREATE TABLE PURCHASEORDER ( PURCHASEORDERNUM VARCHAR(30) PRIMARY KEY, ITEM VARCHAR(30) NOT NULL, DESCRIPTION VARCHAR(255), UNITPRICE INTEGER, QUANTITY INTEGER, REQUESTorEMAIL VARCHAR(30) NOT NULL)
图 5. 在 Geronimo 服务器中创建数据库
成功创建了 PURCHASEORDER 表之后,您将看到它出现在 DB Viewer 中,如 图 6 所示。
图 6. 表创建成功
数据库池配置
现在您可以使用 http://localhost:8080/console 处的 Geronimo 管理控制台在 Geronimo 中创建数据库池 PurchaseOrderDataSource。
在左窗格中选择 Database Pools,然后选择 Using the Geronimo database pool wizard,如 图 7 所示。完成后续步骤,如 图 8 和 图 9 所示。
图 7. 创建数据库池
键入 PurchaseOrderDataSource 作为数据库池名、Derby Embedded 作为类型,如 图 8 所示。
图 8. 选择数据库类型
从 Driver JAR 下拉列表中选择 org.apache.derby/derby/10.1.1.0/jar。您可将用户名和口令字段留空。选择 ExampleDatabase 作 为数据库名(参见 图 9)。
图 9. 选择数据库驱动和数据库名
只要将未填充的字段留空,即可使用默认值,单击 Test Connection 按钮来测试连接(参见 图 10)。
图 10. 测试数据库连接池
现在,您应看到测试结果,表示您已连接到 Derby,如 图 11 所示。
图 11. 成功测试连接
选择 Deploy 按钮后,您应看到数据库池已成功创建(参见 图 12)。
图 12. 数据库池创建成功
部署
既然已完成了数据库配置,那么也就准备好在 Geronimo 中部署包含 EJB 和 MDB 的应用程序了(po-ejb.jar)。po-ejb.jar 文件位 于 $part1.home/deploy 目录下。
您可以使用命令行,也可以使用基于控制台的部署,分别介绍如下。
命令行部署
下载文件 part1.zip 的 $part1.home 目录中有用于部署(deploy.cmd)和取消部署(undeploy.cmd)的脚本。
务必在使用前修改命令文件中的 JAVA_HOME 和 GERONIMO_HOME。
控制台部署
使用 http://localhost:8080/console 处的 Geronimo 管理控制台部署 po-ejb.jar 文件,如 图 13 所示。
图 13. 部署新应用程序
成功部署应用程序后,您将接收到如 图 14 所示的消息。
图 14. 部署成功
测试
最后,您可创建一个客户机或测试程序来测试您的应用程序。
创建客户机
您的客户机程序(参见 清单 14)将向 POTopic 发布一条带有采购请求信息的 JMS 消息。由于 PurchaseOrderMDB 侦听 POTopic,服 务器将调用 onMessage() 方法,此方法又会调用 PurchaseOrderEJB 在数据库中创建采购订单。
客户机 PurchaseOrderPublisher.java 位于 $part1.home/src/examples/po/test 目录中。
清单 14. 发布 JMS 消息的客户机程序
public class PurchaseOrderPublisher { public static void main(String a[]) throws Exception { Logger log = Logger.getLogger("PurchaseOrderPublisher"); javax.jms.TopicConnection conn = null; javax.jms.TopicPublisher publisher = null; javax.jms.TopicSession session = null; try { // JMS JNDI Properties for Apache Geronimo Server java.util.Hashtable env = new java.util.Hashtable(); env.put("java.naming.facTory.initial", "org.activemq.jndi.ActiveMQInitialContextFacTory"); env.put("java.naming.provider.url", "tcp://localhost:61616"); env.put("topic.POTopic", "POTopic"); env.put("connectionFacToryNames", "POConnectionFacTory"); // create a new initial context with jndi properties javax.naming.Context ctx = new javax.naming.InitialContext(env); // lookup the connection facTory javax.jms.TopicConnectionFacTory facTory = (javax.jms.TopicConnectionFacTory) ctx .lookup("POConnectionFacTory"); // create a new TopicConnection conn = facTory.createTopicConnection(); javax.jms.Topic mytopic =(javax.jms.Topic) ctx.lookup("POTopic"); // create a new TopicSession session = conn.createTopicSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); //create a Topic Publisher to publish messages to 'POTopic' publisher = session.createPublisher(mytopic); // start the topic connection conn.start(); // create a new purchase order with test data PurchaseOrderBean poBean = new PurchaseOrderBean(); Random random = new Random(); String poNum = "PO" + random.nextInt(); poBean.setPurchaseOrderNum(poNum); poBean.setItem("Pens"); poBean.setDescription("Need pens for Marketing dept."); poBean.setUnitPrice(new Integer(2)); poBean.setQuantity(new Integer(100)); poBean.setRequesTorEmail("user1@localhost.com"); // create a jms message javax.jms.ObjectMessage poMsg =session.createObjectMessage(poBean); // publish the jms message to 'POTopic' publisher.publish(poMsg); } catch (Exception e) { log.severe("Error Occurred: " + e); } finally { // release all jms resources if (publisher != null) publisher.close(); if (session != null) session.close(); if (conn != null) conn.close(); } }// end main}// end class
运行测试
下载的 part1.zip 文件中提供了一个脚本文件(参见 下载 部分),修改 $part1.home/runtester.cmd 中的 JAVA_HOME、J2EE_JAR 和 GERONIMO_HOME(参见 图 15)。
图 15. 测试应用程序
现在您应看到 Geronimo 控制台中显示出一些日志记录,如 图 16 所示。
图 16. Geronimo 服务器日志
如果 PURCHASEORDER 数据库中添加了一条新记录,则本测试将被视为成功。
结果
现在检查数据库,看看 PURCHASEORDER 表中是否有记录项,如 图 17 所示。
图 17. 检查数据库表中是否有新记录项
太棒了!您已经完成了本系列教程第 1 部分的学习。
在第 2 部分中,您将开发一个电子邮件应用程序,此应用程序将在 Apache James 中部署。
结束语
您已成功完成了这个共分三部分的系列教程的第 1 部分。您创建了一个 MDB 和一个带有 CMP 的实体 bean。这些 bean 协同工作,向 系统中添加采购订单。
请继续关注第 2 部分,您将使用 Apache James 邮件应用程序平台来构建一个电子邮件应用程序;另外还有第 3 部分,在第 3 部分 中您要将这篇教程中创建的两个 bean 以及第 2 部分中创建的电子邮件应用程序联系在一起,完成整个应用程序。
本文配套源码
一个人的期望值越大,心理承受力就会越小,就越经受不住失败的打击,