Enterprise JavaBeans 组件和 CORBA 客户端:开发者指南
2012-07-16 09:32
615 查看
本文讨论如何让用 CORBA 支持的任何语言编写的客户端能够访问 Enterprise JavaBeansTM 组件 (“EJBTM 组件”)。本文针对深入了解 JavaTM 2 Platform, Enterprise Edition ("J2EETM") 和公共对象请求代理结构(Common Object Request Broker Architecture,CORBA)的程序员。
J2EE 技术简化了企业应用程序,因为它将它们建立在标准、模块化和可重用组件的基础上,而该组件又基于 Enterprise JavaBeansTM(EJBTM) 体系结构,它也提供了完整的一组针对于那些组件的服务,并自动处理应用程序行为的许多细节。通过自动化应用程序开发的许多耗时且困难的任务,J2EE 技术使企业开发人员能够将重点放在增值上,也就是增强业务逻辑,而不是放在构建基础结构上。
EJBTM 服务器端组件模型简化了事务型、可伸缩和可移植的中间件组件的开发。Enterprise JavaBeans 服务器减少了中间件开发的复杂程度,因为它为诸如事务、安全、数据库连接等中间件服务提供了支持。
CORBA 是一个对象管理组织(Object Management Group,OMG)标准,它是一个开放的、供应商无关的体系结构和基础结构,计算机应用程序可以使用它来通过网络一起工作。由于使用了标准的 Internet Inter-ORB Protocol,(IIOP),因些来自任何供应商的基于 CORBA 的程序可以与来自相同或其他供应商的基于 CORBA 程序进行互操作,前一程序可以在几乎所有的计算机、操作系统、编程语言和网络上,后一程序可以在几乎所有的其他计算机、操作系统、编程语言和网络上。 要进一步学习 CORBA,请访问http://www.omg.org/gettingstarted/gettingstartedindex.htm。
CORBA 技术补充了 Java 平台,因为它提供了分布式对象框架、支持此框架的服务以及与其他语言的互操作性。CORBA 技术是 Java 2 平台的主要部分,它正用于 Enterprise JavaBeans 组件、 运行在 Internet Inter-ORB 协议上的Java 远程方法调用 API ("Java RMI-IIOP"),以及 Java IDL API ("Java IDL")。
OMG 接口定义语言(Interface Definition Language,IDL)可用于描述一些接口,该接口由远程对象实现。IDL 可用于定义接口的名称,以及定义每个属性和方法的名称。一旦创建 IDL 文件,就可以在任何语言中,使用 IDL 编译器来生成客户端存根模块 (stub) 和服务器骨架语句 (server skeleton),OMG已经为此定义了这种语言映射的规范。要进一步了解 OMG IDL,请访问 http://www.omg.org/gettingstarted/omg_idl.htm。
Java IDL 使得分布式 Java 应用程序能够透明地调用远程网络服务上的操作,而该服务使用对象管理组织 (http://www.omg.org/) 定义的行业标准 OMG IDL 和 IIOP。运行在 IIOP API 上的 Java RMI 使得可以通过
编写 EJB 组件的开发人员可以遵循 Java RMI 编程模型,并将它用于他们的分布式对象模型,在该模型中,跨越所有应用程序服务器常见的所需传输是 Java RMI-IIOP。在异构服务器环境中,到 CORBA 的 EJB 体系结构的标准映射使得能够进行下述的互操作:
使用来自某一供应商 ORB 的客户端可以访问驻留在服务器上的企业 bean,而该服务器支持由另一供应商提供的 Enterprise JavaBeans 技术(“EJB 服务器”)。
一台 EJB 服务器上的企业 bean 可以访问另一台 EJB 服务器上的企业 bean。
除了Java 编程语言之外,用某一语言编写的 CORBA 客户端可以访问任何 EJB 组件,前提是要有一个从 OMG IDL 到那种编程语言的映射。
本文档的其余部分提供了 CORBA 客户端应用程序的例子,该应用程序访问了企业 bean 对象。在本文档中,CORBA 客户端就是使用 CORBA 支持的任何语言编写的客户端应用程序,这些编程语言包括 Java 编程语言、C++、C、Smalltalk、COBOL、Ada、Lisp 或 Python。虽然本例中的 Java 代码特定于企业 bean,但开发 CORBA 的客户端的过程是相同的,并且开发的 CORBA 客户端可以访问使用 Java RMI-IIOP API 创建的服务器。
可以在 链接到类似例子 中找到一些链接,它们指向其他实现了 J2EE 技术的供应商提供的类似应用程序。
下面的几节展示了 CORBA 客户端的一般开发过程,开发完的 CORBA 客户端可以访问企业 bean:
编写 Enterprise JavaBean 组件
生成 CORBA IDL
创建 CORBA 客户端
部署 Enterprise JavaBean 组件
运行客户端可执行文件
本文档也包括:
创建 Java RMI-IIOP 客户端应用程序
如何增强应用程序
针对复杂接口的技巧
链接到类似例子
为了使例子变得简单,我们采取了一些捷径。有关构建更加高级的解决方案的信息,请参阅 针对复杂接口的技巧。
在
[b]编译本节编写的文件,例如:[/b]
这些命令在当前目录中为所有的 .java 文件创建了类文件。这个命令和本文中的其他命令假定已经正确设置了 J2EE_HOME 环境变量。使用 $J2EE_HOME 是 Unix® 操作系统的规定。当在 Microsoft Windows 操作环境中,请替换 %J2EE_HOME%。
[b]针对 Java 类文件运行
[/code]
在前面的例子中,我们包括了 .jar 文件和
在上面的
在 Java 类文件上运行
注意:许多生成文件包含了只能在 Java 编程环境中使用的 API 。 例如,目前
注意: 由于 CORBA 异常不支持继承,因此针对 IDL 映射的 Java 语言创建了
使用 C++ 供应商的“IDL to C++”编译器来编译 IDL 文件,以便生成对应于 IDL 的 C++ 代码。不同的供应商之间,这个过程的步骤会有区别,因此有必要参考产品文档,取得针对供应商的特定步骤。
在本例中,客户端代码执行下面的一些操作:
创建对象请求代理(ORB)。ORB 将对象请求服务连接到提供它们的对象。
注册值工厂。
在命名上下文中查找
从返回给
创建
在日志中记录消息。
告诉应用程序服务器不再使用 EJB 引用。
使用类似于下面的 C++ 代码来创建客户端。准确的代码可能与 C++ 实现有关。这些代码是针对于 ORBacus for C++ 4.0.5 编写的,因此本例中的一些 C++ 代码可能特定于该产品。
使用 C++ 编译器来编译所有的 C++ 文件,包括 Client.cpp 文件,创建客户端可执行文件。不同平台之间,这样的一些工具的区别甚大,因此有必要参考产品文档,获得它的说明。
通过键入如下命令,从终端窗口或命令行提示中启动 RI 应用程序:
当 J2EE 1.3 RI 指出“J2EE 启动完成”时,键入如下命令,从另一终端窗口或命令提示中运行部署工具:
从部署工具中,选择
在 Application File Name 字段中,输入
在 Application Display Name 字段中,输入
选择 OK 来保存设置,关闭这个对话窗口。
从部署工具中,选择
如果出现 Introduction 屏幕,选择 Next,否则继续。
在 New EnterpriseBean Wizard 中,在 Contents 框中选择 Edit。
扩展 Available Files 列表,添加下面的 4 个
选择
选择
选择
选择
选择 Next 按扭,直到看到
选择
选择
选择 OK 保存设置并关闭这个对话窗口。
选择 Finish.
从部署工具中,选择
如果只运行 Java RMI-IIOP 客户端,选择 Return Client JAR。
选择 Next。
在
选择 Finish。
选择 File -> Exit 来退出部署工具。
现在已经部署了具有
在这个 URL 中,
要在其上查找引用的宿主计算机是
如果您正在使用 J2EE 1.3 Reference Implementation,应该会看到类似于如下的一条消息,该消息是在应用程序服务器上被打印的:
[/code]
不同的操作系统之间,停止运行中进程的过程是不同的,因此如果正在使用不同的服务器,可以参考系统文档以取得详细信息。
在客户端 CLASSPATH 中,必须包括客户端
当使用 J2EE 1.3 RI 部署应用程序时,检查 Deploy 屏幕第一页上的 Deploytool 中的
下面的代码是 Java RMI-IIOP 版本的
使用下面的命令,在
[/code]
像 部署 Enterprise JavaBean 组件中所描述的那样部署 Enterprise JavaBean 组件。当运行 Java RMI-IIOP 客户应用程序时,记得在Tools -> Deploy 页中选择 Return Client JAR 。 Deployment 主题中的一些命令指导您启动 J2EE RI 或其他应用程序服务器。
使用类似于如下命令运行客户应用程序:
在 J2EE RI 正在运行的窗口中,将会看到:
[/code]
在运行客户端的窗口中,将会看到:
[/code]
停止 J2EE 服务器。
如何增强应用程序
针对复杂接口的技巧
链接到类似例子
开发使用值类型的例子。
为达到此目的,当运行
在
避免将复杂的 Java 类,比如
在将这些类开映射到 IDL 后,将强制您使用客户端编程语言实现它们。此外,由于 Java Object Serialization 和 RMI-IIOP API 使得类的线路格式和内部表示能够随时间不断发展,因此您的 CORBA 客户端应用程序可能在不同的 JavaTM 2 Platform, Standard Edition (J2SETM) 实现或版本上不兼容。
从 IDL 开始。
您可能想在返回类型或方法参数中使用复杂的数据结构。在本例中,试着从 IDL 开始。在 IDL 中定义数据结构,甚至定义异常,然后将它们用在 EJB 接口中。这将可以防止逆向映射的产出物进入 CORBA 接口。
例如,刚开始试着在 IDL 中定义
避免重载 EJB 接口。
CORBA IDL 不支持方法重载,符合 IDL 映射规范的 Java 语言解决了这一点,其方式是创建 IDL 方法定义,将方法名与它的所有 IDL 参数类型组合起来。对于使用非 Java 编程语言的开发人员来说,这带来了非常不友好的方法名。
考虑使用桥。
如果可用的选项仍然太有限,或者影响到想编写的代码,就可以考虑使用服务器端桥。在“链接到类似例子”一节列出了一些站点,您可以从这些站点中获得更多有关如何构建桥的信息。
IONA - EJB-CORBA and CORBA-EJB Interoperability 位于 http://www.iona.com/whitepapers/CORBA-EJBInteropWPV02-00.pdf。
BEA - EJB-to-CORBA/Java Simpapp Sample Application 位于 http://edocs.bea.com/wle/wle50/interop/ejbcorba.htm。
Borland - Sevens steps to build a VisiBroker C++ CORBA Client for an EJB Server 位于http://www.borland.com/devsupport/appserver/faq/ejbcpp/ejb_cpp.html。
J2EE 技术简化了企业应用程序,因为它将它们建立在标准、模块化和可重用组件的基础上,而该组件又基于 Enterprise JavaBeansTM(EJBTM) 体系结构,它也提供了完整的一组针对于那些组件的服务,并自动处理应用程序行为的许多细节。通过自动化应用程序开发的许多耗时且困难的任务,J2EE 技术使企业开发人员能够将重点放在增值上,也就是增强业务逻辑,而不是放在构建基础结构上。
EJBTM 服务器端组件模型简化了事务型、可伸缩和可移植的中间件组件的开发。Enterprise JavaBeans 服务器减少了中间件开发的复杂程度,因为它为诸如事务、安全、数据库连接等中间件服务提供了支持。
CORBA 是一个对象管理组织(Object Management Group,OMG)标准,它是一个开放的、供应商无关的体系结构和基础结构,计算机应用程序可以使用它来通过网络一起工作。由于使用了标准的 Internet Inter-ORB Protocol,(IIOP),因些来自任何供应商的基于 CORBA 的程序可以与来自相同或其他供应商的基于 CORBA 程序进行互操作,前一程序可以在几乎所有的计算机、操作系统、编程语言和网络上,后一程序可以在几乎所有的其他计算机、操作系统、编程语言和网络上。 要进一步学习 CORBA,请访问http://www.omg.org/gettingstarted/gettingstartedindex.htm。
CORBA 技术补充了 Java 平台,因为它提供了分布式对象框架、支持此框架的服务以及与其他语言的互操作性。CORBA 技术是 Java 2 平台的主要部分,它正用于 Enterprise JavaBeans 组件、 运行在 Internet Inter-ORB 协议上的Java 远程方法调用 API ("Java RMI-IIOP"),以及 Java IDL API ("Java IDL")。
OMG 接口定义语言(Interface Definition Language,IDL)可用于描述一些接口,该接口由远程对象实现。IDL 可用于定义接口的名称,以及定义每个属性和方法的名称。一旦创建 IDL 文件,就可以在任何语言中,使用 IDL 编译器来生成客户端存根模块 (stub) 和服务器骨架语句 (server skeleton),OMG已经为此定义了这种语言映射的规范。要进一步了解 OMG IDL,请访问 http://www.omg.org/gettingstarted/omg_idl.htm。
Java IDL 使得分布式 Java 应用程序能够透明地调用远程网络服务上的操作,而该服务使用对象管理组织 (http://www.omg.org/) 定义的行业标准 OMG IDL 和 IIOP。运行在 IIOP API 上的 Java RMI 使得可以通过
javax.rmiAPI 来对 CORBA 服务器和应用程序进行编程。
编写 EJB 组件的开发人员可以遵循 Java RMI 编程模型,并将它用于他们的分布式对象模型,在该模型中,跨越所有应用程序服务器常见的所需传输是 Java RMI-IIOP。在异构服务器环境中,到 CORBA 的 EJB 体系结构的标准映射使得能够进行下述的互操作:
使用来自某一供应商 ORB 的客户端可以访问驻留在服务器上的企业 bean,而该服务器支持由另一供应商提供的 Enterprise JavaBeans 技术(“EJB 服务器”)。
一台 EJB 服务器上的企业 bean 可以访问另一台 EJB 服务器上的企业 bean。
除了Java 编程语言之外,用某一语言编写的 CORBA 客户端可以访问任何 EJB 组件,前提是要有一个从 OMG IDL 到那种编程语言的映射。
本文档的其余部分提供了 CORBA 客户端应用程序的例子,该应用程序访问了企业 bean 对象。在本文档中,CORBA 客户端就是使用 CORBA 支持的任何语言编写的客户端应用程序,这些编程语言包括 Java 编程语言、C++、C、Smalltalk、COBOL、Ada、Lisp 或 Python。虽然本例中的 Java 代码特定于企业 bean,但开发 CORBA 的客户端的过程是相同的,并且开发的 CORBA 客户端可以访问使用 Java RMI-IIOP API 创建的服务器。
可以在 链接到类似例子 中找到一些链接,它们指向其他实现了 J2EE 技术的供应商提供的类似应用程序。
开发访问 Enterprise JavaBean 组件的 CORBA 客户端
这是一个关于如何开发 CORBA 客户端应用程序以便访问 EJB 组件的例子。在本例中,客户端是用 C++ 编程语言编写的,但客户端可以是由 CORBA 支持的任何语言编写的。下面的几节展示了 CORBA 客户端的一般开发过程,开发完的 CORBA 客户端可以访问企业 bean:
编写 Enterprise JavaBean 组件
生成 CORBA IDL
创建 CORBA 客户端
部署 Enterprise JavaBean 组件
运行客户端可执行文件
本文档也包括:
创建 Java RMI-IIOP 客户端应用程序
如何增强应用程序
针对复杂接口的技巧
链接到类似例子
为了使例子变得简单,我们采取了一些捷径。有关构建更加高级的解决方案的信息,请参阅 针对复杂接口的技巧。
第 1 部分:编写 Enterprise JavaBean 组件
下面的一些例子展示了企业 bean 的代码,它将从 Java RMI-IIOP 和 CORBA 客户端接收发送给应用程序服务器的字符串日志消息。企业 bean 将在服务器上把它们与当前服务器时间一起打印出来。在
/Java/src/ejbinterop目录中创建如下文件:
Logger.java、
LoggerHome.java、
LoggerEJB.java和
LogMessage.java。
Logger.java
Logger.java文件是企业 bean 的远程接口,因此,它扩展了
EJBObject。远程接口提供了 EJB 对象的远程客户端视图,并定义了可由远程客户端调用的 business 方法。
//Code Example 1: Logger.java packageejbinterop; importjavax.ejb.EJBObject; importjava.rmi.RemoteException; /** * Accepts simple String log messages and prints * them on the server. */ public interface Logger extends EJBObject { /** * Logs the given message on the server with * the current server time. */ void logString(String message) throws RemoteException; }
LoggerHome.java
LoggerHome.java文件扩展了
EJBHome。
EJBHome接口必须由所有 EJB 组件的远程 home 接口来扩展。home 接口定义了一些方法,使得远程客户端可以创建、查找和删除 EJB 对象,以及创建、查找和删除不针对 EJB 实例的 home business 方法。
//Code Example 2: LoggerHome.java packageejbinterop; importjava.rmi.RemoteException; importjavax.ejb.EJBHome; importjavax.ejb.CreateException; public interface LoggerHome extends EJBHome { Logger create() throws RemoteException, CreateException; }
LoggerEJB.java
LoggerEJB.java文件包含了会话 bean 的代码。会话 bean 是一种企业 bean,它由客户端创建,并且通常只在一个客户/服务器会话期间存在。会话 bean 执行像计算或访问客户端数据库这样的操作。在本例中,企业 bean 从客户端接收简单的字符串日志消息,并在服务器上打印它们。
//LoggerEJB.java packageejbinterop; importjavax.ejb.*; importjava.util.*; importjava.rmi.*; importjava.io.*; /** * Accepts simple String log messages and prints * them on the server. */ public class LoggerEJB implements SessionBean { public LoggerEJB() {} public void ejbCreate() {} public void ejbRemove() {} public void ejbActivate() {} public void ejbPassivate() {} public void setSessionContext(SessionContext sc) {} /** * Logs the given message on the server with * the current server time. */ public void logString(String message) { LogMessage msg = new LogMessage(message); System.out.println(msg); } }
LogMessage.java
LogMessage.java文件取得当前的日期和时间,然后创建格式化字串来显示消息,并将消息打印到服务器。
//LogMessage.java packageejbinterop; importjava.io.Serializable; importjava.util.Date; importjava.text.*; /** * Simple message class that handles pretty * printing of log messages. */ public class LogMessage implements Serializable { private String message; private long datetime; /** * Constructor taking the message. This will * take the current date and time. */ public LogMessage(String msg) { message = msg; datetime = (new Date()).getTime(); } /** * Creates a formatted String showing the message. */ public String toString() { StringBuffer sbuf = new StringBuffer(); DateFormat dformat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG); FieldPosition fpos = new FieldPosition(DateFormat.DATE_FIELD); dformat.format(new Date(datetime), sbuf, fpos); sbuf.append(": "); sbuf.append(message); return sbuf.toString(); } }
[b]编译本节编写的文件,例如:[/b]
javac -classpath $J2EE_HOME/lib/j2ee.jar:.. *.java
这些命令在当前目录中为所有的 .java 文件创建了类文件。这个命令和本文中的其他命令假定已经正确设置了 J2EE_HOME 环境变量。使用 $J2EE_HOME 是 Unix® 操作系统的规定。当在 Microsoft Windows 操作环境中,请替换 %J2EE_HOME%。
第 2 部分:生成 CORBA IDL
本节讨论如何从 Java 类文件中生成接口定义语言(Interface Definition Language,IDL),并且假定 Java 类文件已在前一节中生成。在本例中,我们将使用rmic编译器,以便将 Java 代码映射到 IDL。IDL 提供了纯声明性的、编程语言无关的方式来指定对象的 API。
[b]针对 Java 类文件运行
rmic编译器,该 Java 类文件已在前一步骤中生成,其命令如下:[/b]
rmic -idl -noValueMethods -classpath $J2EE_HOME/lib/j2ee.jar:<path_to_ejbinterop_dir> -d <path_to_where_idl_files_should_be_generated> ejbinterop.Loggerejbinterop.LoggerHome
[/code]
在前面的例子中,我们包括了 .jar 文件和
ejbinterop文件的目录,.jar 文件中包含有
javax.ejb包的定义。如果您正在使用 JavaTM2 Platform, Enterprise Edition (J2EETM), version 1.3 Reference Implementation (RI),那么
.jar文件就位于
$J2EE_HOME/lib/j2ee.jar。
在上面的
rmic命令行中,我们推荐了一种捷径——使用
noValueMethods选项。这个选项告诉
rmic跳过具有参数或返回类型的任何方法,这里的返回类型将被映射到 CORBA 值类型。有利的方面在于它将防止我们生成许多不必要的 IDL,在 C++客户端中,我们可能必须实现这些 IDL。不利的方面在于我们只能使用原始的数据类型、数组和字符串,而不能使用自己的 Java 类类型来作为参数或返回类型。 有关进一步信息,请阅读 针对复杂接口的技巧。
在 Java 类文件上运行
rmic编译器会生成下面的一些文件,文件所处的目录由上面
rmic语句的 -d 选项指出:
java/lang/Ex.idl
java/lang/Exception.idl
java/lang/Object.idl
java/lang/Throwable.idl
java/lang/ThrowableEx.idl
javax/ejb/CreateEx.idl
javax/ejb/CreateException.idl
javax/ejb/EJBHome.idl
javax/ejb/EJBMetaData.idl
javax/ejb/EJBObject.idl
javax/ejb/Handle.idl
javax/ejb/HomeHandle.idl
javax/ejb/RemoveEx.idl
javax/ejb/RemoveException.idl
ejbinterop/Logger.idl
ejbinterop/LoggerHome.idl
注意:许多生成文件包含了只能在 Java 编程环境中使用的 API 。 例如,目前
EJBMetaData实现特定于每个应用程序服务器,因此很难开发等效设施,以便在除 Java 平台外的平台上继续超时工作。一种选择是将它们从 IDL 中删除,但如果这样做,那么每次改变 Java 接口,并从
rmic编译器中重生成 IDL 文件时,就必须从 IDL 中删除它们。
注意: 由于 CORBA 异常不支持继承,因此针对 IDL 映射的 Java 语言创建了
Ex类,它包含了代表实际 Java 异常的 CORBA 值类型。在这个基本的例子中,不必过多担心异常支持。有关异常的进一步信息,请参阅
http://java.sun.com/j2se/1.4.2/docs/guide/idl/jidlExceptions.html。
使用 C++ 供应商的“IDL to C++”编译器来编译 IDL 文件,以便生成对应于 IDL 的 C++ 代码。不同的供应商之间,这个过程的步骤会有区别,因此有必要参考产品文档,取得针对供应商的特定步骤。
第 3 部分:创建 CORBA 客户端
客户端应用程序可以使用 CORBA 支持的任何语言编写。下面的例子提供了针对于 C++ 客户端的代码,只要给予对象请求代理人( Object Request Broker,简称 ORB)和LoggerHome对象的
corbanameURL,它就会在服务器上将简单字符串消息记录到日志中。您必须根据 C++ ORB 供应商的库来调整
include语句,并修改注册值工厂的代码。本例是针对 ORBacus for C++ 4.0.5 编写的,因此本例中的一些 C++ 代码是特定于该产品的。
corbanameURL 是可阅读的 URL 格式,它允许您访问 CORBA 对象。它用于从特定命名上下文解析字符串化的名称。这是 J2EE v 1.3 平台中的新特性,它作为 CORBA 互操作命名服务(Interoperable Naming Service,简称 INS)的一部分。INS 是 CORBA 对象服务(CORBA Object Services,简称COS)命名服务的扩展,在以前版本的 J2EE 平台中已经交付使用。为了进一步了解 INS,请访问http://java.sun.com/j2se/1.4.2/docs/guide/idl/jidlNaming.html#INS。
在本例中,客户端代码执行下面的一些操作:
创建对象请求代理(ORB)。ORB 将对象请求服务连接到提供它们的对象。
注册值工厂。
在命名上下文中查找
corbanameURL 指向的
LoggerHome对象。
从返回给
LoggerHome对象的对象中执行安全的向下转换。
创建
LoggerEJB对象引用。
在日志中记录消息。
告诉应用程序服务器不再使用 EJB 引用。
使用类似于下面的 C++ 代码来创建客户端。准确的代码可能与 C++ 实现有关。这些代码是针对于 ORBacus for C++ 4.0.5 编写的,因此本例中的一些 C++ 代码可能特定于该产品。
//Code Example: Client.cpp
#include <fstream.h>
// C++ ORB Vendor specific include files
// These are from C++ ORBacus 4.0.5
#include <OB/CORBA.h>
#include <OB/OBORB.h>
// Include files generated from our IDL
#include <java/lang/Exception.h>
#include <java/lang/Throwable.h>
#include <javax/ejb/CreateException.h>
#include <javax/ejb/RemoveException.h>
#include <ejbinterop/Logger.h>
#include <ejbinterop/LoggerHome.h>
/**
* Given an ORB and a corbaname URL for a LoggerHome
* object, logs a simple string message on the server.
*/
void
run(CORBA::ORB_ptr orb, const char* logger_home_url)
{
cout << "Looking for: " << logger_home_url << endl;
// Look up the LoggerHome object in the naming context
// pointed to by the corbaname URL
CORBA::Object_var home_obj
= orb->string_to_object(logger_home_url);
// Perform a safe downcast
ejbinterop::LoggerHome_var home
=ejbinterop::LoggerHome::_narrow(home_obj.in());
assert(!CORBA::is_nil(home));
// Create a Logger EJB reference
ejbinterop::Logger_var logger = home->create();
CORBA::WStringValue_var msg =
new CORBA::WStringValue((const CORBA::WChar*)L"Message
from a C++ client");
cout << "Logging..." << endl;
// Log our message
logger->logString(msg);
// Tell the application server we won't use this
// EJB reference any more
logger->remove();
cout << "Done" << endl;
}
/**
* Simple main method that checks arguments, creates an
* ORB, and handles exceptions.
*/
int
main(int argc, char* argv[])
{
int exit_code = 0;
CORBA::ORB_var orb;
try {
// Check the arguments
if (argc != 2) {
cerr << "Usage: Client <corbaname URL of LoggerHome>" << endl;
return 1;
}
// Create an ORB
orb = CORBA::ORB_init(argc, argv);
// Register value factories
// NOTE: This is overkill for the example since we'll never
// get these exceptions. Also, the _OB_id method is a
// proprietary feature of ORBacus C++ generated code.
CORBA::ValueFactory factory = newjava::lang::Throwable_init;
orb -> register_value_factory(java::lang::Throwable::_OB_id(),
factory);
factory -> _remove_ref();
factory = newjava::lang::Exception_init;
orb -> register_value_factory(java::lang::Exception::_OB_id(),
factory);
factory -> _remove_ref();
factory = newjavax::ejb::CreateException_init;
orb -> register_value_factory(javax::ejb::CreateException::_OB_id(),
factory);
factory -> _remove_ref();
factory = newjavax::ejb::RemoveException_init;
orb ->
register_value_factory(javax::ejb::RemoveException::_OB_id(),
factory);
factory -> _remove_ref();
// Perform the work
run(orb, argv[1]);
} catch(const CORBA::Exception& ex) {
// Handle any CORBA related exceptions
cerr << ex._to_string() << endl;
exit_code = 1;
}
// Release any ORB resources
if (!CORBA::is_nil(orb)) {
try {
orb -> destroy();
} catch(const CORBA::Exception& ex) {
cerr << ex._to_string() << endl;
exit_code = 1;
}
}
return exit_code;
}
使用 C++ 编译器来编译所有的 C++ 文件,包括 Client.cpp 文件,创建客户端可执行文件。不同平台之间,这样的一些工具的区别甚大,因此有必要参考产品文档,获得它的说明。
第 4 部分:部署 Enterprise JavaBean 组件
使用满意的应用程序服务器部署企业 bean。下面的一些步骤描述了如何部署LoggerEJB组件,它使用了 J2EE 1.3 Reference Implementation (RI)。
通过键入如下命令,从终端窗口或命令行提示中启动 RI 应用程序:
$J2EE_HOME/bin/j2ee -verbose
当 J2EE 1.3 RI 指出“J2EE 启动完成”时,键入如下命令,从另一终端窗口或命令提示中运行部署工具:
$J2EE_HOME/bin/deploytool
从部署工具中,选择
File
->
New
->
Application。
在 Application File Name 字段中,输入
Logger.ear,以指出要在其中创建应用程序的文件。
在 Application Display Name 字段中,输入
Logger。
选择 OK 来保存设置,关闭这个对话窗口。
从部署工具中,选择
File
->
New
->
Enterprise Bean。
如果出现 Introduction 屏幕,选择 Next,否则继续。
在 New EnterpriseBean Wizard 中,在 Contents 框中选择 Edit。
扩展 Available Files 列表,添加下面的 4 个
.class文件,它们来自
ejbinterop包:
Logger.class、
LoggerHome.class、
LoggerEJB.class和
LogMessage.class。选择 OK,然后选择 Next。
选择
Stateless
Session
Bean
Type。
选择
ejbinterop.LoggerEJB用于
Enterprise
Bean
Class。
选择
ejbinterop.LoggerHome用于
Remote
Home
Interface。
选择
ejbinterop.Logger用于
Remote
Interface。
选择 Next 按扭,直到看到
Security
Settings页。
选择
Deployment
Settings按扭。
选择
Support
Client
Choice.
选择 OK 保存设置并关闭这个对话窗口。
选择 Finish.
从部署工具中,选择
Tools
->
Deploy。
如果只运行 Java RMI-IIOP 客户端,选择 Return Client JAR。
选择 Next。
在
JNDI
Namefor our LoggerEJB 字段中输入
ejbinterop/logger。
选择 Finish。
选择 File -> Exit 来退出部署工具。
现在已经部署了具有
LoggerEJB组件的 Logger 应用程序,它准备接收消息。
第 5 部分:运行客户端可执行文件
[b] 运行客户端可执行文件。运行客户端可执行程序的一种方法是,切换到包含可执行客户端文件的目录,然后在终端窗口中输入下面的 URL:[/b]Client corbaname:iiop:1.2@localhost:1050#ejbinterop/logger
在这个 URL 中,
Client是要运行的应用程序的名称。
corbaname指出将从特定的命名上下文中解析字符串化的名称。
iiop:1.2告诉 ORB 使用 IIOP 协议和 GIOP 1.2。
要在其上查找引用的宿主计算机是
localhost——本地计算机。为了扩展这个例子,以便在两台计算机上运行,请输入计算机的 IP 地址和主机名,而不是
localhost,服务器要在该计算机上运行。
1050是端口号,命名服务会在该端口上侦听请求。 在 J2EE v.1.3 RI 中,默认情况下,命名服务要在其上侦听的默认端口号是端口 1050。到目前为止,散列标记 (hash mark) 上的引用部分(
Client corbaname:iiop:1.2@localhost:1050) 是某个 URL,它返回根命名上下文。
ejbinterop/logger是要在命名上下文中解析的名称。
如果您正在使用 J2EE 1.3 Reference Implementation,应该会看到类似于如下的一条消息,该消息是在应用程序服务器上被打印的:
is the name to be resolved from the Naming Service.
Sep 21, 2001 3:33:07 PM PDT: Message from a C++ client[code]ejbinterop/
logger
[/code]
第 6 部分:停止 J2EE 服务器
[b]停止 J2EE 服务器。为了停止服务器,可以在终端窗口或命令行提示中,输入这条命令。[/b]$J2EE_HOME/bin/j2ee -stop
不同的操作系统之间,停止运行中进程的过程是不同的,因此如果正在使用不同的服务器,可以参考系统文档以取得详细信息。
创建 Java RMI-IIOP 客户端应用程序
使用相同的例子,可以容易地开发连接到企业 bean 的 Java RMI-IIOP 客户端,。与使用 C++ 的例子的区别在于:在客户端 CLASSPATH 中,必须包括客户端
.jar文件的位置,该文件是由运行需要的企业 bean 的应用程序服务器创建的。那个
.jar文件包含了必要的客户端存根模块。
当使用 J2EE 1.3 RI 部署应用程序时,检查 Deploy 屏幕第一页上的 Deploytool 中的
Return Client Jar框。
下面的代码是 Java RMI-IIOP 版本的
LoggerEJB组件客户端。遵循与 C++ 客户端例子所展示的相同步骤。当运行客户端时,使用与 C++ 例子中相同的 URL。
//Code Example: LogClient.java
packageejbinterop;
importjava.rmi.RemoteException;
importjavax.rmi.*;
importjava.io.*;
importjavax.naming.*;
importjavax.ejb.*;
/**
* Simple Java RMI-IIOP client that uses an EJB component.
*/
public class LogClient
{
/**
* Given a corbaname URL for a LoggerHome,
* log a simple String message on the server.
*/
public static void run(String loggerHomeURL)
throws CreateException, RemoveException,
RemoteException, NamingException
{
System.out.println("Looking for: " + loggerHomeURL);
// Create an InitialContext. This will use the
// CosNaming provider we will specify at runtime.
InitialContext ic = new InitialContext();
// Lookup the LoggerHome in the naming context
// pointed to by the corbaname URL
Object homeObj = ic.lookup(loggerHomeURL);
// Perform a safe downcast
LoggerHome home
= (LoggerHome)PortableRemoteObject.narrow(homeObj,
LoggerHome.class);
// Create a Logger EJB reference
Logger logger = home.create();
System.out.println("Logging...");
// Log our message
logger.logString("Message from a Java RMI-IIOP client");
// Tell the application server we won't use this
// EJB reference anymore
logger.remove();
System.out.println("Done");
}
/**
* Simple main method to check arguments and handle
* exceptions.
*/
public static void main(String args[])
{
try {
if (args.length != 1) {
System.out.println("Args: corbaname URL of LoggerHome");
System.exit(1);
}
LogClient.run(args[0]);
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
}
使用 Java RMI-IIOP 客户端运行应用程序
当使用 Java RMI-IIOP 客户端,而不是 C++ 客户端运行示例应用程序时,请遵循这些步骤:使用下面的命令,在
ejbinterop/ 目录中编译 .
java文件:
javac -classpath $J2EE_HOME/lib/j2ee.jar:<ejbinterop_directory> *.java
[/code]
像 部署 Enterprise JavaBean 组件中所描述的那样部署 Enterprise JavaBean 组件。当运行 Java RMI-IIOP 客户应用程序时,记得在Tools -> Deploy 页中选择 Return Client JAR 。 Deployment 主题中的一些命令指导您启动 J2EE RI 或其他应用程序服务器。
使用类似于如下命令运行客户应用程序:
java -classpath $J2EE_HOME/lib/j2ee.jar: <path to LoggerClient.jar>/LoggerClient.jar: <directory_above_ejbinterop>:<ejbinterop_directory> ejbinterop.LogClient corbaname:iiop:1.2@localhost:1050#ejbinterop/logger
在 J2EE RI 正在运行的窗口中,将会看到:
Jan 31, 2002 2:27:47 PM PST: Message from a Java RMI-IIOP client
[/code]
在运行客户端的窗口中,将会看到:
Looking for: corbaname:iiop:1.2@localhost:1050#ejbinterop/logger Logging... Done
[/code]
停止 J2EE 服务器。
超越基本应用程序
本部分包括下述信息:如何增强应用程序
针对复杂接口的技巧
链接到类似例子
如何增强应用程序
要增强应用程序,您可以:开发使用值类型的例子。
为达到此目的,当运行
rmic时删除
-noValueMethods开关。重新运行 C++ 语言的 IDL 的映射编译器,检查它是否支持已经生成的值类型。
在
Logger中添加另一方法,它实际取得
LogMessage。
针对复杂接口的技巧
对于运用不同语言的客户端和服务器之间的通信,接口是关键。为了在这方面获得成功,应该考虑下面的建议:避免将复杂的 Java 类,比如
java.util中的集合,用于方法参数或返回类型。
在将这些类开映射到 IDL 后,将强制您使用客户端编程语言实现它们。此外,由于 Java Object Serialization 和 RMI-IIOP API 使得类的线路格式和内部表示能够随时间不断发展,因此您的 CORBA 客户端应用程序可能在不同的 JavaTM 2 Platform, Standard Edition (J2SETM) 实现或版本上不兼容。
从 IDL 开始。
您可能想在返回类型或方法参数中使用复杂的数据结构。在本例中,试着从 IDL 开始。在 IDL 中定义数据结构,甚至定义异常,然后将它们用在 EJB 接口中。这将可以防止逆向映射的产出物进入 CORBA 接口。
例如,刚开始试着在 IDL 中定义
LogMessage类,然后在 Logger EJB 组件中,将 IDL 编译的 Java 语言结果类用作方法参数。
避免重载 EJB 接口。
CORBA IDL 不支持方法重载,符合 IDL 映射规范的 Java 语言解决了这一点,其方式是创建 IDL 方法定义,将方法名与它的所有 IDL 参数类型组合起来。对于使用非 Java 编程语言的开发人员来说,这带来了非常不友好的方法名。
考虑使用桥。
如果可用的选项仍然太有限,或者影响到想编写的代码,就可以考虑使用服务器端桥。在“链接到类似例子”一节列出了一些站点,您可以从这些站点中获得更多有关如何构建桥的信息。
链接到类似例子
实现 J2EE 技术的几个供应商都有一些优秀的例子和技巧,用于集成 CORBA 和 Enterprise JavaBeans 技术:IONA - EJB-CORBA and CORBA-EJB Interoperability 位于 http://www.iona.com/whitepapers/CORBA-EJBInteropWPV02-00.pdf。
BEA - EJB-to-CORBA/Java Simpapp Sample Application 位于 http://edocs.bea.com/wle/wle50/interop/ejbcorba.htm。
Borland - Sevens steps to build a VisiBroker C++ CORBA Client for an EJB Server 位于http://www.borland.com/devsupport/appserver/faq/ejbcpp/ejb_cpp.html。
相关文章推荐
- Enterprise JavaBeans组件慨述(1)
- Enterprise JavaBeans组件慨述(2)
- Enterprise JavaBeans组件慨述(3)
- 什么是 Enterprise JavaBeans 组件?
- Enterprise JavaBeans组件慨述(4)
- Enterprise JavaBeans组件慨述(5)
- Enterprise JavaBeans组件慨述(6)
- Enterprise JavaBeans组件慨述(7)
- 什么是 Enterprise JavaBeans 组件?第一部分:EJB 体系结构的历史和目标
- Enterprise JavaBeans组件慨述(8)
- 什么是 Enterprise JavaBeans 组件?第二部分:EJB 编程模型
- Enterprise JavaBeans 3.0 EJB服务器端组件
- Java应用OpenCV指南其二:OpenCV组件浅析
- Mastering Enterprise JavaBeans 3.0
- Enterprise JavaBeans导论4
- Java 文件上传组件 Apache Commons FileUpload 应用指南(二)——FileUpload如何工作?
- firefox附加组件开发者指南(三)——XUL简介(中)
- Java 文件上传组件 Apache Commons FileUpload 应用指南(二)——FileUpload如何工作?
- Java 文件上传组件 Apache Commons FileUpload 应用指南——FileUpload如何工作?
- RabbitMQ-Java客户端API指南-上