300 likes | 428 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として渡される。
RMI:Remote Method Invocation RemoteClass LocalMainClass method LocalRuntime RemoteRuntime 192.168.0.1 192.168.0.2 Remote Classのmethodを Callbyreferenceで呼びたいのがRMI
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プログラミングあらたな問題
Remote インタフェースの実装 publicinterface MoneyRemote extendsRemote { publicvoid increment() throws RemoteException; publicvoid printMoney() throws RemoteException; publicint getMoney() throws RemoteException; }
MoneyLocalClient publicclass MoneyLocalClient { publicstaticvoid main(String argv[]){ MoneyRemote remotemoney; //インタフェースのみの宣言である点に注意 //codebaseがなければキャスト例外を起すはず try { String location = "rmi://localhost/MoneyServer" ; remotemoney=(MoneyRemote)Naming.lookup(location); System.out.println("Remote obj: " + remotemoney ); System.out.println("money local client:"+remotemoney.getMoney()); remotemoney.increment(); //remote呼び出し remotemoney.printMoney();//remote呼び出し } catch (Exception e) { System.out.println("err: " + e); e.printStackTrace(); } } }
MoneyRemoteImpl publicclass MoneyRemoteImpl extendsUnicastRemoteObjectimplementsMoneyRemote { //ここのpublic必須 <- なぜか理由を考えてみてね。 publicMoneyRemoteImpl() throws RemoteException { super(); } int money = 0; publicvoid increment() throws RemoteException { money++; } publicvoid printMoney() throws RemoteException { System.out.println("Remote Money is:" + money); } publicint getMoney() throws RemoteException { return money; } }
RemoteMain publicclass RemoteMain { publicstaticvoid main(String argv[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { MoneyRemoteImpl money = new MoneyRemoteImpl(); money.increment(); Naming.rebind("rmi://localhost/MoneyServer", money); //実は名前は何でもよい。 System.out.println("MoneyServer bound in registry"); money.printMoney(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }
コマンド • Stubの生成 • rmic -v1.2 jp.ac.sfc.keio.sfc.tailor.rmi.test.remote.MoneyRemoteImpl • Stubはクライアントにコピーが必要 • Codebaseのためのjar化 • jar cvf 1rmiMoneyRemoteImpl.jar jp\ac\sfc\keio\sfc\tailor\rmi\test\ • Rmiregistryの起動 • jar cvf 1rmiMoneyRemoteImpl.jar jp\ac\sfc\keio\sfc\tailor\rmi\test\ • サーバの起動 • java -Djava.rmi.server.codebase=http://www.ht.sfc.keio.ac.jp/~tailor/rg/1rmiMoneyRemoteImpl.jar -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.test.remote.RemoteMain • クライアントの起動 • java -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.test.local.MoneyLocalClient
わざとcodebaseでエラーを起す。 • java -Djava.rmi.server.codebase=http://www.ht.sfc.keio.ac.jp/~tailor/rgX/ -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.test.remote.RemoteMain • Rmiregistryのcodebaseに開発コードがないことを確認
rmiregistryの正体 package jp.ac.sfc.keio.sfc.tailor.rmi.registry; import java.rmi.AlreadyBoundException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import jp.ac.sfc.keio.sfc.tailor.rmi.test.remote.MoneyRemoteImpl; public class RegistryMain { /** * rmiregistryが何をしているか知るプログラム */ public static void main(String[] args) { MoneyRemoteImpl money; try { money = new MoneyRemoteImpl(); money.increment(); Registry reg = LocateRegistry.createRegistry(1099); reg.bind("MoneyServer", money); } catch (RemoteException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } catch (AlreadyBoundException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } }
万能rmiサーバを作成する。 public interface Compute extends Remote { Object executeTask(Task t) throws RemoteException; }
Task import java.io.Serializable; public interface Task extends Serializable { Object execute(); }
TaskMillis public class TaskMillis implements Task { public Object execute() { //executeはObjectを返しますので、プリミティブ・タイプのlongではなく、そのラッパーのLongが返り値 return new Long(System.currentTimeMillis()); } }
ComputeEngine publicclass ComputeEngine extends UnicastRemoteObject implements Compute { publicComputeEngine() throws RemoteException { super(); } public Object executeTask(Task t) { returnt.execute(); } publicstaticvoid main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { String name = "rmi://localhost/Compute"; Compute engine = new ComputeEngine(); Naming.rebind(name, engine); System.out.println("ComputeEngine bound"); } catch (Exception e) { System.err.println("ComputeEngine exception: " + e.getMessage()); e.printStackTrace(); } } }
ComputeClientMillis public class ComputeClientMillis { static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { String name = "rmi://localhost/Compute"; Compute comp = (Compute) Naming.lookup(name); // ここからは、処理に応じて変わる。これは、サーバ時計を表示する例。 Long millis = (Long) (comp.executeTask(new TaskMillis())); System.out.println("Remote Date : " + new Date(millis.longValue())); System.out.println("Local Date : " + new Date()); } catch (Exception e) { System.err.println("ComputePi exception: " + e.getMessage()); e.printStackTrace(); } } }
実行コマンド • rmic -v1.2 jp.ac.sfc.keio.sfc.tailor.rmi.compute.ComputeEngine • jar cvf 2rmiCompute.jar jp\ac\sfc\keio\sfc\tailor\rmi\compute\ • start rmiregistry • java -Djava.rmi.server.codebase=http://www.ht.sfc.keio.ac.jp/~tailor/rg/2rmiCompute.jar -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.compute.ComputeEngine • java -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.compute.ComputeClientMillis
ComputeClientPrime ublic class ComputeClientPrime { public static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { String name = "rmi://localhost/Compute"; Compute comp = (Compute) Naming.lookup(name); TaskPrime taskprime =new TaskPrime(); //taskprime.setPrimenum("69143"); taskprime.setPrimenum(args[0]); // ここからは、処理に応じて変わる。これは、サーバ時計を表示する例。 Boolean ansprime = (Boolean) (comp.executeTask(taskprime)); System.out.println("prime : " + ansprime.booleanValue()); } catch (Exception e) { System.err.println("ComputePi exception: " + e.getMessage()); e.printStackTrace(); } } }
TaskPrime package jp.ac.sfc.keio.sfc.tailor.rmi.compute; import java.math.BigInteger; publicclass TaskPrime implements Task { String primenum="69127"; public Object execute() { returnnew Boolean(getPrime(primenum)); } privateboolean getPrime(String prime) { BigInteger n = new BigInteger(prime); if (n.compareTo(BigInteger.ZERO) <= 0) { System.out.println("自然数を入力して下さい"); System.exit(1); } System.out.println("入力された数は " + n.toString()); if (n.compareTo(BigInteger.ONE) == 0) { System.out.println("素数ではありません"); returnfalse; } elseif (n.compareTo(BigInteger.valueOf(2)) == 0) { System.out.println("素数です"); returnfalse; } BigInteger r = n.mod(BigInteger.valueOf(2)); if (r.compareTo(BigInteger.ZERO) == 0) { System.out.println("除算可能な数は 2"); System.out.println("素数ではありません"); returnfalse; } BigInteger s = this.bigIntegerSqrt(n); for (BigInteger d = BigInteger.valueOf(3); d.compareTo(s) <= 0; d = d.add(BigInteger.valueOf(2))) { r = n.mod(d); if (r.compareTo(BigInteger.ZERO) == 0) { System.out.println("除算可能な数は " + d.toString()); System.out.println("素数ではありません"); returnfalse; } } System.out.println("素数です"); returntrue; } publicstatic BigInteger bigIntegerSqrt(BigInteger x){ BigInteger b1 = new BigInteger(x.toString()), b2 = (b1.pow(2).add(x)).shiftRight(1).divide(b1); while(b2.compareTo(b1) < 0){ b1 = new BigInteger(b2.toString()); b2 = (b1.pow(2).add(x)).shiftRight(1).divide(b1); } return b1; } public String getPrimenum() { return primenum; } publicvoid setPrimenum(String primenum) { this.primenum = primenum; } }
素数計算をさせる • java -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.compute.ComputeClientPrime 69143 • java -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.compute.ComputeClientPrime 69149 • java -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.compute.ComputeClientPrime 69151 • java -Djava.security.policy=securitypolicy.txt jp.ac.sfc.keio.sfc.tailor.rmi.compute.ComputeClientPrime 69157