PROGRAMACION DISTRIBUIDA Ejemplo de uso de estrategias de diseño con RMI Héctor Pérez 2 Ejemplo de callback: SwiftEagle shot() setdirection() Target nearnessreport(target,observer) signal? explode() SwiftEagle (Server) Is near Missile (remote) shot(initpos,password) getposition():position setdirection(direction) nearnessreport(target,observer) explode() turnoff() Observer (remote) ObserverTarget (Server) signal() MissileControler (Client)
3 Dos estrategias de que el Server transmita información al cliente Polling (Estrategia client/server estricta) Callback (Estrategia client/server no estricta) :MissileController :SwiftEagle :MissileController :SwiftEagle isintarget()->false getposition() getposition() Create and register in RMI :TargetObserver nearnessreport(position, observer); isintarget()->false getposition() asclosedtotarget=true observer.signal() isintarget()->true 4 Organización del código
5 Especificación de la aplicación distribuida SwiftEagle (1/3) 6 Especificación de la aplicación distribuida SwiftEagle (2/3) TargetObserver
7 Especificación de la aplicación distribuida SwiftEagle (3/3) TargetObserver 8 Organización del código en paquetes grant{ permission java.security.allpermission; grant{ permission java.security.allpermission; permission java.net.socketpermission "*:1024-","accept, resolve";
9 Tipos de datos comunes public class Direction implements Serializable{ private static final long serialversionuid = 333; public double ux=0; public double uy=0; public double uz=0; public Direction(double ux,double uy,double uz){ double mod=math.sqrt(math. pow(ux, 2)+ Math. pow(uy, 2)+ Math. pow(uz, 2)); if (mod!=0){this.ux=ux/mod;this.uy=uy/mod;this.uz=uz/mod; public class Position implements Serializable { private static final long serialversionuid = 444; public double x, y, z; public Position(double x,double y,double z){ t his.x=x; this.y=y; this.z=z; public class UnknownException extends Exception { private static final long serialversionuid = 1 1 1 ; public class UnreadyException extends Exception { private static final long serialversionuid = 222; 10 Interfaces remotas definidas import java.rmi.remote; import java.rmi.remoteexception; public interface Observer extends Remote { void signal() throws RemoteException; import java.rmi.*; public interface Missile extends Remote { void shot(position initpos, long password) throws UnreadyException, RemoteException; Position getposition() throws RemoteException; void setdirection(direction dir) throws RemoteException; void nearnessreport (Position pos, Observer observer) throws RemoteException; void explode(long password) throws UnknownException,RemoteException; void turnoff() throws RemoteException; Parámetros que se pasan por referencia remota
11 Cliente: Objeto remoto TargetObserver import java.rmi.remote; import java.rmi.remoteexception; public interface Observer extends Remote { void signal() throws RemoteException; import java.rmi.remoteexception; import java.rmi.server.unicastremoteobject; public class TargetObserver extends UnicastRemoteObject implements Observer { public TargetObserver() throws RemoteException { super(); public void signal() throws RemoteException { MissileController.asCloseToTarget = true; 12 Cliente: Clase principal MissileController public class MissileController { public static boolean asclosetotarget=false; public static void main(string[] args) { String missilename=args[0]; try { Observer observer=(observer) new TargetObserver(); // Nuestro objeto de callback long thepassword=(long)(long.max_value*math.random()); Registry registry = LocateRegistry.getRegistry(); Missile themissile = (Missile) registry.lookup(missilename); themissile.shot(new Position(0,0,0), thepassword); //*** Comienza el control del missil ***// themissile.setdirection(new Direction(1,1,10)); themissile.nearnessreport(new Position(0,0,1000), observer);//pasamos objeto de callback al server while(!asclosetotarget){ código necesario? Thread.sleep(500); Position pos=themissile.getposition(); System.out.println("current position: "+pos.x+" "+pos.y+" "+pos.z); try{ themissile.explode( thepassword); catch(unknownexception u) { System.out.println("Eres un intruso y no exploto"); themissile.turnoff(); try { UnicastRemoteObject.unexportObject(observer, false); catch (NoSuchObjectException e) {... catch (Exception e) { System.err.println("Excepción del cliente: " + e.tostring());
13 Servidor: Clase servidora SwiftEagle (1/3) public class SwiftEagle extends Thread implements Missile {. public void shot(position initpos, long password) throws UnreadyException {... public Position getposition() throws RemoteException {... public void setdirection(direction dir)throws RemoteException {... public void explode(long password)throws UnknownException, RemoteException{... public void turnoff() throws RemoteException{... Observer observer; public void nearnessreport(position target, Observer observer) throws RemoteException { this.target=target; this.observer=observer; Objeto de callback public void run(){ observer.signal();... 14 Servidor: Clase servidora SwiftEagle (2/3) public class SwiftEagle extends Thread implements Missile {... public void run() { while (!interrupted()) { try {sleep(update_period); catch (InterruptedException e){break; pos.x+=vel*dir.ux*update_period/1000.0; // Actualizamos pos.y y pos.z también... if (target!=null) { double currenttargetdist=math.sqrt(...); if (currenttargetdist>targetdist){ target=null; targetdist=double.max_value; callback try { observer.signal(); catch (RemoteException e) { else {targetdist=currenttargetdist; try {UnicastRemoteObject.unexportObject(this, false); catch (NoSuchObjectException e) { // Close run
15 Servidor: Clase servidora SwiftEagle (3/3) public class SwiftEagle extends Thread implements Missile { /. public static void main (String[] args) { String missilename= null; if (args.length >=1) missilename = args[0]; SwiftEagle eagle=new SwiftEagle(); try{ Remote rmtref= UnicastRemoteObject.exportObject(eagle,0); Registry theregistry=locateregistry.createregistry(1099); theregistry.rebind(args[0], rmtref); catch (RemoteException e) { System.err.println("Error en Servidor SwiftEagle " +args[0]); System.exit(-1); System.out.println("Servidor SwiftEagle " +args[0]+ " READY"); // Close main // Close SwftAegle 16 Ejecución Cliente Servidor SwitfEagle
17 SwiftEagle: Variaciones (1/2) Cómo minimizar los cambios en el código de negocio? 18 SwiftEagle: Uso del patrón proxy clase modificada clase nueva
19 Cliente: Nueva clase proxy SwiftEagle public class SwiftEagle { Registry registry = null; String missilename = Misil7831 ; Missile themissile = null; // Constructor del proxy public SwiftEagle(){ try { registry = LocateRegistry.getRegistry(); // Localiza el Registry en el puerto 1099 this.themissile = (Missile) registry.lookup(missilename); // Localiza el misil catch (RemoteException e) {... catch (NotBoundException e) {... Invocación remota public void setdirection(direction dir) { try { themissile.setdirection(dir); catch (RemoteException e) {... public Position getposition() throws RemoteException {...... 20 Cliente: Clase principal MissileController modificada public class MissileController { public static boolean asclosetotarget=false; public static void main(string[] args) { try { Observer observer=(observer) new TargetObserver(); // Nuestro objeto de callback long thepassword=(long)(long.max_value*math.random()); // *** Se genera el proxy ***// SwiftEagle themissile = new SwiftEagle (); Código nuevo themissile.shot(new Position(0,0,0), thepassword); //*** Comienza el control del missil ***// themissile.setdirection(new Direction(1,1,10)); themissile.nearnessreport(new Position(0,0,1000), observer);//pasamos objeto de callback al server while(!asclosetotarget){ Thread.sleep(500); Position pos=themissile.getposition(); System.out.println("current position: "+pos.x+" "+pos.y+" "+pos.z); try{ themissile.explode( thepassword); catch(unknownexception u) { System.out.println("Eres un intruso y no exploto"); themissile.turnoff(); try { UnicastRemoteObject.unexportObject(observer, false); catch (NoSuchObjectException e) {... catch (Exception e) { System.err.println("Excepción del cliente: " + e.tostring());
21 SwiftEagle: Variaciones (2/2) Cómo minimizar los cambios en el código de negocio? Cómo implementar la carga dinámica de clases? 22 SwiftEagle: Carga dinámica de clases (1/6) grant{ permission java.security.allpermission; grant{ permission java.security.allpermission; permission java.net.socketpermission "*:1024-","accept, resolve";
23 SwiftEagle: Carga dinámica de clases (2/6) public class SwiftEagle extends Thread implements Missile { /. public static void main (String[] args) { String missilename= null; if (args.length >=1) missilename = args[0]; SwiftEagle eagle=new SwiftEagle(); try{ Remote rmtref= UnicastRemoteObject.exportObject(eagle,0); Registry theregistry=locateregistry.getregistry(); theregistry.rebind(args[0], rmtref); catch (RemoteException e) { System.err.println("Error en Servidor SwiftEagle " +args[0]); System.exit(-1); System.out.println("Servidor SwiftEagle " +args[0]+ " READY"); // Close main // Close SwftAegle 24 SwiftEagle: Carga dinámica de clases (3/6)
25 SwiftEagle: Carga dinámica de clases (4/6) Dado que el registro no tiene acceso a las clases del proyecto, debemos indicarle dónde puede descargarlas (http, file, ftp, etc) 26 SwiftEagle: Carga dinámica de clases (5/6) Por defecto, el rmiregistry sólo permite cargar las clases que están en su CLASSPATH
27 SwiftEagle: Carga dinámica de clases (6/6) Para habilitar la carga dinámica de stubs, debemos modificar la propiedad UseCodebaseOnly del rmiregistry si es TRUE, la carga de clases sólo se realiza desde el CLASSPATH y desde el java.rmi.server.codebase de la JVM del rmiregistry