Zeroc Ice 返回"值类型对象"的实现

[b][size=medium]引言:[/size][/b]

最近比较搓,忙得没空写写博客,回想一下又好像没忙什么事。得反省一下了,当然此是后话。

本文就Zeroc Ice方法返回复杂类的对象(return by-value, not by-reff),做以简单说明。之所以有这篇文章,只因笔者发现网上流传的中文文章中有这么个空白,英文的也没个直接的说明。

此文用BBCode编写。

[b][size=medium]内容:[/size][/b]

一、ICE方法返回对象的实现
二、机制的简要说明
三、一个Exception的解决
四、资源信息

[b][size=medium]正文:[/size][/b]

[b]一、ICE方法返回对象的实现。[/b]

[b][size=small]1,模型设计。[/size][/b]

[img]http://dl.iteye.com/upload/attachment/525355/bbbd5869-82d2-38e2-bb77-2c9ee4efc1e8.jpg[/img]

如上图“class_diagram.JPG”所示,Bond(债券)为JavaBean,MainOperator(主操作者)有一个方法“Bond getBean(String beanUID)”返回一个JavaBean。

[b][size=small]2,具体实现。[/size][/b](各代码所在文件名,请参看首注释中的“file”注释)

[u]A)slice定义[/u]


/*
* file: BondDef.ice
* by: zhaoningbo
* date: 2011-07-25 15:51
*/
#ifndef BEAN_BOND_DEF
#define BEAN_BOND_DEF
module com{
module number{
module bean{

// 债券Bean
class Bond{

// Files
string bName;
string bCode;

// Methods
string getbName();
void setbName(string bName);

string getbCode();
void setbCode(string bCode);

};

};
};
};
#endif



/*
* file: MainOperatorDef.ice
* by: zhaoningbo
* date: 2011-07-25 16:02
*/
#ifndef OPERATOR_MAINOPERATOR_DEF
#define OPERATOR_MAINOPERATOR_DEF
module com{
module number{

// 预定义
module bean{
class Bond;
};

module operator{

// 总执行者
interface MainOperator{
// 获取Bond对象
idempotent com::number::bean::Bond getBean(string beanUID);
};
};
};
};
#endif


[u]B)slice2java生成ice的java接口类集[/u]

[u]C)编写服务方[/u]

[b][size=small](i)实现Bond。[/size][/b]因为Bond是个抽象类,需要给定一个实现BondI。


/*
* file: BondI.java
*/
package com.number.bond;

import java.io.Serializable;
import Ice.Current;
import com.number.bean.Bond;

/**
* 自定义债券Bean
* 注:实现Bond时,直接实现Override即可,无需添加其他的类元素。
* @author zhnb
*
*/
public class BondI extends Bond implements Serializable {

private static final long serialVersionUID = 8758902536680272427L;

@Override
public String getbCode(Current current) {
return this.bCode;
}

@Override
public String getbName(Current current) {
return this.bName;
}

@Override
public void setbCode(String bCode, Current current) {
this.bCode = bCode;
}

@Override
public void setbName(String bName, Current current) {
this.bName = bName;
}

}


[b][size=small](ii)加个dao层数据提供者[/size][/b](仅图好看)


/*
* file: BondLCData.java
*/
package com.number.dao;

import java.io.Serializable;
import com.number.bond.BondI;

/**
* 数据提供类
* @author zhnb
*
*/
public class BondLCData implements Serializable {

private static final long serialVersionUID = -5413237344986060553L;

// 单值
public static BondI BONDLC_DATA_SINGLE = null;
static{
BondI bondI= new BondI();
bondI.setbCode("600006");
bondI.setbName("青岛啤酒");

BONDLC_DATA_SINGLE = bondI;
}

}


[b][size=small](iii)实现操作者业务类[/size][/b]


/*
* file: MainOperatorI.java
*/
package com.number.operator;

import java.io.Serializable;
import Ice.Current;
import com.number.bean.Bond;
import com.number.dao.BondLCData;

/**
* 主操作业务类
* @author zhnb
*
*/
public class MainOperatorI extends _MainOperatorDisp implements Serializable {

private static final long serialVersionUID = 1017768576442347413L;

@Override
public Bond getBean(String beanUID, Current current) {

// 获取一个BondLC对象
Bond bond = BondLCData.BONDLC_DATA_SINGLE;

return bond;
}

}


[b][size=small](ix)发布业务类,注册到服务[/size][/b]


/*
* file: MainOperatorServer.java
*/
package com.number.operator;

