240 likes | 403 Views
Java Distributed Objects 1. Masayuki Iwai tailor@ht.sfc.keio.ac.jp. Table of contents. 第 1 回 10 月 11 日木曜日 5 限 Distibuted objects の目指す世界 Rmi 以前 tutorial Rmi tutorial 第 2 回 10 月 19 日金曜日 6 限 Rmi Advanced tutorial Rmi tutorial custom socket package Activatable 第 3 回 10 月 17 日木曜日 5 限
E N D
Java Distributed Objects1 Masayuki Iwai tailor@ht.sfc.keio.ac.jp
Table of contents • 第1回10月11日木曜日5限 • Distibuted objectsの目指す世界 • Rmi 以前 tutorial • Rmi tutorial • 第2回10月19日金曜日6限 • Rmi Advanced tutorial • Rmi tutorial • custom socket package • Activatable • 第3回10月17日木曜日5限 • Jini programming • Java Space programming • Distributed Objectsの世界
Distibuted objectsの目指す世界 • タスクの依頼 • 自由な連携 take write take read write
Local Method Invocation LocalMainClass LocalRuntime 192.168.0.1 • Local Method Invocation LocalClass localClass=new LocalClass(); outputObj=localClass.method(inputObj); • inputObjはprimitive型でない限りcall by referenceとして渡される。
メソッドの引数と返り値について • call by reference • 参照渡し • call by value • 値渡し
CallbyTestMain package jp.ac.sfc.keio.sfc.tailor.callbyLocal; publicclass CallbyTestMain extends Thread { String str = "0"; StringBuffer sbuf = new StringBuffer("0"); int i = 0; TestObj obj = new TestObj(); publicstaticvoid main(String args[]) { CallbyTestMain calltester = new CallbyTestMain(); calltester.start(); } publicvoid run() { CallTesterLocalMethods funcs = new CallTesterLocalMethods(); funcs.setStringBuffer(sbuf); funcs.setString(str); funcs.setPrimitive(i); funcs.setObject(obj); System.out.println("Primitive:"+i); System.out.println("String:"+str); System.out.println("StringBuffer:"+sbuf); obj.printTestObj(); System.out.println("=========== LOOP START============"); while (i < 4) { { i++; str=""+i; sbuf.append(i); obj.increment(); } System.out.println("----------------------------------"); funcs.printPrimitive(); funcs.printString(); funcs.printStringBuffer(); funcs.printObject(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO自動生成された catch ブロック e.printStackTrace(); } }//whie end System.out.println("=========== LOOP END============"); System.out.println("Primitive:"+i); System.out.println("String:"+str); System.out.println("StringBuffer:"+sbuf); obj.printTestObj(); } }
CallTesterLocalMethods package jp.ac.sfc.keio.sfc.tailor.callbyLocal; publicclass CallTesterLocalMethods { privateint i; private String str; private StringBuffer sbuf; private TestObj obj; void setPrimitive(int i) { this.i = i; } void printPrimitive() { System.out.println("Primitive:" + i); } void setString(String str) { this.str = str; } void printString() { System.out.println("String:"+str); } publicvoid setStringBuffer(StringBuffer sbuf) { this.sbuf=sbuf; } void printStringBuffer() { System.out.println("StringBuffer:"+sbuf); } void setObject(TestObj obj) { this.obj = obj; } void printObject() { obj.printTestObj(); } }
TestObj package jp.ac.sfc.keio.sfc.tailor.callbyLocal; publicclass TestObj { privateint i=0; publicvoid increment(){ i++; } publicvoid printTestObj(){ System.out.println("Object:"+i); } }
動きを予想してみよう。 Primitive:0 String:0 StringBuffer:0 Object:0 =========== LOOP START============ ---------------------------------- Primitive:【 】 String:【 】 StringBuffer:【 】 Object:【 】 ---------------------------------- Primitive:【 】 String:【 】 StringBuffer:【 】 Object:【 】 ---------------------------------- Primitive:【 】 String:【 】 StringBuffer:【 】 Object:【 】 ---------------------------------- Primitive:【 】 String:【 】 StringBuffer:【 】 Object:【 】 =========== LOOP END============ Primitive:【 】 String:【 】 StringBuffer:【 】 Object:【 】
RMI:Remote Method Invocation RemoteClass LocalMainClass method LocalRuntime RemoteRuntime 192.168.0.1 192.168.0.2 Remote Classのmethodを Callbyreferenceで呼びたいのがRMI
RMI:OutputStream • ソケットの作成が必要 • Bytedataのみをコピー可能 A B ByteData OutputStream VM_A VM_B
RMI:ObjectOutputStream • java.io.Serializableを実装したオブジェクト • Objectを一時直列化しネットワークを経由してコピーを行う • BがCをよみがえらせるには,Cのクラスファイルが必要 C C A B 0100101001010 ObjectOutputStream VM_A VM_B
Dateオブジェクトの移動 • Dateクラスは、Serializableインターフェースを実装している。 • 直列化可能という意味のマークキングインタフェース • Methodは持たない。 • 移動させたいObjectクラス定義の際に、 Serializable を実装
Interfaceによるremoteでのオブジェクト復元 • Inferfaceでキャストすることで • //Mony money= new MonyImpl(); • Mony money= new MonyImpl2(); 移動オブジェクトの実装変更が可能 呼び出し先では常に • Mony money = (Mony) (ois.readObject()); • money.printMoney(); • money.increment(); しかし、objectの移動にもかかわらずcall by referenceでない。
Castは万能か? • 実はディレクトリを分けると • Remote側で以下のエラーがおこる。 • java.lang.ClassCastException: jp.ac.sfc.keio.sfc.tailor.remote.withinterface2.local.MonyImpl2 cannot be cast to jp.ac.sfc.keio.sfc.tailor.remote.withinterface2.remote.Mony の Inferaceだけではだめ 実はキャスト(オブジェクト復元)にはimpleクラスがいるのだ
NetworkClassLoaderで実装クラスを呼び寄せる。 import java.util.*; import java.io.*; import java.net.*; public class NetworkClassLoader extends ClassLoader { InputStream in = null; ByteArrayOutputStream out = new ByteArrayOutputStream(1024); public NetworkClassLoader(){ this("localhost",8081); } public NetworkClassLoader(String host, int port){ try { Socket s = new Socket(host,port); in = s.getInputStream(); } catch (Throwable e) { e.printStackTrace(); } } protected Class findClass( String name ) throws ClassNotFoundException { try { byte buff[] = new byte[1024]; int n,m; int len=0; while ((n = in.read(buff, 0 , 1024)) >= 0) { out.write(buff,0,n); len += n ; } byte data[] = new byte[len]; data=out.toByteArray(); return defineClass(null, data, 0, len); } catch (Throwable e) { e.printStackTrace(); throw new ClassNotFoundException(); } } }
rmic -v1.2 MoneyRemoteImple • start rmiregistry • rmiregistry & • java -Djava.rmi.server.codebase=file:/C:workspace\ -Djava.security.policy=policy.txt MoneyRemoteImple
RMI:Bの側にCのクラスファイルがない場合RMI:Bの側にCのクラスファイルがない場合 • Interfaceを利用したCastだけではだめ • BはCを保持しておく必要がないが最終的にはCの情報が必要->NetworkClassLoader Cの情報をダウンロード C NetworkClassServer NetworkClassLoader interface C C C’ A serializable B C 0100101001010 ObjectOutputStream VM_A VM_B
RMI:すこし立ち止まって • クラスサーバは果たしてLocalRuntimeにある必要はあるのか? Cの情報をダウンロード C NetworkClassServer NetworkClassServer interface C C C’ A serializable B C 0100101001010 ObjectOutputStream VM_A VM_B
RMI:Marshalled Object • MarshalledObject=serialized object+そのロード元 (可能な場合) となるコードベース URL • BはCを知る必要がない:webserverは何処にあってもよい:動作はVM_B上 C http/get websrver Cクラスの解決情報 C C C C C’ A serializable B ObjectOutputStream VM_A VM_B
RMI: MarshalledObjectの実装 public final class MarshalledObject implements Serializable { /** * @serial Bytes of serialized representation. If <code>objBytes</code> is * <code>null</code> then the object marshalled was a <code>null</code> * reference. */ private byte[] objBytes = null; /** * @serial Bytes of location annotations, which are ignored by * <code>equals</code>. If <code>locBytes</code> is null, there were no * non-<code>null</code> annotations during marshalling. */ private byte[] locBytes = null; /** * @serial Stored hash code of contained object. * * @see #hashCode */ }
RMI:Object I/O Streamの2つの問題 • オブジェクト単位 public class Account implements Serializable{ public void setMoney(){….} public Money getMony(){….} public void addMony(){….} public void subMony(){….} } =================書き出す側 VM_A=================== Socket s = ss.accept(); ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); Account acc= Bank.getAccount(me); oos.writeObject(acc); s.close(); =================読み出す側 VM_B=================== ObjectInputStream ois = new ObjectInputStream(s.getInputStream()); Account acc= (Account) (ois.readObject()); acc.addMony(1000); AccountクラスってRemoteに最新のものあるの? これって変更されるのRemoteのAccountクラスだよね
RMI: • Socket/ObjectStreamレベルのことはStabが行う。 • Stabクラスはrmic –v1.2 ServerClassのコマンドで生成 • 実はMarshalledObjectを利用してRMIは実装されている。 • コードベースのためWebserverが必要 • スタブオブジェクトが必要:動作はVM_A上 C クラスCは必要ない WEBSERVER インタフェースC’ UnicastRemoteObject C C C’ A C_stub C_stub B RMI VM_A VM_B
RMI:SocketProgrammingではない。 =================サーバ側 VM_A=================== public class AccountImpleextends UnicastRemoteObject implements IAccount{ } AccountImple acc= Bank.getAccountImple (me); Naming.rebind(“registryhostname/Account_Iwai”,acc); 起動方法 >>java MainClass java.rmi.server.codebase=http://codebasehost/accout.jar =================クライアンド側 VM_B=================== String location = "rmi://registryhostname/Account_Iwai" ; acc=(IAccount)Naming.lookup(location); acc.addMony(1000); Socketプログラミングあらたな問題