分散共有空間(1)

並列分散ソフトウェア

                                       電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/sie/
http://www.is.tsukuba.ac.jp/~yas/index-j.html
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html

■今日の重要な話

■フィードバック

台数効果の課題に対するコメント。

半数近くは、うまく線形な台数効果を観測するのに成功していた。

sakura の CPU 数は、6 なので、6 スレッドか最も速いはずである。それ以上、 スレッドを増やして測定しても、あまり意味はない。逆に、6 以上に増やして よい効果が現れた時には、測定方法が怪しい。

データ量が少なくて、うまく台数効果が図れていない人が何人かいた。

thr_setconcurrency()で要求した数と実際にシステムが割当てる数が食い違う ことがある。スレッドの数も同時に変える。thr_getconcurrency() で確認す る。

きちんと検算している人がいる。

浮動小数点の場合、シングルスレッドで動かした時の答えとマルチスレッドで 動かした時の答えが違うことがある。計算の順序が変るので。

(A+B)+C!=A+(B+C)。

変数や関数の名前も、きちんと考える習慣を付けるとよい。

■分散共有空間

JavaSpaces を例題にする。Linda の Tupple 空間の考え方を Java で実現し たもの。

Jini/RMI 技術を使ってる。

■Java RMI

Remote Method Invocation. Java 言語で書かれたプログラム間のORB (Object Request Broker). ORB は、オブジェクト指向が入っている RPC (Remote Procedure Call).

別の Java 仮想計算機間オブジェクトのメソッドを呼び出す仕組み。 RMI いくつかの層を見えなくする。

◆HORB

RMI が入ったのは、JDK 1.1 から。それ以前に、電総研(現在の産電総研)の平 野氏によるHORBが開発された。

http://horb.a02.aist.go.jp/horb-j/

◆Java で TCP/IP を直接使う

RMI より下のレベルでは、TCP/IP を直接使うクラスがある。
java.net.Socket
TCP/IP クライアント側
java.net.ServerSocket
TCP/IP サーバ側
java.net.DatagramSocket
UDP/IP
java.net.MulticastSocket
UDP/IP マルチキャスト

◆RMI におけるサーバとクライアント

サーバもクライアントも Java で書かれたオブジェクト。 サーバは、実行に先立ち、RMI のサーバであると宣言する必要がある(非対称)。

インタフェース Remote を付ける。

src/java/rmi/Remote.java
public interface Remote {}
これを見つけると、コンパイラが特殊なコードを生成する。
Stub
クライアント側のスタブ(RPC用語)。サーバのオブジェクトと同じインタフェース を持つ。受け付けたメソッド呼出しを通信に変換する。
Skelton
サーバ側のスタブ(RPC用語)。
名前サービス registry がある。転送には、TCP/IP が使われる。

◆java.rmi.server.UnicastRemoteObject

サーバ側で継承すべきクラス。
java.lang.Object (class)
  |
  +--java.rmi.server.RemoteObject (class)
        |
        +--java.rmi.server.RemoteServer (class)
              |
              +--java.rmi.server.UnicastRemoteObject (class)
これに加えて、interface Remote を implements する。

クライアント側は、これに比べて簡単。違いは、サーバに接続する部分部分と、 分散固有の例外を受ける部分。

■ローカルのカウンタ

ローカルで動作するプログラムを、RMI で動作するように書き直す。

◆ローカル/インタフェース


----------------------------------------------------------------------
   1: //
   2: // Counter.java
   3: //
   4: 
   5: public interface Counter
   6: {
   7:     void up();
   8:     int getValue();
   9:     void reset(int newVal);
  10: };
----------------------------------------------------------------------

インタフェースを定義しなくてもよいが、リモートとの比較のためにあえて定 義する。

◆ローカル/オブジェクト


----------------------------------------------------------------------
   1: //
   2: // CounterObject.java
   3: //
   4: public class CounterObject implements Counter
   5: {
   6:     int val;
   7:     public CounterObject(int initVal)
   8:     {
   9:         val = initVal ;
  10:     }
  11:     public void up()
  12:     {
  13:         val ++ ;
  14:     }
  15:     public int getValue()
  16:     {
  17:         return( val );
  18:     }
  19:     public void reset(int newVal)
  20:     {
  21:         val = newVal ;
  22:     }
  23: };