import java.io.Serializable;
import Ice.ObjectAdapter;

/**
* 主操作服务发布者
* @author zhnb
*
*/
public class MainOperatorServer implements Serializable {

private static final long serialVersionUID = -691557224337330222L;

public static void main(String[] args) {

// 0, 声明执行状态
int status = 0;
Ice.Communicator ic = null;

try {

// 1, 初始化环境
// 加载属性文件
ic = Ice.Util.initialize();

// 2, 初始化Adapter

String name = "MainOperatorServer";
String endpoints = "default -h 127.0.0.1 -p 9999";
ObjectAdapter objAdapter = ic.createObjectAdapterWithEndpoints(
name, endpoints);

// 3, 创建伺服者
Ice.Object servant = new MainOperatorI();

// 4, 添加伺服者至适配器
objAdapter.add(servant, Ice.Util.stringToIdentity("MainOperatorUID"));

// 5, 激活
objAdapter.activate();

System.out.println("<<MainOperatorUID started>>");
// 6, 等待关闭
ic.waitForShutdown();

} catch (Exception e) {
e.printStackTrace();
status = 1;
} finally {
if (ic != null) {
ic.destroy();
}
System.exit(status);
}

}


以上类中MainOperatorI主是个普通接口的实现方式,很简单。BondI是个类的实现方式,需要留意。

[u]D)编写客户方[/u]

[b][size=small](i)编写请求者[/size][/b]


/*
* file: MainOperatorClient.java
*/
package com.number.operator;

import java.io.Serializable;
import Ice.ObjectPrx;
import com.number.bean.Bond;
import com.number.bond.ObjectFactory4Bond;
import com.number.except.UGenericException;

/**
* 请求数据者(通用接口方式)
* @author zhnb
*
*/
public class MainOperatorClient implements Serializable {

private static final long serialVersionUID = -3207025201067021445L;

/**
* 获取债券对象
* @param bondUID 债券标志
* @return
*/
public Bond getBean(String bondUID){

Bond bond = null;

try {
// 获取代理
MainOperatorPrx mainOperatorPrx = this.getOwnPrx();

/*
// 添加自定义类
Ice.ObjectFactory factory = new ObjectFactory4Bond();
this.ic.addObjectFactory(factory, com.number.bond.BondI.ice_staticId());
*/
bond = mainOperatorPrx.getBean("anyThingAsArg");

} catch (UGenericException e) {
e.printStackTrace();
}

return bond;
}

// =========以<下>为私有方法,提供ICE支撑。=========
// 获取服务端提供的代理
private MainOperatorPrx mainOperatorPrx = null;

// Ice通讯员(为回收资源时,方便自动回收)
private Ice.Communicator ic = null;

// GC回收时,自动销毁Ice.Communicator。
@Override
protected void finalize() throws Throwable {
if (this.ic != null) {
ic.destroy();
}
super.finalize();
}

/**
* 获取代理
*
* @return 本类的代理
*/
private MainOperatorPrx getOwnPrx() throws UGenericException {

// 代理为空时,自动获取代理。
if (this.mainOperatorPrx == null) {
// 环境为空时,初始化环境
if (this.ic == null) {
// 1, 初始化环境
ic = Ice.Util.initialize();
}
// 2, 创建代理基类对象
String str = "MainOperatorUID:default -h 127.0.0.1 -p 9999";

ObjectPrx objPrx = this.ic.stringToProxy(str);
// 3, 获取代理
this.mainOperatorPrx = MainOperatorPrxHelper.checkedCast(objPrx);

// 4, 测试是否可用,不可用时抛出异常。
if (this.mainOperatorPrx == null) {
throw new UGenericException(str + ", request proxy faild.");
}
}
return this.mainOperatorPrx;
}
// =========以<上>为私有方法,提供ICE支撑。=========
}


[b][size=small](ii)为客户端写个手工测试类[/size][/b]


/*
* file: StartAllClient.java
*/
package com.number.start;

import java.io.Serializable;
import com.number.bean.Bond;
import com.number.operator.MainOperatorClient;

/**
* 启动使用者
* @author zhnb
*
*/
public class StartAllClient implements Serializable {

private static final long serialVersionUID = -6282697303788648813L;

public static void main(String[] args) {

MainOperatorClient moc = new MainOperatorClient();
Bond bond = moc.getBean("something");

StringBuffer info = new StringBuffer();
if (bond == null) {
info.append("null");
} else {
info.append("Bond@" + bond.hashCode() + ":");

info.append("bName=" + bond.bName);
info.append(",bCode=" + bond.bCode);

info.append(":");
info.append("bName=" + bond.getbName());
info.append(",bCode=" + bond.getbCode());
}

System.out.println(info.toString());
System.exit(0);
}

}


