Zeroc Ice返回值类型对象的实现(转帖)

引言:

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

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

    此文用BBCode编写。

内容:

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

正文:

一、ICE方法返回对象的实现。

    1,模型设计。

 Zeroc 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? ?? !? 不是一直这么个写法嘛?!

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

二、机制的简要说明

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

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

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

三、一个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上去。

    定位: 正文 | 一、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 


补充:

    有未说明清楚的问题,欢迎尾随追贴。~,=

你可能感兴趣的:(Zeroc Ice返回值类型对象的实现(转帖))