• 一个简单的CORBA例子


    因为对CORBA分析的需要,这里写一个简单的CORBA例子。从JDK1.2开始,JDK中集成了ORB的实现,本例子使用了JDK1.7,对于JDK1.2+应该都没有问题。这个例子实现一个简单的加减乘除的功能的计算器,客户端将参数和请求的方法名传送到服务端,服务端处理这个请求并将结果返回给客户端。

    我们知道不同编程语言中的类型的表达,内存模型是不一样的,为此CORBA发明了一套中间描述语言IDL,不同语言平台的ORB实现负责将IDL中的类型映射到本地类型中。因此IDL是我们编写CORBA程序的出发点,首先,我们用IDL来描述我们的接口/对象:

     1 module com{
     2     module bes{
     3         module corba{
     4             module test{
     5                 interface Calc{
     6                     void add(in long a,in long b,out long c);
     7                     void sub(in long a,in long b,out long c);
     8                     void multi(in long a,in long b,out long c);
     9                     void div(in long a,in long b,out long c);
    11                 };
    12             };
    13         };
    14     };
    15 };

    当然接口Calc中的方法的返回值不一定为void,这里将返回值放到了out类型的参数c中,方法可以带有多个out类型的参数。然后我们用idlj工具(jdk自带)将Calc.idl转换为对应java的描述,并生成Stub和POA等类:

    idlj给我们生成很多文件,首先我们来看一下UML图:

    上面的图不涉及工具类CalcHelper和CalcHolder,这两个类的作用在后而阐述。

    package com.bes.corba.test;
    
    
    /**
    * com/bes/corba/test/_CalcStub.java .
    * 由IDL-to-Java 编译器 (可移植), 版本 "3.2"生成
    * 从Hello.idl
    * 2016年2月15日 星期一 下午09时08分34秒 CST
    */
    
    public class _CalcStub extends org.omg.CORBA.portable.ObjectImpl implements com.bes.corba.test.Calc
    {
    
      public void add (int a, int b, org.omg.CORBA.IntHolder c)
      {
                org.omg.CORBA.portable.InputStream $in = null;
                try {
                    org.omg.CORBA.portable.OutputStream $out = _request ("add", true);
                    $out.write_long (a);
                    $out.write_long (b);
                    $in = _invoke ($out);
                    c.value = $in.read_long ();
                    return;
                } catch (org.omg.CORBA.portable.ApplicationException $ex) {
                    $in = $ex.getInputStream ();
                    String _id = $ex.getId ();
                    throw new org.omg.CORBA.MARSHAL (_id);
                } catch (org.omg.CORBA.portable.RemarshalException $rm) {
                    add (a, b, c        );
                } finally {
                    _releaseReply ($in);
                }
      } // add
    
      public void sub (int a, int b, org.omg.CORBA.IntHolder c)
      {
                org.omg.CORBA.portable.InputStream $in = null;
                try {
                    org.omg.CORBA.portable.OutputStream $out = _request ("sub", true);
                    $out.write_long (a);
                    $out.write_long (b);
                    $in = _invoke ($out);
                    c.value = $in.read_long ();
                    return;
                } catch (org.omg.CORBA.portable.ApplicationException $ex) {
                    $in = $ex.getInputStream ();
                    String _id = $ex.getId ();
                    throw new org.omg.CORBA.MARSHAL (_id);
                } catch (org.omg.CORBA.portable.RemarshalException $rm) {
                    sub (a, b, c        );
                } finally {
                    _releaseReply ($in);
                }
      } // sub
    
      public void multi (int a, int b, org.omg.CORBA.IntHolder c)
      {
                org.omg.CORBA.portable.InputStream $in = null;
                try {
                    org.omg.CORBA.portable.OutputStream $out = _request ("multi", true);
                    $out.write_long (a);
                    $out.write_long (b);
                    $in = _invoke ($out);
                    c.value = $in.read_long ();
                    return;
                } catch (org.omg.CORBA.portable.ApplicationException $ex) {
                    $in = $ex.getInputStream ();
                    String _id = $ex.getId ();
                    throw new org.omg.CORBA.MARSHAL (_id);
                } catch (org.omg.CORBA.portable.RemarshalException $rm) {
                    multi (a, b, c        );
                } finally {
                    _releaseReply ($in);
                }
      } // multi
    
      public void div (int a, int b, org.omg.CORBA.IntHolder c)
      {
                org.omg.CORBA.portable.InputStream $in = null;
                try {
                    org.omg.CORBA.portable.OutputStream $out = _request ("div", true);
                    $out.write_long (a);
                    $out.write_long (b);
                    $in = _invoke ($out);
                    c.value = $in.read_long ();
                    return;
                } catch (org.omg.CORBA.portable.ApplicationException $ex) {
                    $in = $ex.getInputStream ();
                    String _id = $ex.getId ();
                    throw new org.omg.CORBA.MARSHAL (_id);
                } catch (org.omg.CORBA.portable.RemarshalException $rm) {
                    div (a, b, c        );
                } finally {
                    _releaseReply ($in);
                }
      } // div
    
      // Type-specific CORBA::Object operations
      private static String[] __ids = {
        "IDL:com/bes/corba/test/Calc:1.0"};
    
      public String[] _ids ()
      {
        return (String[])__ids.clone ();
      }
    
      private void readObject (java.io.ObjectInputStream s) throws java.io.IOException
      {
         String str = s.readUTF ();
         String[] args = null;
         java.util.Properties props = null;
         org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props);
       try {
         org.omg.CORBA.Object obj = orb.string_to_object (str);
         org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl) obj)._get_delegate ();
         _set_delegate (delegate);
       } finally {
         orb.destroy() ;
       }
      }
    
      private void writeObject (java.io.ObjectOutputStream s) throws java.io.IOException
      {
         String[] args = null;
         java.util.Properties props = null;
         org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props);
       try {
         String str = orb.object_to_string (this);
         s.writeUTF (str);
       } finally {
         orb.destroy() ;
       }
      }
    } // class _CalcStub

    _CalcStub是存根类,有过远程调用编程经验的读者应该对这个词比较熟悉,它是远程对象在本地的一个代理(Proxy)。从业务划分角度来说,CORBA这些底层的东西不应该太多地污染到我们的应用,比如这个_CalcStub是我们不希望在业务代码中出现的,我们只需要看到我们需要的Calc。客户端从ORB中拿到的Calc接口实现其实是一个_CalcStub,客户程序对Calc接口中的方法进行调用时,_CalcStub将相应方法的调用转发到服务端,然后将服务器的响应返回给客户端,从而成功从欺骗客户端程序。

    _CalcStub继承了ObjectImpl类,这使得_CalcStub能够关联到ORB环境中,从而完成远程调用。

    idlj工具并没有直接在Calc.java中定义idlj方法的java语言描述,而是在CalcOperation.java中。Calc接口继承了IDLEntity,org.omg.CORBA.Object和CalcOperation三个接口:

    IDLEntity是一个标记接口,表明Calc接口是一种IDL接口,这个与org.omg.CORBA.Object有点相类似,但实现了org.omg.CORBA.Object接口的对象不一定是IDL描述的,因此这里单独把IDLEntity拎出来。

    org.omg.CORBA.Object接口定义了一些CORBA相关的方法,因为客户端所使用的是Calc,参数传递到ORB中语义上也是 Calc类型,当然我们不能将非IDL的对象传递到ORB中,ORB无法完成那样子的操作;Calc接口继承 org.omg.CORBA.Object(ORB层面使用的是org.omg.CORBA.Object),那就意味了通过编译器来保证类型安全(避免 强制转换,ClassCastException之类的异常)。

    package com.bes.corba.test;
    
    
    /**
    * com/bes/corba/test/CalcOperations.java .
    * 由IDL-to-Java 编译器 (可移植), 版本 "3.2"生成
    * 从Hello.idl
    * 2016年2月15日 星期一 下午09时08分34秒 CST
    */
    
    public interface CalcOperations 
    {
      void add (int a, int b, org.omg.CORBA.IntHolder c);
      void sub (int a, int b, org.omg.CORBA.IntHolder c);
      void multi (int a, int b, org.omg.CORBA.IntHolder c);
      void div (int a, int b, org.omg.CORBA.IntHolder c);
    } // interface CalcOperations

    CalcOperation是相对应的IDL映射。

    package com.bes.corba.test;
    
    
    /**
    * com/bes/corba/test/CalcPOA.java .
    * 由IDL-to-Java 编译器 (可移植), 版本 "3.2"生成
    * 从Hello.idl
    * 2016年2月15日 星期一 下午09时08分34秒 CST
    */
    
    public abstract class CalcPOA extends org.omg.PortableServer.Servant
     implements com.bes.corba.test.CalcOperations, org.omg.CORBA.portable.InvokeHandler
    {
    
      // Constructors
    
      private static java.util.Hashtable _methods = new java.util.Hashtable ();
      static
      {
        _methods.put ("add", new java.lang.Integer (0));
        _methods.put ("sub", new java.lang.Integer (1));
        _methods.put ("multi", new java.lang.Integer (2));
        _methods.put ("div", new java.lang.Integer (3));
      }
    
      public org.omg.CORBA.portable.OutputStream _invoke (String $method,
                                    org.omg.CORBA.portable.InputStream in,
                                    org.omg.CORBA.portable.ResponseHandler $rh)
      {
        org.omg.CORBA.portable.OutputStream out = null;
        java.lang.Integer __method = (java.lang.Integer)_methods.get ($method);
        if (__method == null)
          throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);
    
        switch (__method.intValue ())
        {
           case 0:  // com/bes/corba/test/Calc/add
           {
             int a = in.read_long ();
             int b = in.read_long ();
             org.omg.CORBA.IntHolder c = new org.omg.CORBA.IntHolder ();
             this.add (a, b, c);
             out = $rh.createReply();
             out.write_long (c.value);
             break;
           }
    
           case 1:  // com/bes/corba/test/Calc/sub
           {
             int a = in.read_long ();
             int b = in.read_long ();
             org.omg.CORBA.IntHolder c = new org.omg.CORBA.IntHolder ();
             this.sub (a, b, c);
             out = $rh.createReply();
             out.write_long (c.value);
             break;
           }
    
           case 2:  // com/bes/corba/test/Calc/multi
           {
             int a = in.read_long ();
             int b = in.read_long ();
             org.omg.CORBA.IntHolder c = new org.omg.CORBA.IntHolder ();
             this.multi (a, b, c);
             out = $rh.createReply();
             out.write_long (c.value);
             break;
           }
    
           case 3:  // com/bes/corba/test/Calc/div
           {
             int a = in.read_long ();
             int b = in.read_long ();
             org.omg.CORBA.IntHolder c = new org.omg.CORBA.IntHolder ();
             this.div (a, b, c);
             out = $rh.createReply();
             out.write_long (c.value);
             break;
           }
    
           default:
             throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);
        }
    
        return out;
      } // _invoke
    
      // Type-specific CORBA::Object operations
      private static String[] __ids = {
        "IDL:com/bes/corba/test/Calc:1.0"};
    
      public String[] _all_interfaces (org.omg.PortableServer.POA poa, byte[] objectId)
      {
        return (String[])__ids.clone ();
      }
    
      public Calc _this() 
      {
        return CalcHelper.narrow(
        super._this_object());
      }
    
      public Calc _this(org.omg.CORBA.ORB orb) 
      {
        return CalcHelper.narrow(
        super._this_object(orb));
      }
    
    
    } // class CalcPOA

    CalcPOA:它工作在服务端,POA是Portable Object Adapter的缩写,这里Adapter(适配器)的语义是指适配相应的编程语言中的对象(比如在java中那意思就是指 Java对象的适配器),适配器的作用有三点:

    1:接受客户端发过来的调用请求,反序列化(Unmarshalling)参数,方法名等,然后将请求分发给对应的Servant。POA和Servant之间的关系如下图。

    2:将对象引用(Object Reference)和相应的Servant起来(可以看到Servant._object_id方法),比如我们在EJB中的有状态会话Bean。

    3:负责Servant的生命周期管理(如创建,钝化,销毁等),这里又让我联想到了EJB的生命周期。到这里这里我们可以清楚Home接口存在的理由。

    好吧,我们要实现的例子确实很简单,在这个例子中,读者只需要了解到第一点即可(CORBA水很深,很容易死里面去的)。idlj为我们生成的POA中,集Servant,CalcOperation和InvocationHandler于一身,有越殂代疱的嫌疑,当然这并不影响程序的正常执行,当然如果服务端比较关注2,3两点的话,自己实现POA还是很有必要的,但这已经超出了本文的范围。

    同样地ORB的东西不应该玷污到我们服务端的业务逻辑 ,Servant和InvocationHandler将POA关联到ORB中去。注意Servant和InvocationHandler是两接口是分开的,这一点还不是太清楚(也许是为了特性的划分吧)。

    package com.bes.corba.test;
    
    
    /**
    * com/bes/corba/test/CalcHelper.java .
    * 由IDL-to-Java 编译器 (可移植), 版本 "3.2"生成
    * 从Hello.idl
    * 2016年2月15日 星期一 下午09时08分34秒 CST
    */
    
    abstract public class CalcHelper
    {
      private static String  _id = "IDL:com/bes/corba/test/Calc:1.0";
    
      public static void insert (org.omg.CORBA.Any a, com.bes.corba.test.Calc that)
      {
        org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
        a.type (type ());
        write (out, that);
        a.read_value (out.create_input_stream (), type ());
      }
    
      public static com.bes.corba.test.Calc extract (org.omg.CORBA.Any a)
      {
        return read (a.create_input_stream ());
      }
    
      private static org.omg.CORBA.TypeCode __typeCode = null;
      synchronized public static org.omg.CORBA.TypeCode type ()
      {
        if (__typeCode == null)
        {
          __typeCode = org.omg.CORBA.ORB.init ().create_interface_tc (com.bes.corba.test.CalcHelper.id (), "Calc");
        }
        return __typeCode;
      }
    
      public static String id ()
      {
        return _id;
      }
    
      public static com.bes.corba.test.Calc read (org.omg.CORBA.portable.InputStream istream)
      {
        return narrow (istream.read_Object (_CalcStub.class));
      }
    
      public static void write (org.omg.CORBA.portable.OutputStream ostream, com.bes.corba.test.Calc value)
      {
        ostream.write_Object ((org.omg.CORBA.Object) value);
      }
    
      public static com.bes.corba.test.Calc narrow (org.omg.CORBA.Object obj)
      {
        if (obj == null)
          return null;
        else if (obj instanceof com.bes.corba.test.Calc)
          return (com.bes.corba.test.Calc)obj;
        else if (!obj._is_a (id ()))
          throw new org.omg.CORBA.BAD_PARAM ();
        else
        {
          org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate ();
          com.bes.corba.test._CalcStub stub = new com.bes.corba.test._CalcStub ();
          stub._set_delegate(delegate);
          return stub;
        }
      }
    
      public static com.bes.corba.test.Calc unchecked_narrow (org.omg.CORBA.Object obj)
      {
        if (obj == null)
          return null;
        else if (obj instanceof com.bes.corba.test.Calc)
          return (com.bes.corba.test.Calc)obj;
        else
        {
          org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate ();
          com.bes.corba.test._CalcStub stub = new com.bes.corba.test._CalcStub ();
          stub._set_delegate(delegate);
          return stub;
        }
      }
    
    }

    CalcHelper:从名字上可以看出,它是一个工具类,它的职责在有:

    1、通过提供narrow方法和RepositoryId等信息来实现类型安全。

    2、与Any类型之间的进行转换。

    3、从InputStream中读出Calc(对象引用),将Calc写出到OutputStream中。

    我们的例子中将只用到第一点。

    package com.bes.corba.test;
    
    /**
    * com/bes/corba/test/CalcHolder.java .
    * 由IDL-to-Java 编译器 (可移植), 版本 "3.2"生成
    * 从Hello.idl
    * 2016年2月15日 星期一 下午09时08分34秒 CST
    */
    
    public final class CalcHolder implements org.omg.CORBA.portable.Streamable
    {
      public com.bes.corba.test.Calc value = null;
    
      public CalcHolder ()
      {
      }
    
      public CalcHolder (com.bes.corba.test.Calc initialValue)
      {
        value = initialValue;
      }
    
      public void _read (org.omg.CORBA.portable.InputStream i)
      {
        value = com.bes.corba.test.CalcHelper.read (i);
      }
    
      public void _write (org.omg.CORBA.portable.OutputStream o)
      {
        com.bes.corba.test.CalcHelper.write (o, value);
      }
    
      public org.omg.CORBA.TypeCode _type ()
      {
        return com.bes.corba.test.CalcHelper.type ();
      }
    
    }

    CalcHolder:这个类在Calc被作为out或者inout类型的参数传递时候被使用,如果我们在另一个IDL方法中使用Calc作为参数,那么生成的代码将会是这样子的:

    void test(int a, int b, CalcHolder calc)
    

    CalcHolder负责从InputStream或者OuputStream分别读出和写入Calc,从CalcHolder生成的代码中我们可以看出,CalcHolder的_read和_write方法将相应的操作委托给了CalcHelper。

    哆嗦了这么多,是时候拿出我们的客户端和服务端了。

    服务端代码:

    CalculatorImpl是Servant的实现,它继承了CalcPOA类。

    package com.bes.corba.impl;
    
    import org.omg.CORBA.IntHolder;
    
    import com.bes.corba.test.CalcPOA;
    
    public class CalculatorImpl extends CalcPOA{
    
        @Override
        public void add(int a, int b, IntHolder c) {
            c.value=a+b;
        }
    
        @Override
        public void sub(int a, int b, IntHolder c) {
            c.value=a-b;
        }
    
        @Override
        public void multi(int a, int b, IntHolder c) {
            c.value=a*b;
        }
    
        @Override
        public void div(int a, int b, IntHolder c) {
            c.value=a/b;
        }
    }

    Server类:

    package com.bes.corba.test;
    
    import org.omg.CORBA.ORB;
    import org.omg.CosNaming.NameComponent;
    import org.omg.CosNaming.NamingContextExt;
    import org.omg.CosNaming.NamingContextExtHelper;
    import org.omg.PortableServer.POA;
    import org.omg.PortableServer.POAHelper;
    
    import com.bes.corba.test.Calc;
    import com.bes.corba.test.CalcHelper;
    import com.bes.corba.impl.CalculatorImpl;
    
    public class Server {
        public static void main(String[] args) throws Exception{
            /*
             * ORB 初始化。
             */
            ORB orb=ORB.init(args,null);
            
            /*
             * 获取根POA并初始化。
             */
            POA rootPoa=POAHelper.narrow(orb.resolve_initial_references("RootPOA") );
            rootPoa.the_POAManager().activate();
            
            /*
             * 构建一个CalculatorImpl。
             */
            CalculatorImpl calculatorImpl=new CalculatorImpl();
            
            /*
             * 将Servant注册到RootPOA中,建立Servant到Object Reference的相互映射,
             * 注意这里具体行为跟RootPOA的POA Policy有关。
             */
            org.omg.CORBA.Object ref=rootPoa.servant_to_reference(calculatorImpl);
            Calc iref=CalcHelper.narrow(ref);
            
            /*
             * 获取命名服务。
             */
            org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
            NamingContextExt ncRef= NamingContextExtHelper.narrow(objRef);
            
            /*
             * 将对象引用以相应的名字发布到命名服务中。
             */
            String name="Calc";
            NameComponent path[] = ncRef.to_name(name);
            ncRef.rebind(path,iref);
            
            System.out.println("Calculator server ready...");
            
            /*
             * 阻塞直到ORB关闭。
             */
            orb.run();
        }
    }

    客户端代码Client

    package com.bes.corba.test;
    
    import org.omg.CORBA.IntHolder;
    import org.omg.CORBA.ORB;
    import org.omg.CosNaming.NamingContextExt;
    import org.omg.CosNaming.NamingContextExtHelper;
    
    import com.bes.corba.test.Calc;
    import com.bes.corba.test.CalcHelper;
    
    public class Client {
        public static void main(String[] args) throws Exception{
            /*
             * ORB 初始化。
             */
            ORB orb=ORB.init(args,null);
            
            /*
             * 获取命名服务。
             */
            org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
            NamingContextExt ncRef=NamingContextExtHelper.narrow(objRef);
            
            /*
             * 从命名服务中查找相应的对象引用,并进行类型转型。
             */
            
            String name="Calc";
            Calc calc=CalcHelper.narrow(ncRef.resolve_str(name));
            
            /*
             * 调用对象的方法。
             */
            IntHolder result=new IntHolder();
            
            calc.add(1,2,result);
            System.out.printf("1+2=%d
    ",result.value);
        }
    }

    启动命名服务,命名服务器不一定运行在对象服务器的进程中,尤其是在一个分布式的环境中,命名服务器与对象服务器通常是一对多的关系。

    orbd -ORBInitialPort 1050 -ORBInitialHost localhost&
    

     启动服务端:

    java HelloServer -ORBInitialPort 1050 -ORBInitialHost localhost
    

    ORBInitialPort和ORBInitialHost参数指定了命名服务器的主机名和端口号。

    启动客户端:

    java com.bes.corba.test.Client -ORBInitialPort 1050 -ORBInitialHost localhost
    

     

  • 相关阅读:
    springmvc常用注解之@Controller和@RequestMapping
    解决nginx负载均衡的session共享问题
    iOS顶部滑动菜单:FDSlideBar 与NinaPagerView
    C#中使用WeiFenLuo.WinFormsUI.Docking.dll实现窗口停靠效果
    [转]C#使用Log4Net记录日志
    ICSharpCode.SharpZipLib 开源压缩库使用示例
    WorldWind源码剖析系列:日志类Log
    [转]反射基础
    WorldWind源码剖析系列:星球球体的加载与渲染
    Vue 前端路由 vue-router
  • 原文地址:https://www.cnblogs.com/mosmith/p/5190679.html
Copyright © 2020-2023  润新知