Sistemas de Operación 3 Enterprise JavaBeans Los EJBs proporcionan un modelo de componentes distribuido estándar del lado del servidor. El objetivo de los EJBs es dotar al programador de un modelo que le permita abstraerse de los problemas generales de una aplicación empresarial (concurrencia, transacciones, persistencia, seguridad, ...) para centrarse en el desarrollo de la lógica de negocio en sí. El hecho de estar basado en componentes permite que éstos sean flexibles y sobre todo reutilizables. No hay que confundir los Enterprise JavaBeans con los JavaBeans. Los JavaBeans también son un modelo de componentes creado por Sun Microsystems para la construcción de aplicaciones, pero no pueden utilizarse en entornos de objetos distribuidos al no soportar nativamente la invocación remota (RMI). Enterprise JavaBeans Enterprise JavaBeans Enterprise JavaBeans Los EJBs se disponen en un contenedor EJB dentro del servidor de aplicaciones. La especificación describe cómo el EJB interactúa con su contenedor y cómo el código cliente interactúa con la combinación del EJB y el contenedor. Dado que se trata simplemente de interfaces Java y no de clases concretas, el contenedor EJB genera clases para esas interfaces que actuarán como un proxy en el cliente. El cliente invoca un método en los proxies generados que a su vez sitúa los argumentos del método en un mensaje y envía dicho mensaje al servidor EJB. Los proxies usan RMI-IIOP para comunicarse con el servidor EJB (RMI-IIOP denota la interface RMI de Java sobre el sistema CORBA). El servidor llamará a un método correspondiente a una instancia de la clase de implementación Java para manejar la llamada del método remoto. Enterprise JavaBeans Cada EJB debe facilitar dos interfaces y una clase de implementación Java: Interfaz "Home” La interfaz "home" permite al código cliente manipular ciertos métodos de clase del EJB, esto es, métodos que no están asociados a ninguna instancia particular. Por ejemplo: creación, borrado y búsqueda... Interfaz remota La interfaz remota especifica los métodos de instancia públicos encargados de realizar las operaciones. Clase de implementación EJB Las clases de implementación EJB las suministran los desarrolladores de aplicaciones, que facilitan la lógica de negocio ("business logic") o mantienen los datos ("business data") de la interfaz de objeto, esto es, implementan todos los métodos especificados por la interfaz remota y, posiblemente, algunos de los especificados por la interfaz "home". Enterprise JavaBeans Existen tres tipos de Entreprise Java Beans: EJBs de Entidad (Entity EJBs): Su objetivo es encapsular los objetos del lado del servidor que almacena los datos. Los EJBs de entidad presentan la característica fundamental de la persistencia: Persistencia gestionada por el contenedor (CMP): el contenedor se encarga de almacenar y recuperar los datos del objeto de entidad mediante el mapeo de una tabla de la base de datos. Persistencia gestionada por el bean (BMP): el propio objeto entidad se encarga, mediante una base de datos u otro mecanismo, de almacenar y recuperar los datos a los que se refiere, por lo cual, la responsabilidad de implementar los mecanismos de persistencia es del programador. Enterprise JavaBeans Enterprise JavaBeans EJBs de Sesión (Session EJBs): Gestionan el flujo de la información en el servidor. Generalmente sirven a los clientes como una fachada de los servicios proporcionados por otros componentes disponibles en el servidor. Puede haber dos tipos: con estado (stateful). Los beans de sesión con estado son objetos distribuidos que poseen un estado. El estado no es persistente, pero el acceso al bean se limita a un solo cliente. sin estado (stateless). Los beans de sesión sin estado son objetos distribuidos que carecen de estado asociado permitiendo por tanto que se los acceda concurrentemente. No se garantiza que los contenidos de las variables de instancia se conserven entre llamadas al método. Enterprise JavaBeans Enterprise JavaBeans EJBs dirigidos por mensajes (Message-driven EJBs): Son los únicos beans con funcionamiento asíncrono. Usando el Java Messaging System (JMS), se suscriben a un tema (topic) o a una cola (queue) y se activan al recibir un mensaje dirigido a dicho tema o cola. No requieren de su instanciación por parte del cliente. Enterprise JavaBeans Un EJB a través de un "EJB Container" ofrece varios servicios y funcionalidades, algunas son las siguientes: Servicios ("Middleware") Esta posiblemente sea la mayor ventaja de un EJB. Cuando se diseña un componente de Software se deben definir varios servicios para su funcionamiento, algunos pueden ser: ▪ Si ocurre un error que procedimiento debe ejecutarse ? ▪ Si la base de datos especificada se encuentra desactivada, existe otra alternativa ? ▪ No fue posible cumplir exitosamente "x" procedimiento, se deben retractar sus acciones parciales o reinvocar la transacción ? Estos Servicios (comúnmente llamados "Middleware") por lo general son requeridos además de la lógica contenida en los componentes principales, obviamente estos servicios ("Middleware") aún deben ser diseñados, sin embargo, mediante un "EJB Container" se ofrecen algunos de estos. Enterprise JavaBeans División de Trabajo La posibilidad de dividir "Servicios"(EJB Container) de "Componentes Principales"(EJB'S) permite una clara división de trabajo, esto es, un diseñador de "componentes"(EJB's) puede concentrar sus esfuerzos en la "lógica de proceso" sin preocuparse del diseño de servicios. Y de la misma manera un "diseñador" de servicios("Middleware") concentrarse en su área. Esta división de trabajo trae consigo otra pregunta: Como se logra la interoperabilidad ? La interoperabilidad entre "Servicios" y "Componentes" se debe a la existencia de especificaciones para EJB's, estas especificaciones (parte primordial de J2EE ) definen los requerimientos para un "EJB Container" y los requisitos para un "Enterprise Java Bean". Procedimientos Remotos ( RMI ) Debido a la solución que intenta ofrecer "Enterprise Java Beans" su diseño gira alrededor de procedimientos remotos. Enterprise JavaBeans Diversos Vendedores El uso de especificaciones para EJB's permite que existan diversos vendedores tanto de "EJB Containers" los cuales son incluidos en un java application server, así como "Enterprise Java Bean's" los cuales resuelven algún tipo de lógica. Lo anterior permite ejecutar cualquier "EJB" en cualquier "EJB Container", esto es, puede adquirir un conjunto de EJB's producidos por Inprise o inclusive desarrollarlos dentro de su empresa y estos podrán ser ejecutados en un "EJB Container" de IBM, Inprise o JBoss. En lo que se refiere a diferencias en costo y calidad, generalmente estas dependen de las funcionalidades que van más allá de las especificaciones EJB. El "EJB Container" de IBM ofrece una integración más eficiente con sus productos (Domino, DB2), mientras Inprise puede desarrollar su "EJB Container" orientado hacia ambientes financieros, Oracle hacia manufactura y sus productos en "Bases de Datos", etc. Diversos Clientes Un EJB puede interactuar con una gran gamma de clientes desde: JSP o Servlets , bases de datos , Applets , sistemas ERP (SAP, JDEdward's). Enterprise JavaBeans Asimismo, algunas de las desventajas son las siguientes: Tiempo de Desarrollo El desarrollar un Sistema con EJB's es sumamente complejo, aunque para ciertas empresas puede presentar una solución ideal, debido a la complejidad-tiempo de (traduciéndose en costo) para muchas corporaciones EJB's resultan una solución sobrada, denominada en Ingles: "overkill". Conocimiento exhausto de Java EJB's es uno de los principales componentes de J2EE y por esta razón también depende fuertemente de otras partes de J2EE: Como RMI , JNDI y JDBC. Enterprise JavaBeans HolaMundoRemote.java package com.saludo; import java.rmi.RemoteException; import javax.ejb.EJBObject; public interface HolaMundoRemote extends EJBObject{ public String saludo(String nombre) throws RemoteException; } HolaMundoHome.java package com.saludo; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome; public interface HolaMundoHome extends EJBHome{ HolaMundoRemote create() throws RemoteException, CreateException; } Enterprise JavaBeans HolaMundoRemote.java package com.saludo; import java.rmi.RemoteException; import javax.ejb.EJBException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; public class HolaMundoBean implements SessionBean{ private static final long serialVersionUID ; // Nuestro método "de negocio" public String saludo(String nombre){ System.out.println("Un cliente me ha invocado"); return "Hola, " + nombre; } // Métodos del ciclo de vida del Bean (obligatorios) public void ejbCreate(){} public void ejbActivate() throws EJBException, RemoteException {} public void ejbPassivate() throws EJBException, RemoteException {} public void ejbRemove() throws EJBException, RemoteException {} public void setSessionContext(SessionContext arg0) throws EJBException, RemoteException {} } jar cfv holamundo.jar com/saludo/* META-INF/ejb-jar.xml Enterprise JavaBeans ejb-jar.xml <?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtd/ejb-jar_2_0.dtd"> <ejb-jar> <description>Ejemplo de EJB Simple</description> <enterprise-beans> <session> <display-name>Bean HolaMundo</display-name> <ejb-name>HolaMundo</ejb-name> <home>com.saludo.HolaMundoHome</home> <remote>com.saludo.HolaMundoRemote</remote> <ejb-class>com.saludo.HolaMundoBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Bean</transaction-type> </session> </enterprise-beans> </ejb-jar> Para instalar la aplicación: jar cfv holamundo.jar com/saludo/* META-INF/ejb-jar.xml Ello conlleva generar un fichero java comprimido (.jar) que colocaremos en otro directorio concreto del servidor de aplicaciones. Enterprise JavaBeans HolaMundoRemote.java import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.rmi.PortableRemoteObject; import com.saludo.HolaMundoHome; import com.saludo.HolaMundoRemote; public class BeanCliente { public static void main(String[] args) { // Preparación de propiedades para construir el contexto inicial de JNDI Properties prop = new Properties(); prop.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory"); prop.put(Context.PROVIDER_URL, "localhost:1099"); try{ InitialContext jndiContext = new InitialContext(prop); // obtener el contexto inicial antes preparado System.out.println(" >> Obtenido un contexto JNDI"); Object ref = jndiContext.lookup("HolaMundo"); // Obtener una referencia al Bean System.out.println(" >> Obtenida una referencia al Bean \"HolaMundo\""); HolaMundoHome home = (HolaMundoHome) // Obtener una referencia a la interfaz Home PortableRemoteObject.narrow(ref, HolaMundoHome.class); HolaMundoRemote h = home.create(); // Creación de la interfaz remota a partir del Home: System.out.println("Invocando el EJB: " + h.saludo("Pedro")); // Invocamos finalmente al Bean }catch(Exception ex){ System.out.println(ex.toString()); } } } Enterprise JavaBeans Resultado de ejecución: >> Obtenido un contexto JNDI >> Obtenida una referencia al Bean "HolaMundo" Invocando el EJB: Hola, Pedro