----------------------------------------------------------------------

◆ローカル/利用


----------------------------------------------------------------------
   1: //
   2: // CounterUser.java
   3: //
   4: 
   5: class CounterUser
   6: {
   7:     public static void main(String argv[])
   8:     {
   9:         Counter c1 = new CounterObject( 10 );
  10:         for( int i=0 ; i<3 ; i++ )
  11:         {
  12:             c1.up();
  13:             System.out.println("c1.value=="+c1.getValue());
  14:         }
  15:     }
  16: };
----------------------------------------------------------------------

実行例:

----------------------------------------------------------------------
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/Counter.java [←]
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/CounterObject.java [←]
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/CounterUser.java [←]
% ls Counter*java [←]
Counter.java            CounterObject.java      CounterUser.java
% rm *.class [←]
% javac CounterUser.java  [←]
% ls *.class [←]
Counter.class           CounterObject.class     CounterUser.class
% java CounterUser [←]
c1.value==11
c1.value==12
c1.value==13
% java CounterUser [←]
c1.value==11
c1.value==12
c1.value==13
% []
----------------------------------------------------------------------

オブジェクト c1 を、main で作って実行している。実行する度に新しいオブ ジェクトが new される。

■RMIによるカウンタの利用

ローカルで動作するプログラムを、RMI で動作するように書き直す。

◆リモート・インタフェース

RMI でアクセス可能にするオブジェクトには、必ずインタフェースを定義する。

----------------------------------------------------------------------
   1: //
   2: // RemoteCounter.java
   3: //
   4: 
   5: public interface RemoteCounter extends java.rmi.Remote
   6: {
   7:     public void up() throws java.rmi.RemoteException;
   8:     public int  getValue() throws java.rmi.RemoteException;
   9:     public void reset(int newVal) throws java.rmi.RemoteException;
  10: }
----------------------------------------------------------------------

リモート・インタフェースの特徴:

◆リモート・オブジェクト


----------------------------------------------------------------------
   1: //
   2: // RemoteCounterObject.java
   3: //
   4: 
   5: import java.rmi.*;
   6: import java.rmi.server.*;
   7: 
   8: public class RemoteCounterObject extends java.rmi.server.UnicastRemoteObject
   9:     implements RemoteCounter 
  10: {
  11:     int val;
  12:     public RemoteCounterObject(int initVal) throws RemoteException
  13:     {
  14:         super();
  15:         val = initVal ;
  16:     }
  17:     public void up() throws java.rmi.RemoteException
  18:     {
  19:         val ++ ;
  20:     }
  21:     public int getValue() throws java.rmi.RemoteException
  22:     {
  23:         return( val );
  24:     }
  25:     public void reset(int newVal) throws java.rmi.RemoteException
  26:     {
  27:         val = newVal ;
  28:     }
  29: };
  30: 
----------------------------------------------------------------------

java.rmi.server.UnicastRemoteObject の代りに java.rmi.activation.Activatable を使うと呼び出された時に起動される。

オブジェクトは、serialize (直列化) されてコピーで渡される。

◆サーバ


----------------------------------------------------------------------
   1: //
   2: // RemoteCounterServer.java
   3: //
   4: 
   5: import java.rmi.*;
   6: import java.rmi.server.*;
   7: 
   8: public class RemoteCounterServer
   9: {
  10:     public static void main(String argv[])
  11:     {
  12:         if( argv.length != 1 )
  13:         {
  14:             System.err.println("Usage% java RemoteCounterServer rmiregistry-portno");
  15:             System.exit( 1 );
  16:         }
  17:         String rmiregport = argv[0];
  18: 
  19:         if( System.getSecurityManager() == null )
  20:             System.setSecurityManager( new RMISecurityManager() );
  21: 
  22:         try
  23:         {
  24:             RemoteCounter c1 = new RemoteCounterObject( 10 );
  25:             String c1_name = "rmi://localhost:"+rmiregport+"/Counter/c1" ;
  26:             Naming.rebind( c1_name,c1 );
  27: 
  28:             RemoteCounter c2 = new RemoteCounterObject( 20 );
  29:             String c2_name = "rmi://localhost:"+rmiregport+"/Counter/c2" ;
  30:             Naming.rebind( c2_name,c2 );
  31:         }
  32:         catch (Exception e)
  33:         {
  34:             System.err.println("RemoteCounterServer error:"+e.getMessage());
  35:             e.printStackTrace();
  36:         }
  37:     }
  38: };
