1.概述
CORBA: Common Object Request Broker Architecture。
CORBA是一套标准,包含了相关的API以及通信协议的定义,开发者据此可以实现一种与WebService类似的远程调用机制。
我直观地认为,CORBA程序的运行涉及3个进程:
1)Server进程通常时持续运行的,在运行之初它会将对象注册到2);
2)Name Service存放着不同的对象引用,这些对象通过name进行标识;
3)Client进程在需要时会拿着相应的name去向2)索要某一对象引用,得到之后便可调用对象的方法了。
2. JacORB
JacORB一类的产品对CORBA做了实现(包括通信协议等等),因此我们只剩下自己的业务代码需要写了。
也其它的产品比如Orbix,只不过后者是个商业软件。
3. JacORB的安装
2)解压:本例中解压到C:\jacorb-2.3.1。
3)操作系统用户环境变量:
添加JACORB_HOMEC:\jacorb-2.3.1
修改CLASSPATH为.;%JAVA_HOME%\jre\lib;%JACORB_HOME%\lib\antlr-2.7.2.jar;
%JACORB_HOME%\lib\backport-util-concurrent.jar;%JACORB_HOME%\lib\idl.jar;
%JACORB_HOME%\lib\jacorb.jar;%JACORB_HOME%\lib\logkit-1.2.jar;
%JACORB_HOME%\lib\picocontainer-1.2.jar;%JACORB_HOME%\lib\slf4j-api-1.5.6.jar;
%JACORB_HOME%\lib\slf4j-jdk14-1.5.6.jar;%JACORB_HOME%\lib\wrapper-3.1.0.jar;
修改PATH添加%JACORB_HOME%\bin
4)修改C:\jacorb-2.3.1\etc\jacorb.properties:
ORBInitRef.InterfaceRepository=file:/c:/jacorb-2.3.1/IR_Ref
jacorb.naming.ior_filename=c:/jacorb-2.3.1/NS_Ref
其中IR_Ref跟NS_Ref文件所在的位置可以任意,不需要一定跟这一致。这些文件也不需要预先创建。
5)修改C:\jacorb-2.3.1\bin\jaco.bat.tpl:
改名为jaco.bat并将文件内容中的@JAVA_CMD@改成java,将原来的“@JACORB_HOME@”改成“%JACORB_HOME %”。
6)命令行执行ns,查看是否有错误。
4. IDL的编译
IDL:Interface Definition Language,它并非编程语言,只是一般的描述性语言,通常在IDL文件中包括接口以及一些数据类型的定义,有例为证:
module demo
{
module hello {interfaceGoodDay {
string hello_simple();
wstring hello_wide( in wstring msg );
};
};
};
通过使用JacORB所带的idl编译工具,我把IDL文件映射成Java代码。
修改C:\jacorb-2.3.1\bin
idl.bat.tpl:
改名为idl.bat,打开,将@JAVA_CMD@直接改成java。
然后在命令行执行:H:\>idl -d C:\DEV\IDLSample C:\DEV\IDLSample\server.idl
其中-d选项后面跟的目录为idl文件编译后生成的java文件的输出目录。
生成的结果包括以下java文件:
_GoodDayStub.java
GoodDay.java
GoodDayHelper.java
GoodDayHolder.java
GoodDayOperations.java
GoodDayPOA.java
GoodDayPOATie.java
5.编写Server程序
1)首先编写GoodDayImpl继承自GoodDayPOA:
代码
packagecorbaimpl;importdemo.hello.GoodDayPOA;publicclassGoodDayImplextendsGoodDayPOA {
@OverridepublicString hello_simple() {//TODO Auto-generated method stubreturn"Hello from CORBA server";
}
@OverridepublicString hello_wide(String msg) {//TODO Auto-generated method stubreturn"Hello from CORBA server, and the parameter 'msg' is:"+msg;
}
}
2)编写程序入口类Main
代码
packagecorbaimpl;importjava.util.Properties;importorg.omg.CosNaming.NamingContextExt;importorg.omg.CosNaming.NamingContextExtHelper;importorg.omg.PortableServer.POA;importorg.omg.PortableServer.POAHelper;publicclassMain {publicstaticvoidmain(String[] args) {
System.out.println(">>>>Start to initialize CORBA stuff");
System.setProperty("jacorb.home","C:\\jacorb-2.3.1");try{
Properties props=newProperties();//props.put("org.omg.CORBA.ORBClass","org.jacorb.orb.ORB");
props.put("org.omg.CORBA.ORBSingletonClass","org.jacorb.orb.ORBSingleton");
props.put("org.omg.CORBA.ORBInitRef.NameService","corbaloc::localhost:9527/NameService");//org.omg.CORBA.ORB orb=org.omg.CORBA.ORB.init(args, props);//POA poaRoot=POAHelper.narrow(orb.resolve_initial_references("RootPOA"));//poaRoot.the_POAManager().activate();//GoodDayImpl impl=newGoodDayImpl();//org.omg.CORBA.Object obj=poaRoot.servant_to_reference(impl);//NamingContextExt nc=NamingContextExtHelper.narrow(orb.resolve_initial_references("NameService"));//nc.bind(nc.to_name("CorbaSample_Server"), obj);//orb.run();
}catch(Exception ex) {
ex.printStackTrace();
}
System.out.println(">>>>End the CORBA server");
}
}
上面的代码主要做的一件事是,实例化一个GoodDayImpl对象,并通过NamingContextExt的bind()方法将该对象注册到Name Service上。最后orb.run()方法会阻塞线程,等待Client程序的连接。
6.编写Client程序
代码
importjava.util.Properties;importorg.omg.CosNaming.NamingContextExt;importorg.omg.CosNaming.NamingContextExtHelper;importdemo.hello.GoodDay;importdemo.hello.GoodDayHelper;publicclassMain {staticorg.omg.CORBA.ORB orb=null;staticGoodDay gd=null;publicstaticvoidmain(String[] args) {
System.out.println(">>>>Start to initialize client stuff");
Properties props=newProperties();
props.put("org.omg.CORBA.ORBClass","org.jacorb.orb.ORB");
props.put("org.omg.CORBA.ORBSingletonClass","org.jacorb.orb.ORBSingleton");
props.put("ORBInitRef.NameService","corbaloc::localhost:9527/NameService");try{
orb=org.omg.CORBA.ORB.init(args, props);
NamingContextExt nc=NamingContextExtHelper.narrow(orb.resolve_initial_references("NameService"));
gd=GoodDayHelper.narrow(nc.resolve(nc.to_name("CorbaSample_Server")));//String s=gd.hello_simple();
System.out.println(s);
String s2=gd.hello_wide("\"call me client\"");
System.out.println(s2);
}catch(Exception e) {
e.printStackTrace();
}
}
}
虽然Client也有由IDL编译生成的代码,但它并没有我们后来实现的GoodDayImpl类,但我们却可以在这里调用该类的方法并得到返回,这里面也就是CORBA机制在起作用。
7.运行程序
1)首先,就像我们在概述中的图片中所看见的,我们需要一个Name Service,由于我们装了JacORB,可以用它提供的Name Service,启动方法是在命令行执行:
“ns -DOAPort=9527”,其中9527即Name
Service进程所要监听的端口,你也可以指定不同的。
2)启动Server,命令行进入相关的classes目录,执行“java
corbaimpl.Main”
3)启动Client,命令行进入相关的classes目录,执行“java
Main”(当时我把Main放在default package下的,所以这里不需要写package名),正常在Client执行后会有两行输出:
Hello from CORBA server.
Hello from CORBA server, and the parameter 'msg' is: “call me
client”.
8.遇到的各种错误
话说JacORB的配置确实是比较那个,你知道的……,google出来的也常常是化石级别的帖子。
1)配置完成后在命令行执行ns命令,出现错误是“NoClassDefFoundError”,请检查以下两项:
>>JAVA_HOME路径中是否包含空格。此前我一直都把jdk安装在C:\Program files下,所以一直提示“NoClassDefFoundError:
org/jacorb/naming/NameServer”
>>是否已经将C:\jacorb-2.3.1\lib下必要的jar文件路径都添加到CLASSPATH中了,我比较不求甚解,因为一开始试了几个后还是报NoClassDefFoundError,后来很生气很暴力地把lib下所有的jar都添加到CLASSPATH中了(参见上面的环境变量定义)。
2)关于ns与orbd
前面我们说了,在运行Server跟Client之前,需要将Name
Service先运行起来,我在写这个例子的最开始明明ns已经正常启动了,Server却始终连接不上,google到的帖子中有说要执行:start orbd
-ORBInitialPort 1050
执行完了之后还真可以连上,Client也工作正常,搞得我很莫名。后来我稍稍研究了一下,发现跟代码中初始化ORB对象前设置的Properties有关系。
如果写成这种形式:
props.put("org.omg.CORBA.ORBInitialPort","xxx");
props.put("org.omg.CORBA.ORBInitialHost","localhost");
则能连上orbd,但连不上JacORB的ns(Server程序提示org.omg.CORBA.OBJECT_NOT_EXIST,ns命令行输出错误“Received a request with a non-jacorb object key”)。
如果写成这种形式:
props.put("org.omg.CORBA.ORBInitRef.NameService","corbaloc::localhost/NameService");
则能连上JacORB的ns,但连不上orbd。
后来知道orbd是Java(Sun)提供的一个简单的Name Service实现,而连接它所需要的Properties的写法正是第一种。
3)关于corbaloc中的端口
上面提到Server在初始化ORB时提供的属性为:
代码
System.setProperty("jacorb.home","C:\\jacorb-2.3.1");
props.put("org.omg.CORBA.ORBClass","org.jacorb.orb.ORB");
props.put("org.omg.CORBA.ORBSingletonClass","org.jacorb.orb.ORBSingleton");
props.put("org.omg.CORBA.ORBInitRef.NameService","corbaloc::localhost:9527/NameService");
这么写完全可以连上jacorb的ns,不过~~,corbaloc中的端口9527被忽略,即这里可以随便写端口号,或者不写端口,一样能连上。
如果~~,如果Server初始化ORB时提供的属性仅为:
props.put("org.omg.CORBA.ORBInitRef.NameService","corbaloc::localhost:9527/NameService");
也完全可以连上jacorb的ns,不过这时你在corbaloc中提供的端口必须是ns正在监听的端口,即启动ns时参数DOAPort的值。
而对于Client,测试发现的情况是无论如何写法,必须在corbaloc中标识出ns的监听端口,否则无法连接。
此点目前无解中,存疑。