引言:
最近比較搓,忙得沒空寫寫博客,回想一下又好像沒忙什麼事。得反省一下瞭,當然此是後話。
本文就Zeroc Ice方法返回復雜類的對象(return by-value, not by-reff),做以簡單說明。之所以有這篇文章,隻因筆者發現網上流傳的中文文章中有這麼個空白,英文的也沒個直接的說明。
此文用BBCode編寫。
內容:
一、ICE方法返回對象的實現
二、機制的簡要說明
三、一個Exception的解決
四、資源信息
正文:
一、ICE方法返回對象的實現。
1,模型設計。
如上圖“class_diagram.JPG”所示,Bond(債券)為JavaBean,MainOperator(主操作者)有一個方法“Bond getBean(String beanUID)”返回一個JavaBean。
2,具體實現。(各代碼所在文件名,請參看首註釋中的“file”註釋)
A)slice定義
Java代碼
/*
* 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
Java代碼
/*
* 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
B)slice2java生成ice的java接口類集
C)編寫服務方
(i)實現Bond。因為Bond是個抽象類,需要給定一個實現BondI。
Java代碼
/*
* 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;
}
}
(ii)加個dao層數據提供者(僅圖好看)
Java代碼
/*
* 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;
}
}
(iii)實現操作者業務類
Java代碼
/*
* 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;
}
}
(ix)發佈業務類,註冊到服務
Java代碼
/*
* 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是個類的實現方式,需要留意。
D)編寫客戶方
(i)編寫請求者
Java代碼
/*
* 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支撐。=========
}
(ii)為客戶端寫個手工測試類
Java代碼
/*
* 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'”……
哦~&*……*出錯瞭!
Java代碼
Exception in thread "main" Ice.NoObjectFactoryException
reason = ""
type = "::com::number::bean::Bond"
at IceInternal.BasicStream.readObject(BasicStream.java:1444)
Why? ?? !? 不是一直這麼個寫法嘛?!
——如果是這麼個寫法,我也就不花功夫寫這篇文章瞭。
二、機制的簡要說明
返回值有兩種方式,一種是Ice最喜歡(也是最推薦的)“引用”方式,另一種是“傳值”方式。在ICE中的含意如下:
“引用”,即客戶端不會拿到類型實體的副本,隻拿到一個代理,可以抽象成一個遠程指針(C系)或者一個對象引用(J系)。
“傳值”,跟“引用”相對,即拿到類型實體的副本。
(此處略去二者特點,即使用范圍,約一千字。)
因此傳接口的時候,就類似於“遠程過程調用”的感覺,屬於“行為”性。可抽象成一系列的接口,實現C-S間的規范協議。而傳值時,有“序列反序列”的味道,屬於“實體”性。需要傳方有個打包成序列的模板,收方有個解包成對象的模板。回觀上文報錯,釋然瞭。
三、一個Exception的解決
一個Exception指的是“NoObjectFactoryException”,無對象工廠異常。當客戶方拿到一箱Bond的零件後,他找不到工廠給的對象裝配圖。傻眼瞭的意思。
人工建圖。沒有拿到模型,但是知道有個“Bond.java”抽象的不能使,那就直接實現一個最基礎的吧。造個BondI當臨時模板使著吧,先!
Java代碼
/*
* 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上去吧!
(i)創建一個ObjectFactory規范下的裝配圖
Java代碼
/*
* 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
}
}
(ii)拿到這箱Bond前,把裝配圖傳到ObjectFactory上去。
定位: 正文 | 一、ICE方法返回對象的實現 | 2,具體實現。| D)編寫客戶方
找到:“MainOperatorClient.java”第34~38行,把註釋部分放出來。
註釋掉的這兩行代碼,將裝配圖“BondI”放到ObjectFactory上去。以備裝配工查看。
(iii)再次運行,通過。顯示如下
Java代碼
!!>type=::com::number::bean::Bond
Bond@12830537:bName=青島啤酒,bCode=600006:bName=青島啤酒,bCode=600006
四、資源信息
你可以在code google上下載到此demo的源代碼,隻需熱身一下你的SVN。
Java代碼
svn checkout http://number-icedemo-base.googlecode.com/svn/trunk/ number-icedemo-base-read-only
補充:
有未說明清楚的問題,歡迎尾隨追貼。~,=