並列分散ソフトウェア 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-14
あるいは、次のページから手繰っていくこともできます。
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
参考文献
Eric Freeman, Susanne Hupfer, and Ken Arnold: "JavaSpaces Principles, Patterns, and Practice", Addison Wesley Publishing Company (1999/06). ISBN: 0201309556
interface JavaSpace を実現したオブジェクト
---------------------------------------------------------------------- Linda JavaSpace 説明 ---------------------------------------------------------------------- out write タプルをタプル空間内に生成する。 in take タプルを取り去る rd read in/takeと似ているが、タプルがタプルスペースに残る。 ----------------------------------------------------------------------ライブタプル(eval命令)は、ない。JavaSpaces が提供する空間の特徴
net/jini/core/entry/Entry.java: public interface Entry extends java.io.Serializable { }
net/jini/space/JavaSpace.java: public interface JavaSpace { Lease write(Entry entry, Transaction txn, long lease) throws TransactionException, RemoteException; long NO_WAIT = 0; Entry read(Entry tmpl, Transaction txn, long timeout) throws UnusableEntryException, TransactionException, InterruptedException, RemoteException; Entry readIfExists(Entry tmpl, Transaction txn, long timeout) throws UnusableEntryException, TransactionException, InterruptedException, RemoteException; Entry take(Entry tmpl, Transaction txn, long timeout) throws UnusableEntryException, TransactionException, InterruptedException, RemoteException; Entry takeIfExists(Entry tmpl, Transaction txn, long timeout) throws UnusableEntryException, TransactionException, InterruptedException, RemoteException; EventRegistration notify(Entry tmpl, Transaction txn, RemoteEventListener listener, long lease, MarshalledObject handback) throws TransactionException, RemoteException; Entry snapshot(Entry e) throws RemoteException; }
notify() では、マッチするテンプレートが write された時、 RemoteEventListener の notify(emoteEvent theEvent) が呼ばれる。
snapshot() では、エントリのスナップショットが返される。元のエントリが 更新されても、変化しない。read(), take() のテンプレート用。
public class PDSoftSpaceFinder extends java.lang.Object { public PDSoftSpaceFinder(); public static net.jini.space.JavaSpace getSpace(java.lang.String); public static net.jini.space.JavaSpace getSpace(); }
---------------------------------------------------------------------- 1: // From the JavaSpaces book 2: //package jsbook.chapter1.helloWorld; 3: 4: import net.jini.core.entry.Entry; 5: 6: public class Message implements Entry { 7: public String content; 8: 9: public Message() { 10: } 11: } ----------------------------------------------------------------------
---------------------------------------------------------------------- 1: // 2: // HelloWriter.java 3: // 4: 5: import net.jini.space.JavaSpace; 6: 7: class HelloWriter { 8: public static void main(String[] argv) 9: { 10: JavaSpace space = PDSoftSpaceFinder.getSpace(); 11: if( space == null ) 12: { 13: System.err.println("No JavaSpace found."); 14: System.exit( 1 ); 15: } 16: Message msg = new Message(); 17: msg.content = "Hello" ; 18: try 19: { 20: space.write(msg, null, net.jini.core.lease.Lease.FOREVER); 21: System.out.println("HelloWriter: wrote["+msg.content+"]"); 22: } 23: catch( Exception e ) 24: { 25: System.err.println("JavaSpace write error "+e.getMessage()); 26: e.printStackTrace(); 27: System.exit( -1 ); 28: } 29: System.exit( 0 ); 30: } 31: } ----------------------------------------------------------------------
Lease write(Entry entry, Transaction txn, long lease) throws TransactionException, RemoteException;トランザクションは、複数の操作をグループ化するもの。null を 指定すれば、その機能は使われない。
lease は、時間を指定する。その時間だけは、空間がそのエントリを記憶して いる。空間が Garbage Collection に使う。Lease.FOREVER は、無限に覚えて いることを意味する。単位は、ミリ秒。
(transient-outrigger.jar では、サーバを落とすと消える。)
---------------------------------------------------------------------- 1: // 2: // HelloReader.java 3: // 4: 5: import net.jini.space.JavaSpace; 6: 7: public class HelloReader { 8: public static void main(String[] argv) 9: { 10: JavaSpace space = PDSoftSpaceFinder.getSpace(); 11: if( space == null ) 12: { 13: System.err.println("No JavaSpace found."); 14: System.exit( 1 ); 15: } 16: 17: Message template = new Message(); 18: Message result; 19: try 20: { 21: result = (Message)space.read(template, null, Long.MAX_VALUE); 22: System.out.println("HelloReader: read ["+result.content+"]"); 23: } 24: catch( Exception e ) 25: { 26: System.err.println("JavaSpace read error "+e.getMessage()); 27: e.printStackTrace(); 28: System.exit( -1 ); 29: } 30: 31: System.exit( 0 ); 32: } 33: } ----------------------------------------------------------------------
Entry read(Entry tmpl, Transaction txn, long timeout) throws UnusableEntryException, TransactionException, InterruptedException, RemoteException;read の最初の引数は、テンプレートである。 read は、空間からテンプレートとマッチするエントリを読み出す。
次の2つの規則を満たした時に、テンプレートとエントリはマッチする
public class Vegetable implements Entry { } public class Fruit implements Entry { } public class Apple extends Fruit { } public class Orange extends Fruit { }図
「同じ値」は、serialize してバイトレベルで同じという意味。エントリは、 空間にある時にはserialize された形で保存されている。
null を和いるとカードに使う問題点は、「本当に null の値を持つエントリ 探す」ということができないこと。 区別したい時には、Boolean を添える。
public class NotePtr implements Entry { public Boolean ptrIsNull; public Node ptr; } ... NodePtr template = new NodePtr(); template.ptrIsNull = new Boolean(true); template.ptr = null; // for completeness; null by defaultnull をワイルドカードに使ったので、空間に置くエントリのフィールドは、 オブジェクトにする。int, boolean, float, double などは、Integer, Boolean, Float, Double などの wrappe クラスを使う。
read() は、マッチするエントリがなければ、timeout するまで待つ。 Long.MAX_VALUE は、無限に待つことを意味する。待ちたくない時には、 JavaSpaces.NO_WAIT を使うか、raedIfExists() を使う。
注意:連続する read() が同じオブジェクトを返す保証はない。
---------------------------------------------------------------------- 1: // 2: // HelloTaker.java 3: // 4: 5: import net.jini.space.JavaSpace; 6: 7: public class HelloTaker { 8: public static void main(String[] argv) 9: { 10: JavaSpace space = PDSoftSpaceFinder.getSpace(); 11: if( space == null ) 12: { 13: System.err.println("No JavaSpace found."); 14: System.exit( 1 ); 15: } 16: 17: Message template = new Message(); 18: Message result; 19: try 20: { 21: result = (Message)space.take(template, null, Long.MAX_VALUE); 22: System.out.println("HelloTaker: took ["+result.content+"]"); 23: } 24: catch( Exception e ) 25: { 26: System.err.println("JavaSpace read error "+e.getMessage()); 27: e.printStackTrace(); 28: System.exit( -1 ); 29: } 30: 31: System.exit( 0 ); 32: } 33: } % diff HelloReader.npr HelloTaker.npr 2c2 < 2: // HelloReader.java --- > 2: // HelloTaker.java 7c7 < 7: public class HelloReader { --- > 7: public class HelloTaker { 21,22c21,22 < 21: result = (Message)space.read(template, null, Long.MAX_VALUE); < 22: System.out.println("HelloReader: read ["+result.content+"]"); --- > 21: result = (Message)space.take(template, null, Long.MAX_VALUE); > 22: System.out.println("HelloTaker: took ["+result.content+"]"); % ----------------------------------------------------------------------take() は、read() と同じだが、エントリを空間から取り去る所が異なる。 複数の take() が重なったとしても、 エントリは1つにしか取られない。
---------------------------------------------------------------------- % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-14/ex/PDSoftSpaceFinder.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-14/ex/Message.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-14/ex/HelloWriter.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-14/ex/HelloReader.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-14/ex/HelloTaker.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-14/ex/Makefile % make clean % make hello javac -classpath .:/home/yshinjo/jini1_1/lib/transient-outrigger.jar PDSoftSpaceFinder.java Note: PDSoftSpaceFinder.java uses or overrides a deprecated API. Note: Recompile with -deprecation for details. javac -classpath .:/home/yshinjo/jini1_1/lib/transient-outrigger.jar Message.java javac -classpath .:/home/yshinjo/jini1_1/lib/transient-outrigger.jar HelloWriter.java javac -classpath .:/home/yshinjo/jini1_1/lib/transient-outrigger.jar HelloReader.java javac -classpath .:/home/yshinjo/jini1_1/lib/transient-outrigger.jar HelloTaker.java % ----------------------------------------------------------------------
rmiregistry で使うポート番号は、ぶつからないように、各自の uid を使う。 rmiregistry は自動的に終了しないので、実験が終わったら ^C (Control-C) で殺す。---------------------------------------------------------------------- % make run-rmiregistry rmiregistry `id | sed -e 's;uid=;;' -e 's;(.*;;'` (最後に ^C で止める) ----------------------------------------------------------------------
注意: sakura に rmiregistry を動かしっ放しの人がいる。この実験を始める 前にps で調べて kill しておくこと。
残りの一方のウインドウで Writer を動作させる。---------------------------------------------------------------------- % make run-TransientSpace java -Djava.security.policy=/home/yshinjo/jini1_1/policy/policy.transient-outrigger -Djava.rmi.server.codebase=file:/home/yshinjo/jini1_1/lib/outrigger-dl.jar -classpath .:/home/yshinjo/jini1_1/lib/transient-outrigger.jar -Dcom.sun.jini.use.registry=yes -Dcom.sun.jini.outrigger.spaceName=JavaSpace -Dcom.sun.jini.rmiRegistryPort=`id | sed -e 's;uid=;;' -e 's;(.*;;'` -jar /home/yshinjo/jini1_1/lib/transient-outrigger.jar Warning: file url in codebase component may cause problems (file:/home/yshinjo/jini1_1/lib/outrigger-dl.jar) Warning: Your are using the com.sun.jini.use.registry property in order to bind this Outrigger server into an RMI registry. Direct support for binding Outrigger servers into RMI registries is going to be removed in a future version of the Jini(TM) Software Kit (JSK). (最後に ^C で止める) ----------------------------------------------------------------------
最後のウインドウで Reader や Taker を動作させる。---------------------------------------------------------------------- % set prompt="Writer% " Writer% make run-HelloWriter HelloWriter: wrote[Hello] Writer% make run-HelloWriter HelloWriter: wrote[Hello] Writer% ----------------------------------------------------------------------
3回目の take は止まる。別ウインドウで write すれば、先に進む。---------------------------------------------------------------------- % make -n run-HelloReader java -Djava.security.policy=/home/yshinjo/jini1_1/policy/policy.transient-outrigger -Djava.rmi.server.codebase=file:/home/yshinjo/jini1_1/lib/outrigger-dl.jar -classpath .:/home/yshinjo/jini1_1/lib/transient-outrigger.jar -Dcom.sun.jini.use.registry=yes -Dcom.sun.jini.outrigger.spaceName=JavaSpace -Dcom.sun.jini.rmiRegistryPort=`id | sed -e 's;uid=;;' -e 's;(.*;;'` HelloReader % make run-HelloReader HelloReader: read [Hello] % make run-HelloReader HelloReader: read [Hello] % make run-HelloReader HelloReader: read [Hello] % make run-HelloReader HelloReader: read [Hello] % % make run-HelloTaker HelloTaker: took [Hello] % make run-HelloTaker HelloTaker: took [Hello] % make run-HelloTaker ^Cmake: *** [run-HelloTaker] Error 130 % ----------------------------------------------------------------------
タプルがない状態先に take/read すると、止まる。この状態で、write すれ ば、read/take が終了する。
read() でのマッチングは、serialize された形で比較される。
空間に入れた出すと、オブジェクトが増えることがある。
public class E1 implements Entry { public Integer obj1; public Integer obj2; } Integer obj = Integer(0); E1 e = new E1(); e.obj1 =obj; e.obj2 =obj;図
引数なしのコンストラクタが必要である。
read(), take() でのエントリの復元
read(), take() のテンプレートがループの中で不変な場合、 snapshot() を作ると効率が良くなる。
古い (jini1_1) の policy/policy.transient-outrigger は、弱い。
---------------------------------------------------------------------- 1: // 2: // PDSoftSpaceFinder.java 3: // 4: 5: import java.rmi.*; 6: 7: import net.jini.space.JavaSpace; 8: import com.sun.jini.mahout.binder.RefHolder; // {transient-outrigger,...}.jar 9: 10: public class PDSoftSpaceFinder { 11: public static JavaSpace getSpace(String name) 12: { 13: try 14: { 15: String rport ; 16: if( System.getProperty("com.sun.jini.use.registry") == null ) 17: { 18: System.err.println("Run with -Dcom.sun.jini.use.registry=yes"); 19: } 20: else if( (rport=System.getProperty("com.sun.jini.rmiRegistryPort")) == null ) 21: { 22: System.err.println("Run with -Dcom.sun.jini.rmiRegistryPort=myUID"); 23: } 24: else 25: { 26: String url = "//localhost:"+rport+"/"+name ; 27: RefHolder rh = (RefHolder)Naming.lookup(url); 28: return (JavaSpace)rh.proxy(); 29: } 30: // thru 31: } 32: catch( Exception e ) 33: { 34: System.err.println(e.getMessage()); 35: } 36: return null; 37: } 38: 39: public static JavaSpace getSpace() 40: { 41: String spaceName = System.getProperty("com.sun.jini.outrigger.spaceName"); 42: if( spaceName == null ) 43: { 44: // System.err.println("run with -Dcom.sun.jini.outrigger.spaceName=JavaSpace"); 45: // return( null ); 46: spaceName = "JavaSpace" ; 47: // thru 48: } 49: return getSpace( spaceName ); 50: } 51: } ----------------------------------------------------------------------
次の課題から1つを選んで提出しなさい。問題を難しい方に変えてもよい。締 め切りは、2002/02/27 (水曜日) 18:00 とする。(23:59:59 ではない)。
レポートは、次のような形式の電子メールで送ること。
---------------------------------------------------------------------- To: yas@is.tsukuba.ac.jp Subject: [pdsoft/space] <内容に関したサブジェクト> 学籍番号 000000 (各自の学籍番号で置き換える) 名前 漢字の名前 <内容> ----------------------------------------------------------------------
初期化: Stringurl = argv[0]; webCounter c = new webCounter(url,0); space.write(webCounter,null,Lease.FOREVER); アクセスされた時: 増やすには、take して 増やして、write する。
("stream",0,val0) ("stream",1,val1) ("stream",2,val2) ... ポインタ ("stream","head",0) ("stream","tail",0) ストリームに要素を追加: int index; in("stream","tail",?index); out("stream","tail",index+1); out("stream",index,new_element); ストリームから要素を取り出す: int index; in("stream","head",?index); out("stream","head",index+1); in("stream",index,?element);これは、複数source、複数sink。
source、sinkが1つなら、head, tail をタプルスペースに置かなくてもよい。
head の代わりに、局所変数でアクセスする。
ストリームから要素を取り出す: int index=0 ; while( ... ) { rd("stream",index++,?element); }