EJBs (aspectos avanzados) Mario Muñoz Organero Departamento de Ingeniería Telemática http://www.it.uc3m.es/mario Índice del tema Desarrollo de un cliente EJB Transacciones EJB Query Language Excepciones en EJBs Seguridad en EJBs Mario Muñoz Organero. Servidores de información 2 Desarrollando clientes EJB Tipos de clientes JDBC (over TCP/IP?) RMI/IIOP HTT P Web server (running servlets, JSPs) Acts as EJB client Home user Runs Internet Browser Mario Muñoz Organero. EJB server Database/legacy server RM I/ II OP Bank clerk, running a Java app (using Swing, etc.) that acts as an EJB client Servidores de información 4 ¿Quién puede actuar de cliente de los EJBs? Otros EJBs Servlets Aplicaciones Java Applets Java Se requiere el arranque de servicios como el JNDI, o un setup cuidadoso (classpath, versión de la JVM, etc.) Si se dan los permisos apropiados Clientes no Java Los EJBs son compatibles con CORBA Mario Muñoz Organero. Servidores de información 5 Comportamiento de un cliente Mario Muñoz Organero. Servidores de información 6 Código de ejemplo. Paso 1: JNDI Lookup // Obtener un contexto inicial: Hashtable properties = new Hashtable(); properties.put(INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory"); properties.put(PROVIDER_URL, "iiop://"); InitialContext iCtx = new InitialContext(properties); // o mediante la propiedad java.naming.factory.initial // Lookup, y hacer narrow al objecto: Object homeRef = iCtx.lookup("AccountHome"); //nombre JNDI AccountHome home = (AccountHome) PortableRemoteObject.narrow(homeRef, AccountHome.class); Mario Muñoz Organero. Servidores de información 7 Código de ejemplo. Paso 2: usando el interfaz Home // Usar la interfaz Home para crear nuevos EJBs: Account acc1 = home.create(“Mario", “UC3M"); // O usar los métodos finder para encontrar existentes: Account acc2 = home.findByPrimaryKey(12345); EJBs Collection fatAccounts = home.findClientsByMinimalBalance(100000); Mario Muñoz Organero. Servidores de información 8 Código de ejemplo. Paso 3: Usando la referencias EJB // Sencillamente invocar los métodos de negocio: acc1.setBalance(acc1.getBalance() - 100); acc2.setBalance(acc2.getBalance() + 97); // Commisión... for (Iterator i = facAccounts.iterator(); i.hasNext(); ) { Account fatAccount = (Account) i.next(); fatAccount.setMaxCredit(1000000); } Mario Muñoz Organero. Servidores de información 9 Recordar las “Exceptions”... Los finders pueden lanzar FinderException Los métodos create pueden lanzar CreateException Los métodos de negocio pueden lanzar excepciones particulares Cualquiera de los métodos puede lanzar RemoteException Hay que usar pues bloques try/catch Mario Muñoz Organero. Servidores de información 10 El patron de Home Factory El primer paso en los clientes de EJB es hacer un JNDI lookup Un patrón común: crear una home factory Uso: ClientHome = (ClientHome) HomeFactory.lookup("JNDI_Name", "ClientHome"); La clase factory proporciona un único método estatico -- lookup Hace un narrow de la búsqueda en el JNDI y devuelve un Object al que se le debe hacer un downcast El segundo parámetro es el nombre de la clase, usado para el narrowing Usando "class.forName(name)" Internamente, la factory contiene el objeto InitialContext Puede también proporcionar un API para obtenerlo Mario Muñoz Organero. Servidores de información 11 El patrón Session Facade Usado para minimizar: El acoplamiento entre clientes y Entity beans El riesgo de que los clientes hagan mal uso de los métodos de negocio Retardos en la red Los puntos de cambio si se modifica la lógica de negocio La idea: crear un Session EJB que proporciona los métodos de acceso para los clientes Los clientes solo interactúan con los session bean(s) Los Entity EJBs proporcionan (solo) un interfaz local Los Session EJB acceden a los entity EJBs localmente Mario Muñoz Organero. Servidores de información 12 Otras prácticas recomendadas Evitar llamar a los métodos de los EJB directamente desde los JSP La necesidad de capturar excepciones remotas complicaría el código JSP Usar wrappers (beans o etiquetas personalizadas) Evitar “poner a fuego” la “properties JNDI” Por ejemplo, guardar los valores de las propiedades del hashtable en un fichero Mario Muñoz Organero. Servidores de información Transacciones 13 ¿Qué son las transacciones? Una transacción es un conjunto de operaciones que cambia un conjunto de datos de forma atómica (consistencia). Conjunto de operaciones indivisible Agrupación de operaciones sencillas Si una de algo falla se deshace la transacción Éxito: Se hace un "commit" Fallo: se deshace con un "roll back" El efecto de la transacción que falla mantiene los datos invariantes. Una transacción exitosa es persistente Ejemplo: transferencia bancaria Mario Muñoz Organero. Servidores de información 15 Definiciones Objeto Transaccional : Un objecto que se usa (invocación de sus métodos) dentro de una transacción Solo se asocia con una transacción a la vez Los EJBs pueden ser objetos transaccionales Cliente Transaccional : Programa que invoca métodos en objetos transaccionales. Gestor de Transacciones: Programa que coordina la realización de la transacción Mario Muñoz Organero. Servidores de información 16 El Contexto de la Transacción Una sola transacción puede involucrar a múltiples objetos y operaciones. Un contexto de transacción representa la transacción compartida por los participantes Por defecto, se propaga automáticamente entre objetos transaccionales (EJBs). Mario Muñoz Organero. Servidores de información 17 Servidores de información 18 JTA: el API Java para Transacciones Mario Muñoz Organero. Delimitación de transacciones dentro de los EJBs Si se usa container-managed transaction demarcation (CMT) no hay que programar nada El contenedor de EJB gestiona las transacciones automáticamente Interacción con bases de datos Comienzo y fin de transacciones Creación y propagación del contexto de la transacción. Incluso con two-phase commit (2PC) El programador solo especifica el comportamiento transaccional de los métodos que desee No se programa – se edita el deployment descriptor (XML) Además se soporta: bean-managed transaction demarcation (BMT) y client-managed transaction demarcation. Mario Muñoz Organero. Servidores de información 19 Valores del atributo de transacciones Cuando se usa CMT, los beans (o mejor dicho, los métodos dentro de los beans) tienen un “transaction attribute” Tiene uno de estos 6 valores posibles: NotSupported Supports Required RequiresNew Mandatory Never Mario Muñoz Organero. Servidores de información 20 Valores : Supports y NotSupported Supports: Si el que invoca el método (cliente, u otro método) tiene un contexto de transacción, se propaga al bean Si no, no se usa un contexto de transacción Se usa esto para situaciones en las que “da igual” NotSupported: Si el que invoca el método tiene un contexto de transacción éste se suspende durante la invocación al método Si no, no se usa un contexto de transacción Mario Muñoz Organero. Servidores de información 21 Valores : Required y RequiresNew Required: Si el que invoca el método tiene un contexto de transacción se le propaga al bean Si no, el contenedor crea uno nuevo I.e., el método siempre se ejecuta en un contexto de transacción, pero no crea uno si ya existe uno. Este es el valor por defecto RequiresNew: En cualquier caso se crea un contexto de transacción nuevo para la invocación del método Se usa para meter el método en una transacción pero cuando no se quiere que el fallo del método tenga repercusiones fuera. Mario Muñoz Organero. Servidores de información 22 Valores : Mandatory y Never Mandatory: Si el que invoca el método tiene un contexto de transacción se le propaga al bean Si no, se lanza una excepción TransactionRequiredException TransactionRequiredLocalException o Se usa cuando se quiere que el invocador tenga un contexto de transacción Never: Si el que invoca el método tiene un contexto de transacción se lanza una excepción RemoteException o EJBException En otro caso el método se ejecuta sin transacción Se usa para recursos no transaccionales Mario Muñoz Organero. Servidores de información 23 Servidores de información 24 Ejemplo en el DD <ejb-jar> … <assembly-descriptor> <container-transaction> <method> <ejb-name>AccountExpl</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> <container-transaction> <method> <ejb-name>AccountImpl</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar> Mario Muñoz Organero. Abortando una Transacción Con CMT no se pueden crear transacciones pero si abortarlas. Si un método de negocio quiere abortar una transacción debe invocar setRollBackOnly en su objeto de contexto EJB Lo que normalmente se hace antes de enviar una excepción Se usa getRollBackOnly para ver si la transacción ha sido abortada Servidores de información Mario Muñoz Organero. 25 Transacciones “Bean-Managed” Solo disponibles para session y message-driven EJBs Un método de negocio puede usar JTA para crear un objeto UserTransaction y usarlo como su contexto de transacción (ejecutar getUserTransaction() del EJBContext) begin, commit, rollback, El bean que crea la transacción será el responsable de hacer el commit o el rollback Métodos de UserTransaction: setRollbackOnly En stateless session beans, el método que inicia la transacción debe acabarla Una instancia que inicia una transacción debe acabarla antes de comenzar otra. Mario Muñoz Organero. Servidores de información 26 La interfaz SessionSynchronization Los stateful session EJBs (solamente) si usan transacciones gestionadas por el contenedor pueden solicitar notificaciones de eventos de transacción Le permite al bean mantener una caché que podrá sincronizar con una base de datos Para ello el bean solo SessionSynchronization Hay 3 métodos en la interfaz: que implementar afterBegin beforeCompletion tiene Se puede abortar la transacción con setRollbackOnly en el contexto de la sesión afterCompleteion(boolean) El parametro indica commit (true) o rollback Mario Muñoz Organero. Servidores de información 27 Prácticas recomendadas con transacciones Se prefiere el control de transacciones por el contenedor Se prefiere usar Required, RequiresNew y Mandatory sobre las otras opciones Supports, NotSupported y Never no siempre se implementan Mario Muñoz Organero. Servidores de información 28 EJB Query Language Qué es EJB QL Un lenguaje de consultas usado con CMP Para los métodos “finder” Tecnicamente, un subconjunto modificado de SQL Más portable que SQL Soportado por todos los servidores J2EE Normalemente se compila a un lenguaje nativo del servidor de aplicaciones. Mario Muñoz Organero. Servidores de información 30 Una Query EJB QL EJB QL solo incorpora queries SELECT Cada query tiene 3 partes: SELECT FROM WHERE (opcional) La query puede tener parametros Los pasados al método “finder” Mario Muñoz Organero. Servidores de información 31 EJB QL: Ejemplo 1 SELECT DISTINCT Object(c) FROM Customer c Encuentra a todos los clientes Retorna una collection No retorna duplicados (por el DISTINCT) "Object" es requerido para las variables en la parte del SELECT "Customer c" declara la variable de identificación "c" de tipo "Customer" Mario Muñoz Organero. Servidores de información 32 EJB QL Ejemplo 2 SELECT DISTINCT Object(c) FROM Customer c, IN (c.accounts) a WHERE a.balance < 0.0 Retorna todos los clientes con al menos un descubierto en cuenta. "IN (c.accounts) a" sigue a la “container-managed relationship” accounts de los Customer "WHERE a.balance < 0.0" tiene la misma semántica que en SQL WHERE limitando los resultados devueltos Mario Muñoz Organero. Servidores de información 33 EJB QL Ejemplo 3 SELECT DISTINCT Object(c) FROM Customer c WHERE (c.address.country = ?1) AND (c.address.city = ?2) Esta query acepta 2 parámetros Aparecen como "?1" y "?2" en el código Se pueden usar para implementar un método finder con 2 argumentos Retorna los clientes de un determinado pais y ciudad Mario Muñoz Organero. Servidores de información 34 Ejemplo DD <entity> <description>Una descripción</description> <ejb-name>AccountImpl2</ejb-name> <home>eb.AccountHome</home> <remote>eb.Account</remote> <ejb-class>eb.AccountImpl2Bean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.Integer</prim-key-class> <reentrant>False</reentrant> <cmp-field> <field-name>accno</field-name> </cmp-field> <cmp-field> <field-name>customer</field-name> </cmp-field> <primkey-field>accno</primkey-field> <query> <query-method> <method-name>findByNumber</method-name> <method-params> <method-param>int</method-param> </method-params> </query-method> <ejb-ql>SELECT OBJECT(o) FROM accountsample o WHERE o.accno = ?1</ejb-ql> </query> </entity> Mario Muñoz Organero. Servidores de información 35 Métodos Select Son similares a los finders: En la clase del entity bean, deben empezar con "ejbSelect" En CMP entity beans, se definen abstractos Y se proporcionan las secuencias EJB QL en el deployment descriptor En BMP entity beans, se implementan manualmente Retornan interfaces de componente del bean o una collection Al contrario que los finders, los métodos select no se reflejan en la interfaz Home Son para el propio uso del bean Mario Muñoz Organero. Servidores de información 36 Excepciones en los EJBs Tipos de excepciones En J2SE hay 2 tipos de excepciones: Runtime exception Checked exceptions Para los EJBs se suele hacer otra distinción: Application Relacionadas con la lógica de negocio System exceptions exceptions Que representan problemas en la ejecución del sistema Mario Muñoz Organero. Servidores de información 38 Excepciones de aplicación Excepciones para reportar problemas en la ejecución de la lógica de negocio Es tarea del excepciones. e.g., public void withdraw(float amount) throws OverdraftException cliente recuperar o reportar esta “El cliente" aquí no significa la aplicación cliente sino cualquiera que haya realizado la invocación del método del EJB que lanza la excepción. La excepciones de aplicación tienen que ser subclases de Exception, pero no subclases de RuntimeException (i.e., deben ser “checked”) Mario Muñoz Organero. Servidores de información 39 Excepciones de aplicación (cont.) Si se lanza una excepción de aplicación, y no se captura en el servidor, se manda al cliente Como ocurre con RMI “regular”, el cliente sencillamente invoca el método y obtiene una excepción como resultado (de forma transparente). CreateException, FinderException y RemoveException son ejemplos de excepciones de aplicación. Mario Muñoz Organero. Servidores de información 40 Excepciones de sistema Usadas para reportar problemas a nivel de sistema Fallo al buscar el contexto JNDI Fallo al obtener una conexión a una base de datos Problemas de comunicación ... etc. Los clientes no capturan estas excepciones Si ocurre una excepción de sistema el bean debería: Si son “Runtime exceptions”: propagar la excepción al contenedor Todas las otras clases: envolverlas en una nueva EJBException y relanzarlas Mario Muñoz Organero. Servidores de información 41 El patrón "Generic Application Exception" Un patrón común sugiere definir una superclase para todas la excepciones de aplicación Todos los métodos de negocio deben ser declarados como "throws MyAppException" en la clase bean y en la interfaz de componente "MyAppException" o como se quiera Incluso si no van a lanzar excepciones De esta manera, los clientes tienen que meter la llamada a los métodos de negocio en un bloque try/catch Si los beans evolucionan y lanzan nuevas excepción el código de cliente ya está preparado con su bloque try/catch Aunque se añadirá la parte necesaria para tratar la nueva excepción En la práctica, hace que las excepciones de aplicación se traten como excepciones en tiempo de ejecución. Mario Muñoz Organero. Servidores de información 42 Seguridad en EJBs Objetivos de seguridad La portabilidad no se debe ver afectada Transparencia, Aislamiento y Abstracción Extensibilidad Flexibilidad Los desarrolladores de los beans no tienen por qué conocer nada sobre la seguridad Los desarrolladores de aplicaciones pueden manejar la seguridad sin modificar el código de los beans Los mecanismos de seguridad no deben imponer políticas de seguridad Independencia de implementación Interoperabilidad Entre servidores, entre vendedores … Mario Muñoz Organero. Servidores de información 44 Terminología de seguridad en J2EE Un principal es todo aquello que puede ser autenticado Cada principal tiene asociados unos atributos de seguridad (security attributes) Por ejemplo un usuario o un servidor Usados para saber a qué recursos puede acceder el principal Un principal se identifica presentando credenciales (credentials) Una credencial contiene o referencia atributos de seguridad Las credenciales se adquieren por autenticación Las credenciales también pueden ser adquiridas por delegación de otro principal. Mario Muñoz Organero. Servidores de información 45 Seguridad “Container-Based” La seguiridad para los componentes (EJBs) se proporciona por el contenedor en el que se ejecutan. Seguridad declarativa: definida en los “deployment descriptors” Incluye la definición de roles de seguridad, reglas de control de acceso y requisitos de autenticación. Se mapean por el desarrollador de la aplicación a un entorno de ejecución concreto Seguridad programática: Uso explícito de los APIs de seguridad por parte del código de los componentes Proporciona flexibilidad e.g., el mismo método puede comportarse de forma distinta en función del principal Principales métodos: getCallerPrincipal y isCallerInRole, definidos en EJBContext. Mario Muñoz Organero. Servidores de información 46 Autenticación en J2EE J2EE no dicta un método de autenticación Cada implementación debe proporcionar sus herramientas de autenticación Soluciones típicas lo hacen por HTTP, HTTPS (HTTP sobre SSL), y basadas en formularios También hay soluciones de autenticación no basadas en Web Una implementación podría por ejemplo basarse en las herramientas del sistema operativo e.g., login en Unix o WinNT Mario Muñoz Organero. Servidores de información 47 Responsabilidades en la seguridad de los EJB Mario Muñoz Organero. Servidores de información 48 Responsabilidades en la seguridad de los EJB Mario Muñoz Organero. Servidores de información 49 El papel del proveedor del Bean Los mecanismos de seguridad no deberían ser implementados dentro de los EJBs Las políticas de seguridad no deberían estar codificadas “a fuego” La misma aplicación, cuando se despliega sobre diferentes entornos puede requerir diferentes políticas. Conclusión: El proveedor de un bean no debería involucrarse en la seguridad. El proveedor del bean se debería limitar a ofrecer referencias a roles para la provisión de seguridad (e.g., que roles se asumen definidos) a través de los descriptores de despliegue Mario Muñoz Organero. Servidores de información 50 APIs disponibles para el proveedor del Bean getCallerPrincipal retorna el “nombre” del principal Util para generar logs por ejemplo, o como base para el acceso a una base de datos… No se debería asumir la existencia de ciertos nombres. i.e., evitar código como if (principal.equals("root")) ... isCallerInRole(String roleName) premite al proveedor del bean codificar comportamientos distintos para un mismo método en función del role de seguridad del principal. Es mejor proporcionar diferentes métodos y usar las declaraciones en el descriptor de despliegue para especificar si un role puede o no acceder al método. Mario Muñoz Organero. Servidores de información 51 Referencias a Roles El proveedor del bean no puede asumir la existencia de roles “estandar” (e.g., "superusuario", "administrador", etc.) Por lo tanto, el proveedor del bean usará referencias a roles La definición aparece en el descriptor de despliegue (dentro de la descripción del bean) Por ejemplo: <security-role-ref> <description>Security role for customers</description> <role-name>customer</role-ref> <role-link> Nombre del role en el contenedor </role-link> </security-role-ref> Las referencias son mapeadas a los roles disponibles por el ensamblador de la aplicación. Mario Muñoz Organero. Servidores de información 52 El ensamblador de la aplicación Encargado de añadir el descriptor de despliegue. Define los roles de seguridad assembly-descriptor al A veces es la misma persona que el proveedor del bean Mapea roles de seguiridad con referencias a roles (definidos por el proveedor del bean) Especifica los permisos que cada role tiene sobre los métodos de los EJBs A veces se deja esta misión al encargado de desplegar la aplicación. Mario Muñoz Organero. Servidores de información 53 Roles de seguridad En el DD: <assembly-descriptor> <!-- Identifies those security roles defined for an EJB module.--> <security-role> <!-- Describes a security role. --> <description> Administrator role for bean. </description> <!-- Identifies a logical role name that this EJB module uses. --> <role-name> Nombre del role en el contenedor </role-name> </security-role> </assembly-descriptor> Mario Muñoz Organero. Servidores de información 54 Permisos de los métodos. El que ensambla la aplicación (o el que la despliega) puede especificar qué métodos pueden ser invocados por qué roles. Por ejemplo (dentro del assembly-descriptor): <method-permissions> <role-name>client</role-name> <method> <ejb-name>Account</ejb-name> <method-name>getBalance</method-name> </method> ... more methods ... </method-permissions> <method-permissions> <role-name>clerk</role-name> <method> <ejb-name>Account</ejb-name> <method-name>*</method-name> </method> </method-permissions> Mario Muñoz Organero. Servidores de información 55 Asociando roles con principales El que despliega la aplicación usará una semántica propia del contenedor. Por ejemplo, en WebLogic se tiene en el fichero weblogic.xml algo así: <security-role-assignment> <role-name>PayrollAdmin</role-name> <principal-name>Tanya</principal-name> <principal-name>Fred</principal-name> <principal-name>system</principal-name> </security-role-assignment> Mario Muñoz Organero. Servidores de información 56 Identidades de seguridad Cuando se invoca un método de un EJB se hace usando una identidad de seguridad Un principal y uno o más roles Normalmente, cuando un método de un EJB m1 invoca otro método m2, m2 se invoca con la misma identidad Si embargo, se puede especificar que un método se invoca siempre con una identidad determinada Solo aplica a llamadas entre métodos de un bean Mario Muñoz Organero. Servidores de información 57