並行分散ソフトウェア/並列分散ソフトウェア 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.cs.tsukuba.ac.jp/~yas/sie/pdsoft-2005/2006-02-03
あるいは、次のページから手繰っていくこともできます。
http://www.cs.tsukuba.ac.jp/~yas/sie/
http://www.cs.tsukuba.ac.jp/~yas/
XML は、WWW で使われている HTML (Hyper Text Markup Language) と同様に、マークアップ言語の一種。
マークアップ言語とは、文書(テキスト)に、「ここは表題」、「ここは箇条 書」といった、文書の構造を示す目印(マーク)を付ける機能を持つ言語。
マークアップ言語の種類
HTML でも XML でも、マークアップのために、テキストにタグ(tag)を埋め込 む。HTML の場合、タグの種類と意味があらかじめ規定されており、その規定 の範囲でしか WWW データを表現することができない。
これに対して、XML では、定められた方式で新たなタグを定義することが可能 になっている。XML を使えば、特定の応用分野に特化したマークアップ言語を 文書の作成者が設計することができるようになる。
XML 形式の文書は、WWW ブラウザでの利用のように、人間が目にすることがあ る場所でも使われるが、むしろプログラムとプログラムがネットワークを越え てデータを交換するために使われることが多い。
World Wide Web コンソーシアムのXMLのページ
http://www.w3.org/XML/
Web サービスを、一般の World Wide Web と紛れないように呼ぶ時には、 「XML Web サービス」と言う。
Web サービスでは、異なるプログラミング言語で書かれたコンポーネントも相 互に接続できる。
XML-RPC では、クライアントとサーバの間の通信は、XML により行われる。ク ライアントは、手続きの名前や入力パラメタを XML の形式にまとめて、サー バへ送る。サーバでは、手続きが実行され、その結果もXMLの形でクライアン トへ返される。 XML-RPC では、クライアントとサーバの間の通信には、WWW で使わ れている HTTP が使われる。
XML-RPC では、メッセージが長くなり過ぎたり、型付けに問題があっ た。これを解決するために、SOAP (Simple Object Access Protocol) が作られた。
SOAP は、最初は、Simple Object Access Protocol の略であったが、 Object-Oriented ではないということで、この略は捨てられた。
XML-RPC では、データを交換するための中間形式として XML を使っていただ けであったが、SOAP では、XML のデータを直接 XML として渡すことができる。
SOAP では、HTTP の他に電子メールも通信媒体として使う事ができる。 SOAP 用に、HTTP のヘッダがいくつか拡張されたが、 実際問題として活用しにくい。 SOAP は、Microsoft 社などにより提案され、その後、W3C で標準化が行われ ている。
XMethodshttp://www.xmethods.net/
Amazon.com Web サービスhttp://www.amazon.com/gp/aws/sdk/
Google検索エンジンhttp://www.google.com/apis/
Webサービス同好会http://objectclub.esm.co.jp/webservice/
三省堂デイリーコンサイスhttp://www.btonic.com/ws/
WSDL で記述するもの
1: <?xml version='1.0' encoding='UTF-8'?> 2: 3: <!--generated by GLUE--> 4: 5: <definitions name='Counter' 6: targetNamespace='http://www.themindelectric.com/wsdl/Counter/' 7: xmlns:tns='http://www.themindelectric.com/wsdl/Counter/' 8: xmlns:electric='http://www.themindelectric.com/' 9: xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' 10: xmlns:http='http://schemas.xmlsoap.org/wsdl/http/' 11: xmlns:mime='http://schemas.xmlsoap.org/wsdl/mime/' 12: xmlns:xsd='http://www.w3.org/2001/XMLSchema' 13: xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/' 14: xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/' 15: xmlns='http://schemas.xmlsoap.org/wsdl/'> 16: 17: <message name='getValue0SoapIn'/> 18: <message name='getValue0SoapOut'> 19: <part name='Result' type='xsd:int'/> 20: </message> 21: <message name='reset1SoapIn'> 22: <part name='newVal' type='xsd:int'/> 23: </message> 24: <message name='reset1SoapOut'/> 25: <message name='up2SoapIn'/> 26: <message name='up2SoapOut'/> 27: 28: <portType name='CounterSoap'> 29: <operation name='getValue'> 30: <input name='getValue0SoapIn' message='tns:getValue0SoapIn'/> 31: <output name='getValue0SoapOut' message='tns:getValue0SoapOut'/> 32: </operation> 33: <operation name='reset' parameterOrder='newVal'> 34: <input name='reset1SoapIn' message='tns:reset1SoapIn'/> 35: <output name='reset1SoapOut' message='tns:reset1SoapOut'/> 36: </operation> 37: <operation name='up'> 38: <input name='up2SoapIn' message='tns:up2SoapIn'/> 39: <output name='up2SoapOut' message='tns:up2SoapOut'/> 40: </operation> 41: </portType> 42: 43: <binding name='CounterSoap' type='tns:CounterSoap'> 44: <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> 45: <operation name='getValue'> 46: <soap:operation soapAction='getValue' style='rpc'/> 47: <input name='getValue0SoapIn'> 48: <soap:body use='encoded' namespace='http://tempuri.org/Counter' 49: encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> 50: </input> 51: <output name='getValue0SoapOut'> 52: <soap:body use='encoded' namespace='http://tempuri.org/Counter' 53: encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> 54: </output> 55: </operation> 56: <operation name='reset'> 57: <soap:operation soapAction='reset' style='rpc'/> 58: <input name='reset1SoapIn'> 59: <soap:body use='encoded' namespace='http://tempuri.org/Counter' 60: encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> 61: </input> 62: <output name='reset1SoapOut'> 63: <soap:body use='encoded' namespace='http://tempuri.org/Counter' 64: encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> 65: </output> 66: </operation> 67: <operation name='up'> 68: <soap:operation soapAction='up' style='rpc'/> 69: <input name='up2SoapIn'> 70: <soap:body use='encoded' namespace='http://tempuri.org/Counter' 71: encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> 72: </input> 73: <output name='up2SoapOut'> 74: <soap:body use='encoded' namespace='http://tempuri.org/Counter' 75: encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> 76: </output> 77: </operation> 78: </binding> 79: 80: <service name='Counter'> 81: <documentation> 82: // ICounter.java//</documentation> 83: <port name='CounterSoap' binding='tns:CounterSoap'> 84: <soap:address location='http://127.0.0.1:4031/soap/Counter/c1'/> 85: </port> 86: </service> 87: </definitions>
UDDI では、UDDI レジストリと呼ばれるデータベースに次のような情報を格納 する。
UDDI を利用する Web サービスのクライアント
HTTP サーバを内蔵しているので、手軽に試すのに適している。 WSDL を自動生成する機能がある。
The Mind Electric社は、2003年にwebMethods社により買収された。
1: // 2: // ICounter.java 3: // 4: 5: public interface ICounter 6: { 7: void up(); 8: int getValue(); 9: void reset(int newVal); 10: };単に利用するだけならば、インタフェースを定義しなくてもよいが、リモート との比較のためにあえて定義する。カウンタは、3つの手続きを持つものであ る。
1: // 2: // Counter.java 3: // 4: public class Counter implements ICounter 5: { 6: int val; 7: public Counter(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: };3つの手続きとコンストラクタを実現している。
// // CounterLocal.java // class CounterLocal { public static void main(String argv[]) { ICounter c1 = new Counter( 10 ); for( int i=0 ; i<3 ; i++ ) { c1.up(); System.out.println("c1.value=="+c1.getValue()); } } };coins での実行例:
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/Makefile% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/ICounter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/Counter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/CounterLocal.java
% make CounterLocal
javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar ICounter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar Counter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterLocal.java % make run-CounterLocal
java -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterLocal c1.value==11 c1.value==12 c1.value==13 % make run-CounterLocal
java -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterLocal c1.value==11 c1.value==12 c1.value==13 %
![]()
オブジェクト c1 を、main で作って実行している。実行する度に新しいオブ ジェクトが new される。
1: 2: import electric.registry.Registry; 3: import electric.server.http.HTTP; 4: 5: public class CounterServer 6: { 7: public static void main( String[] args ) throws Exception 8: { 9: if( args.length != 2 ) 10: { 11: System.err.println("Usge: %% java CounterServer portno name"); 12: System.exit( 1 ); 13: } 14: String portno = args[0]; 15: String name = args[1]; 16: String url = "http://localhost:" + portno + "/soap" ; 17: HTTP.startup( url ); 18: 19: Registry.publish( name, new Counter(10) ); 20: System.out.println("Ok."); 21: } 22: }このプログラムは、2つの引数を取る。
HTTP.Startup() で、Glue に含まれている Web サービスのサーバを起動して いる。その結、果新しいスレッドが作られるので、このプログラムは、main() が終了しても、動き続けることになる。
Registry.publish() は、Glue に含まれている機能である。 これは、与えられた名前で、オブジェクトをアクセス可能にする。
1: 2: import electric.registry.Registry; 3: 4: public class CounterClient 5: { 6: public static void main( String[] args ) throws Exception 7: { 8: if( args.length != 3 ) 9: { 10: System.err.println("Usge: %% java CounterClient hostname portno name"); 11: System.exit( 1 ); 12: } 13: String hostname = args[0]; 14: String portno = args[1]; 15: String name = args[2]; 16: String url = "http://" + hostname + ":" + portno + "/soap/" + name + ".wsdl"; 17: System.out.println("url is " + url ); 18: ICounter c1 = (ICounter) Registry.bind( url, ICounter.class ); 19: for( int i=0 ; i<3 ; i++ ) 20: { 21: c1.up(); 22: System.out.println("c1.value=="+c1.getValue()); 23: } 24: } 25: }このプログラムは、3つの引数を取る。
サーバは、は自動的に終了しないので、実験が終わったら ^C (Control-C)で 殺す。
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/Makefile% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/ICounter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/Counter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/CounterServer.java
% make clean
rm -f *.class *.npr % make CounterServer
javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar ICounter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar Counter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterServer.java % make run-CounterServer
java -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterServer 8080 Counter/c1 GLUE 1.2 (c) 2001 The Mind Electric startup server on http://130.158.86.29:8080/soap Ok. (最後に ^C で止める)
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/Makefileクライアントのプログラムを2回実行しても、同じカウンタが使われている所 に注意する。% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/ICounter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/CounterClient.java
% make CounterClient
javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar ICounter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterClient.java % ls
CounterClient.class ICounter.class Makefile CounterClient.java ICounter.java % make run-CounterClient
javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterClient.java java -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterClient localhost 8080 Counter/c1 url is http://localhost:8080/soap/Counter/c1.wsdl c1.value==11 c1.value==12 c1.value==13 % make run-CounterClient
javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterClient.java java -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterClient localhost 8080 Counter/c1 url is http://localhost:8080/soap/Counter/c1.wsdl c1.value==14 c1.value==15 c1.value==16 %
![]()
実際に Web サービスを利用する場合には、いくつかの方法が選べる。
% make run-CounterServerjava -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterServer 8080 Counter/c1 Exception in thread "main" java.net.BindException: Address already in use at java.net.PlainSocketImpl.socketBind(Native Method) at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:331) at java.net.ServerSocket.bind(ServerSocket.java:309) at java.net.ServerSocket.
(ServerSocket.java:183) at java.net.ServerSocket. (ServerSocket.java:139) at javax.net.DefaultServerSocketFactory.createServerSocket(DashoA6275) at electric.net.socket.tcp.TCPSocketFactory.createServerSocket(Unknown Source) at electric.net.socket.SocketServer.createServerSocket(Unknown Source) at electric.net.socket.SocketServer.startup(Unknown Source) at electric.net.http.WebServer.startup(Unknown Source) at electric.net.http.WebServer.startWebServer(Unknown Source) at electric.server.http.HTTP.startup(Unknown Source) at electric.server.http.HTTP.startup(Unknown Source) at electric.server.http.HTTP.startup(Unknown Source) at CounterServer.main(CounterServer.java:17) make: *** [run-CounterServer] Error 1 % ![]()
同じポート番号が使われていた時、Address already in use というエラーが 出る。その時には、まず、自分のプログラム(の残がい)がどこかで動いてい ないかを調べる。他の同じ演習をしている人のプログラムの残がいを見つけた 時には、残がいだったら殺してもらう。本当に別のプログラムに使われていた 時には、別のコンピュータに移動するか、以下のように別のポート番号を指定 して走らせる。
% make run-CounterServer port=1231java -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar CounterServer 1231 Counter/c1 GLUE 1.2 (c) 2001 The Mind Electric startup server on http://130.158.86.29:1231/soap Ok. (最後に ^C で止める)
% telnet 130.158.86.29 8080得られた WSDLの例。Trying 130.158.86.29... Connected to 130.158.86.29. Escape character is '^]'. GET /soap/Counter/c1.wsdl HTTP/1.0
![]()
HTTP/1.1 200 OK Content-Type: text/xml Server: GLUE/1.2 Content-Length: 2959 <?xml version='1.0' encoding='UTF-8'?> <!--generated by GLUE--> <definitions name='Counter' ... > ... </definitions> Connection closed by foreign host. %
![]()
Web サービスでは、WWW の技術を使ってアクセス制御を行うことができる。
別の Java 仮想計算機間オブジェクトのメソッドを呼び出す仕組み。 RMI いくつかの層を見えなくする。
比較的軽い。非力なコンピュータに向いている。
http://horb.a02.aist.go.jp/horb-j/
中身が空のインタフェース Remote を付ける。
src/java/rmi/Remote.java public interface Remote {}これを見つけると、コンパイラが特殊なコードを生成する。
java.lang.Object (class) | +--java.rmi.server.RemoteObject (class) | +--java.rmi.server.RemoteServer (class) | +--java.rmi.server.UnicastRemoteObject (class)これに加えて、interface Remote を implements する。
クライアント側は、これに比べて簡単。違いは、サーバに接続する部分部分と、 分散固有の例外を受ける部分。
1: // 2: // IRCounter.java 3: // 4: 5: public interface IRCounter 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: // RCounter.java 3: // 4: 5: import java.rmi.*; 6: import java.rmi.server.*; 7: 8: public class RCounter extends java.rmi.server.UnicastRemoteObject 9: implements IRCounter 10: { 11: int val; 12: public RCounter(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:
オブジェクトは、serialize (直列化) されてコピーで渡される。
1: // 2: // RCounterServer.java 3: // 4: 5: import java.rmi.*; 6: import java.rmi.server.*; 7: 8: public class RCounterServer 9: { 10: public static void main(String argv[]) 11: { 12: if( argv.length != 1 ) 13: { 14: System.err.println("Usage% java RCounterServer 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: IRCounter c1 = new RCounter( 10 ); 25: String name = "rmi://localhost:"+rmiregport+"/Counter/c1" ; 26: Naming.rebind( name,c1 ); 27: } 28: catch (Exception e) 29: { 30: System.err.println("RCounterServer error:"+e.getMessage()); 31: e.printStackTrace(); 32: } 33: } 34: };Exception を catch したら、最後に System.exit( 1 ) した方がよい。
rmiregistry に登録する時には、次のような URL が使える。
port は、rmiregistry が使うポート番号で、デフォルトでは 1099。 大勢で1つのホストを使うとぶつかる。
string は単なる文字列。フラットな名前空間。
1: // 2: // RCounterClient.java 3: // 4: 5: import java.rmi.*; 6: 7: class RCounterClient 8: { 9: public static void main(String argv[]) 10: { 11: if( argv.length != 2 ) 12: { 13: System.err.println("Usage% java RCounterClient hostname rmiregistry-portno"); 14: System.exit( 1 ); 15: } 16: String hostname = argv[0]; 17: String rmiregport = argv[1]; 18: 19: IRCounter c1 ; 20: try 21: { 22: if( System.getSecurityManager() == null ) 23: System.setSecurityManager( new RMISecurityManager() ); 24: String name = "rmi://"+hostname+":"+rmiregport+"/Counter/c1"; 25: c1 = (IRCounter) Naming.lookup( 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: };
一方のウインドウで rmiregistry を起動する。ポート番号は、ぶつからない ように uid を使う。rmiregistry は自動的に終了しないので、実験が終わっ たら ^C (Control-C)で殺す。
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/Makefile一方のウインドウでサーバを動作させる。サーバもは自動的に終了しないので、 実験が終わったら ^C (Control-C)で殺す。% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/IRCounter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/RCounter.java
% make run-rmiregistry
javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar IRCounter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar RCounter.java rmic RCounter rmiregistry 8080 (最後に ^C で止める)
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/Makefile% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/IRCounter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/RCounter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/RCounterServer.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/RCounterServer.policy
% make RCounterServer
javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar IRCounter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar RCounter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar RCounterServer.java rmic RCounter % make run-RCounterServer
java -Djava.security.policy=./RCounterServer.policy RCounterServer 8080 (最後に ^C で止める)
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/Makefile% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/IRCounter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/RCounter.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/RCounterClient.java
% wget http://www.is.tsukuba.ac.jp/~yas/sie/cdsoft-2005/2006-02-03/ex/RCounterClient.policy
% make RCounterClient
javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar IRCounter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar RCounter.java javac -classpath .:/home/lab/Denjo/yas/glue/electric/lib/GLUE-STD.jar:/home/lab/Denjo/yas/glue/electric/lib/servlet.jar RCounterClient.java rmic RCounter % make run-RCounterClient
java -Djava.security.policy=./RCounterClient.policy RCounterClient localhost 8080 c1.value==11 c1.value==12 c1.value==13 % make run-RCounterClient
java -Djava.security.policy=./RCounterClient.policy RCounterClient localhost 8080 c1.value==14 c1.value==15 c1.value==16 %
![]()
Java の標準のセキュリティのポリシー(java コマンドで利用される)は、 jre/lib/security/java.policy に記述されている。
System.setSecurityManager( new RMISecurityManager() ) した時には、 標準よりきつくなる。実験する時には、少し緩めないとつながらない。
以下の例では、localhost と *.tsukuba.ac.jp からのアクセスを許している。
1: // 2: // RCounterServer.policy 3: // 4: 5: grant { 6: permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect,resolve"; 7: permission java.net.SocketPermission "*.tsukuba.ac.jp:1024-", "accept,listen,connect,resolve"; 8: };[RCounterClient.policy]
1: // 2: // RCounterClient.policy 3: // 4: 5: grant { 6: permission java.net.SocketPermission "localhost:1024-", "listen,connect,resolve"; 7: permission java.net.SocketPermission "*.tsukuba.ac.jp:1024-", "listen,connect,resolve"; 8: };クライアント側では、うまく設定すると、サーバ側に置かれたクラスを動的に http や ftp でロードして実行できる。その時には、 java.rmi.server.codebase プロパティを使う。
RMI でオブジェクトを渡す時には、interface Serializable を implements する。
serialize 不要のフィールドには、transient をつける。
serialization は、RMI だけでなく、オブジェクトをファイルに落とす時にも 使える。
ある。
ヒント: main() では、カウンタそのものではなく、カウンタ・オブジェクト を生成するオブジェクトを追加し、遠隔からアクセス可能にする。新たにカウ ンタ・オブジェクトを生成するたびにそれを遠隔からアクセス可能にする。
言語は Java でなくてもよい。