----------------------------------------------------------------------

Exception を catch したら、最後に System.exit( 1 ) した方がよい。

rmiregistry に登録する時には、次のような URL が使える。

myhost は、自分自身のホスト名。実験では、よく localhost を使う。

port は、rmiregistry が使うポート番号で、デフォルトでは 1099。 大勢で1つのホストを使うとぶつかる。sakura を使う時には、1099 は避ける こと。

string は単なる文字列。フラットな名前空間。

◆クライアント


----------------------------------------------------------------------
   1: //
   2: // RemoteCounterClient.java
   3: //
   4: 
   5: import java.rmi.*;
   6: 
   7: class RemoteCounterClient
   8: {
   9:     public static void main(String argv[])
  10:     {
  11:         if( argv.length != 2 )
  12:         {
  13:             System.err.println("Usage% java RemoteCounterClient hostname rmiregistry-portno");
  14:             System.exit( 1 );
  15:         }
  16:         String hostname = argv[0];
  17:         String rmiregport = argv[1];
  18:             
  19:         RemoteCounter c1 ;
  20:         try
  21:         {
  22:             if( System.getSecurityManager() == null )
  23:                 System.setSecurityManager( new RMISecurityManager() );
  24:             String c1_name = "rmi://"+hostname+":"+rmiregport+"/Counter/c1";
  25:             c1 = (RemoteCounter) Naming.lookup( c1_name );
  26:             for( int i=0 ; i<3 ; i++ )
  27:             {
  28:                 c1.up();
  29:                 System.out.println("c1.value=="+c1.getValue());
  30:             }
  31:         }
  32:         catch (Exception e)
  33:         {
  34:             e.printStackTrace();
  35:         }
  36:     }
  37: };
----------------------------------------------------------------------

◆コンパイルと実行(サーバ側)

サーバ側では、ウインドウを2枚開く。

一方のウインドウで rmiregistry を起動する。ポート番号は、ぶつからない ように uid を使う。rmiregistry は自動的に終了しないので、実験が終わっ たら ^C (Control-C)で殺す。


----------------------------------------------------------------------
% id [←]
uid=4031(yshinjo) gid=4031(yshinjo)
% rmiregistry 4031 [←]
(最後に ^C で止める)
----------------------------------------------------------------------
一方のウインドウでサーバを動作させる。サーバもは自動的に終了しないので、 実験が終わったら ^C (Control-C)で殺す。

----------------------------------------------------------------------
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounter.java [←]
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterObject.java [←]
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterServer.java [←]
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterServer.policy [←]
% rm *class [←]
% rmic RemoteCounterObject [←]
% ls *class [←]
RemoteCounter.class             RemoteCounterObject_Skel.class
RemoteCounterObject.class       RemoteCounterObject_Stub.class
% javac RemoteCounterServer.java [←]
% java -Djava.security.policy=./RemoteCounterServer.policy RemoteCounterServer 4031 [←]
(最後に ^C で止める)
----------------------------------------------------------------------
rmic で作られるRemoteCounterObject*.class のうち、サーバ側側で必要なの は、RemoteCounterObject.class (本体)とRemoteCounterObject_Skel.class (スケルトン、サーバ側スタブ)のみ。RemoteCounterObject_Stub.class は、 不要。

◆コンパイルと実行(クライアント側)

クライアント側では、ウインドウを1枚開く。

----------------------------------------------------------------------
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounter.java [←]
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterObject.java [←]
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterClient.java [←]
% wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterClient.policy [←]
% rm *class [←]
% rmic RemoteCounterObject [←]
% ls *class [←]
RemoteCounter.class             RemoteCounterObject_Skel.class
RemoteCounterObject.class       RemoteCounterObject_Stub.class
% javac RemoteCounterClient.java [←]
% java -Djava.security.policy=./RemoteCounterClient.policy RemoteCounterClient localhost 4031 [←]
c1.value==11
c1.value==12
c1.value==13
% java -Djava.security.policy=./RemoteCounterClient.policy RemoteCounterClient localhost 4031 [←]
c1.value==14
c1.value==15
c1.value==16
% java -Djava.security.policy=./RemoteCounterClient.policy RemoteCounterClient localhost 4031 [←]
c1.value==17
c1.value==18
c1.value==19
% []
----------------------------------------------------------------------

