Paradigmas en Computación Distribuida Un Modelo de Componentes Distribuidos Por Yudith Cardinale y Mariela Curiel Sep – Dic 2002 Objetos distribuidos (Distributed object computing). Todas las ventajas de la programación orientada por objetos. Desarrollo basado en componentes (Component-based development). Industrialización del desarrollo de software. Modelos de Programación para Aplicaciones Distribuidas Software Orientado a Componentes Llamadas a procedimientos remoto Invocación a un método remoto (RMI) Modelo de programación basado en eventos (Java Beans) Software Orientado a Componentes Software Orientado a Componentes Los componentes son elementos autocontenidos de software que pueden controlarse en forma dinámica y ensamblarse para construir aplicaciones. Funcionan de acuerdo a un conjunto de reglas y especificaciones. Proveen cierta funcionalidad que puede ser reutilizada en diferentes lugares. Representa la industrialización del desarrollo de software. En la industria electrónica como en otras industrias se está acostumbrado a utilizar componentes para construir placas, tarjetas, etc. En el campo del software la idea es la misma. Se puede crear un interfaz de usuario en un programa en base a componentes: paneles, botones, menús, etc. Con la utilización de componentes se gana en calidad y rapidez de desarrollo. Los java beans (oct. 1996) constituyen la arquitectura de componentes de Java (independiente de la plataforma) y su uso ha probado ser de incalculable valor en el desarrollo de network-aware applications. Otros componentes: VBX (Visual Basic Extension), ActiveX (Microsoft), OpenDoc (Apple-IBM y otros) (No son portables) 1 ¿Qué es JavaBeans? ¿Qué es JavaBeans? Un JavaBean o bean es un componente de software que se puede reutilizar y que puede ser manipulado a través de un programa o de una herramienta de programación visual. Para ello, se define un interfaz que permite a la herramienta de programación o IDE (Integrated Development Environment), interrogar al componente y conocer las propiedades que define y los tipos de sucesos (events) que puede generar en respuesta a diversas acciones. ¾ Hace ¿Qué es JavaBeans? ¿Qué es JavaBeans? ¾ Si se tiene una aplicación que usa varios beans, los mismos pueden distribuirse en múltiples máquinas y servidores. ¾ Dirigido a personas diestras en el negocio, pero no necesariamente buenos en la programación. posible escribir componentes WORA (write once run anywhere) en Java. ¾ Ideal para desarrollar soluciones para ambientes con Sistemas de Operación y hardware heterogéneos (Java). ¾ Los beans deben residir dentro de un Container. ¾ El container provee el ambiente necesario para diseñar y crear aplicaciones basadas en beans. Ofrece las facilidades de comunicación con otros beans. ¾ Los JavaBeans pueden ser ellos mismos containers de otros beans. Objetivos de JavaBeans Objetivos de JavaBeans ¾ Portables: ¾ Compatibles escritos en Java sin ningún código nativo. ¾ Livianos: componentes pequeños para ensamblarlos en otros más grandes. ¾ Simples: facilidad de implementación y manipulación de Beans sin o con herramientas de desarrollo. con otros modelos de componentes: posibilidad de usar Javabeans como una clase de ActiveX, OpenDoc y otros modelos de componentes. ¾ Con capacidad de comunicación: para acceder datos remotos vía RMI, JavaIDL, http, etc. 2 Características Básicas Propiedades: es un atributo público del JavaBean que afecta a su apariencia o a su conducta. Eventos: es el mecanismo utilizado por un componente para enviar notificaciones a otros componentes. Personalización: El programador puede alterar la apariencia y la conducta del bean a tiempo de diseño y de ejecución. Esto es necesario si se quiere que el bean sea re-utilizado. Características Básicas Propiedades ¾ Una propiedad es un atributo del JavaBean que afecta a su apariencia o a su conducta. Por ejemplo, un botón puede tener las siguientes propiedades: el tamaño, la posición, el título, el color de fondo, el color del texto, si está o no habilitado, etc. Persistencia: Se puede guardar y restaurar el estado de los beans. Se utiliza la serialización de objetos de JAVA para dar soporte a la persistencia. El que desarrolla el bean decide cuáles propiedades son persistentes y cuáles transitorias. Introspección: Permite a la herramienta de programación o IDE analizar cómo trabaja el bean (exposición de propiedades y métodos) Propiedades Las especificaciones JavaBeans definen un conjunto de convenciones (design patterns) que el IDE usa para inferir qué métodos corresponden a propiedades. public void setNombrePropiedad(TipoPropiedad valor) public TipoPropiedad getNombrePropiedad( ) Propiedades Propiedades Simples: representa un único valor. Propiedades Propiedades indexadas: tienen asociado más de un valor (arreglos, vectores) private int[] numeros={1,2,3,4}; //miembro de la clase que se usa para guardar el valor de la propiedad private String nombre; //métodos set y get de la propiedad denominada Nombre public void setNombre(String nuevoNombre){ nombre=nuevoNombre; } public String getNombre(){ return nombre; } //métodos set y get de la propiedad denominada Numeros, para el array completo public void setNumeros(int[] nuevoValor){ numeros=nuevoValor; } public int[] getNumeros(){ return numeros; } //métodos get y set para un elemento de array public void setNumeros(int indice, int nuevoValor){ numeros[indice]=nuevoValor; } public int getNumeros(int indice){ return numeros[indice]; } 3 Propiedades Propiedades ligadas (bound): Los objetos de una clase que tiene una propiedad ligada notifican a otros objetos (listeners) interesados, cuando el valor de dicha propiedad cambia, permitiendo a estos objetos realizar alguna acción. Property Owner Property 1 Changed Propiedades Propiedades restringidas (constrained): similares a una propiedad ligada salvo que los objetos (listeners) a los que se les notifica el cambio del valor de la propiedad tienen la opción de vetar cualquier el cambio. Property 2 Changed propertyChange() Method Property Owner setProperty() vetoableChange() Property n Changed throw PropertyVetoException If change is rejected throw PropertyVetoException If change is rejected VetoableChangeListeners propertyChangeListener Eventos son mensajes que se envían de un objeto a otro, notificando al receptor que algo interesante ha ocurrido. ¾ El componente que envía el mensaje es el que dispara (fire) el evento. ¾ El receptor es llamado listener y es quien maneja (handle) el evento. ¾ Muchos objetos pueden estar esperando un determinado evento. Eventos ¾ Eventos: Eventos import java.util.*; public class SalarioEvent extends EventObject { protected int anteSueldo, nuevoSueldo; public SalarioEvent(Object fuente, int anterior, int nuevo) { super(fuente); nuevoSueldo=nuevo; anteSueldo=anterior; } public int getNuevoSueldo(){ return nuevoSueldo;} public int getAnteSueldo(){ return anteSueldo;} } Register Event Listener Event Source Event Object Fire Event Event Listener • El generador del evento envía la notificación de su ocurrencia mediante la invocación de un método en el listener. Se usan métodos estándar de Java; no se agregaron instrucciones especiales al lenguaje. • Cuando se llama al método se pasa un objeto como parámetro que contiene información sobre el evento ocurrido. Eventos import java.beans.*; import java.util.*; // Clase Asalariado public class Asalariado{ private Vector salarioListeners=new Vector(); private int sueldo; public Asalariado() { sueldo=20; } public void setSueldo(int nuevoSueldo){ int anteSueldo=sueldo; sueldo=nuevoSueldo; if(anteSueldo!=nuevoSueldo){ SalarioEvent event=new SalarioEvent(this, anteSueldo, nuevoSueldo); notificarCambio(event); } } 4 import java.util.*; public int getSalario(){ return sueldo; } public synchronized void addSalarioListener(SalarioListener listener) { salarioListeners.addElement(listener); } public synchronized void removeSalarioListener(SalarioListener listener){ salarioListeners.removeElement(listener); } private void notificarCambio(SalarioEvent event){ Vector lista; synchronized(this){ lista=(Vector)salarioListeners.clone(); } for(int i=0; i<lista.size(); i++){ SalarioListener listener=(SalarioListener)lista.elementAt(i); listener.enteradoCambioSueldo(event); }}} public interface SalarioListener extends EventListener { public void enteradoCambioSueldo(EventObject e); } // Listener public class Hacienda implements SalarioListener{ public Hacienda() { } public void enteradoCambioSueldo(EventObject ev){ SalarioEvent event=(SalarioEvent)ev; System.out.println("Hacienda: nuevo sueldo "+event.getNuevoSueldo()); System.out.println("Hacienda: sueldo anterior "+event.getAnteSueldo()); } } Personalización Hacienda funcionario1 = new Hacienda(); Asalariado empleado = new Asalariado(); Funcionario1 debe realizar: empleado.addSalarioListener(funcionario1); Persistencia ¾ ¾ ¾ Capacidad para salvar y recuperar estados de los Beans junto con los valores personalizados Es necesario que los Beans implementen la interfaz Serializable Las propiedades que no se requiere que sean serializables deben marcarse como transient El grado de reuso de un componente depende, a menudo, de cuán fácilmente se puede adaptar a los requerimientos de diferentes aplicaciones. ¾ En general, debe ser posible ¨personalizar¨ un bean a través de una herramienta visual o directamente en el código. ¾ Cada bean provee su propia clase ¨customizer¨. Ésta permite al diseñador/usuario personalizar el Bean visualmente. ¾ Descubrir las Propiedades de un Bean ¾ Proceso por el cual una herramienta de desarrollo es capaz de descubrir las propiedades, métodos y eventos asociados a un Bean ¾ Se puede realizar de dos formas: A través del mecanismo de reflexión de Java Realizando queries al BeanInfo de una clase (Introspección). 5 import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName(args[0]); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString()); } catch (Throwable e) { System.err.println(e); } } } Descubrir las Propiedades de un Bean ¾ Introspección: es un mecanismo para proveer información sobre el Bean explícitamente. Esto se logra creando una clase que existe específicamente para describir el bean [Developing JAVA For an invocation of: java DumpMethods java.util.Stack the output is: public java.lang.Object java.util.Stack.push(java.lang.Object) public synchronized java.lang.Object java.util.Stack.pop() public synchronized java.lang.Object java.util.Stack.peek() public boolean java.util.Stack.empty() public synchronized int java.util.Stack.search(java.lang.Object) Patrones de Diseño ¾ Patrones de nombres estándares para las propiedades y los eventos de un bean Beans. RobertEnglander. O’Really, 1997] Patrones de Diseño Los métodos que recuperan o asignan valores a los atributos deben comenzar con la palabra “get”/”set” en minúsculas seguido del nombre de la propiedad con la primera letra en mayúscula. Se denominan métodos asesores. public X getPropertyName() public void setPropertyName(X x) Patrones de Diseño public X[] getPropertyName() public void setPropertyName (X[] x) public X getPropertyName(int i) public void setPropertyName (int i, X x) Corresponden a los métodos asesores de una propiedad indexada. Sin el correspondiente método “set”, indica una propiedad readonly public X getPropertyName() 6 Patrones de Diseño Propiedades “Bound”: Se deben implementar dos mecanismos: 1. 2. Si el valor de la propiedad cambia, se genera el evento PropertyChangeEvent a todos los listeners registrados. El evento puede ocurrir cuando el método set es invocado. Para permitir que los listeners se registren, el Bean tiene que implementar los siguientes métodos: Patrones de Diseño Propiedades “Constrained”: Para construir propiedades vetables, un bean debe definir los siguientes métodos: public void addVetableChangeListener (VetableChangeListener l) public void removeVetableChangeListener (VetableChangeListener l) private void VetableChangeSupport() Si el cambio es vetado, el listener indica su desaprobación con PropertyVetoException public void addPropertyChangeListener (PropertyChangeListener l) public void removePropertyChangeListener (PropertyChangeListener l) Introspección: Clase BeanInfo Patrones de Diseño Manejo de eventos • Los nombres de los eventos deben seguir el formato EventNameEvent (ejemplo TimerEvent) • La interfaz del listener debe seguir el formato EventNameListener (ejemplo TimerListener) • El Bean debe implementar los métodos: public void addEventNameListener (EventNameListener e) public void removeEventNameListener (EventNameListener e) Introspección: Clase BeanInfo ¾ El nombre de la clase BeanInfo asociada a un Bean debe seguir el modelo: Class NameBeanBeanInfo implements SimpleBeanInfo ¾ Mecanismo flexible y poderoso para almacenar información sobre los Beans. ¾ La idea es implementar una interfaz llamada BeanInfo que va a ser interrogada por el constructor de Beans Introspección: Clase BeanInfo ¾ Es necesario crear métodos que retornen los descriptores de las características: Event SetDescriptor[ ] getEventSetDescriptors() Method Descriptor[ ] getMethodDescriptors() Property Descriptor[ ] getPropertyDescriptors() 7 Qué clases de Java pueden ser Beans? ¿Más de un tipo de aplicación puede usarla?¿Otros se benefician al usarla? ¿Existen diferentes formas de personalizarla? ¿Es fácil explicar su propósito? ¿Contiene toda la información necesaria para manejarla?, ¿Posee buen encapsulado? Qué clases de Java pueden ser Beans? Un bean es una clase que obedece a ciertas reglas: Debe tener un constructor por defecto (sin argumentos). Debe tener persistencia, es decir, implementar la interfaz Serializable Debe poseer instrospección. 8