利用动态调用方式实现分布式应用(上)
(本文转载自软件工程专家网www.21cmm.com)
苏洋
CORBA规范中定义动态调用接口(Dynamic Invocation Interface,DII)和动态骨架接口(Dynamic Skeleton Interface,DSI)的目的在于增加分布式应用程序设计的灵活性。
通常,基于客户端存根程序的情况下,需要预先知道被调用方法的名称、参数、返回值类型等信息。但是,在实际应用中往往在设计客户端应用时,不知道服务对象实现的具体细节,甚至服务对象实例还没有被创建。根据这种情况,CORBA定义了另外一种客户对象调用服务对象实现方法的方式:客户端以动态调用接口(DII)方式实现,而服务对象以动态骨架接口(DSI)形式创建。这样,在分布式应用程序设计时,很大程度上减少了客户端应用程序创建时对服务对象的依赖程度,提高了分布式应用程序设计的灵活性。
客户端动态调用接口(DII)
动态调用方式下创建客户端和服务对象实现应用时不再依靠桩程序和骨架程序对服务对象的引用。因此,在IDL到Java语言映射过程中需要指定映射工具的动态调用映射选项“-dynamic_marshal”,在VisiBroker中映射的方式为:
idl2java -dynamic_marshal filename.idl
在创建基于动态调用的分布式应用程序的客户端应用时,在客户端应首先创建请求(Request)对象,并在请求对象中指定服务对象中方法名称以及应用的参数等。创建请求对象后,以同步形式或异步形式查询服务对象的运行情况,并在服务对象运行结束后解析返回结果,结束动态调用请求。
在动态调用方式下,客户端必须向服务对象提出服务请求(Request)。Request对象代表客户对象向服务对象提出调用请求。创建Request对象的方式有两种:一是通过对调用对象的引用,用被引用对象的_request方法创建Request对象,然后调用Request对象的add_value方法添加方法调用需要的参数; 另一种方式是调用被引用对象的_create_request方法来创建对服务对象的调用请求。利用_request方法创建请求对象的例子代码为:
org.omg.CORBA.Request request = serverObject._request(“getName”)
在上面的代码中创建的请求对象用于调用服务对象的名称为getName的方法。
服务请求由对服务对象的引用、要调用的服务对象方法名称和参数列表构成。请求的参数以元素列表的形式实现,其中元素是NamedValue结构类型的实例,该结构定义如下:
typedef unsigned long Flags;
struct NamedValue
{
Identifier name;
any argument;
long len;
Flags arg_modes;
}
其中参数的意义分别为加入列表中的元素的名称、变量值、变量长度和参数的模式标识。
CORBA为动态调用接口定义了很多方法,用于在客户端创建调用请求、查询返回结果和对返回结果进行解析等。下面介绍常用的客户端实现动态调用的方法:
1. void create_request( in Context ctx,
in Identifier operation,
in NVList arg_list,
inout NamedValue result,
out Request request,
in Flags req_flags)
其中参数分别为调用请求应用的context对象、调用的方法名称、调用方法的参数、调用返回结果、新的返回请求和请求标志等。
2. boolean poll_response( in Request req)
其中的参数req为用户创建的服务请求。该方法用于查询在以异步形式向服务对象发送的服务请求的完成情况。返回TRUE说明请求已经完成,否则说明未完成。
3. get_response() raises (WrongTransaction)
该方法用于查询以同步方式向服务对象发送的服务请求的完成情况。方法返回调用请求的结果。如果服务对象端的被调用方法没有完成,则get_response方法一直等待直至请求完成。
类似的方法还有get_next_response,用于在客户端发送多个调用请求的情况下查询下一个请求的执行情况。
服务对象动态骨架接口(DSI)
服务对象动态骨架接口(DSI)位于服务对象端,用于动态处理客户端提出的服务请求。动态骨架接口通过对象适配器接收客户端服务请求,并将该请求传递给服务对象实现。
在处理客户请求时,服务对象实现不去分析客户是使用桩方法还是动态调用接口来提出对象服务请求; 同时,发出调用的客户程序也不去分辨服务对象接收服务请求是不是通过服务对象骨架。
服务对象端CORBA对象结构如下图所示:
基于动态骨架接口的服务对象实现程序的编写步骤为:
● 以DynamicImplementation接口为父对象创建服务对象实现程序;
● 实现DynamicImplementation接口的invoke方法,应用接收客户对象提出的服务对象请求;
● 通过narrow方法获得对根POA的引用;
● 通过根POA的create_POA方法创建服务POA(POA Servant),在服务POA中指定服务对象方法的实现;
在创建服务对象实现程序时,必须实现抽象类DynamicImplementation中的invoke等方法。该类的定义为:
package org.omg.CORBA;
public abstract class DynamicImplementation
extends org.omg.CORBA.portable.ObjectImpl
{
public abstract void invoke(org.omg.CORBA.ServerRequest request);
}
可以看出:DynamicImplementation抽象类中定义了抽象方法invoke。该方法用于在服务对象实现程序中处理客户对象提出的服务请求。在该方法中,首先分析request实例中的调用方法名称,来分析客户提出的方法在服务对象实现端是否有定义。如果没有定义,则抛出BAD_OPERATION异常。其代码为:
if (!request.operation().equals(“getName”))
{
throw new org.omg.CORBA
.BAD_OPERATION();
}
上面的代码中,通过request对象的operation方法,分析需要调用的方法名称。因此,可以在程序中判断该方法是否在服务对象端有实现。在request请求的方法名称正确的情况下,服务对象实现端应用调用适合的方法来处理用户请求。