rmic で作られるRemoteCounterObject*.class のうち、クライアント側で必要 なのは、RemoteCounterObject_Stub.class (クライアント側スタブ)のみ。 RemoteCounterObject.class と RemoteCounterObject_Skel.class は不要。

◆クライアント側stub

rmic -keep でコンパイルすると、_Stub.java が残される。

----------------------------------------------------------------------
   1: // Stub class generated by rmic, do not edit.
   2: // Contents subject to change without notice.
   3: 
   4: public final class RemoteCounterObject_Stub
   5:     extends java.rmi.server.RemoteStub
   6:     implements RemoteCounter, java.rmi.Remote
   7: {
   8:     private static final java.rmi.server.Operation[] operations = {
   9:         new java.rmi.server.Operation("int getValue()"),
  10:         new java.rmi.server.Operation("void reset(int)"),
  11:         new java.rmi.server.Operation("void up()")
  12:     };
  13:     
  14:     private static final long interfaceHash = 5217325697641540004L;
  15:     
  16:     private static final long serialVersionUID = 2;
  17:     
  18:     private static boolean useNewInvoke;
  19:     private static java.lang.reflect.Method $method_getValue_0;
  20:     private static java.lang.reflect.Method $method_reset_1;
  21:     private static java.lang.reflect.Method $method_up_2;
  22:     
  23:     static {
  24:         try {
  25:             java.rmi.server.RemoteRef.class.getMethod("invoke",
  26:                 new java.lang.Class[] {
  27:                     java.rmi.Remote.class,
  28:                     java.lang.reflect.Method.class,
  29:                     java.lang.Object[].class,
  30:                     long.class
  31:                 });
  32:             useNewInvoke = true;
  33:             $method_getValue_0 = RemoteCounter.class.getMethod("getValue", new java.lang.Class[] {});
  34:             $method_reset_1 = RemoteCounter.class.getMethod("reset", new java.lang.Class[] {int.class});
  35:             $method_up_2 = RemoteCounter.class.getMethod("up", new java.lang.Class[] {});
  36:         } catch (java.lang.NoSuchMethodException e) {
  37:             useNewInvoke = false;
  38:         }
  39:     }
  40:     
  41:     // constructors
  42:     public RemoteCounterObject_Stub() {
  43:         super();
  44:     }
  45:     public RemoteCounterObject_Stub(java.rmi.server.RemoteRef ref) {
  46:         super(ref);
  47:     }
  48:     
  49:     // methods from remote interfaces
  50:     
  51:     // implementation of getValue()
  52:     public int getValue()
  53:         throws java.rmi.RemoteException
  54:     {
  55:         try {
  56:             if (useNewInvoke) {
  57:                 Object $result = ref.invoke(this, $method_getValue_0, null, -1068577784738248554L);
  58:                 return ((java.lang.Integer) $result).intValue();
  59:             } else {
  60:                 java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
  61:                 ref.invoke(call);
  62:                 int $result;
  63:                 try {
  64:                     java.io.ObjectInput in = call.getInputStream();
  65:                     $result = in.readInt();
  66:                 } catch (java.io.IOException e) {
  67:                     throw new java.rmi.UnmarshalException("error unmarshalling return", e);
  68:                 } finally {
  69:                     ref.done(call);
  70:                 }
  71:                 return $result;
  72:             }
  73:         } catch (java.lang.RuntimeException e) {
  74:             throw e;
  75:         } catch (java.rmi.RemoteException e) {
  76:             throw e;
  77:         } catch (java.lang.Exception e) {
  78:             throw new java.rmi.UnexpectedException("undeclared checked exception", e);
  79:         }
  80:     }
  81:     
  82:     // implementation of reset(int)
  83:     public void reset(int $param_int_1)
  84:         throws java.rmi.RemoteException
  85:     {
  86:         try {
  87:             if (useNewInvoke) {
  88:                 ref.invoke(this, $method_reset_1, new java.lang.Object[] {new java.lang.Integer($param_int_1)}, 2435635625292702899L);
  89:             } else {
  90:                 java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
  91:                 try {
  92:                     java.io.ObjectOutput out = call.getOutputStream();
  93:                     out.writeInt($param_int_1);
  94:                 } catch (java.io.IOException e) {
  95:                     throw new java.rmi.MarshalException("error marshalling arguments", e);
  96:                 }
  97:                 ref.invoke(call);
  98:                 ref.done(call);
  99:             }
 100:         } catch (java.lang.RuntimeException e) {
 101:             throw e;
 102:         } catch (java.rmi.RemoteException e) {
 103:             throw e;
 104:         } catch (java.lang.Exception e) {
 105:             throw new java.rmi.UnexpectedException("undeclared checked exception", e);
 106:         }
 107:     }
 108:     
 109:     // implementation of up()
 110:     public void up()
 111:         throws java.rmi.RemoteException
 112:     {
 113:         try {
 114:             if (useNewInvoke) {
 115:                 ref.invoke(this, $method_up_2, null, 4665897731548305845L);
 116:             } else {
 117:                 java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash);
 118:                 ref.invoke(call);
 119:                 ref.done(call);
 120:             }
 121:         } catch (java.lang.RuntimeException e) {
 122:             throw e;
 123:         } catch (java.rmi.RemoteException e) {
 124:             throw e;
 125:         } catch (java.lang.Exception e) {
 126:             throw new java.rmi.UnexpectedException("undeclared checked exception", e);
 127:         }
 128:     }
 129: }
