经过一周的折腾,终于搞清楚了如何搭建一个JAVA下的CORBA应用(在JAVA下是JACORB),下面对过程进行一引总结,
主要是借助ECLIPSE、以及JACORB在ECLIPSE下的插件ORBStudio_7.7.7.jar,对于此控件的配置见6,至于使用只需要将其拷贝到ECLIPSE的\plugins目录
1、正确的Java编译环境,主要是JAVA_HOHME(如:D:\Java)\、CLASSPATH(至少包括.;)环境变量
2、添加、设置JACORB环境变量JACORM_HOME及值(如:D:\Java\JacORB)
3、将%JAVA_HOME%、bin、%JACORB_HOME%\bin添加到PATH环境变量
4、将%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar配置值添加到CLASSPATH环境变量
5、将%JACORB_HOME%\lib\antlr-2.7.2.jar;%JACORB_HOME%\lib\antlr-2.7.2.jar;%JACORB_HOME%\lib\avalon-framework-4.1.5.jar;%JACORB_HOME%\lib\concurrent-1.3.2.jar;%JACORB_HOME%\lib\idl.jar;%JACORB_HOME%\lib\jacorb.jar;%JACORB_HOME%\lib\wrapper-3.0.3.jar;%JACORB_HOME%\lib\logkit-1.2.jar;%JACORB_HOME%\classes;添加到CLASSPATH环境变量
(注:将%JACORB_HOME%\bin添加PATH环境主要是方便能人命令行启动JACORB的各项任务命名,如果不想从命名行启动JACORB的各项任务,可以忽略此操作4、5)
6、ECLIPSE下的ORBStudio配置,启动ECLIPSE,
Window->Preferences->ORB Studion->
IDL Compiler->选择JacORB,双击展开IDL Compiler,选择JacOR,配置参数
IDL Command: java
Command Options:-cp "D:\Java\JacORB\lib\idl.jar;D:\Java\JacORB\lib\logkit-1.2.jar" org.jacorb.idl.parser -d %D% %F%
(注意:此处的D:\Java\JacORB视个人环境而定)
APPLY->OK
7、启动ECLIPSE,新建JAVA项目,一切默认即可,新建文件
NEW->OTHERS->CORBA Wizard->IDL files->NEXT->设置IDL文件路径及文件名称(此处以默认值为例)->Finish
打开simple.idl,将看到已经有了默认内容
(大致意思是定义了一个模块,此模块对应到JAVA里面就是一个PACKAGE,此模块(包)中定义了一个名为 MyService 的 interface,此interface定义了一个名为operation1的方法,此方法还接收一个string类型的传入参数,大致就是这么个意思,至于IDM的协议规范,参见具体文档)
8、生成CORBA框架代码,右键simple.idl文件,ORB Menu->Compile,
此时会在src目录生成一个MyServer的包,此包里面将会生成
_MyServiceStub.java
MyService.java
MyServiceHelper.java
MyServiceHolder.java
MyServiceOperations.java
MyServicePOA.java
MyServicePOATie.java
这几个文件,至于具体各是什么意义,我也理太清楚,只知道
MyService变是IDL文件中定义的接口文件,后面会经常用于与org.omg.CORBA.Object打交道
MyServiceHelper应该是个服务类,后面会经常用到,应该是将对象的org.omg.CORBA.Object、interface(MyService)之间进行包装转换用
MyServiceHolder看代码,觉得是个载体对象,具体如何用,目前还不太清楚
MyServiceOperations字面上看就是定义接口的操作的类,实际是个接口,MyService就是继承自它(严格的说是接口继承,因为MyService也是接口)
MyServicePOA CORBA需要的类,我们实现接口(MyService)的类应该从它继承
MyServicePOATie就不太清楚其用处了
9、利用ORB插件为生成实现接口的类,新建文件
NEW->OTHER->CORBA Wizard->Server->Active object map->next->
IDL fieldname:选择/{项目名称}/simple.idl
interface: 选择MyServer.MyService
package:填写包名称(可以任意名称)
Server classname:MyServiceServerImpl(可以任意取名)
继续next,勾选 Create server class(勾了会自动生成SERVER端的默认代码,代码的内容形貌,取决于6的IDL Compiler选项值及具体的子COMMAND和COMMAND OPTIONS)
10、打开MyServiceServerImpl,实现MyServiceOperations接口定义的方法
11、编写服务端代码,打开Server_AOM文件,默认代码是使用IOR文件进行通信的,为了体现CORAB的跨平台特性,此处使用命名服务的方式运行,
注释掉try{...}里面的代码,编写如下代码,其它代码保持不变,并
import org.omg.CosNaming.*;
修改后的代码
// 启动命名服务需要的参数 props.setProperty("ORBInitRef.NameService", "corbaloc::192.168.0.14:30000/NameService"); // 初始化ORB org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, props); // 获取根POA引用 POA poaRoot = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); // 激活POA管理器 poaRoot.the_POAManager().activate(); // 实例化一个MyServiceServerImpl对象 MyServiceServerImpl serviceImpl = new MyServiceServerImpl(); // 从servant获得一个对象引用 org.omg.CORBA.Object refObj = poaRoot.servant_to_reference(serviceImpl); // 获得对象接口引用 MyServer.MyService service = MyServer.MyServiceHelper.narrow(refObj); // 命名上下文 org.omg.CORBA.Object ncObj = orb.resolve_initial_references("NameService"); NamingContextExt nc = NamingContextExtHelper.narrow(ncObj); // 绑定一个服务引用,以便客户端可以调用 nc.rebind(nc.to_name("Simple.MyService"), service); System.out.println("MyService is running and waiting......"); // 运行ORB orb.run();
对CORBA启动整体流程的理解,
首先是设置参数,
设置ORB的服务端实现类
props.setProperty("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB");
调协ORB的单例类
props.setProperty("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingleton");
设置ORB命名服务的初始化参数,具体意思 corbaloc 协议名称 192.168.0.14 ORB服务器地址(也可以是主机名) 30000 ORB运行的端口
props.setProperty("ORBInitRef.NameService", "corbaloc::192.168.0.14:30000/NameService");
设置了参数后,根据参数初始化一个org.omg.CORBA.ORB的实例
接着从ORB实例中获取一个根POA对象引用,通过调用POAHelper服务方法将POA根引用转换成POA对象,
紧接着调用POA管理器,将其激活
服务器端环境设置完成,
进而创建实现接口的对象的实例,
调用要根POA将其转换成一个org.omg.CORBA.Object对象,
再调用服务方法得到其接口定义对象
通过ORB对象获得一个命名服务器对象,
通过命名服务辅助类得到一个命名上下文
再通过命名上下文实与服务接口绑定(因为服务接口与实现接口的对象的已建立关系,所以此时命名上下文也与接口的实现对象建立了关系)
12、编写客户端代码,还是通过ORB 控件生成客户端代码,新建文件
NEW->OTHER->CORBA Wizard->Client->Simple implementation,与9是基本一样,选择IDL文件,选择接口文件、填写包名称、客户端类名称
13、打开MyServiceClientImpl,找到initORB方法,注释默认添加的代码,
其代码如下:
Properties props = System.getProperties(); props.setProperty("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB"); props.setProperty("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingleton"); // 启动参数 props.setProperty("ORBInitRef.NameService", "corbaloc::192.168.0.14:30000/NameService"); orb = org.omg.CORBA.ORB.init(args, props); // 获得命名服务上下文 // 获得命名服务对象 org.omg.CORBA.Object nsObj = null; try { nsObj = orb.resolve_initial_references("NameService"); } catch (InvalidName e) { // TODO Auto-generated catch block e.printStackTrace(); } // 通过命名服务对象得到命名服务上下文 NamingContextExt nc = NamingContextExtHelper.narrow(nsObj); // 从命名服务上下文中获得特定的命名服务对象 org.omg.CORBA.Object svrObj = null; try { svrObj = nc.resolve_str("Simple.MyService"); } catch (NotFound e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (CannotProceed e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (org.omg.CosNaming.NamingContextPackage.InvalidName e) { // TODO Auto-generated catch block e.printStackTrace(); } // 从将特定命名服务对象中获得服务接口 MyServer.MyService service = MyServiceHelper.narrow(svrObj); target = service;
客户端代码就比较简单了,简单描述一下,
首先还是设置参数,初始化ORB,
从ORB实例对象中获取命名服务对象,
通过命名服务对象辅助类从命名服务对象中获取命名服务上下文对象,
从命名服务上下文对象中获取指定名称的服务的org.omg.CORBA.Object对象,
再通过接口服务对象辅助类从org.omg.CORBA.Object类型的接口服务对象中获取实现该接口服务的实例对象
获取了接口服务对象后,就可以使用该服务了,至于是谁实现了该接口,如何实现的,这里根本不关心,尽管使用就是了:)...
另外还需要修改main方法,取消默认的注释,这样才能调用服务接口定义的方法!
对于这个客户端文件,在原有已导入命名空间的基础上还得导入如下一些
import org.omg.CORBA.ORBPackage.InvalidName; import org.omg.CosNaming.NamingContextPackage.CannotProceed; import org.omg.CosNaming.NamingContextPackage.NotFound; import MyServer.MyServiceHelper;
14、说了代码层面的,就该启动服务了,
首先启动CORBA,
运行->cmd->ns D:/Java/JacORB/CTEST/NS_Ref -p 30000
再运行Server,
右键 Server_AOP->Run As->Java Application
发现了什么,一大堆的红色的错误信息,
大致如下:
org.omg.CORBA.INITIALIZE: can't instantiate default ORB implementation org.jacorb.orb.ORB vmcid: 0x0 minor code: 0 completed: No
at org.omg.CORBA.ORB.create_impl(Unknown Source)
at org.omg.CORBA.ORB.init(Unknown Source)
at Server_AOM.main(Server_AOM.java:36)
Caused by: java.lang.ClassNotFoundException: org.jacorb.orb.ORB
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
... 3 more
一看大致是没有找到org.jacorb.orb.ORB这个类引起的问题,应该是没有引用相关的类引起的,
于是,项目->Properties->Java Build Path->Libraries->Add Library->User Library->next->User Libraries->New->填写用户类库名称->选中刚新建的名称->Add JARs->浏览选择 D:\Java\JacORB\lib\jacorb.jar (注意:此处的D:\Java\JacORB视个人环境而定)
再次运行,可恶,又一在段红色错误提示信息,在此也列出来吧,
org.omg.CORBA.INITIALIZE: can't instantiate default ORB implementation org.jacorb.orb.ORB vmcid: 0x0 minor code: 0 completed: No
at org.omg.CORBA.ORB.create_impl(Unknown Source)
at org.omg.CORBA.ORB.init(Unknown Source)
at Server_AOM.main(Server_AOM.java:36)
Caused by: java.lang.NoClassDefFoundError: org/apache/log/format/Formatter
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at org.jacorb.util.Environment.initLogging(Unknown Source)
at org.jacorb.util.Environment.init(Unknown Source)
at org.jacorb.util.Environment.<clinit>(Unknown Source)
at org.jacorb.orb.BufferManager.<clinit>(Unknown Source)
at org.jacorb.orb.ORB.<init>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
... 3 more
看 Caused by: java.lang.NoClassDefFoundError: org/apache/log/format/Formatter 这句,估计以是没有找到相关的引用类,于是,添加 D:\Java\JacORB\lib\logkit-1.2.jar 到用户类库,具体方法见上,
再次运行,还错误,
org.omg.CORBA.INITIALIZE: can't instantiate default ORB implementation org.jacorb.orb.ORB vmcid: 0x0 minor code: 0 completed: No
at org.omg.CORBA.ORB.create_impl(Unknown Source)
at org.omg.CORBA.ORB.init(Unknown Source)
at Server_AOM.main(Server_AOM.java:36)
Caused by: java.lang.NoClassDefFoundError: org/apache/avalon/framework/logger/Logger
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at org.jacorb.util.Environment.initLogging(Unknown Source)
at org.jacorb.util.Environment.init(Unknown Source)
at org.jacorb.util.Environment.<clinit>(Unknown Source)
at org.jacorb.orb.BufferManager.<clinit>(Unknown Source)
at org.jacorb.orb.ORB.<init>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
... 3 more
看 Caused by: java.lang.NoClassDefFoundError: org/apache/avalon/framework/logger/Logger 这名,估计还是缺少相关的引用类,于是, 添加 D:\Java\JacORB\lib\avalon-framework-4.1.5.jar 到用户类库,具体方法见上,
再次运行,终于不是红色的提示信息了,而是等待已久的
MyService is running and waiting......
终于成功了!
接下来,就是Client运行了,
右键MyServiceClientImpl->Run As->Java Application
OK, 又输出一条信息
A message in the bottle...
此时,Console窗口里面应该只有两条件信息,如
MyService is running and waiting......
A message in the bottle...
终于,这个JAVA下的CORRB应用就算完成了!
最后总结下CORBA应用的大体上的过程吧:
CORBA的配置、初始化参数就不说了,仅说说它如何应用的,
首先定义服务接口 IService ,
然后实现该接口 ServiceImpl,
创建实现该接口对象的实例 implInstance,
通过ORB得到一个与该实例相关联的org.omg.CORBA.Object对象 implInstanceOrbObj ,
通过 IServiceHelper 从 implInstanceOrbObj 中获取 IService 类型的 对象 service ,
通过命名服务上下文,将其绑定到 接口服务对象 service , 同时提供一个服务名称,以便客户端定位到特定的服务,
绑定完毕,就可以运行ORB了,此时Server就处于运行状态(监听客户端的调用),只等待客户端调用,至此,服务端程序运行完毕!
说了这么多,感觉还是不如直接帖代码来的实在,下面就帖出主要文件全部代码
Server_AOM.java
import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.Properties; import org.omg.CosNaming.NamingContextExt; import org.omg.CosNaming.NamingContextExtHelper; import org.omg.PortableServer.IdAssignmentPolicyValue; import org.omg.PortableServer.LifespanPolicyValue; import org.omg.PortableServer.POA; import org.omg.PortableServer.*; public class Server_AOM { public static void main(String[] args) { Properties props = System.getProperties(); props.setProperty("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB"); props.setProperty("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingleton"); try { // // Initialize the ORB. // org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, props); // // // get a reference to the root POA // org.omg.CORBA.Object obj = orb.resolve_initial_references("RootPOA"); // POA poaRoot = POAHelper.narrow(obj); // // // Create policies for our persistent POA // org.omg.CORBA.Policy[] policies = { // poaRoot.create_lifespan_policy(LifespanPolicyValue.PERSISTENT), // poaRoot.create_id_assignment_policy(IdAssignmentPolicyValue.USER_ID), // poaRoot.create_thread_policy(ThreadPolicyValue.ORB_CTRL_MODEL) // }; // // // Create myPOA with the right policies // POA poa = poaRoot.create_POA("MyServiceServerImpl_poa", poaRoot.the_POAManager(), policies); // // // Create the servant // MyServiceServerImpl servant = new MyServiceServerImpl(); // // // Activate the servant with the ID on myPOA // byte[] objectId = "AnyObjectID".getBytes(); // poa.activate_object_with_id(objectId, servant); // // // Activate the POA manager // poaRoot.the_POAManager().activate(); // // // Get a reference to the servant and write it down. // obj = poa.servant_to_reference(servant); // // // ---- Uncomment below to enable Naming Service access. ---- // // org.omg.CORBA.Object ncobj = orb.resolve_initial_references("NameService"); // // NamingContextExt nc = NamingContextExtHelper.narrow(ncobj); // // nc.bind(nc.to_name("MyServerObject"), obj); // // PrintWriter ps = new PrintWriter(new FileOutputStream(new File("server.ior"))); // ps.println(orb.object_to_string(obj)); // ps.close(); // // System.out.println("CORBA Server ready..."); // // // Wait for incoming requests // orb.run(); // 启动命名服务需要的参数 props.setProperty("ORBInitRef.NameService", "corbaloc::192.168.0.14:30000/NameService"); // 初始化ORB org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, props); // 获取根POA引用 POA poaRoot = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); // 激活POA管理器 poaRoot.the_POAManager().activate(); // 实例化一个MyServiceServerImpl对象 MyServiceServerImpl serviceImpl = new MyServiceServerImpl(); // 从servant获得一个对象引用 org.omg.CORBA.Object refObj = poaRoot.servant_to_reference(serviceImpl); // 获得对象接口引用 MyServer.MyService service = MyServer.MyServiceHelper.narrow(refObj); // 命名上下文 org.omg.CORBA.Object ncObj = orb.resolve_initial_references("NameService"); NamingContextExt nc = NamingContextExtHelper.narrow(ncObj); // 绑定一个服务引用,以便客户端可以调用 nc.rebind(nc.to_name("Simple.MyService"), service); System.out.println("MyService is running and waiting......"); // 运行ORB orb.run(); } catch(Exception ex) { ex.printStackTrace(); } } }
MyServiceClientImpl.java
/* * The client implementation is generated by the ORB Studio. */ import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; import java.util.Properties; import org.omg.CosNaming.*; import org.omg.CORBA.ORBPackage.InvalidName; import org.omg.CosNaming.NamingContextPackage.CannotProceed; import org.omg.CosNaming.NamingContextPackage.NotFound; import MyServer.MyServiceHelper; class MyServiceClientImpl { private MyServer.MyService target = null; private org.omg.CORBA.ORB orb = null; /** * Constructor for MyServiceClientImpl * * @throws IOException */ public MyServiceClientImpl() throws IOException { initORB(null); } /** * Constructor for MyServiceClientImpl * * @throws IOException * @see java.lang.Object#Object() */ public MyServiceClientImpl(String[] args) throws IOException { initORB(args); } /** * Initialize ORB. * * @param args * @throws IOException */ public void initORB(String[] args) throws IOException { Properties props = System.getProperties(); props.setProperty("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB"); props.setProperty("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingleton"); // // Initialize the ORB // orb = org.omg.CORBA.ORB.init((String[])args, props); // // // ---- Uncomment below to enable Naming Service access. ---- // // org.omg.CORBA.Object ncobj = orb.resolve_initial_references("NameService"); // // NamingContextExt nc = NamingContextExtHelper.narrow(ncobj); // // org.omg.CORBA.Object obj = nc.resolve_str("MyServerObject"); // // LineNumberReader input = new LineNumberReader(new FileReader("server.ior")); // String ior = input.readLine(); // org.omg.CORBA.Object obj = orb.string_to_object(ior); // // target = MyServer.MyServiceHelper.narrow(obj); // 启动参数 props.setProperty("ORBInitRef.NameService", "corbaloc::192.168.0.14:30000/NameService"); orb = org.omg.CORBA.ORB.init(args, props); // 获得命名服务上下文 // 获得命名服务对象 org.omg.CORBA.Object nsObj = null; try { nsObj = orb.resolve_initial_references("NameService"); } catch (InvalidName e) { // TODO Auto-generated catch block e.printStackTrace(); } // 通过命名服务对象得到命名服务上下文 NamingContextExt nc = NamingContextExtHelper.narrow(nsObj); // 从命名服务上下文中获得特定的命名服务对象 org.omg.CORBA.Object svrObj = null; try { svrObj = nc.resolve_str("Simple.MyService"); } catch (NotFound e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (CannotProceed e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (org.omg.CosNaming.NamingContextPackage.InvalidName e) { // TODO Auto-generated catch block e.printStackTrace(); } // 从将特定命名服务对象中获得服务接口 MyServer.MyService service = MyServiceHelper.narrow(svrObj); target = service; } /** * Obtain ORB Interface. * * @return */ public MyServer.MyService getORBInterface() { return target; } /** * Shutdown ORB. */ public void shutdown() { orb.shutdown(true); } /** * Test driver for MyServiceClientImpl. * * @param args */ public static void main(String[] args) { try { MyServiceClientImpl test = new MyServiceClientImpl(); test.getORBInterface().operation1("A message in the bottle..."); test.shutdown(); } catch(IOException ex) { ex.printStackTrace(); } } }