3.3 Aspectos básicos del ORB y el POA Pseudo-IDL n Problema: especificación del interfaz del ORB en el documento de especificación CORBA n n n n ¿ En qué lenguaje está especificado ? En Pseudo-IDL (PIDL) Similar a IDL Diferencias n n Los interfaces especificados son locales (el API del ORB) El mapping de PIDL al lenguaje de implementación puede desviarse del mapping de IDL (y normalmente se desvía) Interfaz básica del ORB en PIDL (1) module CORBA { // PIDL typedef string ORBid; typedef sequence<string> arg_list; interface ORB; // forward declaration ORB ORB_init(inout arg_list argv, in ORBid orb_identifier); // ... interface ORB { typedef string Objectid; exception InvalidName {}; void run(); void shutdown(in boolean wait_for_completion); void destroy(); Object resolve_initial_references(in Objectid identifier) raises(InvalidName); string object_to_string(in Object obj); Object string_to_object(in string str); // ... } }; Interfaz básica del ORB en PIDL (2) n CORBA::ORB_init n n n CORBA::ORB::run n n n Se queda en un bucle atendiendo peticiones a objetos remotos Se debe llamar desde el thread main CORBA:ORB::destroy n n Método factoría Devuelve una instancia de un ORB en función de los parámetros pasados (iremos viendo algunos valores poco a poco) Destruye el ORB (liberando recursos) CORBA::ORB::resolve_initial_references n n Permite obtener referencias iniciales a determinados objetos Identificadores: RootPOA (POA raíz), NameService (contexto raíz del servicio de nombres), etc. Interfaz básica del ORB en PIDL (y 3) n CORBA::ORB::object_to_string n n n CORBA::ORB::string_to_object n n Permite obtener una referencia a un objeto CORBA como una cadena de caracteres Es legal aplicar esta operación sobre una referencia nil Permite obtener una referencia a un objeto CORBA a partir de su correspondiente representación como cadena de caracteres Un mismo ORB puede devolver distintas cadenas de caracteres en sucesivas invocaciones de object_to_string sobre una misma referencia n n Por tanto, el valor devuelto no puede utilizarse para realizar ningún tipo de comparaciones ¡ Las referencias son opacas ! Interfaz básica del ORB en Java package org.omg.CORBA; public abstract class ORB { public static ORB init(String[] args, java.util.Properties properties) { ... } public static ORB init() { ... } public void run() { ... } public void shutdown(boolean wait_for_completion) { ... } public void destroy() { ... } public abstract org.omg.CORBA.Object resolve_initial_references(String object_name) throws org.omg.CORBA.ORBPackage.InvalidName { ... } public abstract String object_to_string( org.omg.CORBA.Object obj); public abstract org.omg.CORBA.Object string_to_object( String str); public abstract Any create_any(); // .. } Inicialización del ORB (1) n n n init(String[], Properties) es un método estático factoría para crear una instancia de la clase concreta que deriva de la clase abstracta org.omg.CORBA.ORB, en función de parámetros y propiedades Existe una variante de este método para applets (se estudia más adelante) J2SE version 1.2 y superiores incorporan un ORB de CORBA (poco completo) n n El mecanismo anterior permite “enchufar” cualquier ORB de CORBA en J2SE La versión 1.2 no define algunos métodos en org.omg.CORBA.ORB (ej.: destroy) Aplicación CORBA org::omg::CORBA::ORB com::acme::CORBA::ORB Inicialización del ORB (2) n Los parámetros y propiedades se localizan en el siguiente orden n n n n Parámetro argumentos (puede pasarse null) Parámetro propiedades (puede pasarse null) Propiedades del sistema Fichero orb.properties n n ubicado en <java-home>/lib, donde <java-home> es el valor de la propiedad del sistema java.home La variante init() devuelve una instancia singleton n Sólo se usa en casos muy concretos (ej.: factoría de Typecodes) Inicialización del ORB (y 3) n Propiedades estandarizadas Nombre n Significado omg.ORB.CORBA.ORBClass Nombre de la clase concreta que utiliza init(String[], Properties) omg.ORB.CORBA.ORBSingletonClass Nombre de la clase concreta que utiliza init() Ejemplo de invocación java –Dorg.omg.CORBA.ORBClass=com.acme.CORBA.ORB \ -Dorg.omg.CORBA.ORBSingletonClass=\ com.acme.CORBA.ORBSingleton \ es.udc.fbellas.corba.clock.server.Server n Ejemplo de inicialización org.omg.CORBA.ORB orb = ORB.init(args, null); Terminación limpia de servidores n Tanto cliente como servidor deberían llamar a CORBA::ORB::destroy antes de terminar n n Permite liberar recursos CORBA::ORB::shutdown permite terminar el bucle CORBA::ORB::run n n n n wait_for_completion==false => retorna inmediatamente e inicia el proceso de terminación wait_for_completion==true => espera a que todas las peticiones actuales terminen Permite que el servidor ejecute código de finalizacion y llame a CORBA::ORB::destroy ¿ Cómo llamarlo ? n n n Desde una opción del entorno de usuario Una operación especial de un interfaz remoto (con parámetro a false) => gestión de aplicaciones CORBA::ORB::destroy no retorna hasta que todas las peticiones pendientes terminen ConsoleServerORBLoopTerminator (1) package es.udc.fbellas.corba.util.server; import import import import java.io.IOException; java.io.InputStreamReader; java.io.BufferedReader; org.omg.CORBA.ORB; public class ConsoleServerORBLoopTerminator extends Thread { private final static String END_STRING = "stop"; private ORB orb; public ConsoleServerORBLoopTerminator(ORB orb) { this.orb = orb; /* * Mark this thread as daemon. It needs to be daemon because * when the main thread finishes (maybe finished by the * Implementation Repository Console), the Java Virtual Machine * should finish. */ setDaemon(true); } ConsoleServerORBLoopTerminator (y 2) public void run() { System.out.println("Type '" + END_STRING + "' and then <intro> to stop server"); try { /* Read until END_STRING be typed. */ String typedString; do { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); typedString = bufferedReader.readLine(); } while (!typedString.equals(END_STRING)); /* Shutdown ORB. */ orb.shutdown(false); } catch (IOException e) { e.printStackTrace(); } } // run } // class En el main del servidor ... try { ... /* Install ORB loop terminator. */ System.out.println("Server running"); ConsoleServerORBLoopTerminator terminator = new ConsoleServerORBLoopTerminator(orb); terminator.start(); /* Allow the ORB to start processing requests. */ orb.run(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (orb != null) { orb.destroy(); } } catch (org.omg.CORBA.SystemException e) { e.printStackTrace(); } } El pseudo interfaz Object en PIDL (1) module CORBA { interface Object { boolean is_nil(); boolean is_a(in string repository_id); boolean is_equivalent(in Object other_object); // .. }; // ... }; El pseudo interfaz Object en PIDL (2) n CORBA::Object::is_nil n n CORBA::Object::is_a n n Permite comprobar si la referencia es nil Permite comprobar si la referencia es de un tipo determinado (a partir del correspondiente identificador de repositorio) CORBA::Object::is_equivalent n n n Permite comparar dos referencias a objetos remotos true => son iguales, y por tanto, apuntan al mismo objeto remoto false => no son iguales, y por tanto, no sabemos si se refieren al mismo objeto remoto El pseudo interfaz Object en PIDL (y 3) n CORBA::Object::is_equivalent (cont) n Se ha implementado así por razones de eficiencia n n n n n La comparación se hace localmente sobre las IORs Existen campos con formato propietario en la IOR (no necesitan estandarización para interoperabilidad) Si se intentan comparar dos referencias (a un mismo objeto remoto) creadas por otro ORB, el resultado seguramente será false Incluso la comparación de referencias en un ORB creadas por él no tiene porque ser fiable Conclusión: no permite comparar igualdad de objetos Igualdad de objetos n Problema: ¿ cómo comprobar si dos referencias a objetos apuntan al mismo objeto remoto ? n n n CORBA::Object::is_equivalent no sirve Aplicar CORBA::ORB::object_to_string sobre ambas y comparar tampoco sirve Una solución interface Comparable { typdef long ObjectIdentifier; ObjectIdentifier getIdentifier(); }; n n Este interfaz lo heredan todos los interfaces para los que se necesite comparar igualdad de objetos Cada invocación a getIdentifier es una invocación remota El pseudo interfaz Object en Java (1) package org.omg.CORBA; public interface Object { boolean _is_a(String identifier); boolean _is_equivalent(Object that); // .. } El pseudo interfaz Object en Java (2) n CORBA::Object::is_nil no se traduce en ninguna operación n Dado que las referencias nil se mapean a Java como null, basta if (objectReference == null) { // ... } n CORBA::Object::is_a Thermometer thermometer = controller.findByLocation(“Room01”); if (thermometer._is_a(“IDL:TCS/Thermostat:1.0”)) { Thermostat thermostat = ThermostatHelper.narrow(thermometer); // Aplicar operaciones específicas a los termostatos // .. } El pseudo interfaz Object en Java (y 3) n Otra alternativa más frecuente a _is_a Thermometer thermometer = controller.findByLocation(“Room01”); try { Thermostast thermostat = ThermostatHelper.narrow(thermometer); // Aplicar operaciones específicas a los termostatos // ... } catch (org.omg.CORBA.BAD_PARAM e) { // Era un termómetro. } n _is_a está pensado para aplicaciones que usan el DII y no disponen de las clases Helper necesarias en tiempo de compilación POAs y POAManager (1) Aplicación servidora servants POA Petición ORB POAManager POA POAManager Otros POAManagers ... POAManager ... POA Otros POAs POAs y POAManager (2) n API // PIDL module PortableServer { interface POA { ... } interface POAManager { ... } }; // Java package org.omg.CORBA.PortableServer; public interface POA { ... } public interface POAManager { ... } n Una aplicación servidora puede contener múltiples instancias del POA, de manera que pueda soportar objetos con distintas características o formas de implementación de servants n Cada instancia tiene asociada un conjunto de políticas (ej.: multithreading) POAs y POAManager (3) n Todas las aplicaciones disponen al menos del “Root POA” org.omg.CORBA.Object rootPOAObject = orb.resolve_initial_references("RootPOA"); POA rootPOA = POAHelper.narrow(rootPOAObject); n Cada POA tiene asociado un POAManager (que puede encargarse de varios POAs) n n Actúa como una “válvula” que permite regular el flujo de peticiones que le llegan a los objetos de los POAs que gestiona Puede estar en distintos estados n n n En espera, activo, descartando o inactivo Dispone de operaciones para transitar entre estados Para que pueda entregar peticiones a sus POAs tiene que estar en estado “activo” POAs y POAManager (y 4) n Ejemplo de activación del POAManager POAManager rootPOAManager = rootPOA.the_POAManager(); rootPOAManager.activate(); n La operación _this(ORB) de un servant n n n n n Crea un objeto CORBA (si no estaba creado) Lo registra en el Root POA (si no estaba registrado) Crea una referencia para el objeto (si no estaba creada) Retorna la referencia Ejemplo de _this(ORB) ClockImpl clockImpl = new ClockImpl(); Clock clock = clockImpl._this(orb); Implementación de interfaces n n Los interfaces remotos se implementan haciendo uso de clases skeleton generadas por el compilador de IDL Una clase skeleton es una implementación del patrón Adapter n n Al igual que en el patrón estándar Adapter, existen dos posibles enfoques n n n Adapta la interfaz de la clase servant a la invocación de mensajes recibidos por el ORB Basado en herencia Basado en delegación Transparente al cliente Enfoque basado en herencia (1) <<interface>> Generada por el org::omg::CORBA::portable::InvokeHandler compilador de IDL + _invoke(method : String, is : InputStream, handler : ResponseHandler) : OutputStream <<interface>> es::udc::fbellas::corba::clock::idl:ClockOperations org::omg::PortableServer::Servant + getTimeOfDay() : TimeOfDay es::udc::fbellas::corba::clock::idl::ClockPOA Generada por el compilador de IDL + invoke(request : org::omg::CORBA::ServerRequest) + _this(orb : org::omg::CORBA::ORB) : es::udc::fbellas::corbajava::clock::idl::Clock es::udc::fbellas::corba::clock:: Proporcionada por server::ClockImpl el programador + getTimeOfDay() : TimeOfDay Enfoque basado en herencia (y 2) Resto aplicación cliente getTimeOfDay <<interface>> Clock POA invoke <<interface>> InvokeHandler POAManager ClockPOA getTimeOfDay Clase Proxy Cliente ORB ClockImpl Servidor Enfoque basado en delegación (1) Generada por el <<interface>> compilador de IDL org::omg::CORBA::portable::InvokeHandler + invoke(method : String, is : InputStream, handler : ResponseHandler) : OutputStream <<Interface>> es::udc::fbellas::corba::clock::i dl:ClockOperations org::omg::PortableServer::Servant + getTimeOfDay() : TimeOfDay es::udc::fbellas::corba::clock::idl::ClockPOA Generada por el compilador de IDL + invoke(request : org::omg::CORBA::ServerRequest) + _this(orb : org::omg::CORBA::ORB) : es::udc::fbellas::corbajava::clock::idl::Clock es::udc::fbellas::corba::clock::idl::ClockPOATie - _delegate : ClockOperations <<Interface>> - _poa : POA Generada por el <<use>> compilador de IDL es::udc::fbellas::corba::clock::idl:ClockOperations + ClockPOATie(delegate : ClockOperations) + ClockPOATie(delegate : ClockOperations, poa : POA) + getTimeOfDay() : TimeOfDay + getTimeOfDay() : TimeOfDay public TimeOfDay getTimeOfDay() { return _delegate.getTimeOfDay(); es::udc::fbellas::corba::clock:: servertie::ClockImpl } + getTimeOfDay() : TimeOfDay Proporcionada por el programador Enfoque basado en delegación (2) package es.udc.fbellas.corba.clock.servertie; import java.util.Calendar; import es.udc.fbellas.corba.clock.idl.TimeOfDay; import es.udc.fbellas.corba.clock.idl.ClockOperations; class ClockImpl implements ClockOperations { public TimeOfDay getTimeOfDay() { short hour = (short) Calendar.getInstance().get(Calendar.HOUR); short minute = (short) Calendar.getInstance().get(Calendar.MINUTE); short second = (short) Calendar.getInstance().get(Calendar.SECOND); return new TimeOfDay(hour, minute, second); } } Enfoque basado en delegación (3) n Creación del servant y registro en el Root POA ClockImpl clockImpl = new ClockImpl(); ClockPOATie clockPOATie = new ClockPOATie(clockImpl); Clock clock = clockPOATie._this(orb); Enfoque basado en delegación (4) Resto aplicación cliente getTimeOfDay <<interface>> Clock invoke POA <<interface>> InvokeHandler POAManager ClockPOA getTimeOfDay Clase Proxy ORB ClockPOATie <<interface>> ClockOperations getTimeOfDay ClockImpl Cliente Servidor Enfoque basado en delegación (y 5) n El enfoque basado en delegación permite que la clase que implementa el interfaz remoto extienda (herencia de implementación) de otra n n Puede facilitar la implementación de herencia (la simple) En general, ambos enfoques son igual de potentes Herencia simple n IDL <<interface>> Thermometer getTemperature() : Temperature getLocation() : Location <<interface>> Themostat setTemperature(t : Temperature) : void Implementación de la herencia simple (1) n Enfoque 1 (asumiendo que todo el código está en el mismo sevidor) <<interface>> ThermometerOperations <<interface>> ThermostatOperations ThermometerPOA ThermometerImpl ThermostatPOA 1 ThermostatImpl t: ThermometerImpl public int getTemperature() { return t.getTemperature(); } Implementación de la herencia simple (y 2) n Enfoque 2 (asumiendo que todo el código está en el mismo sevidor) <<interface>> ThermometerOperations ThermometerImpl ThermostatImpl 1 <<interface>> ThermostatOperations ThermometerPOATie 1 ThermostatPOATie Herencia múltiple n IDL <<interface>> LandVehicle <<interface>> WaterVehicle <<interface>> AmphibiousVehicle Implementación de la herencia múltiple (1) n Enfoque 1 (asumiendo que todo el código está en el mismo sevidor) <<interface>> LandVehicleOperations <<interface>> WaterVehicleOperations <<interface>> AmphibiousVehicleOperations LandVehiclePOA WaterVehiclePOA AmphibiousVehiclePOA LandVehicleImpl 1 AmphibiousVehicleImpl l: LandVehicleImpl w : WaterVehicleImpl 1 WaterVehicleImpl Implementación de la herencia múltiple (y 2) n Enfoque 2 (asumiendo que todo el código está en el mismo sevidor) LandVehiclePOATie AmphibiousVehiclePOATie WaterVehiclePOATie 1 1 <<interface>> LandVehicleOperations <<interface>> WaterVehicleOperations 1 <<interface>> AmphibiousVehicleOperations LandVehicleImpl 1 AmphibiousVehicleImpl l: LandVehicleImpl w : WaterVehicleImpl 1 WaterVehicleImpl