Zeroc Ice返回值類型對象的實現(轉帖)

引言:java

    最近比較搓,忙得沒空寫寫博客,回想一下又好像沒忙什麼事。得檢討一下了,固然此是後話。app

    本文就Zeroc Ice方法返回複雜類的對象(return by-value, not by-reff),作以簡單說明。之因此有這篇文章,只因筆者發現網上流傳的中文文章中有這麼個空白,英文的也沒個直接的說明。ide

    此文用BBCode編寫。svn

內容:測試

    1、ICE方法返回對象的實現
    2、機制的簡要說明
    3、一個Exception的解決
    4、資源信息this

正文:google

1、ICE方法返回對象的實現。設計

    1,模型設計。代理

 \

    如上圖「class_diagram.JPG」所示,Bond(債券)爲JavaBean,MainOperator(主操做者)有一個方法「Bond getBean(String beanUID)」返回一個JavaBean。指針

    2,具體實現。(各代碼所在文件名,請參看首註釋中的「file」註釋)

    A)slice定義

 

/*
 * 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? ?? !? 不是一直這麼個寫法嘛?!

    ——若是是這麼個寫法,我也就不花功夫寫這篇文章了。

2、機制的簡要說明

   返回值有兩種方式,一種是Ice最喜歡(也是最推薦的)「引用」方式,另外一種是「傳值」方式。在ICE中的含意以下:

   「引用」,即客戶端不會拿到類型實體的副本,只拿到一個代理,能夠抽象成一個遠程指針(C系)或者一個對象引用(J系)。
   「傳值」,跟「引用」相對,即拿到類型實體的副本。
   (此處略去兩者特色,即便用範圍,約一千字。)

    所以傳接口的時候,就相似於「遠程過程調用」的感受,屬於「行爲」性。可抽象成一系列的接口,實現C-S間的規範協議。而傳值時,有「序列反序列」的味道,屬於「實體」性。須要傳方有個打包成序列的模板,收方有個解包成對象的模板。回觀上文報錯,釋然了。

3、一個Exception的解決

    一個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上去吧!

    (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上去。

    定位: 正文 | 1、ICE方法返回對象的實現 | 2,具體實現。| D)編寫客戶方
    找到:「MainOperatorClient.java」第34~38行,把註釋部分放出來。

    註釋掉的這兩行代碼,將裝配圖「BondI」放到ObjectFactory上去。以備裝配工查看。

    (iii)再次運行,經過。顯示以下

Java代碼 
!!>type=::com::number::bean::Bond 
Bond@12830537:bName=青島啤酒,bCode=600006:bName=青島啤酒,bCode=600006 


4、資源信息

    你能夠在code google上下載到此demo的源代碼,只需熱身一下你的SVN。

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


補充:

    有未說明清楚的問題,歡迎尾隨追貼。~,=

相關文章
相關標籤/搜索