----------------------------------------------------------------------

◆クライアント側skeleton


----------------------------------------------------------------------
   1: // Skeleton class generated by rmic, do not edit.
   2: // Contents subject to change without notice.
   3: 
   4: public final class RemoteCounterObject_Skel
   5:     implements java.rmi.server.Skeleton
   6: {
   7:     private static final java.rmi.server.Operation[] operations = {
   8:         new java.rmi.server.Operation("int getValue()"),
   9:         new java.rmi.server.Operation("void reset(int)"),
  10:         new java.rmi.server.Operation("void up()")
  11:     };
  12:     
  13:     private static final long interfaceHash = 5217325697641540004L;
  14:     
  15:     public java.rmi.server.Operation[] getOperations() {
  16:         return (java.rmi.server.Operation[]) operations.clone();
  17:     }
  18:     
  19:     public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
  20:         throws java.lang.Exception
  21:     {
  22:         if (opnum < 0) {
  23:             if (hash == -1068577784738248554L) {
  24:                 opnum = 0;
  25:             } else if (hash == 2435635625292702899L) {
  26:                 opnum = 1;
  27:             } else if (hash == 4665897731548305845L) {
  28:                 opnum = 2;
  29:             } else {
  30:                 throw new java.rmi.UnmarshalException("invalid method hash");
  31:             }
  32:         } else {
  33:             if (hash != interfaceHash)
  34:                 throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
  35:         }
  36:         
  37:         RemoteCounterObject server = (RemoteCounterObject) obj;
  38:         switch (opnum) {
  39:         case 0: // getValue()
  40:         {
  41:             call.releaseInputStream();
  42:             int $result = server.getValue();
  43:             try {
  44:                 java.io.ObjectOutput out = call.getResultStream(true);
  45:                 out.writeInt($result);
  46:             } catch (java.io.IOException e) {
  47:                 throw new java.rmi.MarshalException("error marshalling return", e);
  48:             }
  49:             break;
  50:         }
  51:             
  52:         case 1: // reset(int)
  53:         {
  54:             int $param_int_1;
  55:             try {
  56:                 java.io.ObjectInput in = call.getInputStream();
  57:                 $param_int_1 = in.readInt();
  58:             } catch (java.io.IOException e) {
  59:                 throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
  60:             } finally {
  61:                 call.releaseInputStream();
  62:             }
  63:             server.reset($param_int_1);
  64:             try {
  65:                 call.getResultStream(true);
  66:             } catch (java.io.IOException e) {
  67:                 throw new java.rmi.MarshalException("error marshalling return", e);
  68:             }
  69:             break;
  70:         }
  71:             
  72:         case 2: // up()
  73:         {
  74:             call.releaseInputStream();
  75:             server.up();
  76:             try {
  77:                 call.getResultStream(true);
  78:             } catch (java.io.IOException e) {
  79:                 throw new java.rmi.MarshalException("error marshalling return", e);
  80:             }
  81:             break;
  82:         }
  83:             
  84:         default:
  85:             throw new java.rmi.UnmarshalException("invalid method number");
  86:         }
  87:     }
  88: }
