PROGRAMACION DISTRIBUIDA Ejemplo de uso de estrategias de diseño con RMI Héctor Pérez 2 RCSD: José M. Drake y Héctor Pérez 20/05/2015 Ejemplo de callback: SwiftEagle shot() Target setDirection() nearnessReport(target,observer) ¿signal? Is near explode() SwiftEagle (Server) Missile (remote) ObserverTarget (Server) signal() shot(initPos,password) getPosition():Position setDirection(direction) nearnessReport(target,observer) explode() turnOff() Observer (remote) MissileControler (Client) 3 RCSD: José M. Drake y Héctor Pérez 20/05/2015 Dos estrategias de que el Server transmita información al cliente Polling (Estrategia client/Server estricta) :SwiftEagle :MissileController Callback (Estrategia client/Server no estricta) :SwiftEagle :MissileController getPosition() Create and register in RMI :TargetObserver nearnessReport(position, observer); isInTarget()->false getPosition() isInTarget()->false getPosition() asClosedTotarget=true observer.signal() isInTarget()->true 4 RCSD: José M. Drake y Héctor Pérez Organización del código 20/05/2015 5 RCSD: José M. Drake y Héctor Pérez 20/05/2015 Especificación de la aplicación distribuida SwiftEagle (1/3) 6 RCSD: José M. Drake y Héctor Pérez Especificación de la aplicación distribuida SwiftEagle (2/3) TargetObserver 20/05/2015 7 RCSD: José M. Drake y Héctor Pérez 20/05/2015 Especificación de la aplicación distribuida SwiftEagle (3/3) TargetObserver 8 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 Ejecución Cliente Servidor SwitfEagle 17 RCSD: José M. Drake y Héctor Pérez 20/05/2015 SwiftEagle: Variaciones (1/2) ! ¿Cómo minimizar los cambios en el código de negocio? 18 RCSD: José M. Drake y Héctor Pérez 20/05/2015 SwiftEagle: Uso del patrón proxy clase modificada clase nueva 19 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez SwiftEagle: Carga dinámica de clases (3/6) 20/05/2015 25 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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 RCSD: José M. Drake y Héctor Pérez 20/05/2015 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