|
利用CORBA技术实现分布式应用程序
(来源:http://www.ccw.com.cn)
公共对象请求代理规范(CORBA)是在不同平台、不同语言之间实现对象通信的模型,它为分布式应用环境下对象资源共享、代码重用、可移植和对象间相互访问建立了通用标准,同样也为在大量硬件、软件之间实现互操作提供了良好的解决方案。 |
与传统的DCOM和RIM相比,CORBA体系结构独立于语言、独立于工作平台等方面的特点,使得基于CORBA开发的应用系统在网络实现中具有更大的优势。本文通过利用Java语言编制的客户/服务器程序,简要分析了CORBA的体系结构,希望能对读者理解CORBA有所帮助。 |
对象请求代理(ORB)是CORBA规范的基础,其主要功能是定位服务对象,分析客户对象的请求,获取服务对象的功能接口,在客户与服务对象间建立通信连接。 |
IDL是CORBA的另外一个重要组成部分,用于说明CORBA服务对象完成的功能,但不能够利用IDL实现该功能。IDL是独立于其他编程语言的功能描述性语言,这从另外一个侧面说明了CORBA的语言环境独立性。利用IDL,完成CORBA服务对象方法的说明,然后利用语言映射工具,将用IDL定义的CORBA对象方法说明翻译成高级编程语言的接口说明,最后根据接口说明,利用C++或Java编写对象实现程序。 |
客户对象的桩(Stub)和服务对象的骨架(Skeleton)是IDL与对象实现语言之间的桥梁。 |
客户对象的桩是IDL定义的方法接口经IDL编译器编译后,在编写客户对象时,高级编程语言可应用的用于识别服务对象方法的代码。客户对象的桩提供服务对象接口的简要说明。服务对象的骨架是IDL定义的方法接口经IDL编译器编译后,形成的说明服务对象提供方法的框架。对于服务对象接口中的每个方法,必须在服务对象程序中实现。 |
分布式应用程序设计的主要问题是确定建立在对象级上的客户与服务对象的关系。从其最根本的功能来讲,服务对象提供远程接口,客户对象调用远程接口,客户对象不需要了解远程对象的位置以及实现细节,也不需要了解哪个ORB 用于对象之间的交互。按照实现过程,CORBA的实现分为两种方式:命名服务对象引用方式和字符串化对象引用方式。 |
下面介绍基于CORBA技术,用Java语言在网络中建立分布式应用的具体方法。 |
在服务对象端,模拟股票系统的信息发布,随机生成10支股票的股票名称与价格。在客户端,访问服务器,获得股票名称与价格。其获取方式分为两种:取得全部股票的信息和取得某支股票的价格。 |
根据对象功能的说明,用UML描述出服务对象需要实现的功能: |
getStockValue( StockSymbol :symbol ) :float |
StockSymbolList getStockSymbols() :StockSymbol[] |
根据系统分析及设计结果,用IDL编写出服务对象方法描述程序。 |
/*StockMarket.idl 服务对象方法接口定义文件*/ |
typedef string StockSymbol; |
typedef sequence<StockSymbol> StockSymbolList; |
float getStockValue(in StockSymbol symbol); StockSymbolList getStockSymbols(); |
> idltojava -fno-cpp StockMarket.idl |
其中idltojava为IDL程序翻译程序,该软件随JDK 1.3开发工具包提供。 |
如果使用的JDK版本为1.2以下,可以在Sun公司的Java分类主页中下载该软件,网址为: |
Http://developer.javasoft.com/developer/earlyAccess/jdk12/idltojava.html |
-fno-cpp为idltojava的程序参数,强制编译过程中不使用C语言预处理。 |
编译StockMarket.idl后,在该文件所在目录中生成名称为StockMarket的子目录。其中StockServer.java文件中包括在StockMarket.idl中定义的服务对象接口StockServer,服务对象必须实现该接口。_StockServerImplBase.java中包括实现服务对象程序时用到的其他类,服务对象在实现时必须继承该类。 |
/*StockServerImpl.java 服务对象实现程序*/ |
import org.omg.CORBA.ORB; |
import org.omg.CosNaming.NameComponent; |
import org.omg.CosNaming.NamingContext; |
import org.omg.CosNaming.NamingContextHelper; |
public class StockServerImpl extends |
_StockServerImplBase implements StockServer |
private Vector myStockSymbols; |
private Vector myStockValues; |
private static char ourCharacters[] = { ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’,‘O’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’, ‘Y’, ‘Z’}; |
private static String ourPathName = “StockServer”; |
myStockSymbols = new Vector(); |
myStockValues = new Vector(); |
for (int i = 0; i < 10; i++) |
StringBuffer stockSymbol=new StringBuffer(“ ”); |
for (int j = 0; j < 4; j++) |
stockSymbol.setCharAt(j,ourCharacters[(int)(Math.random()* 26f)]); |
// 将股票名称存储在myStockSymbols中 |
myStockSymbols.addElement(stockSymbol. |
myStockValues.addElement(new Float |
System.out.println(“Generated stock symbols:”); |
for (int i = 0; i < 10; i++) |
System.out.println(myStockSymbols.elementAt |
(i) + “---” +myStockValues.elementAt(i)); |
public float getStockValue(String symbol) |
// 在服务对象的股票价格存储对象中匹配给定的股票名称 |
nt stockIndex = myStockSymbols.indexOf(symbol); |
return ((Float)myStockValues.elementAt(stockIndex)).floatValue(); |
public String[] getStockSymbols() |
String[]symbols = new String |
myStockSymbols.copyInto(symbols); |
public static void main(String args[]) |
ORB orb = ORB.init(args, null); |
StockServerImpl stockServer = new StockServerImpl(); |
orb.connect(stockServer); |
org.omg.CORBA.Object obj = |
orb.resolve_initial_references(“NameService”); |
NamingContext namingContext = |
NamingContextHelper.narrow(obj); |
// 将StockServer对象与命名服务进行绑定 |
NameComponent nameComponent = new |
NameComponent(ourPathName,“”); |
namingContext.rebind(path,stockServer); |
java.lang.Object waitOnMe = new |
System.err.println(“Couldn’t bind StockServer: ” + ex.getMessage()); |
/*StockMarketClient.java客户对象实现程序*/ |
import org.omg.CORBA.ORB; |
import org.omg.CosNaming.NameComponent; |
import org.omg.CosNaming.NamingContext; |
import org.omg.CosNaming.NamingContextHelper; |
public class StockMarketClient |
public static ORB ourORB; |
private StockServer myStockServer; |
if (myStockServer != null) |
// 建立与服务对象StockServer连接的方法 |
org.omg.CORBA.Object obj = |
ourORB.resolve_initial_references(“NameService”); |
NamingContext namingContext = |
NamingContextHelper.narrow(obj); |
NameComponent nameComponent = new NameComponent(“StockServer”,“”); |
NameComponent path[] = { nameComponent }; |
myStockServer =StockServerHelper.narrow(namingContext.resolve(path)); |
System.err.println(“Couldn’t resolve |
System.out.println(“Succesfully bound to a StockServer.”); |
protected void doSomething() |
String[]stockSymbols=myStockServer. |
for (int i = 0; i < stockSymbols. |
System.out.println(stockSymbols[i] |
+ “” + myStockServer.getStockValue(stockSymbols |
catch (org.omg.CORBA.SystemException ex) |
System.err.println(“Fatal error: ” + ex); |
public static void main(String args[]) |
ourORB = ORB.init(args, null); |
StockMarketClient stockClient = new StockMarketClient(); |
在命令行中键入如下命令编译服务对象实现程序,注意TockServerImpl.java和StockServerImpl.java存储在StockMarket目录中。在Unix平台中,用“/”代替“\”: |
> javac StockMarket\StockServerImpl.java |
> java StockMarket\StockServerImpl.java |
在服务对象的计算机中键入如下命令启动对象命名服务: |
> tnameserv -ORBInitialPort 3388 |
如果上述程序编译没有问题,就可以在网络中的任意计算机上运行服务对象。程序运行时需要给定该计算机在网络中的标识和进行网络通信的端口号。本文中服务对象运行的计算机名称为XQ4,在给定端口号时,由于Unix平台小于1024的端口是系统保留的,因此给定的端口号必须大于1024。在命令行中键入如下命令: |
> java StockMarket.StockServerImpl -ORBInitialHost XQ9 -ORBInitialPort 3388 |
由于是应用随机方法产生的股票名称和价格,因此程序每次运行的输出结果会不同。 |
将编译好的客户程序发布到网络中安装了JDK的任意计算机中,在命令行中键入如下命令,注意在命令行中指定对象访问的计算机的名称和端口: |
> java StockMarket.StockMarketClient - |
ORBInitialHost XQ 9 -ORBInitialPort 3388 |
基于CORBA规范,用户可以透明地访问信息,不需要知道信息存在于什么软件中、使用什么硬件平台以及位于企业网络的什么地方。作为面向对象系统的通信核心,CORBA为网络计算带来了真正的互操作性。另外,软件开发人员开发基于CORBA的分布式应用程序不需要了解太多有关网络协议的技术细节,使得软件开发周期大大缩短,同时也加大了代码可重用性。 |
上述程序应用JDK 1.2开发工具,分别在Windows 98、Solaris 2.5应用环境中调试、编译和运行通过。 |
|