----------------------------------------------------------------------

◆セキュリティ

RMI では、クライアント、サーバ、相互にアクセス制御を行う必要がある。

Java の標準のセキュリティのポリシー(java コマンドで利用される)は、 jre/lib/security/java.policy に記述されている。 (sakura:/usr/j2se/jre/lib/security/java.policy)

System.setSecurityManager( new RMISecurityManager() ) した時には、 標準よりきつくなる。実験する時には、少し緩めないとつながらない。

以下の例では、IP アドレス(130.158.85.129と130.158.64.20)を修正して使う こと。sakura (130.158.64.20) を使う時には、そのままでもよい。


----------------------------------------------------------------------
//
// RemoteCounterServer.policy
//

grant { 
	permission java.net.SocketPermission "localhost:1024-", "listen,connect,resolve";
	permission java.net.SocketPermission "130.158.85.129:1024-", "listen,connect,resolve";
	permission java.net.SocketPermission "130.158.64.20:1024-", "listen,connect,resolve";
};
----------------------------------------------------------------------


----------------------------------------------------------------------
//
// RemoteCounterClient.policy
//

grant { 
	permission java.net.SocketPermission "localhost:1024-", "listen,connect,resolve";
	permission java.net.SocketPermission "130.158.85.129:1024-", "listen,connect,resolve";
	permission java.net.SocketPermission "130.158.64.20:1024-", "listen,connect,resolve";
};
----------------------------------------------------------------------

クライアント側では、うまく設定すると、サーバ側に置かれたクラスを動的に http や ftp でロードして実行できる。その時には、 java.rmi.server.codebase プロパティを使う。

◆直列化(serialize)

marshaling/unmarshaling のことを、Java では serialization/deserialization という。日本語では、直列化、または、整列 化。

RMI でオブジェクトを渡す時には、interface Serializable を implements する。

serialize 不要のフィールドには、transient をつける。

serialization は、RMI だけでなく、オブジェクトをファイルに落とす時にも 使える。

■CORBA

Common Object Request Broker Architecture。 OMG (Object Management Group) による ORB。

CORBA の特徴

OMG は仕様を策定するだけで、コードは作らない。

◆CORBA IDL (Interface Definition Language)

CORBA は、C++風のインタフェース定義言語を持つ。

特徴

例:


----------------------------------------------------------------------
   1: module Counter
   2: {
   3:     interface Counter
   4:     {
   5:         void up();
   6:         long getValue();
   7:         void reset(in long newVal);
   8:     };
   9: };
----------------------------------------------------------------------

◆CORBA IDL コンパイラ

IDL コンパイラは、クライアント側の stub とサーバ側のスタブ (skelton)を 生成する。最近の Java には、Java 用の IDL コンパイラがついている。

----------------------------------------------------------------------
% idlj Counter.idl
% ls Counter
Counter.java            CounterHolder.java      _CounterStub.java
CounterHelper.java      CounterOperations.java
% 
----------------------------------------------------------------------

Counter.idl を元にして、ディレクトリ Counter/ 以下にい くつかのファイルが作られる。

手続きのインタフェース CounterOperations.java:


----------------------------------------------------------------------
   1: package Counter;
   2: 
   3: 
   4: /**
   5: * Counter/CounterOperations.java
   6: * Generated by the IDL-to-Java compiler (portable), version "3.0"
   7: * from Counter.idl
   8: * Thursday, February 7, 2002 2:56:17 AM JST
   9: */
  10: 
  11: public interface CounterOperations 
  12: {
  13:   void up ();
  14:   int getValue ();
  15:   void reset (int newVal);
  16: } // interface CounterOperations
----------------------------------------------------------------------

