RMI = Remote Method Invocation Meg tudjuk hívni olyan objektumok metódusait is, amelyek más virtuális gépben futnak Kommunikáció különböző gépeken futó Java programok között Kliens-szerver alkalmazások Elosztott alkalmazások Alternatíva: CORBA Nem csak Java programok/objektumok között © Kozsik Tamás 2000-2006
Kliens-szerver forgatókönyv A szerver program elérhetővé tesz objektumokat bejegyzi őket egy registry-be a távoli objektumok várják, hogy a kliensek meghívják a metódusaikat A kliensek szereznek egy referenciát egy ilyen objektumra aztán hívogatják a távoli objektumok metódusait A részleteket az RMI rendszer elintézi... © Kozsik Tamás 2000-2006
Elosztott objektumok rendszere forgatókönyv Különböző számítógépeken futó különböző virtuális gépekben elhelyezkedő objektumokat bejegyzünk Megkeresik egymást és kommunikálnak egymással hívogatják egymás metódusait Egymás megkeresése: pl. registry-n keresztül A részleteket az RMI rendszer elintézi... © Kozsik Tamás 2000-2006
Tevékenységek Távoli objektumok megkeresése rájuk referencia beszerzése rmiregistry-n keresztül metódushívások paramétereként/eredményeként Kommunikáció a távoli objektummal sima metódushívások a programozó számára a részleteket az RMI elfedi Osztálydefiníciós fájlok továbbítása egymásnak átadott objektumok osztályának betöltése egy másik, távoli virtuális gépből © Kozsik Tamás 2000-2006
© Kozsik Tamás 2000-2006
Dinamikus osztálybetöltés Amikor a távoli objektumok egymás metódusait hívják... … paramétereket adnak át és visszatérési értékeket kapnak Nem biztos, hogy egy virtuális gép ismeri annak az objektumnak az osztályát, amit így kap Az RMI letölti az osztálydefiníciót is © Kozsik Tamás 2000-2006
Távoli objektumok Amelyeknek meg lehet hívni metódusait az RMI segítségével más virtuális gépekből A java.rmi.Remote interfészt megvalósítják Megvalósítanak egy távoli interfészt (a Remote egy kiterjesztését), amiben fel vannak sorolva a távolról elérhető metódusaik © Kozsik Tamás 2000-2006
Távoli metódus Kiterjesztjük a java.rmi.Remote interfészt Ez lesz a „távoli interfész” Ebben vannak definiálva a távolról meghívható metódusok csak ezek hívhatók távolról Ezek a metódusok specifikálják, hogy kiválthatják a java.rmi.RemoteException kivételt © Kozsik Tamás 2000-2006
Mi is történik? A kliens egy „távoli referenciával” rendelkezik a távoli objektumra A kliens virtuális gépben egy proxy objektum van, ami úgy csinál, mintha ő lenne a távoli objektum továbbítja a metódushívásokat a távoli objektumnak Ezt a proxy objektumot stub-nak nevezik © Kozsik Tamás 2000-2006
Stub - csonk: klienscsonk A távoli objektum reprezentánsa a klien virtuális gépekben Amikor távoli objektumra referenciát szerzünk a registry-ből, akkor egy ilyen jön létre Amikor távoli objektumokat paraméterként vagy visszatérési értékként átadunk, akkor ilyen adódik át helyette Ugyanazokat a távoli interfészeket valósítja meg, mint amit a távoli objektum Még cast-olni is lehet © Kozsik Tamás 2000-2006
Mit is kell akkor tennünk? Az elosztott objektumrendszer komponenseinek megtervezése és megvalósítása Fordítás, és utána a csonkok legenerálása A fájlok kitevése a hálóra Futtatás © Kozsik Tamás 2000-2006
Az elosztott objektumrendszer komponenseinek megtervezése és megvalósítása (4/1) El kell dönteni, hogy a rendszerben mely komponensek lesznek távolról elérhetők, és melyek lesznek lokálisak © Kozsik Tamás 2000-2006
Az elosztott objektumrendszer komponenseinek megtervezése és megvalósítása (4/2) A távoli interfészek definiálása a távolról elérhető szolgáltatások definiálása A távoli metódusok paramétereiben és visszatérési értékeiben használt típusok (osztályok és interfészek) megírása © Kozsik Tamás 2000-2006
Az elosztott objektumrendszer komponenseinek megtervezése és megvalósítása (4/3) A távoli osztályok elkészítése implementálják a távoli interfészeket megvalósítják a távolról igénybevehető szolgáltatásokat A metódusok paramétereiben és visszatérési értékeiben használt típusok (osztályok és interfészek) megírása © Kozsik Tamás 2000-2006
Az elosztott objektumrendszer komponenseinek megtervezése és megvalósítása (4/4) Kliensek megvalósítása ráér akkor is, ha a távoli objektumok már üzembe vannak helyezve... © Kozsik Tamás 2000-2006
Fordítás, és utána a csonkok legenerálása Forrásfájlok lefordítása javac A .class fájlokból a csonkok legenerálása rmic többek között ez is része a Development Kit-nek © Kozsik Tamás 2000-2006
A fájlok kitevése a hálóra Minden .class fájlt, amit a kliensek használni szeretnének majd, elérhetővé tesszük egy WEB-szerveren keresztül a távoli interfészek a klienscsonkok a segédosztályok és segédinterfészek (paraméterek, visszatérési értékek típusa...) © Kozsik Tamás 2000-2006
Futtatás Az rmiregistry program ez is része a Development Kit-nek A távoli objektumokat bejegyző programok pl. a szerverek A használó programok kliensek © Kozsik Tamás 2000-2006
Hogyan is kell akkor ilyet írni? Készítsünk el egy távoli objektumot, ami tud összegezni egész számokat! Definiáljuk a szolgáltatást: Adder interfész Megvalósítjuk a távoli objektumot: RemoteAdder osztály Írunk egy kliens programot, ami használja © Kozsik Tamás 2000-2006
Adder interfész Terjesszük ki a java.rmi.Remote interfészt Írjuk bele a szolgáltatást, ami most két metódus add: hozzád egy számot az eddigi összeghez get: lekérdezi az eddigi összeget Gondoskodjunk arról, hogy a metódusok deklarálják a throws klózukban a java.rmi.RemoteException kivételt mellette egyebeket is deklarálhatnának... © Kozsik Tamás 2000-2006
Adder.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Adder extends Remote { void add( int a ) throws RemoteException; int get() throws RemoteException; } © Kozsik Tamás 2000-2006
RemoteAdder osztály Meg kell valósítson egy távoli interfészt, most pl. az Adder interfészt Kiterjesztjük a java.rmi.server.UnicastRemoteObject osztályt Írnunk kell konstruktort is Gondoskodni kell arról, hogy beregisztráljuk az osztály egy példányát egy registry-be pl. írhatunk egy main metódust is benne, ami ezt megteszi... © Kozsik Tamás 2000-2006
RemoteAdder.java (2/1) public class RemoteAdder extends import java.rmi.server.UnicastRemoteObject implements Adder { int sum = 0; public RemoteAdder() throws java.rmi.RemoteException {} public void add( int a ){ sum += a; } public int get(){ return sum; } } © Kozsik Tamás 2000-2006
RemoteAdder.java (2/2) public static void main( String args[] ) throws java.rmi.RemoteException, java.net.MalformedURLException { Adder adder = new RemoteAdder(); String name = "rmi://localhost:8000/Adder"; java.rmi.Naming.rebind(name,adder); } © Kozsik Tamás 2000-2006
Távoli interfész megvalósítása Implementáljuk az interfészben specifikált metódusokat A throws klózban már nem kell feltüntetni a java.rmi.RemoteException kivételt persze, ha akarjuk, kiválthatjuk, és akkor fel kell tüntetni Konstruktort is kell írni, ami viszont kiválthatja ezt a kivételt, tehát nem lehet a default konstruktorra támaszkodni. © Kozsik Tamás 2000-2006
UnicastRemoteObject Érdemes ebből származtatni a távoli objektumok osztályát Kényelmi osztály toString, equals, hashCode “exportálás”, leszármazásnál automatikus Pont-pont (unicast, és nem broadcast) kommunikáció Alapértelmezett socket-os megvalósítása az RMI-nek © Kozsik Tamás 2000-2006
Ha nem leszármazott... Meg kell valósítani az RMI specifikációban adott szemantikával az Object-beli műveleteket Explicit exportálni kell a távoli objektumot hogy az RMI rendszer tudomást szerezzen róla UnicastRemoteObject.exportObject(…) © Kozsik Tamás 2000-2006
A beregisztrálás módja Megfelelő biztonsági felügyelő (security manager) installálása A távoli objektum osztályának példányosítása Bejegyzés pl. rmiregistry-be vagy más szolgáltatóba, pl. JNDI © Kozsik Tamás 2000-2006
Bejegyzés Ahhoz, hogy egy kliens szerezni tudjon egy referenciát élete első távoli objektumára A többire már tud referenciát szerezni ettől Predefinit távoli objektum: RMI registry Név alapján lehet tőle távoli objektumokra referenciát kérni Szolgáltatás elindítása: rmiregistry API hozzá: java.rmi.Naming © Kozsik Tamás 2000-2006
registry rmi://számítógép:port/név Ha nem adunk meg számítógépet, akkor az aktuális számítógép Ha nem adunk meg portot, akkor 1099 Ha bejegyeztünk egy távoli objektumot, akkor már van egy referencia rá, ezért nem lehet őt felszabadítani szemétgyűjtéssel, ezért a main végetérése után nem áll le a prg. © Kozsik Tamás 2000-2006
A kliens Biztonsági felügyelő beállítása Távoli referencia beszerzése Távoli metódusok hívása © Kozsik Tamás 2000-2006
Client.java import java.rmi.*; class Client { public static void main(String[] args) throws Exception { System.setSecurityManager( new RMISecurityManager() ); String name = "rmi://localhost:8000/Adder"; Adder adder = (Adder) Naming.lookup(name); for( int i = 0; i<args.length; i++ ) adder.add(Integer.parseInt(args[i])); System.out.println("Az összeg: "+adder.get()); } © Kozsik Tamás 2000-2006
System.get/setSecurityManager() Biztonsági felügyelő Védi a virtuális gépet és az azt futtató rendszert a letöltött kódtól (pl. lokális fájlrendszer elérése) Kötelező definiálni, ha azt akarjuk, hogy dinamikus osztályletöltés menjen paraméterek, visszatérési értékek, kivételek típusára java.rmi.RMISecurityManager Olyasmi, mint ami az appletek esetén is van Lehet mást is beállítani, vagy jogokat adni egy policy fájllal System.get/setSecurityManager() © Kozsik Tamás 2000-2006
Elhelyezés egy gépen belül kliens Adder.class Client.class policy szerver RemoteAdder.class RemoteAdder_Stub.class © Kozsik Tamás 2000-2006
policy Egy nagyon engedékeny (és ezért nagyon veszélyes) megoldás: grant { permission java.security.AllPermission; }; © Kozsik Tamás 2000-2006
policy Egy nem annyira engedékeny megoldás: grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept"; }; © Kozsik Tamás 2000-2006
Futtatás (Windows) rmiregistry (pl. rmiregistry 8000) szerver indítása java -Djava.rmi.server.codebase= file:/c:\adder\szerver/ RemoteAdder kliens indítása java -Djava.rmi.server.hostname=localhost -Djava.security.policy=policy Client ... © Kozsik Tamás 2000-2006
Elhelyezés HTTP-szerveren A csonk (RemoteAdder_Stub.class) letölthető helyen, pl: http://localhost:8080/adder/ A szerveroldali fájlok egy szerver gépen: Adder.class, RemoteAdder.class, RemoteAdder_Stub.class A kliensoldali fájlok egy kliens gépen: Adder.class, Client.class, policy © Kozsik Tamás 2000-2006
Futtatás rmiregistry szerver indítása (ugyanazon a gépen) java -Djava.rmi.server.codebase= http://localhost:8080/adder/ RemoteAdder kliens indítása java -Djava.rmi.server.hostname=localhost -Djava.security.policy=policy Client ... © Kozsik Tamás 2000-2006
Archívum fájl használata A kliensoldali fájlokat összecsomagoljuk client.jar Esetleg a szerveroldaliakat is... Futtatáskor: -classpath © Kozsik Tamás 2000-2006
Bonyolultabb példa Olyan távoli objektumot fogunk írni, ami valamilyen feladatot old meg. Az, hogy mi a feladat, ismeretlen akkor, amikor a távoli objektumot elkészítjük. Annyit tudunk csak, hogy leírható egy bizonyos interfésszel. A dinamikus osztálybetöltés gondoskodik a többiről… © Kozsik Tamás 2000-2006
Az RMI megvalósítása JRMP RMI over IIOP v1.1 (Skel és Stub) v1.2 (csak Stub) RMI over IIOP © Kozsik Tamás 2000-2006
nem referencia szerint, hanem érték szerint Paraméterátadás Szerializációval A szintaxis hasonlít a lokális metódushívásra, de: nem referencia szerint, hanem érték szerint © Kozsik Tamás 2000-2006
RMI és appletek Egy jó felhasználási területe az RMI-nek a visszahívásos technika egy megvalósítása Az applet (ami egy távoli objektum) beregisztrálja magát egy szervernél (ami szintén egy távoli objektum) A szerver visszahívja az appletet, ha történt valami... © Kozsik Tamás 2000-2006
(un)marshalling Az RMI kommunikáció során a metódushívást elkódolja a rendszer metódus, paraméterek, visszatérési érték Az információkból az egyik fél szerializáció segítségével adatfolyamot állít elő A partner az adatfolyamból visszanyeri az információkat © Kozsik Tamás 2000-2006
LocateRegistry.createRegistry() Ha programból indítanánk az rmiregistry-t java.rmi.registry.LocateRegistry osztály public static void main( String[] args ) throws Exception { LocateRegistry.createRegistry(1099); Remote r = new RemoteAdder(); Naming.rebind("rmi://localhost/Adder",r); } © Kozsik Tamás 2000-2006
Szemétgyűjtés Sokkal nehezebb feladat az elosztott szemétgyűjtés, mint az egy virtuális gépen belüli Az RMI-ben megvalósítottak egy ilyet A használt hálózati objektumok segítik ezt a szemétgyűjtő mechanizmust © Kozsik Tamás 2000-2006
Aktiválás Ha olyan szerver kell, amelyet a rendszer automatikusan tud aktiválni, amikor erre szükség van java.rmi.activation Származtassunk le az Activatable osztályból a UnicastRemoteObject helyett Példa: to be done... © Kozsik Tamás 2000-2006