OK,看样子写完了,可以跑了吧。试个……(提交一下,我去瞅个行号~。=)

念叨着,“先启服务run 'MainOperatorServer'……再启客户run 'StartAllClient'”……

哦~&*……*出错了!


Exception in thread "main" Ice.NoObjectFactoryException
reason = ""
type = "::com::number::bean::Bond"
at IceInternal.BasicStream.readObject(BasicStream.java:1444)


Why? ?? !? 不是一直这么个写法嘛?!

——如果是这么个写法,我也就不花功夫写这篇文章了。

[b]二、机制的简要说明[/b]

返回值有两种方式,一种是Ice最喜欢的(也是最推荐的)“引用”方式,另一种是“传值”方式。在ICE中的含意如下:

“引用”,即客户端不会拿到类型实体的副本,只拿到一个代理,可以抽象成一个远程指针(C系)或者一个对象引用(J系)。
“传值”,跟“引用”相对,即拿到类型实体的副本。
(此处略去二者特点,即使用范围,约一千字。)

因此引用的时候,就类似于“远程过程调用”的感觉,属于“行为”性。可抽象成一系列的接口,实现C-S间的规范协议。而传值时,有“序列反序列”的味道,属于“实体”性。需要传方有个打包成序列的模板,收方有个解包成对象的模板。回观上文报错,释然了。

[b]三、一个Exception的解决[/b]

一个Exception指的是“NoObjectFactoryException”,无对象工厂异常。当客户方拿到一箱Bond的零件后,他找不到工厂给的对象装配图。傻眼了的意思。

人工建图。没有拿到模型,但是知道有个“Bond.java”抽象的不能使,那就直接实现一个最基础的吧。造个BondI当临时模板使着吧,先!


/*
* file: BondI.java
*/
package com.number.bond;

import java.io.Serializable;
import Ice.Current;
import com.number.bean.Bond;

/**
* 自定义债券Bean(LC, 本地类)
* @author zhnb
*
*/
public class BondI extends Bond implements Serializable {

private static final long serialVersionUID = 8758902536680272427L;

// Methods
@Override
public String getbCode(Current current) {
return this.bCode;
}

@Override
public String getbName(Current current) {
return this.bName;
}

@Override
public void setbCode(String bCode, Current current) {
this.bCode = bCode;
}

@Override
public void setbName(String bName, Current current) {
this.bName = bName;
}

}


建好了,怎么告诉装配工呢。ICE的装配工,会看已有的图纸,也会手机上网去ObjectFactory试着查还没装到自己包里的图纸。那我们就把装配图传到ObjectFactory上去吧!

[b][size=small](i)创建一个ObjectFactory规范下的装配图[/size][/b]


/*
* file: ObjectFactory4Bond.java
*/
package com.number.bond;

import Ice.Object;
import Ice.ObjectFactory;

/**
* 传值方式,必须实现一个自定义类工厂。
* @author zhnb
*
*/
public class ObjectFactory4Bond implements ObjectFactory {

@Override
public Object create(String type) {
System.out.println("!!>type=" + type);
if (type.equals(com.number.bond.BondI.ice_staticId())) {
return new BondI();
}
return null;
}

@Override
public void destroy() {
// TODO Auto-generated method stub

}

}


[b][size=small](ii)拿到这箱Bond前,把装配图传到ObjectFactory上去。[/size][/b]

定位: 正文 | 一、ICE方法返回对象的实现 | 2,具体实现。| D)编写客户方
找到:“MainOperatorClient.java”第34~38行,把注释部分放出来。

注释掉的这两行代码,将装配图“BondI”放到ObjectFactory上去。以备装配工查看。

[b][size=small](iii)再次运行,通过。显示如下[/size][/b]


!!>type=::com::number::bean::Bond
Bond@12830537:bName=青岛啤酒,bCode=600006:bName=青岛啤酒,bCode=600006


[b]四、资源信息[/b]

你可以在code google上下载到此demo的源代码,只需热身一下你的SVN。


svn checkout http://number-icedemo-base.googlecode.com/svn/trunk/ number-icedemo-base-read-only


[b][size=medium]补充:[/size][/b]

有未说明清楚的问题,欢迎尾随追贴。~,=
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值