クライアント側スタブ _CounterStub.java:

----------------------------------------------------------------------
   1: package Counter;
   2: 
   3: 
   4: /**
   5: * Counter/_CounterStub.java
   6: * Generated by the IDL-to-Java compiler (portable), version "3.0"
   7: * from Counter.idl
   8: * Thursday, February 7, 2002 2:56:17 AM JST
   9: */
  10: 
  11: public class _CounterStub extends org.omg.CORBA.portable.ObjectImpl implements Counter.Counter
  12: {
  13:   // Constructors
  14:   // NOTE:  If the default constructor is used, the
  15:   //        object is useless until _set_delegate (...)
  16:   //        is called.
  17:   public _CounterStub ()
  18:   {
  19:     super ();
  20:   }
  21: 
  22:   public _CounterStub (org.omg.CORBA.portable.Delegate delegate)
  23:   {
  24:     super ();
  25:     _set_delegate (delegate);
  26:   }
  27: 
  28:   public void up ()
  29:   {
  30:     org.omg.CORBA.portable.InputStream _in = null;
  31:     try {
  32:        org.omg.CORBA.portable.OutputStream _out = _request ("up", true);
  33:        _in = _invoke (_out);
  34:     } catch (org.omg.CORBA.portable.ApplicationException _ex) {
  35:        _in = _ex.getInputStream ();
  36:        String _id = _ex.getId ();
  37:        throw new org.omg.CORBA.MARSHAL (_id);
  38:     } catch (org.omg.CORBA.portable.RemarshalException _rm) {
  39:        up ();
  40:     } finally {
  41:         _releaseReply (_in);
  42:     }
  43:   } // up
  44: 
  45:   public int getValue ()
...
  64:   public void reset (int newVal)
...
  91:   private void readObject (java.io.ObjectInputStream s)
  92:   {
  93:      try 
  94:      {
  95:        String str = s.readUTF ();
  96:        org.omg.CORBA.Object obj = org.omg.CORBA.ORB.init ().string_to_object (str);
  97:        org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl) obj)._get_delegate ();
  98:        _set_delegate (delegate);
  99:      } catch (java.io.IOException e) {}
 100:   }
 101: 
 102:   private void writeObject (java.io.ObjectOutputStream s)
 103:   {
 104:      try 
 105:      {
 106:        String str = org.omg.CORBA.ORB.init ().object_to_string (this);
 107:        s.writeUTF (str);
 108:      } catch (java.io.IOException e) {}
 109:   }
 110: } // class _CounterStub

----------------------------------------------------------------------

◆tnameserv

Java には、tnameserv と呼ばれる、CORBA 用の名前サーバがついている。 rmiregistry と類似の機能を提供する。

■課題

sakura で問題なく動作したとの連絡が入っている。きちんと元の締切り通り 提出することが望ましい。

次の課題から1つを選んで提出しなさい。問題を難しい方に変えてもよい。締 め切りは、2002/02/13 (水曜日) 18:00 とする。(23:59:59 ではない)。

レポートは、次のような形式の電子メールで送ること。

----------------------------------------------------------------------
To: yas@is.tsukuba.ac.jp
Subject: [pdsoft/rmi] <内容に関したサブジェクト>

学籍番号 000000 (各自の学籍番号で置き換える)
名前 漢字の名前

<内容>
----------------------------------------------------------------------

★カウンタにメソッドの追加

カウンタの利用の例で、インタフェースにメソッ ドを1つ追加しなさい。メソッドとしては、たとえば、down() (値を1つ減ら す)が考えられる。

★RMI自由課題

カウンタと同程度の複雑さを持つインタフェース を定義し、RMI で呼び出せるようにしなさい。 ここで同じ程度の複雑さとは、内部に刻々と変化する変数を含むものである。 メソッドの数は少なくてもよい。

★HORB

カウンタ、またはそれと同程度の複雑さを持つ オブジェクトを、HORB を使って呼び出せるようにしなさい。

★CORBA

カウンタ、またはそれと同程度の複雑さを持つ オブジェクトを、CORBA を使って呼び出せるようにしなさい。
↑[もどる] ←[1月17日] ・[1月24日] →[1月31日]
Last updated: 2002/02/07 20:20:58
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>