You are on page 1of 96

JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer

para uso con JBoss Enterprise Application Platform 5

Mark Newton Ale Justin

Manual del usuario de JBoss Microcontainer

JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer para uso con JBoss Enterprise Application Platform 5 Edicin 5.1.0
Autor Autor Editor Copyright 2011 Red Hat, Inc. The text of and illustrations in this document are licensed by Red Hat under a Creative Commons AttributionShare Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version. Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law. Red Hat, Red Hat Enterprise Linux, the Shadowman logo, JBoss, MetaMatrix, Fedora, the Infinity Logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries. Linux is the registered trademark of Linus Torvalds in the United States and other countries. Java is a registered trademark of Oracle and/or its affiliates. XFS is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries. MySQL is a registered trademark of MySQL AB in the United States, the European Union and other countries. All other trademarks are the property of their respective owners. Mark Newton Ale Justin Misty Stanley-Jones mark.newton@jboss.org ajustin@redhat.com misty@redhat.com

Este manual est dirigido a aquellos desarrolladores Java que desean utilizar el microcontenedor JBoss para implementar entornos Java modulares y personalizados para sus aplicaciones.

Prefacio v 1. Convenciones del Documento .......................................................................................... v 1.1. Convenciones Tipogrficas ................................................................................... v 1.2. Convenciones del documento ............................................................................... vi 1.3. Notas y Advertencias .......................................................................................... vii 2. Cmo obtener ayuda y hacer sus comentarios ............................................................... viii 2.1. Necesita ayuda? .............................................................................................. viii 2.2. Necesitamos sus comentarios! ........................................................................... viii I. Introduccin al tutorial sobre el Microcontainer 1. Prerequisitos para el uso de este manual 1.1. Instale Maven ...................................................................................................... 1.2. Configuracin especial de Maven para los ejemplos del microcontenedor ................. 1.3. Descarga de los ejemplos .................................................................................... 1 3 3 6 7

2. Introduccin al microcontenedor 9 2.1. Funcionalidades ................................................................................................... 9 2.2. Definiciones ......................................................................................................... 9 2.3. Instalacin .......................................................................................................... 10 3. Construccin de servicios 3.1. Introduccin al ejemplo de recusos humanos ....................................................... 3.2. Compilacin del proyecto de ejemplo HRManager ................................................ 3.3. Creacin de POJOs ........................................................................................... 3.3.1. Descriptores de implementacin XML ....................................................... 3.4. Conexin de POJOs ........................................................................................... 3.4.1. Consideraciones especiales ..................................................................... 3.5. Trabajar con servicios ......................................................................................... 3.5.1. Configuracin de un servicio .................................................................... 3.5.2. Probar un servicio ................................................................................... 3.5.3. Empacar un servicio ................................................................................ 4. Uso de los servicios 4.1. Bootstrap del microcontenedor ............................................................................ 4.2. Implementacin del servicio ................................................................................ 4.3. Acceso directo ................................................................................................... 4.4. Acceso indirecto ................................................................................................. 4.5. Carga de clase dinmica .................................................................................... 4.5.1. Problemas con cargadores de clase creados con los descriptores de implementacin ................................................................................................. 5. Agregar comportamiento con AOP 5.1. Creacin de un aspecto ...................................................................................... 5.2. Configuracin del microcontenedor para AOP ...................................................... 5.3. Aplicacin de un aspecto .................................................................................... 5.4. Callbacks del ciclo de vida .................................................................................. 5.5. Agregar bsquedas de servicios por medio de JNDI ............................................. II. Conceptos avanzados con el microcontenedor 6. Modelos de componentes 6.1. Interacciones permitidas con los modelos de componentes ................................... 6.2. Un Bean sin dependencias ................................................................................. 6.3. Uso del microcontenedor con Spring ................................................................... 6.4. Uso de Guice con el microcontenedor ................................................................. 11 11 12 12 12 13 13 14 14 15 16 19 21 23 24 26 27 30 31 31 33 34 36 38 41 43 43 43 43 44 iii

Manual del usuario de JBoss Microcontainer 6.5. MBeans de legado y mezcla de diferentes modelos de componentes ..................... 46 6.6. Exponer POJOs como MBeans ........................................................................... 46 7. Inyeccin avanzada de dependencias y ldC 7.1. Fbrica de valores .............................................................................................. 7.2. Callbacks ........................................................................................................... 7.3. Modo de acceso del Bean .................................................................................. 7.4. Alias Bean ........................................................................................................ 7.5. Soporte para anotaciones XML (o metadatos) ...................................................... 7.6. Autowire ............................................................................................................. 7.7. Fbrica de beans ............................................................................................... 7.8. Constructor de metadatos Bean .......................................................................... 7.9. ClassLoader personalizado ................................................................................. 7.10. Modo controlador .............................................................................................. 7.11. Ciclo ................................................................................................................ 7.12. Oferta y demanda ............................................................................................ 7.13. Instalaciones .................................................................................................... 7.14. Imitacin perezosa ............................................................................................ 7.15. Ciclo de vida .................................................................................................... 8. El sistema virtual de archivos 8.1. API pblica VFS ................................................................................................. 8.2. Arquitectura VFS ................................................................................................ 8.3. Implementaciones existentes ............................................................................... 8.4. Ganchos de extensin ........................................................................................ 8.5. Funcionalidades ................................................................................................. 9. La capa ClassLoading 9.1. ClassLoader ....................................................................................................... 9.2. ClassLoading ..................................................................................................... 9.3. Carga de clase VFS ........................................................................................... 10. Marco de trabajo de la implementacin virtual 10.1. Manejo agnstico de tipos de implementacin .................................................... 10.2. Separacin del reconocimiento de la estructura de la lgica del ciclo de vida de la implementacin ..................................................................................................... 10.3. Control de flujo natural en forma de anexos ....................................................... 10.4. Detalles de la implementacin y del cliente, usuario y uso del servidor ................. 10.5. Mquina de estado nico .................................................................................. 10.6. Escaneo de clases en busca de anotaciones ..................................................... A. Historial de revisiones 49 49 50 51 52 53 54 55 56 57 58 58 59 59 60 60 61 62 68 68 69 69 71 71 76 80 81 81 81 84 85 85 86 87

iv

Prefacio
1. Convenciones del Documento
Este manual utiliza varias convenciones para resaltar algunas palabras y frases y llamar la atencin sobre ciertas partes especficas de informacin. En ediciones PDF y de papel, este manual utiliza tipos de letra procedentes de Liberation Fonts . Liberation Fonts tambin se utilizan en ediciones de HTML si estn instalados en su sistema. Si no, se muestran tipografas alternativas pero equivalentes. Nota: Red Hat Enterprise Linux 5 y siguientes incluyen Liberation Fonts predeterminadas.
1

1.1. Convenciones Tipogrficas


Se utilizan cuatro convenciones tipogrficas para llamar la atencin sobre palabras o frases especficas. Dichas convenciones y las circunstancias en que se aplican son las siguientes: Negrita monoespaciado Utilizada para resaltar la entrada del sistema, incluyendo comandos de shell, nombres de archivo y rutas. Tambin se utiliza para resaltar teclas claves y combinaciones de teclas. Por ejemplo: Para ver el contenido del archivo my_next_bestselling_novel en su directorio actual de trabajo, escriba el comando cat my_next_bestselling_novel en el intrprete de comandos de shell y pulse Enter para ejecutar el comando. El ejemplo anterior incluye un nombre de archivo, un comando de shell y una tecla clave. Todo se presenta en negrita-monoespaciado y distinguible gracias al contexto. Las combinaciones de teclas se pueden distinguir de las teclas claves mediante el guin que conecta cada parte de una combinacin de tecla. Por ejemplo: Pulse Enter para ejecutar el comando. Pulse Control+Alt+F2 para cambiar a la primera terminal virtual. Pulse Control+Alt+F1 para volver a su sesin de Ventanas-X. La primera oracin resalta la tecla clave determinada que se debe pulsar. La segunda resalta dos conjuntos de tres teclas claves que deben ser presionadas simultneamente. Si se discute el cdigo fuente, los nombres de las clase, los mtodos, las funciones, los nombres de variables y valores de retorno mencionados dentro de un prrafo sern presentados en Negritamonoespaciado. Por ejemplo: Las clases de archivo relacionadas incluyen filename para sistema de archivos, file para archivos y dir para directorios. Cada clase tiene su propio conjunto asociado de permisos. Negrita proporcional Esta denota palabras o frases encontradas en un sistema, incluyendo nombres de aplicacin, texto de cuadro de dilogo, botones etiquetados, etiquetas de cajilla de verificacin y botn de radio; ttulos de men y ttulos del sub-men. Por ejemplo:

https://fedorahosted.org/liberation-fonts/

Prefacio Seleccionar Sistema Preferencias Ratn desde la barra del men principal para lanzar Preferencias de Ratn. En la pestaa de Botones, haga clic en la cajilla ratn de mano izquierda y luego haga clic en Cerrar para cambiar el botn principal del ratn de la izquierda a la derecha (adecuando el ratn para la mano izquierda). Para insertar un caracter especial en un archivo de gedit, seleccione desde la barra del men principal Aplicaciones Accessories Mapa de caracteres. Luego, desde la barra de menes de mapa de caracteres elija Bsqueda Hallar, teclee el nombre del caracter en el campo Bsqueda y haga clic en Siguiente. El caracter buscado se resaltar en la Tabla de caracteres. Haga doble clic en este caracter resaltado para colocarlo en el campo de Texto para copiar y luego haga clic en el botn de Copiar. Ahora regrese a su documento y elija Editar Pegar desde la barra de men de gedit. El texto anterior incluye nombres de aplicacin; nombres y elementos del men de todo el sistema; nombres de men de aplicaciones especficas y botones y texto hallados dentro de una interfaz grfica de usuario, todos presentados en negrita proporcional y distinguibles por contexto. Itlicas-negrita monoespaciado o Itlicas-negrita proporcional Ya sea negrita monoespaciado o negrita proporcional, la adicin de itlicas indica texto reemplazable o variable. Las itlicas denotan texto que usted no escribe literalmente o texto mostrado que cambia dependiendo de la circunstancia. Por ejemplo: Para conectar a una mquina remota utilizando ssh, teclee ssh nombredeusuario@dominio.nombre en un intrprete de comandos de shell. Si la mquina remota es example.com y su nombre de usuario en esa mquina es john, teclee ssh john@example.com. El comando mount -o remount file-system remonta el sistema de archivo llamado. Por ejemplo, para volver a montar el sistema de archivo /home, el comando es mount -o remount /home. Para ver la versin de un paquete actualmente instalado, utilice el comando rpm -q paquete. ste entregar el resultado siguiente: paquete-versin-lanzamiento. Observe las palabras en itlicas y negrita sobre nombre de usuario, domain.name, sistema de archivo, paquete, versin y lanzamiento. Cada palabra es un marcador de posicin, tanto para el texto que usted escriba al ejecutar un comando como para el texto mostrado por el sistema. Aparte del uso estndar para presentar el ttulo de un trabajo, las itlicas denotan el primer uso de un trmino nuevo e importante. Por ejemplo: Publican es un sistema de publicacin de DocBook.

1.2. Convenciones del documento


Los mensajes de salida de la terminal o fragmentos de cdigo fuente se distinguen visualmente del texto circundante. Los mensajes de salida enviados a una terminal se muestran en romano monoespaciado y se presentan as:
books books_tests Desktop Desktop1 documentation downloads drafts images mss notes photos scripts stuff svgs svn

vi

Notas y Advertencias Los listados de cdigo fuente tambin se muestran en romano monoespaciado, pero se presentan y resaltan de la siguiente manera:
package org.jboss.book.jca.ex1; import javax.naming.InitialContext; public class ExClient { public static void main(String args[]) throws Exception { InitialContext iniCtx = new InitialContext(); Object ref = iniCtx.lookup("EchoBean"); EchoHome home = (EchoHome) ref; Echo echo = home.create(); System.out.println("Created Echo"); System.out.println("Echo.echo('Hello') = " + echo.echo("Hello")); } }

1.3. Notas y Advertencias


Finalmente, utilizamos tres estilos visuales para llamar la atencin sobre la informacin que de otro modo se podra pasar por alto.

Nota
Una nota es una sugerencia, atajo o enfoque alternativo para una tarea determinada. Ignorar una nota no debera tener consecuencias negativas, pero podra perderse de algunos trucos que pueden facilitarle las cosas.

Importante
Los cuadros con el ttulo de importante dan detalles de cosas que se pueden pasar por alto fcilmente: cambios de configuracin nicamente aplicables a la sesin actual, o servicios que necesitan reiniciarse antes de que se aplique una actualizacin. Ignorar estos cuadros no ocasionar prdida de datos, pero puede causar enfado y frustracin.

Advertencia
Las advertencias no deben ignorarse. Ignorarlas muy probablemente ocasionar prdida de datos.

vii

Prefacio

2. Cmo obtener ayuda y hacer sus comentarios


2.1. Necesita ayuda?
Si encuentra dificultades con alguno de los procedimientos descritos en este documento, visite el Portal del cliente de Red Hat en http://access.redhat.com. A travs del portal del cliente, usted podr: buscar o navegar a travs de la base de artculos de soporte tcnico sobre productos de Red Hat. enviar un caso de soporte a Servicios de Soporte Global de Red Hat (GSS) acceder a otra documentacin del producto. Red Hat alberga una lista grande de correos electrnicos para discutir sobre software de Red Hat y tecnologa. Encontrar un listado de las listas de correo disponibles al pblico en https:// www.redhat.com/mailman/listinfo. Haga clic en el nombre de la lista a la que quiera suscribirse o para acceder a los archivos de listados.

2.2. Necesitamos sus comentarios!


Si encuentra algun error o si se le ocurre una manera de mejorar este manual, nos encantara escuchar sus sugerencias. Complete un reporte en Bugzilla frente al producto JBoss Enterprise Application Platform 5 y el componente doc-JBoss_Microcontainer_User_Guide. El siguiente enlace le llevar a un reporte de error ya completado para este producto: http:// 2 bugzilla.redhat.com/ . Llene la siguiente plantilla en el campo de Description de Bugzilla. Sea tan especifico como le sea posible al describir el problema, esto ayudar a asegurarnos de que lo podemos solucionar rpidamente.
URL del documento:

Nmero de la seccin y nombre:

Describa el problema:

Sugerencias para mejorar:

Informacin adicional:

Asegrese de darnos su nombre para poder darle todo el crdito por reportar el problema.

https://bugzilla.redhat.com/enter_bug.cgi?product=JBoss%20Enterprise%20Application%20Platform%205&component=docJBoss_Microcontainer_User_Guide&version=5.1.1&short_desc=Bug%20in%20JBoss%20Microcontainer%20User%20Guide

viii

Parte I. Introduccin al tutorial sobre el Microcontainer

Prerequisitos para el uso de este manual


Para poder utilizar los ejemplos en este manual es necesario instalar y configurar el software de soporte y debe descargar el cdigo para los ejemplos.

1.1. Instale Maven


Los ejemplos utilizados en este proyecto requieren Maven v2.2.0 o posteriores. Descargue Maven directamente de la pgina de inicio de Apache Maven e instale y configure su sistema tal como se describe en Procedimiento 1.1, Instale Maven. Procedimiento 1.1. Instale Maven 1. Verifique que tiene instalado Java Developer Kit 1.6 o posteriores. Este tambin es un requerimiento para la plataforma empresarial. Asegrese de que tiene instalado Java en su sistema y configure la variable de entorno JAVA_HOME en su ~/.bash_profile para Linux o en las propiedades del sistema para Windows. Para mayor informacin con relacin a la configuracin de las variables de entorno, consulte el paso Paso 4 en este procedimiento. 2. Descargue Maven

Nota
Este paso y en el futuro se asume que ha guardado Maven en la ubicacin sugerida en su sistema operativo. Maven, como cualquier otra aplicacin Java se puede instalar en cualquier lugar razonable en su sistema.

Visite http://maven.apache.org/download.html. Haga clic en el enlace de fichero zip compilado, por ejemplo apache-maven-2.2.1-bin.zip Seleccione un espejo de descarga de la lista.

Para usuarios de Linux


Guarde el fichero zip en su directorio home.

Para usuarios de Windows


Guarde el fichero zip en su directorio C:\Documents and Settings\user_name. 3. Instale Maven

Para usuarios de Linux


Extraiga el archivo zip en su directorio home. Si seleccion el fichero zip en el paso 2 y no vuelve a nombrar el directorio, el directorio extrado se llama apache-maven-version. 3

Captulo 1. Prerequisitos para el uso de este manual

Para usuarios de Windows


Extraiga el fichero zip en C:\Program Files\Apache Software Foundation. Si seleccion el fichero zip en el paso 2 y no vuelve a nombrar el directorio, el directorio extrado se llama apachemaven-version. 4. Configure las variables del entorno

Para usuarios de Linux


Agregue las siguientes lneas a su ~/.bash_profile. Asegrese de cambiar el [username] a su nombre de usuario real y verifique que el directorio Maven es de hecho el nombre del directorio. El nmero de la versin puede ser diferente del que se lista a continuacin.
export M2_HOME=/home/[username]/apache-maven-2.2.1 export M2=$M2_HOME/bin export PATH=$M2:$PATH

Al incluir M2 al comienzo de su ruta, la versin Maven que acab de instalar ser la versin predeterminada utilizada. Puede que tambin quierar establecer la ruta de su variable de entorno JAVA_HOME con la ubicacin del JDK en su sistema.

Para usuarios de Windows


Agregue las variables de entorno M2_HOME, M2 y JAVA_HOME. 1. Oprima Start+Pause|Break. Se presenta la ventana de propiedades del sistema. 2. Haga clic en la pestaa Advanced y luego haga clic en el botn Environment Variables. 3. Bajo System Variables, seleccione Path. 4. Haga clic en Edit y agregue las dos rutas Maven usando un punto y coma para separar cada entrada. No se requieren comillas alrededor de las rutas. Agregue la variable M2_HOME y establezca la ruta como C:\Program Files\Apache Software Foundation\apache-maven-2.2.1. Agregue la variable M2 y configure el valor como %M2_HOME%\bin. 5. En la misma ventana, cree la variable de entorno JAVA_HOME: Agregue la variable %JAVA_HOME% y establezca el valor con la ubicacin de su JDK. Por ejemplo C:\Program Files\Java\jdk1.6.0_02. 6. En la misma ventana actualice o cree la variable de entorno de la ruta: Agregue la variable %M2% para permitir que se ejecute Maven desde la lnea de comandos. Agregue la variable %JAVA_HOME%\bin para establecer la ruta con la instalacin correcta de Java. 7. Haga clic en OK hasta que la ventana System Properties se cierre.

Instale Maven 5. Implemente los cambios en .bash_profile

Solo para los usuarios de Linux


Para actualizar los cambios realizados al .bash_profile en la sesin de la terminal actual proporcione su .bash_profile.
[localhost]$ source ~/.bash_profile

6.

Update gnome-terminal profile

Solo para los usuarios de Linux


Actualice el perfil de la terminal para asegurarse de que las iteraciones posteriores de la terminal gnome (o la terminal Konsole) lean las nuevas variables de entorno. 1. Haga clic en Edit Profiles 2. Seleccione Default y luego haga clic en el botn Edit. 3. En la ventana Editing Profile, haga clic en la pestaa Title and Command. 4. Seleccione la opcin Run command as login shell. 5. Cierre todas las terminales que tenga abiertas. 7. Verifique los cambios en las variables de entorno y en la instalacin de Maven

Para usuarios de Linux


Para verificar que los cambios se han implementado correctamente, abra una terminal y ejecute los siguientes comandos: Ejecute echo $M2_HOME, el cual debe retornar el siguiente resultado.
[localhost]$ echo $M2_HOME /home/username/apache-maven-2.2.1

Ejecute echo $M2, el cual debe retornar el siguiente resultado.


[localhost]$ echo $M2 /home/username/apache-maven-2.2.1/bin

Ejecute echo $PATH y verifique que el directorio Maven /bin est includo.
[localhost]$ echo $PATH /home/username/apache-maven-2.2.1/bin

Ejecute which mvn, el cual debe presentar la ruta al Maven ejecutable.


[localhost]$ which mvn ~/apache-maven-2.2.1/bin/mvn

Ejecute mvn -version, la cual debe presentar la versin de Maven, la versin Java relacionada y la informacin relacionada con el sistema operativo.

Captulo 1. Prerequisitos para el uso de este manual

[localhost]$ $ mvn -version Apache Maven 2.2.1 (r801777; 2009-08-07 05:16:01+1000) Java version: 1.6.0_0 Java home: /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre Default locale: en_US, platform encoding: UTF-8 OS name: "Linux" version: "2.6.30.9-96.fc11.i586" arch: "i386" Family: "unix"

Para usuarios de Windows


Para verificar que los cambios se han implementado correctamente, abra una terminal y ejecute el siguiente comando: En una lnea de comandos ejecute mvn -version
C:\> mvn -version Apache Maven 2.2.1 (r801777; 2009-08-06 12:16:01-0700) Java version: 1.6.0_17 Java home: C:\Sun\SDK\jdk\jre Default locale: en_US, platform encoding: Cp1252 OS name: "windows xp" version: "5.1" arch: "x86" Family: "windows"

Ha configurado de manera exitosa Maven para utilizarlo con los ejemplos en este manual.

1.2. Configuracin especial de Maven para los ejemplos del microcontenedor


Maven es un sistema modular de construccin que llama las dependencias cuando se necesitan. Los ejemplos en este manual asumen que ha includo el bloque de XML en Ejemplo 1.1, Archivo settings.xml de ejemplo en su ~/.m2/settings.xml (Linux) o C:\Documents and Settings\username\.m2\settings.xml (Windows). Si el archivo no existe entonces crelo primero. Ejemplo 1.1. Archivo settings.xml de ejemplo
<settings> <profiles> <profile> <id>jboss.repository</id> <activation> <property> <name>!jboss.repository.off</name> </property> </activation> <repositories> <repository> <id>snapshots.jboss.org</id> <url>http://snapshots.jboss.org/maven2</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>repository.jboss.org</id> <url>http://repository.jboss.org/maven2</url> <snapshots> <enabled>false</enabled> </snapshots> </repository>

Descarga de los ejemplos


</repositories> <pluginRepositories> <pluginRepository> <id>repository.jboss.org</id> <url>http://repository.jboss.org/maven2</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>snapshots.jboss.org</id> <url>http://snapshots.jboss.org/maven2</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> </profiles> </settings>

1.3. Descarga de los ejemplos


Los ejemplos en este manual le muestran cmo crear un proyecto maven que dependa del JBoss Microcontainer utilizando Maven. Puede descargarlos de images/examples.zip . Esta ubicacin cambiar pero la hemos includo para su conveniencia. Despus de descargar el archivo ZIP que contiene los ejemplos, extraiga su contenido en un lugar conveniente y mire los ejemplos para familiarizarse con su estructura.

Introduccin al microcontenedor
El microcontenedor JBoss es un rediseo del JBoss JMX Microkernel para soportar la implementacin POJO directa y el uso autnomo fuera del servidor de aplicaciones JBoss. El microcontenedor est diseado para llenar las necesidades especificas de los desarrolladores Java que queran utilizar tcnicas de programacin orientadas a objetos para implementar software de manera rpida. Adems permite implementar software en un amplio rango de dispositivos desde plataformas de computacin mviles, entornos de computacin de grande escala y lo que se encuentre entre estos dos.

2.1. Funcionalidades
Todas las funcionalidades del microkernel JMX Implementacin POJO directa (no hay necesidad de estndar/XMBean o MBeanProxy) Inyeccin directa de dependencias de estilo IOC Administracin mejoarada del ciclo de vida Control adicional sobre las dependencias Integracin transparente AOP Sistema virtual de archivos Marco de trabajo de implementacin virtual Carga de clase OSGi

2.2. Definiciones
Este manual usa algunos trminos que puede que no le sean familiares. Algunos de ellos se definen en Lista de definicin del mMicrocontenedor. Lista de definicin del mMicrocontenedor Microkernel JMX JBoss JMX Microkernel es un entorno Java modular. Es diferente de los entornos estndar como J2EE ya que el desarrollador puede escoger exactamente los componentes que son parte del entorno y dejar por fuera el resto. POJO Un POJO (del ingls Plain Old Java Object) es un objeto Java modular y reutilizable. El nombre se utiliza para enfatizar que un objeto dado es un objeto Java normal, no es un objeto especial y en particular no es un JavaBean empresarial. El trmino lo utiliz por primera vez Martin Fowler, Rebecca Parsons y Josh MacKenzie in September 2000 en una charla en la cual estaban resaltando los muchos beneficios de codificar la lgica empresarial en objetos java normales en lugar de utilizar beans de entidad. Bean Java Un bean Java es un componente software re-utilizable que se puede manipular visualmente en una herramienta de construccin.

Captulo 2. Introduccin al microcontenedor Un bean Java es un pedazo de cdigo independiente. No requiere herencias de ninguna clase o interfaz base en particular. Aunque los beans Java se crean principalmente en IDEs grficos tambin se pueden desarrollar en simples editores de texto. AOP Aspect-Oriented Programming (AOP) es un paradigma de programacin en el cual las funciones secundarias o de soporte se aislan de la lgica empresarial del programa principal. Es un subgrupo de la programacin orientada a objetos.

2.3. Instalacin
El microcontenedor es una parte integral de la plataforma empresarial. En el manual de configuracin y administracin encontrar mayor informacin sobre la instalacin y configuracin de la plataforma empresarial.

10

Construccin de servicios
Los servicios son pedazos de cdigo que realizan tareas que mltiples clientes necesitan. Poara nuestro propsito pondremos algunas restricciones adicionales en la definicin de un servicio. Los servicios deben tener nombres nicos, a los cuales se puede hacer referencia o los clinetes pueden llamar. El interior de un servicio debe ser invisible y sin importancia para los clientes. Este es el concepto "caja negra"de la programacin orientada a objetos (OOP del ingls object-oriented programming). En OOP, cada objeto es independente y ningn otro objeto necesita saber cmo hace su trabajo. En el contexto del microcontenedor, los servicios se construyen desde POJOs. Un POJO es casi un servicio como tal pero no se puede acceder por un nombre nico y debe ser creado por el cliente que lo necesita. Aunque un POJO se debe crear en tiempo de ejecucin por parte del cliente, no es necesario implementarlo por medio de una clase separada con el fin de proporcionar una interfaz bien definida. Con tal de que no se borren los mtodos y campos y el acceso a ellos no sea restringido, no hay necesidad de recompilar los clientes para utilizar un POJO recin creado.

Nota
El iImplementar una interfaz solo es necesario con el fin de permitir que un cliente escoja entre implementaciones opcionales. Si el cliente se compila frente a una interfaz, se pueden proporcionar muchas implementaciones diferentes de la interfaz sin tener que recompilar el cliente. La interfaz se asegura de que las firmas de mtodo no cambien.

El resto de este manual consiste de la creacin del servicio de recursos humanos utilizando el microcontenedor para capturar y modularizar la lgica empresarial de la aplicacin. Despus de que el microcontenedor est instalado, el cdigo de ejemplo se encuentra en examples/User_Guide/ gettingStarted/humanResourcesService.

3.1. Introduccin al ejemplo de recusos humanos


Al familiarizarse con la estructura del directorio de los archivos en el ejemplo note que usa la 1 estructura del directorio estndar Maven . Los archivos fuente Java se encuentran en los paquetes debajo del directorio examples/ User_Guide/gettingStarted/humanResourcesService/src/main/java/org/jboss/ example/service despus de extraer el archivo ZIP. Cada una de estas clases representa un POJO simple que no implementa ninguna interfaz especial. La clase ms importante es HRManager, la cual representa el punto de entrada del servicio proporcionando todos los mtodos pblicos que los clientes llamarn. Mtodos que la clase HRManager proporciona addEmployee(Employee employee) removeEmployee(Employee employee)
1

http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html

11

Captulo 3. Construccin de servicios getEmployee(String firstName, String lastName) getEmployees() getSalary(Employee employee) setSalary(Employee employee, Integer newSalary) isHiringFreeze() setHiringFreeze(boolean hiringFreeze) getSalaryStrategy() setSalaryStrategy(SalaryStrategy strategy) El servicio de recursos humanos est compuesto de unas pocas clases, las cuales mantienen una lista de empleados y sus detalles (direcciones y salarios, en este caso). Al utilizar la interfaz SalaryStrategy es posible configurar el HRManager de manera que hayan disponibles diferentes implementaciones de la estrategia de salario para poner lmites mnimos y mximos en los salarios para diferentes roles de empleados.

3.2. Compilacin del proyecto de ejemplo HRManager


Para compilar el cdigo fuente, escriba mvn compile desde el directorio humanResourcesService/. Esto crea un nuevo directorio llamado target/classes, el cual contiene las clases compiladas. Para limpiar el proyecto y borrar el directorio destino emita el comando mvn clean.

3.3. Creacin de POJOs


antes de poder utilizar un POJO, necesita crearlo. Necesita un mecanismo de nombrado que le permita registrar una referencia a la instancia POJO con un nombre. Los clientes necesitan este nombre para utilizar el POJO. El microcontenedor proporciona dicho mecanismo: un controlador. Un controlador le permite implementar sus servicios basados en POJO en un entorno en tiempo de ejecucin.

3.3.1. Descriptores de implementacin XML


Despus de compilar las clases, use un descriptor de implementacin XML para crear instancias de ellas. El descriptor contiene una lista de beans representandos instancias individuales. Cada bean tiene un nombre nico de manera que los clientes lo pueden llamar en tiempo de ejecucin. El siguiente descriptor implementa una instancia del HRManager:
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd" xmlns="urn:jboss:bean-deployer:2.0"> <bean name="HRService" class="org.jboss.example.service.HRManager"/> </deployment>

Este XML crea una instancia de la clase HRManager y la registra con el nombre HRService. Este archivo se le pasa a un programa de implementacin XML asociado con el microcontenedor en tiempo de ejecucin, el cual realiza la implementacin real e instancia los beans. 12

Conexin de POJOs

3.4. Conexin de POJOs


Las instancias individuales POJO solo pueden proporcionar comportamientos relativamente simples. El verdadero poder de los POJOs viene de conectarlos entre ellos para realizar tareas complejas. Cmo puede conectar POJOs para seleccionar diferentes implementaciones de estrategia de salarios? El siguiente descriptor de implementacin XML hace justamente eso:
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd" xmlns="urn:jboss:bean-deployer:2.0"> <bean name="HRService" class="org.jboss.example.service.HRManager"> <property name="salaryStrategy"><inject bean="AgeBasedSalary"/></property> </bean> <bean name="AgeBasedSalary" class="org.jboss.example.service.util.AgeBasedSalaryStrategy"/> </deployment>

Este XML crea una instancia de la implementacin de la estrategia de salario incluyendo un elemento <bean> adicional. Esta vez, se selecciona AgeBasedSalaryStrategy. Luego el cdigo inyecta una referencia a este bean en la instancia de HRManager creada utilizando el bean HRService. La inyeccin es posible ya que la clase HRManager contiene un mtodo setSalaryStrategy(SalaryStrategy strategy). Mientras tanto detrs de bastidores el microcontenedor JBoss llama a este mtodo en la instancia HRManager recin creada y le pasa una referencia a la instancia AgeBasedSalaryStrategy. El descriptor de implementacin XML causa la misma secuencia de eventos como si hubiera escrito el siguiente cdigo:
HRManager hrService = new HRManager(); AgeBasedSalaryStrategy ageBasedSalary = new AgeBasedSalaryStrategy(); hrService.setSalaryStrategy(ageBasedSalary);

Adems de realizar la inyeccin por medio de los mtodos setter de las propiedades, el microcontenedor JBoss tambin puede realizar la inyeccin por medio de parmetros del constructor si es necesario. Para obtener mayores detalles consulte el captulo sobre 'Inyeccin' en la parte II 'Desarrollo POJO.'

3.4.1. Consideraciones especiales


Aunque es posible el crear instancias de clases utilizando el elemento <bean> en el descriptor de implementacin, no siempre es la mejor manera. Por ejemplo, el crear instancias de las clases Employee y Address es innecesario ya que el cliente crea estas en respuesta a la entrada del usuario. Todava son parte del servicio pero no se referencian en el descriptor de implementacin.

Realice comentarios en su cdigo


Puede definir mltiples beans dentro de un descriptor de implementacin en tanto cada uno tenga un nombre nico, el cual se utiliza para realizar inyecciones como se mostr anteriormente. Sin embargo, todos los beans no necesariamente representan servicios. Aunque un servicio se puede implementar utilizando un solo bean, usualmente se utilizan mltiples beans. Un bean usualmente representa el punto de entrada del servicio y contiene los mtodos pblicos que los clientes llaman. En este ejemplo, el punto de entrada es el bean HRService. El descriptor de implementacin XML no indica si un bean representa un servicio o si un bean es el punto de entrada del servicio. Es una buena idea 13

Captulo 3. Construccin de servicios el utilizar comentariosy un esquema de nombrado obvio para diferenciar los beans de servicio de los beans que no son de servicio.

3.5. Trabajar con servicios


Despus de crear POJOs y conectarlos para formar servicios, necesita configurar los servicios, probarlos y empacarlos.

3.5.1. Configuracin de un servicio


Los servicios se pueden configurar de dos maneras: Inyeccin de referencias entre instancias POJO Inyeccin de valores en propiedades POJO En este ejemplo se utiliza el segundo mtodo. El siguiente descriptor de implementacin configura la instancia de HRManager de la siguiente manera: Se implementa una congelacin en la contratacin La AgeBasedSalaryStrategy implementa un nuevo valor de salario mnimo y mximo. El inyectar referencias enter instancias POJO es una manera de configurar un servicio; sin embargo, tambin podemos inyectar valores en propiedades POJO. El siguiente descriptor de implementacin muestra cmo podemos configurar la instancia HRManager para que realice una congelacin en la contratacin y para que la AgeBasedSalaryStrategy tenga un valor de salario mnimo y mximo:
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd" xmlns="urn:jboss:bean-deployer:2.0"> <bean name="HRService" class="org.jboss.example.service.HRManager"> <property name="hiringFreeze">false</property> <property name="salaryStrategy"><inject bean="AgeBasedSalary"/></property> </bean> <bean name="AgeBasedSalary" class="org.jboss.example.service.util.AgeBasedSalaryStrategy"> <property name="minSalary">1000</property> <property name="maxSalary">80000</property> </bean> </deployment>

Las clases deben tener mtodos setter pblicos para las propiedades relevantes de manera que los valores se puedan inyectar. Por ejemplo, la clase HRManager tiene un mtodo setHiringFreeze(boolean hiringFreeze) y la clase AgeBasedSalaryStrategy tiene los mtodos setMinSalary(int minSalary) y setMaxSalary(int maxSalary). Los valores en el descriptor de implementacin se convierten de cadenas a los tipos relevantes (boolean, int, etc) por medio de PropertyEditors JavaBean. Muchos PropertyEditors se brindan por defecto para los tipos estndar, pero puede crear los propios si es necesario. Consulte el captulo de propiedades en la parte II 'Desarrollo POJO' para obtener mayores detalles.

14

Probar un servicio

3.5.2. Probar un servicio


Despus de crear sus POJOs y de conectarlos para formar servicios, necesita probarlos. JBoss Microcontainer le permite la prueba de unidades de POJOs individuales as como de servicios por medio del uso de una clase MicrocontainerTest. La clase org.jboss.test.kernel.junit.MicrocontainerTest hereda de junit.framework.TestCase, configurando cada prueba realizando bootstrap en JBoss Microcontainer y agregando un BasicXMLDeployer. Luego busca la ruta de clase para un descriptor de implementacin XML con el mismo nombre que la clase de prueba terminado en .xml y que se encuentra en el nombre del paquete de la clase que representa la estructura del directorio. Cualquier bean que se encuentre en este archivo se implementan y luego se pueden acceder utilizando un mtodo conveniente llamado getBean(String name). Puede encontrar ejemplos de estos descriptores de implementacin en Ejemplo 3.1, Listado del directorio src/test/resources. Ejemplo 3.1. Listado del directorio src/test/resources

log4j.properties org jboss example service HRManagerAgeBasedTestCase.xml HRManagerLocationBasedTestCase.xml HRManagerTestCase.xml util AgeBasedSalaryTestCase.xml LocationBasedSalaryTestCase.xml

El cdigo de prueba se encuentra en el directorio the src/test/java : Ejemplo 3.2. Listado del directorio src/test/java

org jboss example service HRManagerAgeBasedTestCase.java HRManagerLocationBasedTestCase.java HRManagerTestCase.java HRManagerTest.java HRManagerTestSuite.java util AgeBasedSalaryTestCase.java LocationBasedSalaryTestCase.java SalaryStrategyTestSuite.java

La clase HRManagerTest extiende MicrocontainerTest con el fin de configurar un nmero de empleados a utilizar como base para la prueba. Ejemplos individuales luego crean sub-clases en HRManagerTest para realizar el trabajo en s. Tambin se includyen un par de clases TestSuite que se utilizan para agrupar ejemplos individuales por comodidad. Para ejecutar las pruebas escriba mvn test desde el directorio humanResourcesService/. Debe ver alguna salida de registro DEBUG, el cual muestra a JBoss Microcontainer inicando e 15

Captulo 3. Construccin de servicios implementando los desde el archivo XML relevante antes de ejecutar cada prueba. Al final de la prueba se borra la implementacin de los beans y se apaga el microcontenedor.

Nota
Algunas de las pruebas tal como HRManagerTestCase, AgeBasedSalaryTestCase y LocationBasedSalaryTestCase prueban POJOs individuales. Otras pruebas tal como HRManagerAgeBasedTestCase y HRManagerLocationBasedTestCase prueban servicios enteros. De cualquier manera, las pruebas se ejecutan de la misma manera. El utilizar la clase MicrocontainerTest facilita el configurar y conducir pruebas completas de cualquier parte de su cdigo. Las clases Address y Employee no se anidan aqu. El escribir pruebas para ellas queda de su parte.

3.5.3. Empacar un servicio


Despus de probar su servicio es hora de empacarlo de manera que otros puedan utilizarlo. La manera ms simple de hacer esto es crear una JAR que contenga todas las clases. Puede escoger el incluir el descriptor de implementacin si hay una manera predeterminada sensible de configurar el servicio, pero es opcional. Procedimiento 3.1. Empacar un servicio 1. Ponga el descriptor de implementacin en el directorio META-INF (opcional) Si decide incluir el descriptor de implementacin por convencin se debe llamar jbossbeans.xml y se debe poner en un directorio META-INF. Esta es la distribucin predeterminada para la plataforma empresarial as que el programa de implementacin JAR reconoce esta distribucin y realiza la implementacin de manera automtica. El descriptor de implementacin no se incluye en el ejemplo de recursos humanos ya que el servicio se configura modificando el descriptor directamente como un archivo a separado. 2. Generacin de la JAR Para generar una JAR que contenga todas las clases compiladas introduzca mvn package desde el directorio humanResourcesService/. Hacer la JAR disponible para otros proyectos Maven Para hacer la JAR disponible para los otros proyectos Maven introduzca mvn install con el fin de copiarlo a su repositorio Maven local. La distribucin final de la JAR se puede ver en Ejemplo 3.3, Listado de los directorios org/jboss/example/service y META-INF. Ejemplo 3.3. Listado de los directorios org/jboss/example/service y META-INF

3.

`-- org `-- jboss `-- example `-- service |-- Address.java |-- Employee.java |-- HRManager.java `-- util |-- AgeBasedSalaryStrategy.java |-- LocationBasedSalaryStrategy.java

16

Empacar un servicio
`-- SalaryStrategy.java `--META-INF `-- MANIFEST.MF `-- maven `-- org.jboss.micrcontainer.examples `-- humanResourceService

Nota
Maven crea automticamente el directorio META-INF/maven y no estar presente si est utilizando uns sistema de construccin diferente.

17

18

Uso de los servicios


El captulo anterior le mostr cmo crear, configurar, probar y empacar un servicio. El siguiente paso es crear un cliente, el cual realizar el trabajo utilizando el servicio. El cliente en este ejemplo usa un Text User Interface (TUI) para aceptar entradas del usuario y presentar los resultados. Esto reduce el tamao y complejidad del cdigo ejemplo. Todos los archivos necesarios se encuentran en el directorio examples/User_Guide/ gettingstarted/commandLineClient, el cual sigue la estructura del directorio estndar Maven, como se puede ver en Ejemplo 4.1, Listar el directorio examples/User_Guide/ gettingstarted/commandLineClient. Ejemplo 4.1. Listar el directorio examples/User_Guide/gettingstarted/ commandLineClient

pom.xml src main assembly aop.xml classloader.xml common.xml pojo.xml config aop-beans.xml classloader-beans.xml pojo-beans.xml run.sh java org jboss example client Client.java ConsoleInput.java EmbeddedBootstrap.java UserInterface.java resources log4j.properties test java org jboss example client ClientTestCase.java ClientTestSuite.java MockUserInterface.java resources jboss-beans.xml target classes log4j.properties

El cliente consiste de las tres clases y una interfaz que se encuentra en el directorio org/jboss/ example/client. UserInterface describe los mtodos que el cliente llama en tiempo de ejecucin para solicitar lla entrada del usuario. ConsoleInput es una implementacin de UserInterface que crea un 19

Captulo 4. Uso de los servicios TUI que el usuario utiliza para interactuar con el cliente. La ventaja de este diseo es que puede crear fcilmente una implementacin Swing de UserInterface en una fecha posterior y puede reemplazar el TUI con un GUI. Tambin puede simular el proceso de ingreso de datos con un script. Luego puede chequear el comportamiento del cliente automticamente usando ejemplos JUnit convencionales que se encuentran en Ejemplo 3.2, Listado del directorio src/test/java. Para que la construccin funcione primero debe construir e instalar auditAspect.jar desde el directorio examples/User_Guide/gettingStarted/auditAspect usando el mvn install command. Se crean un nmero de distribuciones diferentes de clientes, incluyendo una basada en AOP, la cual depende de que auditAspect.jar se encuentre disponible en el repositorio local Maven. Si anteriormente escribi mvn install desde el directorio examples/User_Guide/ gettingStarted entonces humanResourcesService.jar y auditAspect.jar ya se han construdo y empacado junto con el cliente as que este paso no ser necesario. Para compilar el cdigo fuente, se realizan todos los pasos que se encuentran en Procedimiento 4.1, Compilacin del cdigo fuente al emitir el comando mvn package desde el directorio commandLineClient. Procedimiento 4.1. Compilacin del cdigo fuente 1. Ejecute las pruebas de las unidades. 2. 3. construya una JAR cliente. Ensamble una distribucin que contenga todos los archivos necesarios.

Despus de compilar y empacar el cliente, la estructura del directorio en el diretcorio commandLineClient/target incluye los subdirectorios descritos en Ejemplo 4.2, Los subdirectorios del directorio commandLineClient/target. Ejemplo 4.2. Los subdirectorios del directorio commandLineClient/target client-pojo utilizado para llamar al servicio sin AOP. client-cl utilizado para demostrar las funcionalidades de carga de clase. client-aop Agregar soporte AOP. Consulte Captulo 5, Agregar comportamiento con AOP para obtener mayores detalles. Cada sub-directorio representa una distribucin diferente con todos los scripts shell, JARs y descriptores de implementacin XML que se necesitan para ejecutar el cliente en diferentes configuraciones. El resto de este captulo usea la distribucin client-pojo que se encuentra en el sub-directorio client-pojo, el cual se lista en Ejemplo 4.3, Listado del directorio client-pojo. Ejemplo 4.3. Listado del directorio client-pojo

|-|-|-| | | |

client-1.0.0.jar jboss-beans.xml lib |-- concurrent-1.3.4.jar |-- humanResourcesService-1.0.0.jar |-- jboss-common-core-2.0.4.GA.jar |-- jboss-common-core-2.2.1.GA.jar

20

Bootstrap del microcontenedor


| | | | | | | | `-|-- jboss-common-logging-log4j-2.0.4.GA.jar |-- jboss-common-logging-spi-2.0.4.GA.jar |-- jboss-container-2.0.0.Beta6.jar |-- jboss-dependency-2.0.0.Beta6.jar |-- jboss-kernel-2.0.0.Beta6.jar |-- jbossxb-2.0.0.CR4.jar |-- log4j-1.2.14.jar `-- xercesImpl-2.7.1.jar run.sh

Para ejecutar el cliente, cmbiese al directorio client-pojo y escriba ./run.sh. Aparecer el The Ejemplo 4.4, Pantalla del men de HRManager. Ejemplo 4.4. Pantalla del men de HRManager

Men: d) Implementar el servicio de recursos humanos u) Borrar la implementacin del servicio de recursos humanos a) l) r) g) s) t) Agregar empleado Listar los empleados Borrar empleado Ver un salario Establecer un salario Alternar la congelacin de la contratacin

m) Ver el men p) Imprimir el estatus del servicio q) Salir >

Para seleccionar una opcin, introduzca la letra que se muestra en el lado izquierdo y oprima RETURN. Por ejemplo para ver lsa opciones del men introduzca m y luego presione RETURN. El introducir ms de una letra o el introducir una opcin invlida genera un mensaje de error.

Importante
El script run.sh establece el entorno de ejecucin agregando todas las JARs que se encuentran en el directorio lib/ a la ruta de clase usando la propiedad del sistema java.ext.dirs. Tambin agrega el directorio actual y la client-1.0.0.jar usando la eiqueta -cp de manera que el descriptor de implementacin jboss-beans.xml se encuentre en tiempo de ejecucin junto con la clase org.jboss.example.client.Client, la cual se llama para iniciar la aplicacin.

4.1. Bootstrap del microcontenedor


Antes de utilizar el cliente para implementar y llamar a su servicio, mire detalladamente lo que pas durante la construccin:
public Client(final boolean useBus) throws Exception { this.useBus = useBus;

21

Captulo 4. Uso de los servicios


ClassLoader cl = Thread.currentThread().getContextClassLoader(); url = cl.getResource("jboss-beans.xml"); // Start JBoss Microcontainer bootstrap = new EmbeddedBootstrap(); bootstrap.run(); kernel = bootstrap.getKernel(); controller = kernel.getController(); bus = kernel.getBus(); }

Primero que todo se cre una URL que representa el descriptor de implementacin jbossbeans.xml. Esto se necesita luego de manera que el programa de implementacin XML pueda implementar y borrar la implementacin de los beans declarados en el archivo. El mtodo getResource() del cargador de clase de la aplicacin se utiliza ya que se incluye el archivo jboss-beans.xml en la ruta de clase. esto es opcional; el nombre y ubicacin del descriptor de implementacin no son importantes en tanto la URL sea vlida y se pueda llegar a ella. Luego se crea una instancia de JBoss Microcontainer junto con un programa de implementacin XML. Este proceso se llama bootstrapping y se proporciona una clase llamada BasicBootstrap como parte del microcontenedor para tener en cuenta la configuracin programtica. Para agregar un programa de implementacin XML, extienda BasicBootstrap para crear una clase EmbeddedBootstrap y sobrescriba el mtodo protegido bootstrap() as:
public class EmbeddedBootstrap extends BasicBootstrap { protected BasicXMLDeployer deployer; public EmbeddedBootstrap() throws Exception { super(); } public void bootstrap() throws Throwable { super.bootstrap(); deployer = new BasicXMLDeployer(getKernel()); Runtime.getRuntime().addShutdownHook(new Shutdown()); } public void deploy(URL url) { ... deployer.deploy(url); ... } public void undeploy(URL url) { ... deployer.undeploy(url); ... } protected class Shutdown extends Thread { public void run() { log.info("Shutting down"); deployer.shutdown(); } } }

22

Implementacin del servicio El gancho shutdown se asegura de que cuando la MVJ termina, se borra la implementacin de todos los beans en el orden correcto. Los mtodos pblicos deploy/undeploy delegan al BasicXMLDeployer de manera que los beans declarados en jboss-beans.xml se puedan implementar y borrar. Finalmente las referencias al controlador del microcontenedor y el bus se reestablecen as que puede buscar las referencias de beans por su nombre y puede accederlas directamente o indirectamente cuando los necesite.

4.2. Implementacin del servicio


Despus de crear el cliente puede implementar el servicio de recursos humanos. Esto se logra introduciendo la opcin d del TUI. La salida indica que el BasicXMLDeployer ha analizado sintcticamente el archivo jboss-beans.xml usando la URL y ha instanciado los beans que se encuentran adentro.

Nota
El microcontenedor puede instanciar los beans ya que sus clases estn disponibles en la ruta de clase de extensin dentro del archivo lib/humanResourcesService.jar. Tambin puede poner estas clases en una estructura de directorio expandido y agregarla a la ruta de clase de la aplicacin, pero el empacarlos en una JAR usualmente es ms conveniente.

El descriptor de implementacin es completamente separado del archivo humanResourcesService.jar. Esto permite modificarlo para propsitos de pruebas. El archivo jboss-beans.xml en el ejemplo contiene algunos fragmentos de XML comentados, lo cual muestra algunas de las configuraciones posibles.
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd" xmlns="urn:jboss:bean-deployer:2.0"> <bean name="HRService" class="org.jboss.example.service.HRManager"> <!-- <property name="hiringFreeze">true</property> <property name="salaryStrategy"><inject bean="AgeBasedSalary"/></property> --> </bean> <!-- <bean name="AgeBasedSalary" class="org.jboss.example.service.util.AgeBasedSalaryStrategy"> <property name="minSalary">1000</property> <property name="maxSalary">80000</property> </bean> <bean name="LocationBasedSalary" class="org.jboss.example.service.util.LocationBasedSalaryStrategy"> <property name="minSalary">2000</property> <property name="maxSalary">90000</property> </bean> --> </deployment>

23

Captulo 4. Uso de los servicios

Importante
Dependiendo de la manera en que acceda el servicio en tiempo de ejecucin es posible que necesite apagar la aplicacin y re-iniciarla para volver a implementar el servicio y ver sus cambios. Esto reduce la flexibilidad de la aplicacin, pero incrementa el rendimiento en tiempo de ejecucin. Opcionalmente puede simplemente volver a implementar el servicio mientras que la aplicacin est ejecutando. Esto incrementa la flexibilidad pero disminuye el rendimiento en tiempo de ejecucin. Mantenga estas opciones en consideracin al disear sus aplicaciones.

4.3. Acceso directo


Si no se le pasan parmetros al script run.sh cuando se inicia el cliente entonces se busca una referencia al bean HRService usando el controlador del microcontenedor despus de que se ha implementado el servicio:
private HRManager manager; ... private final static String HRSERVICE = "HRService"; ... void deploy() { bootstrap.deploy(url); if (!useBus && manager == null) { ControllerContext context = controller.getInstalledContext(HRSERVICE); if (context != null) { manager = (HRManager) context.getTarget(); } } }

En lugar del buscar inmediatamente una referencia a la instancia del bean, el ejemplo primero busca una referencia a un ControllerContext, luego obtiene una referencia a la instancia del bean del contexto utilizando el mtodo getTarget(). El bean puede existir dentro del microcontenedor en cualquiera de los estados listados en Estados de un Bean dentro del microcontenedor. Estados de un Bean dentro del microcontenedor NO_INSTALADO DESCRITO INSTANCIADO CONFIGURADO INSTALADO Para mantener el registro de en qu estado se encuentra el bean, envulvalo en otro objeto llamado un context, el cual describe el estado actual. El nombre del contexto es el mismo que el nombre del bean. Una vez que un contexto alcanza el estado INSTALADO entonces el bean que representa se considera implementado. Despus de crear una referencia a la instancia del bean que representa el punto de entrada del servicio, puede llamar a los mtodos en este para realizar tareas: 24

Acceso directo

@SuppressWarnings("unchecked") Set<Employee> listEmployees() { if (useBus) ... else return manager.getEmployees(); }

El cliente est accediendo el servicio directamente ya que est utilizando una referencia a la instancia del bean real. El rendimiento es bueno ya que cada llamada de mtodo va directamente al bean. Sin embargo, Qu pasa si desea re-configurar el servicio y volver a implementarlo mientras la aplicacin est ejecutando? La re-configuracin se logra realizando cambios al descriptor de implementacin XML y guardando el archivo. Con el fin de volver a implementar el servicio, se debe borrar la implementacin de la instancia actual. Al borrar la implementacin el controlador del microcontenedor libera su referencia a la instancia del bean, junto con los beans dependientes. Posteriormente estos beans se harn disponibles para el servicio de recoleccin de basura ya que la aplicacin ya no los necesita ms. El volver a implementar el servicio crea nuevas instancias del bean representando la nueva configuracin. Cualquier bsqueda posterior de parte de los clientes recuperar las referencias a estas nuevas instancias y podrn volver a acceder el servicio re-configurado. El problema es que la referencia a la instancia del bean que representa nuestro punto de entrada del servicio va al cach cuando implementa el servicio por primera vez. El borrar la implementacin del servicio no tienen ningn efecto ya que la instancia del bean todava se puede acceder usando la referencia en cach y no ir a la basura hasta que el cliente la libere. De la misma manera, el implementar el servicio de nuevo no generar otra bsqueda ya que el cliente ya tiene una referencia en cach. Por lo tanto continuar utilizando la instancia del bean representando la configuracin del servicio inicial. Puebe probar este comportamiento escribiendo u seguido de RETURN para borrar la implementacin del servicio actual. Debe poder acceder el servicio todava desde el cliente aunque haya 'borrado' la implementacin. Luego, realice algunos cambios a la configuracin utilizando el archivo jbossbeans.xml, guarde el archivo y vuelva a implementarlo usando la opcin d. Puede imprimir el estatus del servicio utilizando la opcin p, la cual muestra que el cliente todava est accediendo la instancia inicial del servicio que se implement.

Aviso
Incluso si modifica el cliente para que busque una nueva referencia cada vez que el servicio se vuelve a implementar, es posible que los nuevos desarrolladores entreguen por error copias de esta referencia a otros objetos. Si todas estas referencias no se limpian al volver a realizar la implementacin se puede presentar el mismo problema de cach.

Para volver a implementar el servicio reconfigurado de manera confiable, apague la aplicacin completamente utilizando la opcin 'q' y reincela usando el script run.sh. Para servicios empresariales tal como transacciones, mensajera y persistencia este es un comportamiento completamente aceptable ya que generalmente se utilizan. No se pueden volver a implementar en tiempo de ejecucin y tambin se benefician del alto rendimiento dado por el uso del acceso directo. 25

Captulo 4. Uso de los servicios Si su servicio cae en esta categoria, considere el utilizar el acceso directo por medio del controlador del microcontenedor.

4.4. Acceso indirecto


El script run.sh se puede llamar con un parmetro opcional bus, el cual hace que las llamadas al servicio de recursos humanos utilicen el bus del microcontenedor. En lugar de utilizar una referencia directa a la instancia del bean que se obtuvo del controlador microcontenedor, el nuevo comportamiento es llamar a un mtodo invoke() en el bus, pasando el nombre del bean, el nombre del mtodo, los argumentos del mtodo y los tipos de mtodo. El bus usa esta informacin para llamar al bean de parte del cliente.
private final static String HRSERVICE = "HRService"; ... @SuppressWarnings("unchecked") Set<Employee> listEmployees() { if (useBus) return (Set<Employee>) invoke(HRSERVICE, "getEmployees", new Object[] {}, new String[] {}); else return manager.getEmployees(); } private Object invoke(String serviceName, String methodName, Object[] args, String[] types) { Object result = null; try { result = bus.invoke(serviceName, methodName, args, types); } catch (Throwable t) { t.printStackTrace(); } return result; }

El bus busca la referencia a la instancia del bean nombrado y llama al mtodo seleccionado usando la reflexin. El cliente nunca tiene una referencia directa a la instancia del bean as que se dice que accede al servicio indirectamente. Ya que el bus no pone en el cach la referencia puede realizar de manera segura los cambios a la configuracin del servicio y se puede volver a implementar en tiempo de ejecucin. Las llamadas posteriores por parte del cliente utilizarn la nueva referencia tal como se espera. El cliente y el servicio han sido desvinculados.

Nota
Este comportamiento se puede probar implementado el servicio y utilizando la opcin p para imprimir el estatus. Borre la implementacin del servicio utilizando la opcin u y observe que es inaccesible. Luego realice algunos cambios al archivo jboss-beans.xml, guarde los cambios e implemente de nuevo usando la opcin d. Imprima el estatus de nuevo usando la opcin p. El cliente est accediendo la nueva configuracin del servicio.

Ya que el bus usa la reflecin para llamar instancias del bean, es un poco ms lento que el acceso directo. El beneficio del enfoque es que solo el bus tiene referencias a las instancias del bean. Cuando un servicio se vuelve a implementar, todas las referencias existentes se pueden limpiar y reemplazar con las nuevas. De esta manera, se puede volver a implementar de manera segura 26

Carga de clase dinmica un servicio en tiempo de ejecucin. Los servicios que no se utilizan con tanta frecuencia o que son especificos para ciertas aplicaciones son buenos candidatos para acceso indirect usando el bus del microcontenedor. Con frecuencia la reduccin en el rendimiento es superior a la flexibilidad que proporciona.

4.5. Carga de clase dinmica


Hasta ahora ha utilizado los cargadores de clase de aplicacin y extensin para cargar todas las clases en la aplicacin. La ruta de clase de la aplicacin se configura por medio del script run.sh utilizando la etiqueta -cp para incluir el directorio actual y la client-1.0.0.jar como se puede ver aqu:
java -Djava.ext.dirs=`pwd`/lib -cp .:client-1.0.0.jar org.jboss.example.client.Client $1

Por comodidad las JARs en el directorio lib se agregaron a la extensin de la ruta de clase del cargador de clase usando la propiedad del sistema java.ext.dirs, en lugar de listar la ruta completa para cada una de las JARs despus de la etiqueta -cp. Ya que la extensin classloader es padre de la aplicacin classloader, las clases del cliente pueden encontrar todas las clases del microcontenedor y las clases del servicio de recursos humanos en tiempo de ejecucin.

Nota
Con las versiones de Java 6 y posteriores puede utilizar un comodn para incluir todas las JARs en un directorio con la etiqueta -cp: java -cp `pwd`/lib/*:.:client-1.0.0.jar org.jboss.example.client.Client $1 Aqu todas las clases en la aplicaci se agregarn a la ruta de clase del cargador de clase de la aplicacin y extensin de la ruta de clase del cargador de clase retendr su valor predeterminado.

Qu pasa si necesita implementar un servicio adicional en tiempo de ejecucin? Si el nuevo servicio est empacado en un archivo JAR debe ser visible para un cargador de clase antes de que cualquiera de sus clases puedan ser cargadas. Ya que ya configur la ruta de clase para el cargador de clase de la aplicacin (y el cargador de clase de extensin) en el arranque, no es fcil el agregar la URL de la JAR. La misma situacin aplica si las clases del servicio se encuentran en una estructura de directorio. A menos de que el directorio a nivel superior se encuentre en el directorio actual (el cual est en la ruta de clase de la aplicacin) entonces el cargador de clase de la aplicacin no encoentrar las clases. Si desea volver a implementar un servicio existente cambiando algunas de sus clases, necesita trabajar teniendo en cuenta las restricciones de seguridad, las cuales le impiden a un cargador de clase existente el volver a cargar las clases. La meta es crear un nuevo cargador de clases que conozca la ubicacin de las clases del nuevo servicio o que pueda cargar nuevas versiones de las clases de un servicio ya existente con el fin de implementar los beans del servicio. JBoss Microcontainer usa el elemento <classloader> en el descriptor de implementacin para lograr esto. La distribucin client-cl contiene el archivo listado en el Ejemplo 4.5, Listado del directorio commandLineClient/target/client-cl . 27

Captulo 4. Uso de los servicios

Ejemplo 4.5. Listado del directorio commandLineClient/target/client-cl

|-- client-1.0.0.jar |-- jboss-beans.xml |-- lib | |-- concurrent-1.3.4.jar | |-- jboss-common-core-2.0.4.GA.jar | |-- jboss-common-core-2.2.1.GA.jar | |-- jboss-common-logging-log4j-2.0.4.GA.jar | |-- jboss-common-logging-spi-2.0.4.GA.jar | |-- jboss-container-2.0.0.Beta6.jar | |-- jboss-dependency-2.0.0.Beta6.jar | |-- jboss-kernel-2.0.0.Beta6.jar | |-- jbossxb-2.0.0.CR4.jar | |-- log4j-1.2.14.jar | `-- xercesImpl-2.7.1.jar |-- otherLib | `-- humanResourcesService-1.0.0.jar |`-- run.sh

Se ha movido el archivo humanResourcesService.jar a un nuevo sub-directorio llamado otherLib. Ya no est disponible para los cargadores de clase de extensin o de la aplicacin, coya ruta de clase se configura en el script run.sh:
java -Djava.ext.dirs=`pwd`/lib -cp .:client-1.0.0.jar org.jboss.example.client.Client $1

Para solucionar esto cree un nuevo cargador de clase durante la implementacin del servicio, crguela en las clases del servicio y cree instancias de los beans. Para ver cmo se logra esto vea el contenido del archivo jboss-beans.xml:
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd" xmlns="urn:jboss:bean-deployer:2.0"> <bean name="URL" class="java.net.URL"> <constructor> <parameter>file:/Users/newtonm/jbossmc/microcontainer/trunk/docs/examples/ User_Guide/gettingStarted/commandLineClient/target/client-cl.dir/otherLib/ humanResourcesService-1.0.0.jar</parameter> </constructor> </bean> <bean name="customCL" class="java.net.URLClassLoader"> <constructor> <parameter> <array> <inject bean="URL"/> </array> </parameter> </constructor> </bean> <bean name="HRService" class="org.jboss.example.service.HRManager"> <classloader><inject bean="customCL"/></classloader> <!-- <property name="hiringFreeze">true</property> <property name="salaryStrategy"><inject bean="AgeBasedSalary"/></property> --> </bean>

28

Carga de clase dinmica


<!-- <bean name="AgeBasedSalary" class="org.jboss.example.service.util.AgeBasedSalaryStrategy"> <property name="minSalary">1000</property> <property name="maxSalary">80000</property> </bean> <bean name="LocationBasedSalary" class="org.jboss.example.service.util.LocationBasedSalaryStrategy"> <property name="minSalary">2000</property> <property name="maxSalary">90000</property> </bean> --> </deployment>

1.

Primero cree una instancia de java.net.URL llamada URL, usando la inyeccin de parmetros en el constructor para especificar la ubicacion del archivo humanResourcesService.jar en el sistema local de archivos. Luego, cree una instancia de un URLClassLoader inyectando el bean URL en el constructor como nico elemento en el array. Incluya un elemento <classloader> en su definicin de bean HRService e inyecte el bean customCL. Esto especifica que la clase HRManager necesita ser cargada por el cargador de clase customCL.

2. 3.

Necesita una manera de decidir cul cargador de clase utilizar para los otros beans en la implementacin. Todos los beans en la implementacin utilizan el cargador de clase del contexto del hilo actual. En este caso el hilo que maneja la implementacin es el hilo principal de la aplicacin, el cual tiene su cargador de clase de contexto establecido para el cargador de clase de la aplicacin durnate el arranque. Si desea puede especificar un cargador de clase diferente para toda la implementacin utilizando un elemento <classloader> como se puede ver en Ejemplo 4.6, Especificar un cargador de clase diferente. Ejemplo 4.6. Especificar un cargador de clase diferente
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd" xmlns="urn:jboss:bean-deployer:2.0"> <classloader><inject bean="customCL"/></classloader> <bean name="URL" class="java.net.URL"> <constructor> <parameter>file:/Users/newtonm/jbossmc/microcontainer/trunk/docs/examples/ User_Guide/gettingStarted/commandLineClient/target/client-cl.dir/otherLib/ humanResourcesService-1.0.0.jar</parameter> </constructor> </bean> <bean name="customCL" class="java.net.URLClassLoader"> <constructor> <parameter> <array> <inject bean="URL"/> </array> </parameter> </constructor> </bean>

29

Captulo 4. Uso de los servicios

... </deployment>

Esto sera necesario para permitir la reconfiguracin del service al borrar los comentarios de los beans AgeBasedSalary o LocationBasedSalary. Los cargadores de clase especificados a nivel del bean sobreescriben el cargador de clase a nivel de la implementacin. Para sobreescribir el cargador de clase a nivel de implementacin y utilizar el cargador de clase predeterminado para un bean, use el valor <null/> as:
<bean name="HRService" class="org.jboss.example.service.HRManager"> <classloader><null/></classloader> </bean>

4.5.1. Problemas con cargadores de clase creados con los descriptores de implementacin
Si crea un nuevo cargador de clase para su servicio utilizando el descriptor de implementacin es posible que no pueda acceder las clases cargadas por este desde el cargador de clase de la aplicacin. En el ejemplo HRManager, el cliente ya no puede poner en cach una referencia directa a la instancia del bean al utilizar el controlador del microcontenedor. Para ver este comportamiento inicie el cliente usando el comando run.sh y luego trate de implementar el servicio. Se presenta una excepcin java.lang.NoClassDefFoundError y la aplicacin termina. En este escenario debe usar el bus para acceder el servicio indirectamente y proporcionar acceso a cualquier clase compartida por el cliente en la ruta de clase de la aplicacin. En este ejemplo, las clases afectadas son Address, Employee y SalaryStrategy.

30

Agregar comportamiento con AOP


La programacin orientada a objetos (OOP del ingls Object Oriented Programming) tiene muchas tcnicas tiles para el desarrollo de software incluyendo la encapsulacin, herencia y polimorfismo. Sin embargo, no soluciona el problema de la lgica de direccionamiento que con frecuencia se repite en muchas clases diferentes. Ejemplos de esto incluye los registros, seguridad y lgica transaccional, la cual es tradicionalmente codificada a fuego en cada clase. Este tipo de lgica se llama un asunto de corte transversal. La programacin orientada a aspectos (AOP del ingles Aspect Oriented Programming funciona para permitir el aplicar asuntos de corte transversal a las clases despus de que se han compilado. Esto mantiene el cdigo fuente libre de lgica, lo cual no es una parte central del propsito principal de la clase y optimiza el mantenimiento. El mtodo depende de la implementacin AOP. Usualmente si una clase implementa una interfaz, cada llamada de mtodo a una instancia de la clase primero pasa por un proxy. Este proxy implementa la misma interfaz, agregando el comportamiento requerido. Opcionalmente, si no se utiliza una interfaz entonces el cdigo byte java de la clase compilada se modifica: los mtodos originales se re-nombran y se reemplazan con mtodos que implementan la lgica de corte transversal. Luego estos nuevos mtodos llaman a los mtodos originales despus de haber ejecutado la lgica de corte transversal. Otro mtodo para lograr el mismo resultado es modificar el cdigo byte para crear una subclase de la clase original que sobreescribe sus mtodos. Los mtodos sobreescritos luego ejecutan la lgica de corte transversal antes de llamar los mtodos correspondiente de la super clase. JBoss AOP es un marco de trabajo para AOP. Utilizndolo puede crear asuntos de corte transversal utilizando mtodos y clases java convencionales. En terminologia de AOP cada asunto est representado por un aspecto que usted implementa utilizando un POJO simple. El comportamiento lo proporciona los mtodos dentro del aspecto llamado consejos. Estos consejos siguen ciertas reglas para su parmetro y retornan tiposy cualquier excepcin que presenten. Dentro de este marco de trabajo puede utilizar nociones convencionales orientadas a objetos tal como la herencia, encapsulacin y composicin para hacer que sus asuntos de corte transversal sean fciles de mantener. Los aspectos se aplican al cdigo utilizando un lenguaje de expresiones que le permite especificar los constructores, los mtodos e incluso los campos de destino. Puede cambiar rpidamente el comportamiento de mltiples clases modificando el archivo de configuracin. Este captulo contiene ejemplos, los cuales demuestran cmo utilizar JBoss AOP junto con el microcontenedor para crear y aplicar un aspecto de auditora al servicio de recursos humanos. El cdigo de auditora se puede poner dentro de la clase HRManager, pero llenara la clase con cdigo que no es relevante para su propsito principal, expandindola y haciendo ms dificil el mantenerla. El diseo del aspecto tambin proporciona modularidad, facilitando el auditar otras clases en el futuro, si el mbito del proyecto cambia. AOP tambin se puede utilizar para aplicar comportamiento adicional durante la fase de implementacin. Este ejemplo crear y enlazar un proxy a una instancia bean en un servicio bsico JNDI, permitiendo accederlo utilizando una bsqueda JNDI en lugar del controlador del microcontenedor.

5.1. Creacin de un aspecto


El directorio examples/User_Guide/gettingStarted/auditAspect contiene todos los archivos necesarios para crear el aspecto. pom.xml src/main/java/org/jboss/example/aspect/AuditAspect.java 31

Captulo 5. Agregar comportamiento con AOP

Ejemplo 5.1. POJO de ejemplo


public class AuditAspect { private String logDir; private BufferedWriter out; public AuditAspect() { logDir = System.getProperty("user.dir") + "/log"; File directory = new File(logDir); if (!directory.exists()) { directory.mkdir(); } } public Object audit(ConstructorInvocation inv) throws Throwable { SimpleDateFormat formatter = new SimpleDateFormat("ddMMyyyy-kkmmss"); Calendar now = Calendar.getInstance(); String filename = "auditLog-" + formatter.format(now.getTime()); File auditLog = new File(logDir + "/" + filename); auditLog.createNewFile(); out = new BufferedWriter(new FileWriter(auditLog)); return inv.invokeNext(); } public Object audit(MethodInvocation inv) throws Throwable { String name = inv.getMethod().getName(); Object[] args = inv.getArguments(); Object retVal = inv.invokeNext(); StringBuffer buffer = new StringBuffer(); for (int i=0; i < args.length; i++) { if (i > 0) { buffer.append(", "); } buffer.append(args[i].toString()); } if (out != null) { out.write("Method: " + name); if (buffer.length() > 0) { out.write(" Args: " + buffer.toString()); } if (retVal != null) { out.write(" Return: " + retVal.toString()); } out.write("\n"); out.flush(); } return retVal; } }

Procedimiento 5.1. Creacin del POJO 1. El constructor chequea a ver si hay un directorio log en el directorio actual de trabajo y lo crea si no lo encuentra.

32

Configuracin del microcontenedor para AOP 2. Luego se define un aviso. Se llama a este aviso cuando se llama al constructor de la clase de destino. Esto crea un nuevo archivo de registro dentro del directorio log para registrar la llamadas de mtodos realizadas en diferentes instancias de la clase destino en archivos separados. Finalmente se define otro aviso. Este aviso aplica a cada llamada de mtodo realizada en la clase destino.El nombre del mtodo y los argumentos se almacenan junto con el valor de retorno. Esta informacin se utiliza para construir un registro de auditora y escribirlo en el archivo de registro actual. Cada aviso llama a inv.invokeNext(), el cual encadena los avisos si se ha aplicado ms de un asunto de corte transversal o para llamar el constructor/mtodo destino.

3.

Nota
Cada aviso se implementa utilizando un mtodo que toma un objeto de invocacin como parmetro, presenta Throwable y retorna Object. En el momento del diseo no se sabe a qu constructores o mtodos se aplicarn estos avisos as que haga los tipos tan genricos como sea posible.

Para compilar la clase y crear un archivo auditAspect.jar que lo puedan utilizar otros ejemplos, escriba mvn install desde el directorio auditAspect.

5.2. Configuracin del microcontenedor para AOP


Antes de aplicar el aspecto de auditora al servicio de recursos humanos, se debe agregar un nmero de JARs a la ruta de clase de la extensin. Se encuentran en el sub-directorio lib de la distribucin client-aop que se encuentra en el directorio examples/User_Guide/gettingStarted/ commandLineClient/target/client-aop.dir: Ejemplo 5.2. Listado del directorio examples/User_Guide/gettingStarted/commandLineClient/target/ client-aop.dir

|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-`-|-`-`--

client-1.0.0.jar jboss-beans.xml lib auditAspect-1.0.0.jar concurrent-1.3.4.jar humanResourcesService-1.0.0.jar javassist-3.6.0.GA.jar jboss-aop-2.0.0.beta1.jar jboss-aop-mc-int-2.0.0.Beta6.jar jboss-common-core-2.0.4.GA.jar jboss-common-core-2.2.1.GA.jar jboss-common-logging-log4j-2.0.4.GA.jar jboss-common-logging-spi-2.0.4.GA.jar jboss-container-2.0.0.Beta6.jar jboss-dependency-2.0.0.Beta6.jar jboss-kernel-2.0.0.Beta6.jar jbossxb-2.0.0.CR4.jar log4j-1.2.14.jar trove-2.1.1.jar xercesImpl-2.7.1.jar log auditLog-18062010-122537 run.sh

33

Captulo 5. Agregar comportamiento con AOP Primero, se necesita lib/auditAspect-1.0.0.jar para crear una instancia del aspecto en tiempo de ejecucin con el fin de ejecutar la lgica. Luego el archivo jar para JBoss AOP (jbossaop.jar) junto con sus dependencias javassist y trove, agrega la funcionalidad AOP. Finalmente, se necesita la jar jboss-aop-mc-int ya que contiene una definicin de esquema XML que le permite definir aspectos dentro de un descriptor de implementacin XML. Tambin contiene cdigo de integracin para crear dependencias entre beans normales y beans de aspecto dentro del microcontenedor, permitindole agregar comportamiento durante las fases de implementacin y de borrado de la implementacin. Ya que est utilizando Maven2 para montar la distribucin cliente-aop, debe agregar estos archivos JAR declarando las dependencias apropiadas en su archivo pom.xml y creando un descriptor de ensamblaje vlido. Puede ver un ejemplo de pom.xml en Ejemplo 5.3, Extracto de ejemplo pom.xml para AOP. Para realizar su construccin utilizando Ant, el procedimiento ser diferente. Ejemplo 5.3. Extracto de ejemplo pom.xml para AOP
<dependency> <groupId>org.jboss.microcontainer.examples</groupId> <artifactId>jboss-oap</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.jboss.microcontainer.examples</groupId> <artifactId>javassist</artifactId> <version>3.6.0.GA</version> </dependency> <dependency> <groupId>org.jboss.microcontainer.examples</groupId> <artifactId>trove</artifactId> <version>2.1.1</version> </dependency> <dependency> <groupId>org.jboss.microcontainer.examples</groupId> <artifactId>jboss-aop-mc-int</artifactId> <version>2.0.0.Beta6</version> </dependency>

5.3. Aplicacin de un aspecto


Ahora que tiene una distribucin vlida que contiene todo lo que necesitad, puede configurar jbossbeans.xml para aplicar el aspecto de auditora. Se encuentra en examples/User_Guide/ gettingStarted/commandLineClient/target/client-aop.dir.
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd" xmlns="urn:jboss:bean-deployer:2.0"> <bean name="AspectManager" class="org.jboss.aop.AspectManager"> <constructor factoryClass="org.jboss.aop.AspectManager" factoryMethod="instance"/> </bean> <aop:aspect xmlns:aop="urn:jboss:aop-beans:1.0" name="AuditAspect" class="org.jboss.example.aspect.AuditAspect" method="audit" pointcut="execution(public org.jboss.example.service.HRManager>new(..)) OR execution(public * org.jboss.example.service.HRManager->*(..))"> </aop:aspect>

34

Aplicacin de un aspecto

... </deployment>

Procedimiento 5.2. Explicacin del cdigo para aplicar un aspecto 1. Antes de que pueda aplicar su aspecto a cualquier clase necesita crear una instancia de org.jboss.aop.AspectManager usando un elemento <bean>. Aqu se utiliza un mtodo de fbrica en lugar de llamar un constructor convencional ya que solo es necesario una instancia del AspectManager en la MVJ en tiempo de ejecucin. 2. Luego se crea una instancia de nuestro aspecto llamada AuditAspect, utilizando el elemento <aop:aspect>. Este se ve similar al elemento <bean> ya que tiene los atributos name y class que se utilizan de la misma manera. Sin embargo, tambin tiene los atributos method y pointcut que puede utilizar para aplicar o enlazar un consejo dentro del aspecto para los constructores y mtodos dentro de otras clases. Estos atributos enlazan el consejo de auditora a todos los constructores y mtodos pblicos dentro de la clase HRManager. Slo es necesario especificar el mtodo audit ya que ha sido sobrecargado dentro de la clase AuditAspect con diferentes parmetros. JBoss AOP sabe cul seleccionar en tiempo de ejecucin dependiendo de si se est realizando una invocacin de mtodo o constructor.

Esta configuracin adicional es todo lo que se necesita para aplicar el aspecto de auditora en tiempo de ejecucin agregando un comportamiento de auditora al servicio Human Resources. Puede probar esto ejecutando el cliente utilizando el script run.sh. Se crea un directorio log al iniciar junto con el directorio lib cuando el microcontenedor crea el bean AuditAspect. Cada implementacin del servicio de recursos humanos hace que aparezca un nuevo archivo de registros dentro del directorio log. El archivo de registro contiene un registro de las llamadas realizadas del cliente al servicio. Se llama algo como auditLog-28112007-163902 y contiene salidas similares a Ejemplo 5.4, Ejemplo de la salida del registro AOP. Ejemplo 5.4. Ejemplo de la salida del registro AOP

Method: getEmployees Return: [] Method: addEmployee Args: (Santa Claus, 1 Reindeer Avenue, Lapland City 25/12/1860) Return: true Method: getSalary Args: (Santa Claus, null - Birth date unknown) Return: 10000 Method: getEmployees Return: [(Santa Claus, 1 Reindeer Avenue, Lapland City 25/12/1860)] Method: isHiringFreeze Return: false Method: getEmployees Return: [(Santa Claus, 1 Reindeer Avenue, Lapland City 25/12/1860)] Method: getSalaryStrategy

Para borrar el comportamiento de auditora, comente los fragmentos relevantes de XML en el descriptor de implementacin y re-inicie la aplicacin.

35

Captulo 5. Agregar comportamiento con AOP

Aviso
El orden de la implementacin s importa. Especificamente cada aspecto debe ser declarado antes de los beans a los que aplica, as que el microcontenedor los implementa en ese orden. Esto se debe a que es posible que el microcontenedor tenga que alterar el cdigo byte de la clase bean para agregar la lgica cross-cutting, antes de crear una instancia y almacena una referencia a esta en el controlador. Si ya se ha creado una instancia normal del bean entonces no es posible.

5.4. Callbacks del ciclo de vida


Adems de aplicar aspectos a los beans que instanciamos utilizando el microcontenedor tambin podemos agregar comportamiento durante el proceso de implementacin y de borrado de la implementacin. Tal como lo mencinamos en Seccin 4.3, Acceso directo, un bean atravieza varios estados diferentes cuando se implementa. Estos incluyen: NOT_INSTALLED el descriptor de implementacin que contiene el bean ha sido analizado sintcticamente junto con cualquier anotacin en el bean mismo. DESCRIBED cualquier dependencia que AOP ha creado ha sido agregada al bean y se han procesado las anotaciones personalizadas. INSTANTIATED se ha creado una instancia del bean. CONFIGURED se han inyectado las propiedades en el bean junto con cualquier otra referencia a los otros beans. CREATE se ha llamado al mtodo create, si est definido en el bean. START se ha llamado al mtodo start, si est definido en el bean. INSTALLED cualquier accin de instalacin personalizada que se defini en el descriptor de implementacin se ha ejecutado y est listo para acceder al bean.

Importante
Los estados CREATE y START estn includos por razones de legado. Esto le permite a los servicios que estaban implementados como MBeans en versiones anteriores de la plataforma empresarial el funcionar correctamente cuando se implementan como beans en la plataforma empresarial 5.1. Si no define ningn mtodo crear/inicar correspondientes en su bean, pasar derecho por estos estados.

36

Callbacks del ciclo de vida Estos estados representan el ciclo de vida del bean. Puede definir un nmero de callbacks para que se apliquen en cualquier momento utilizando un grupo adicional de elementos <aop>. <aop:lifecycle-describe> aplicado al entrar/salir del estado DESCRIBED <aop:lifecycle-instantiate> aplicado al entrar/salir del estado INSTANTIATED <aop:lifecycle-configure> aplicado al entrar/salir del estado CONFIGURED <aop:lifecycle-create> aplicado al entrar/salir del estado CREATE <aop:lifecycle-start> aplicado al entrar/salir del estado START <aop:lifecycle-install> aplicado al entrar/salir del estado INSTALLED As como los elementos <bean> y <aop:aspect>, los elementos <aop:lifecycle-> contienen atributos name y class. El microcontenedor usa estos atributos para crear una instancia de la clase callback, nombrndola de manera que se pueda utilizar cuando los beans entren o salgan del estado relevante durante la implementacin y durante el borrado de la implementacin. Puede especificar cules beans son afectados por el callback utilizando el atributo clases como se puede ver en Ejemplo 5.5, Uso del atributo classes. Ejemplo 5.5. Uso del atributo classes
<aop:lifecycle-install xmlns:aop="urn:jboss:aop-beans:1.0" name="InstallAdvice" class="org.jboss.test.microcontainer.support.LifecycleCallback" classes="@org.jboss.test.microcontainer.support.Install"> </aop:lifecycle-install>

Este cdigo especifica que la lgica adicional en la clase lifecycleCallback se aplica a cualquier clase de bean que est anotada con @org.jboss.test.microcontainer.support.Install antes de que entren y luego de que han dejado el estado INSTALLED. Para que la clase callback funcione, debe contener los mtodos install y uninstall que toman ControllerContext como parmetro, como se puede ver en Ejemplo 5.6, Mtodos de instalacin y desinstalacin. Ejemplo 5.6. Mtodos de instalacin y desinstalacin
import org.jboss.dependency.spi.ControllerContext; public class LifecycleCallback { public void install(ControllerContext ctx) {

37

Captulo 5. Agregar comportamiento con AOP


System.out.println("Bean " + ctx.getName() + " is being installed"; } public void uninstall(ControllerContext ctx) { System.out.println("Bean " + ctx.getName() + " is being uninstalled"; } }

El mtodo install se llama durante la implementacin del bean y se llama al mtodo uninstall durante el borrado de la implementacin.

Nota
Aunque se est agregando comportamiento al proceso de implementacin y de borrado de la implementacin utilizando callbacks, AOP de ehcho no se utiliza aqu. La funcionalidad pointcut expression de JBoss AOP se utiliza para determinar a cules clases bean se aplican los comportamientos.

5.5. Agregar bsquedas de servicios por medio de JNDI


Hasta ahora ha utilizado el microcontenedor para buscar referencias a instancias del bean que representan servicios. Esto no es ideal ya que requiere una referencia al kernel del microcontenedor antes de poder acceder al controlador. Esto se puede ver en Ejemplo 5.7, Bsqueda de referencias a los Beans. Ejemplo 5.7. Bsqueda de referencias a los Beans
private private private private private ... // Start JBoss Microcontainer bootstrap = new EmbeddedBootstrap(); bootstrap.run(); kernel = bootstrap.getKernel(); controller = kernel.getController(); ... ControllerContext context = controller.getInstalledContext(HRSERVICE); if (context != null) { manager = (HRManager) context.getTarget(); } HRManager manager; EmbeddedBootstrap bootstrap; Kernel kernel; KernelController controller; final static String HRSERVICE = "HRService";

El entregar referencias del kernel a todos los clientes que buscan un servicio es un riesgo de seguridad ya que proporciona un amplio acceso a la configuracin del microcontenedor. Para mayor seguridad aplique el patrn ServiceLocator y utilice una clase para realizar bsquedas de parte de los clientes. Incluso puede pasar las referencias del bean junto con sus nombres al ServiceLocator en el momento de la implementacin utilizando un callback del ciclo de vida. En ese escenario, el ServiceLocator puede buscarlos sin llegar a saber del microcontenedor. El borrado de la 38

Agregar bsquedas de servicios por medio de JNDI implementacin posteriormente borrara las referencias del bean del ServiceLocator para evitar ms bsquedas. No sera dificil es escribir su propia implementacin ServiceLocator. En integrar una ya existente tal como JBoss Naming Service (JBoss NS) es incluso ms rpido y tiene el beneficio adicional de cumplir con la especificacin de JNDI - Java Naming and Directory Interface. JNDI habilita a los clientes para acceder diferentes y posiblemente mltiples servicios de nombrado utilizando una API comn. Procedimiento 5.3. Escritura de su propia implementacin ServiceLocator 1. Primero cree una instancia de JBoss NS usando el microcontenedor. 2. 3. 4. Luego, agregue un callback del ciclo de vida para realizar el enlace y des-enlace de las referencias bean durante la implementacin y durante el borrado de la implementacin. Marque las clases bean a las que desea enlazar sus referencias, utilizando anotaciones. Ahora puede ubicar los beans en tiempo de ejecucin utilizando la expresin como se mostr anteriormente.

39

40

Parte II. Conceptos avanzados con el microcontenedor


Esta seccin aborda conceptos avanzados y muestra algunas funcionalidades interesantes del microcontenedor. Se asume que los ejemplos de cdigo en el resto del manual son ejemplos incompletos y es responsabilidad del programador el extrapolarlos y extenderlos como sea necesario.

Modelos de componentes
El JBoss Microcontainer funciona dentro de varios modelos de componentes POJO populares. Los componentes son programas de software re-utilizables que puede desarrollar y ensamblar fcilmente para crear aplicaciones sofisticadas. Una de las metas clave del microcontenedor es la integracin efectiva con estos modelos de componentes. Algunos modelos de componentes populares que se pueden utilizar con el microcontenedor son JMX, Spring y Guice.

6.1. Interacciones permitidas con los modelos de componentes


Antes de discutir la interaccin como algunos de los modelos de componentes populares, es importante el comprender qu tipos de interacciones se permiten. JMX MBeans son un ejemplo de un modelo de componentes. Sus interacciones incluyen la ejecucin de operaciones MBean, referencia a atributos, el configurar atributos y la declaracin explcita de dependencias entre las MBeans nombradas. Las interacciones y comportamientos predeterminados en el microcontenedor son lo que normalmente obtiene de cualquier otro contenedor Inversin de Control (IoC del ingls >Inversion of Control) y es similar a la funcionalidad que los MBeans proporcionan, incluyendo simples invocaciones de mtodo para operaciones, setters/getters para los atributos y dependencias explcitas.

6.2. Un Bean sin dependencias


Ejemplo 6.1, Descriptor de implementacin para un POJO simple muestra un descriptor de implementacin para un POJO simple sin dependencias. Este es el punto inicial para integrar el microcontenedor con Spring o Guice. Ejemplo 6.1. Descriptor de implementacin para un POJO simple
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <bean name="PlainPojo" class="org.jboss.demos.models.plain.Pojo"/> <beanfactory name="PojoFactory" class="org.jboss.demos.models.plain.Pojo"> <property name="factoryClass">org.jboss.demos.models.plain.PojoFactory</property> </beanfactory> </deployment>

6.3. Uso del microcontenedor con Spring


Ejemplo 6.2. Descriptor con soporte para Spring
<beans xmlns="urn:jboss:spring-beans:2.0"> <!-- Adding @Spring annotation handler --> <bean id="SpringAnnotationPlugin" class="org.jboss.spring.annotations.SpringBeanAnnotationPlugin" /> <bean id="SpringPojo" class="org.jboss.demos.models.spring.Pojo"/> </beans>

43

Captulo 6. Modelos de componentes

El espacio de nombre del archivo es diferente del archivo del bean del microcontenedor. El espacio de nombre urn:jboss:spring-beans:2.0 apunta a su versin del puerto del esquema Spring, el cual describe el estilo Spring de su bean. El microcontenedor implementa los beans a manera opuesta de la nocin de fbrica de beans de Spring. Ejemplo 6.3. Uso de Spring con el microcontenedor
public class Pojo extends AbstractPojo implements BeanNameAware { private String beanName; public void setBeanName(String name) { beanName = name; } public String getBeanName() { return beanName; } public void start() { if ("SpringPojo".equals(getBeanName()) == false) throw new IllegalArgumentException("Name doesn't match: " + getBeanName()); } }

Aunque el bean SpringPojo tiene una dependencia en la biblioteca de Spring causada por la implementacin de la interfaz BeanNameAware, su nico propsito es exponer e imitar algo del comportamiento del callback de Spring.

6.4. Uso de Guice con el microcontenedor


El enfoque de Guice es el acomplamiento de tipos. Los beans Guice se generan y se configuran usando mdulos. Ejemplo 6.4. Descriptor de implementacin para la integracin Guice en el microcontenedor
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <bean name="GuicePlugin" class="org.jboss.guice.spi.GuiceKernelRegistryEntryPlugin"> <constructor> <parameter> <array elementClass="com.google.inject.Module"> <bean class="org.jboss.demos.models.guice.PojoModule"/> </array> </parameter> </constructor> </bean> </deployment>

44

Uso de Guice con el microcontenedor Dos partes importantes de observar en este archivo son PojoModule y GuiceKernelRegistryEntryPlugin. PojoModule configura sus beans tal como en Ejemplo 6.5, Configuracin de Beans para Guice. GuiceKernelRegistryEntryPlugin proporciona integracin con el microcontenedor tal como se puede ver en Ejemplo 6.6, Integracin mock con el microcontenedor. Ejemplo 6.5. Configuracin de Beans para Guice
public class PojoModule extends AbstractModule { private Controller controller; @Constructor public PojoModule(@Inject( bean = KernelConstants.KERNEL_CONTROLLER_NAME) Controller controller) { this.controller = controller; } protected void configure() { bind(Controller.class).toInstance(controller); bind(IPojo.class).to(Pojo.class).in(Scopes.SINGLETON); bind(IPojo.class).annotatedWith(FromMC.class). toProvider(GuiceIntegration.fromMicrocontainer(IPojo.class, "PlainPojo")); } }

Ejemplo 6.6. Integracin mock con el microcontenedor


public class GuiceKernelRegistryEntryPlugin implements KernelRegistryPlugin { private Injector injector; public GuiceKernelRegistryEntryPlugin(Module... modules) { injector = Guice.createInjector(modules); } public void destroy() { injector = null; } public KernelRegistryEntry getEntry(Object name) { KernelRegistryEntry entry = null; try { if (name instanceof Class<?>) { Class<?> clazz = (Class<?>)name; entry = new AbstractKernelRegistryEntry(name, injector.getInstance(clazz)); } else if (name instanceof Key) { Key<?> key = (Key<?>)name; entry = new AbstractKernelRegistryEntry(name, injector.getInstance(key)); } } catch (Exception ignored) {

45

Captulo 6. Modelos de componentes


} return entry; } }

Nota
Se crea un Injector desde la clase Modules luego realiza una bsqueda en este para ver si hay beans que coincidan. Consulte Seccin 6.5, MBeans de legado y mezcla de diferentes modelos de componentes para encontrar mayor informacin sobre la declaracin y uso de MBeans de legado.

6.5. MBeans de legado y mezcla de diferentes modelos de componentes


El ejemplo ms simple de mezclar diferentes modelos de contenido se puede ver en Ejemplo 6.7, Inyeccin de un POJO en un MBean. Ejemplo 6.7. Inyeccin de un POJO en un MBean
<server> <mbean code="org.jboss.demos.models.mbeans.Pojo" name="jboss.demos:service=pojo"> <attribute name="OtherPojo"><inject bean="PlainPojo"/></attribute> </mbean> </server>

Para implementar MBeans por medio del microcontenedor debe escribir un manejador nuevo por completo para el modelo de componentes. Consulte system-jmx-beans.xml para obtener mayores detalles. El cdigo de este archivo se encuentra en el cdigo fuente del servidor de aplicaciones JBoss: sub-proyecto system-jmx.

6.6. Exponer POJOs como MBeans


Ejemplo 6.8. Exponer un POJO existenete como un MBean
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <bean name="AnnotatedJMXPojo" class="org.jboss.demos.models.jmx.AtJmxPojo"/> <bean name="XmlJMXPojo" class="org.jboss.demos.models.mbeans.Pojo">

<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(exposedInterface=org.jboss.demos.models.mbeans.Po registerDirectly=true)</annotation> </bean> <bean name="ExposedPojo" class="org.jboss.demos.models.jmx.Pojo"/> <bean name="AnnotatedExposePojo" class="org.jboss.demos.models.jmx.ExposePojo">

46

Exponer POJOs como MBeans


<constructor> <parameter><inject bean="ExposedPojo"/></parameter> </constructor> </bean> </deployment>

Este descriptor presenta un POJO existente como un MBean y lo registra en un servidor MBean. Para exponer un POJO como un MBean finalcelo con una anotacin @JMX asumiendo que ha importado org.jboss.aop.microcontainer.aspects.jmx.JMX. El bean se puede exponer directamente o en su propiedad. Ejemplo 6.9. Presentacin de un POJO como un MBean usando su propiedad
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <bean name="XMLLoginConfig" class="org.jboss.demos.models.old.XMLLoginConfig"/> <bean name="SecurityConfig" class="org.jboss.demos.models.old.SecurityConfig"> <property name="defaultLoginConfig"><inject bean="XMLLoginConfig"/></property> </bean> <bean name="SecurityChecker" class="org.jboss.demos.models.old.Checker"> <property name="loginConfig"><inject bean="jboss.security:service=XMLLoginConfig"/></ property> <property name="securityConfig"><inject bean="jboss.security:service=SecurityConfig"/ ></property> </bean> </deployment>

Puede utilizar cualquiera de los tipos de bsqueda de inyeccin ya sea buscando un POJO simple u obteniendo un MBean del servidor MBean. Una de las opciones de inyeccin es utilizar la inyeccin de tipos, algunas veces llamada autowiring y se puede ver en Ejemplo 6.10, Autowiring. Ejemplo 6.10. Autowiring
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <bean name="FromGuice" class="org.jboss.demos.models.plain.FromGuice"> <constructor><parameter><inject bean="PlainPojo"/></parameter></constructor> <property name="guicePojo"><inject/></property> </bean> <bean name="AllPojos" class="org.jboss.demos.models.plain.AllPojos"> <property name="directMBean"><inject bean="jboss.demos:service=pojo"/></property> <property name="exposedMBean"><inject bean="jboss.demos:service=ExposedPojo"/></ property> <property name="exposedMBean"><inject bean="jboss.demos:service=ExposedPojo"/></ property> </bean> </deployment>

47

Captulo 6. Modelos de componentes El bean FromGuice inyecta el bean Guice por medio de la correspondencia de tipos, en donde PlainPojo se inyecta con una inyeccin de nombres comn. Ahora puede probar a ver si el enlace Guice funciona como se esperaba como se puede ver en Ejemplo 6.11, Prueba de la funcionalidad de Guice. Ejemplo 6.11. Prueba de la funcionalidad de Guice
public class FromGuice { private IPojo plainPojo; private org.jboss.demos.models.guice.Pojo guicePojo; public FromGuice(IPojo plainPojo) { this.plainPojo = plainPojo; } public void setGuicePojo(org.jboss.demos.models.guice.Pojo guicePojo) { this.guicePojo = guicePojo; } public void start() { f (plainPojo != guicePojo.getMcPojo()) throw new IllegalArgumentException("Pojos are not the same: " + plainPojo + "!=" + guicePojo.getMcPojo()); } }

Ejemplo 6.11, Prueba de la funcionalidad de Guice solo proporciona un modelo de componentes alias. El alias es una funcionalidad trivial pero necesaria. Se debe introducir como un modelo nuevo de componentes dentro del microcontenedor con el fin de implementarlo como una dependencia verdadera. Los detalles de la implementacin se pueden ver en Ejemplo 6.12, Cdigo fuente de AbstractController. Ejemplo 6.12. Cdigo fuente de AbstractController
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <alias name="SpringPojo">springPojo</alias> </deployment>

Este descriptor mapea el nombre del SpringPojo al alias del springPojo. El beneficio de los aliases como verdaeros modelos de componentes es que el momento de la implementacin del bean se vuelve menos importante. El alias espera en un estado no-instalado hasta que el bean real lo dispara.

48

Inyeccin avanzada de dependencias y ldC


Hoy en da la Inyeccin de Dependencias (ID), tambin llamada Inversin de Control (IdC), se encuentra en la parte central de muchos marcos de trabajo que adoptan la nocin de un contenedor o un modelo de componentes. En un captulo anterior abordamos los modelos de componentes. El kernel JBoss JMX, el precursor al microcontenedor, solo proporcionaba soporte ligero para ID/IdC , principalmente debido a las limitaciones del acceder los MBeans por medio del servidor MBeans. Sin embargo, con el nuevo modelo de componentes basados en POJO se encuentran disponibles varias nuevas e interesantes funcionalidades. Este captulo muestra la manera en que puede aplicar diferentes conceptos ID con la ayuda del microcotenedor JBoss. Estos conceptos se expresarn por medio del cdigo XML pero tambin puede aplicar la mayora de estas funcionalidades utilizando las anotaciones.

7.1. Fbrica de valores


Una fbrica de valores es un bean, el cual tiene uno o ms mtodos dedicados a generar valores por usted. Consulte Ejemplo 7.1, Fbrica de valores. Ejemplo 7.1. Fbrica de valores
<bean name="Binding" class="org.jboss.demos.ioc.vf.PortBindingManager"> <constructor> <parameter> <map keyClass="java.lang.String" valueClass="java.lang.Integer"> <entry> <key>http</key> <value>80</value> </entry> <entry> <key>ssh</key> <value>22</value> </entry> </map> </parameter> </constructor> </bean> <bean name="PortsConfig" class="org.jboss.demos.ioc.vf.PortsConfig"> <property name="http"><value-factory bean="Binding" method="getPort" parameter="http"/ ></property> <property name="ssh"><value-factory bean="Binding" method="getPort" parameter="ssh"/></ property> <property name="ftp"> <value-factory bean="Binding" method="getPort"> <parameter>ftp</parameter> <parameter>21</parameter> </value-factory> </property> <property name="mail"> <value-factory bean="Binding" method="getPort"> <parameter>mail</parameter> <parameter>25</parameter> </value-factory> </property> </bean>

49

Captulo 7. Inyeccin avanzada de dependencias y ldC Ejemplo 7.2, PortsConfig muestra la manera en que el bean PortsConfig usa el bean de enlace para obtener sus valores por medio de la invocacin del mtodo getPort. Ejemplo 7.2. PortsConfig
public class PortBindingManager { private Map<String, Integer> bindings; public PortBindingManager(Map<String, Integer> bindings) { this.bindings = bindings; } public Integer getPort(String key) { return getPort(key, null); } public Integer getPort(String key, Integer defaultValue) { if (bindings == null) return defaultValue; Integer value = bindings.get(key); if (value != null) return value; if (defaultValue != null) bindings.put(key, defaultValue); return defaultValue; } }

7.2. Callbacks
El descriptor que se puede ver en Ejemplo 7.3, Callbacks para reunir y filtrar beans le permite reunir todos los beans de un cierto tipo e incluso limitar el nmero de beans que coincidan. Junto con el descriptor en Ejemplo 7.3, Callbacks para reunir y filtrar beans, el cdigo Java que se puede ver en Ejemplo 7.4, Un analizador sintctico para reunir todos los editores muestra un Parser, el cual reune todos los Editores. Ejemplo 7.3. Callbacks para reunir y filtrar beans
<bean name="checker" class="org.jboss.demos.ioc.callback.Checker"> <constructor> <parameter> <value-factory bean="parser" method="parse"> <parameter> <array elementClass="java.lang.Object"> <value>http://www.jboss.org</value> <value>SI</value> <value>3.14</value> <value>42</value> </array> </parameter> </value-factory> </parameter> </constructor> </bean> <bean name="editorA" class="org.jboss.demos.ioc.callback.DoubleEditor"/> <bean name="editorB" class="org.jboss.demos.ioc.callback.LocaleEditor"/> <bean name="parser" class="org.jboss.demos.ioc.callback.Parser"> <incallback method="addEditor" cardinality="4..n"/> <uncallback method="removeEditor"/>

50

Modo de acceso del Bean


</bean> <bean name="editorC" class="org.jboss.demos.ioc.callback.LongEditor"/> <bean name="editorD" class="org.jboss.demos.ioc.callback.URLEditor"/>

Ejemplo 7.4. Un analizador sintctico para reunir todos los editores


public class Parser { private Set<Editor> editors = new HashSet<Editor>(); ... public void addEditor(Editor editor) { editors.add(editor); } public void removeEditor(Editor editor) { editors.remove(editor); } }

Observe que incallback y uncallback usan el nombre del mtodo para buscar.
<incallback method="addEditor" cardinality="4..n"/> <uncallback method="removeEditor"/>

Un lmite inferior controla cuntos editores de hecho hacen que el bean progrese de un estado configurado: cardinality=4..n/> Eventualmente se crea Checker y corrige el analizador sintctico. Esto se ilustra en Ejemplo 7.5, El corrector para el analizador sintctico. Ejemplo 7.5. El corrector para el analizador sintctico
public void create() throws Throwable { Set<String> strings = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); for (Object element : elements) strings.add(element.toString()); if (expected.equals(strings) == false) throw new IllegalArgumentException("Illegal expected set: " + expected + "!=" + strings); }

7.3. Modo de acceso del Bean


Con el BeanAccessMode predeterminado no se inspeccionan los campos de un bean. Sin embargo, si especifica un BeanAccessMode diferente entonces los campos son accesibles como parte de las propiedades del bean. Consulte Ejemplo 7.6, Definiciones posibles para BeanAccessMode, Ejemplo 7.7, Configuracin de BeanAccessMode y Ejemplo 7.8, La clase FieldsBean para una implementacin.

51

Captulo 7. Inyeccin avanzada de dependencias y ldC

Ejemplo 7.6. Definiciones posibles para BeanAccessMode


public enum BeanAccessMode { STANDARD(BeanInfoCreator.STANDARD), // Getters and Setters FIELDS(BeanInfoCreator.FIELDS), // Getters/Setters and fields without getters and setters ALL(BeanInfoCreator.ALL); // As above but with non public fields included }

Aqu un valor de cadena se configura como un campo de cadena privado: Ejemplo 7.7. Configuracin de BeanAccessMode
<bean name="FieldsBean" class="org.jboss.demos.ioc.access.FieldsBean" access-mode="ALL"> <property name="string">InternalString</property> </bean>

Ejemplo 7.8. La clase FieldsBean


public class FieldsBean { private String string; public void start() { if (string == null) throw new IllegalArgumentException("Strings should be set!"); } }

7.4. Alias Bean


Cada bean puede tener cualquier nmero de alias. Ya que los nombres de los componentes del microcontenedor se tratan como objetos, el tipo del alias no es limitado. Por defecto no se realiza un reemplazo de la propiedad del sistema; es necesario que establezca la etiqueta de reemplazo de manera explcita como se puede ver en Ejemplo 7.9, Un alias simple de Bean. Ejemplo 7.9. Un alias simple de Bean
<bean name="SimpleName" class="java.lang.Object"> <alias>SimpleAlias</alias> <alias replace="true">${some.system.property}</alias> <alias class="java.lang.Integer">12345</alias> <alias><javabean xmlns="urn:jboss:javabean:2.0" class="org.jboss.demos.bootstrap.Main"/ ></alias> </bean>

52

Soporte para anotaciones XML (o metadatos)

7.5. Soporte para anotaciones XML (o metadatos)


Una de las funcionalidades principales en el microcontenedor de JBoss es el soporte para AOP. Puede utilizar aspectos AOP y beans simples combinadas de cualquier manera. Ejemplo 7.10, Interceptar un mtodo basado en una anotacin trata de interceptar una invocacin de mtodo con base en una anotacin. La anotacin puede provenir de cualquier lado. Puede ser una anotacin de clase verdadera o puede ser una anotacin agregada por medio de la configuracin xml. Ejemplo 7.10. Interceptar un mtodo basado en una anotacin
<interceptor xmlns="urn:jboss:aop-beans:1.0" name="StopWatchInterceptor" class="org.jboss.demos.ioc.annotations.StopWatchInterceptor"/> <bind xmlns="urn:jboss:aop-beans:1.0" pointcut="execution(* @org.jboss.demos.ioc.annotations.StopWatchLog->*(..)) OR execution(* *>@org.jboss.demos.ioc.annotations.StopWatchLog(..))"> <interceptor-ref name="StopWatchInterceptor"/> </bind> </interceptor>

public class StopWatchInterceptor implements Interceptor { ... public Object invoke(Invocation invocation) throws Throwable { Object target = invocation.getTargetObject(); long time = System.currentTimeMillis(); log.info("Invocation [" + target + "] start: " + time); try { return invocation.invokeNext(); } finally { log.info("Invocation [" + target + "] time: " + (System.currentTimeMillis() - time)); } } }

Ejemplo 7.11, Un verdadero ejecutor anotado de clase and Ejemplo 7.12, Ejecutor simple con anotaciones XML muestra algunas maneras diferentes de implementar los ejecutores. Ejemplo 7.11. Un verdadero ejecutor anotado de clase
<bean name="AnnotatedExecutor" class="org.jboss.demos.ioc.annotations.AnnotatedExecutor">

public class AnnotatedExecutor implements Executor { ... @StopWatchLog // <-- Pointcut match! public void execute() throws Exception { delegate.execute(); } }

53

Captulo 7. Inyeccin avanzada de dependencias y ldC

Ejemplo 7.12. Ejecutor simple con anotaciones XML


<bean name="SimpleExecutor" class="org.jboss.demos.ioc.annotations.SimpleExecutor"> <annotation>@org.jboss.demos.ioc.annotations.StopWatchLog</annotation> // <-- Pointcut match! </bean>

public class SimpleExecutor implements Executor { private static Random random = new Random(); public void execute() throws Exception { Thread.sleep(Math.abs(random.nextLong() % 101)); } }

Despus de agregar los beans invocadores del ejecutor, puede ver los ejecutores en accin durante el empleo, buscando salidas del registro tal como Ejemplo 7.13, Salida del registro del ejecutor. Ejemplo 7.13. Salida del registro del ejecutor

JBoss-MC-Demo INFO [15-12-2008 13:57:39] StopWatch - Invocation [org.jboss.demos.ioc.annotations.AnnotatedExecutor@4d28c7] start: 1229345859234 JBoss-MC-Demo INFO [15-12-2008 13:57:39] StopWatch - Invocation [org.jboss.demos.ioc.annotations.AnnotatedExecutor@4d28c7] time: 31 JBoss-MC-Demo INFO [15-12-2008 13:57:39] StopWatch - Invocation [org.jboss.demos.ioc.annotations.SimpleExecutor@1b044df] start: 1229345859265 JBoss-MC-Demo INFO [15-12-2008 13:57:39] StopWatch - Invocation [org.jboss.demos.ioc.annotations.SimpleExecutor@1b044df] time: 47

7.6. Autowire
Autowiring o la inyeccin contextual, es una funcionalidad comn con con marcos de trabajo IdC. Ejemplo 7.14, Incluir y excluir con autowiring le muestra cmo utilizar o excluir beans con autowiring. Ejemplo 7.14. Incluir y excluir con autowiring
<bean name="Square" class="org.jboss.demos.ioc.autowire.Square" autowirecandidate="false"/> <bean name="Circle" class="org.jboss.demos.ioc.autowire.Circle"/> <bean name="ShapeUser" class="org.jboss.demos.ioc.autowire.ShapeUser"> <constructor> <parameter><inject/></parameter> </constructor> </bean> <bean name="ShapeHolder" class="org.jboss.demos.ioc.autowire.ShapeHolder"> <incallback method="addShape"/> <uncallback method="removeShape"/> </bean> <bean name="ShapeChecker" class="org.jboss.demos.ioc.autowire.ShapesChecker"/>

54

Fbrica de beans En ambos casos - ShapeUser y ShapeChecker - solo Circle se debe utilizar ya que Square se excluye en el enlace contextual.

7.7. Fbrica de beans


Cuando quiere ms de una instancia de un bean en particular, necesita utilizar el patrn de fbrica del bean. El trabajo del microcontenedor es configurar e instalar la fbrica de beans como si fuera un bean simple. Luego necesita invocar el mtodo createBean de la fbrica de beans. Por defecto, el microcontenedor crea una instancia GenericBeanFactory, pero puede configurar su propia fbrica. La nica limitacin es que su firma y ganchos de configuracin son similares al de AbstractBeanFactory. Ejemplo 7.15. Fbrica de beans genricas
<bean name="Object" class="java.lang.Object"/> <beanfactory name="DefaultPrototype" class="org.jboss.demos.ioc.factory.Prototype"> <property name="value"><inject bean="Object"/></property> </beanfactory> <beanfactory name="EnhancedPrototype" class="org.jboss.demos.ioc.factory.Prototype" factoryClass="org.jboss.demos.ioc.factory.EnhancedBeanFactory"> <property name="value"><inject bean="Object"/></property> </beanfactory> <beanfactory name="ProxiedPrototype" class="org.jboss.demos.ioc.factory.UnmodifiablePrototype" factoryClass="org.jboss.demos.ioc.factory.EnhancedBeanFactory"> <property name="value"><inject bean="Object"/></property> </beanfactory> <bean name="PrototypeCreator" class="org.jboss.demos.ioc.factory.PrototypeCreator"> <property name="default"><inject bean="DefaultPrototype"/></property> <property name="enhanced"><inject bean="EnhancedPrototype"/></property> <property name="proxied"><inject bean="ProxiedPrototype"/></property> </bean>

Consulte Ejemplo 7.16, BeanFactory extendido para ver el uso de un BeanFactory extendido. Ejemplo 7.16. BeanFactory extendido
public class EnhancedBeanFactory extends GenericBeanFactory { public EnhancedBeanFactory(KernelConfigurator configurator) { super(configurator); } public Object createBean() throws Throwable { Object bean = super.createBean(); Class clazz = bean.getClass(); if (clazz.isAnnotationPresent(SetterProxy.class)) { Set<Class> interfaces = new HashSet<Class>(); addInterfaces(clazz, interfaces); return Proxy.newProxyInstance( clazz.getClassLoader(), interfaces.toArray(new Class[interfaces.size()]), new SetterInterceptor(bean) ); } else

55

Captulo 7. Inyeccin avanzada de dependencias y ldC


{ return bean; } } protected static void addInterfaces(Class clazz, Set<Class> interfaces) { if (clazz == null) return; interfaces.addAll(Arrays.asList(clazz.getInterfaces())); addInterfaces(clazz.getSuperclass(), interfaces); } private class SetterInterceptor implements InvocationHandler { private Object target; private SetterInterceptor(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.startsWith("set")) throw new IllegalArgumentException("Cannot invoke setters."); return method.invoke(target, args); } } }

public class PrototypeCreator { ... public void create() throws Throwable { ValueInvoker vi1 = (ValueInvoker)bfDefault.createBean(); vi1.setValue("default"); ValueInvoker vi2 = (ValueInvoker)enhanced.createBean(); vi2.setValue("enhanced"); ValueInvoker vi3 = (ValueInvoker)proxied.createBean(); try { vi3.setValue("default"); throw new Error("Should not be here."); } catch (Exception ignored) { } }

7.8. Constructor de metadatos Bean


Al utilizar el microcontenedor en su cdigo, use BeanMetaDataBuilder para crear y configurar los metadatos de su bean. Ejemplo 7.17. BeanMetaDataBuilder
<bean name="BuilderUtil" class="org.jboss.demos.ioc.builder.BuilderUtil"/> <bean name="BuilderExampleHolder" class="org.jboss.demos.ioc.builder.BuilderExampleHolder"> <constructor> <parameter><inject bean="BUExample"/></parameter> </constructor> </bean>

56

ClassLoader personalizado Utilizando este concepto no expone su cdigo a ninguno de los detalles de implementacin del microcontenedor.
public class BuilderUtil { private KernelController controller; @Constructor public BuilderUtil(@Inject(bean = KernelConstants.KERNEL_CONTROLLER_NAME) KernelController controller) { this.controller = controller; } public void create() throws Throwable { BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder("BUExample", BuilderExample.class.getName()); builder.addStartParameter(Kernel.class.getName(), builder.createInject(KernelConstants.KERNEL_NAME)); controller.install(builder.getBeanMetaData()); } public void destroy() { controller.uninstall("BUExample"); } }

7.9. ClassLoader personalizado


En el microcontenedor puede definir un ClassLoader personalizado por bean. Al definir un cargador de clase para toda la implementacin, asegrese de no crear una dependencia cclica -- por ejemplo, un cargador de clase recin definido que dependa de s mismo. Ejemplo 7.18. Definicin de un cargador de clase por Bean
<classloader><inject bean="custom-classloader:0.0.0"/></classloader> <!-- this will be explained in future article --> <classloader name="custom-classloader" xmlns="urn:jboss:classloader:1.0" exportall="NON_EMPTY" import-all="true"/> <bean name="CustomCL" class="org.jboss.demos.ioc.classloader.CustomClassLoader"> <constructor> <parameter><inject bean="custom-classloader:0.0.0"/></parameter> </constructor> <property name="pattern">org\.jboss\.demos\.ioc\..+</property> </bean> <bean name="CB1" class="org.jboss.demos.ioc.classloader.CustomBean"/> <bean name="CB2" class="org.jboss.demos.ioc.classloader.CustomBean"> <classloader><inject bean="CustomCL"/></classloader> </bean>

Ejemplo 7.19, Prueba del cargador de clase personalizado muestra una prueba para verificar que el bean CB2 usa un cargador de clase personalizado, el cual limita el mbito del paquete cargable. Ejemplo 7.19. Prueba del cargador de clase personalizado
public class CustomClassLoader extends ClassLoader { private Pattern pattern; public CustomClassLoader(ClassLoader parent) { super(parent); } public Class<?> loadClass(String name) throws ClassNotFoundException {

57

Captulo 7. Inyeccin avanzada de dependencias y ldC


if (pattern == null || pattern.matcher(name).matches()) return super.loadClass(name); else throw new ClassNotFoundException("Name '" + name + "' doesn't match pattern: " + pattern); } public void setPattern(String regexp) { pattern = Pattern.compile(regexp); } }

7.10. Modo controlador


Por defecto el microcontenedor usa el modo controlador AUTO. Lleva a los beans tan lejos como es posible con respecto a las dependencias. Pero hay otros dos modos: MANUAL y ON_DEMAND. Si el bean est marcado como ON_DEMAND entonces no se utilizar ni se instalar hasta que otro bean dependa explcitamente de este. En el modo MANUAL, el usuario microcontenedor debe llevar al bean hacia adelante y atrs junto con el estado. Ejemplo 7.20. Modo controlador Bean
<bean name="OptionalService" class="org.jboss.demos.ioc.mode.OptionalService" mode="On Demand"/> <bean name="OptionalServiceUser" class="org.jboss.demos.ioc.mode.OptionalServiceUser"/> <bean name="ManualService" class="org.jboss.demos.ioc.mode.ManualService" mode="Manual"/> <bean name="ManualServiceUser" class="org.jboss.demos.ioc.mode.ManualServiceUser"> <start> <parameter><inject bean="ManualService" fromContext="context" state="Not Installed"/ ></parameter> </start> </bean>

Nota
Usando el atributo fromContext de la clase inject puede inyectar beans as como su representacin de componentes del microcontenedor inmodificables.

Revise el cdigo de OptionalServiceUser y ManualServiceUser para ver cmo se utiliza la API del microcontenedor para el manejo de beans ON_DEMAND y MANUAL.

7.11. Ciclo
Los beans pueden depender entre ellos en un ciclo. Por ejemplo, A depende de B en la construccin, pero B depende de A durante la configuracin. Debido a la separacin del ciclo de vida del estado detallado del microcontenedor, este problema se puede resolver fcilmente.

58

Oferta y demanda

Ejemplo 7.21. Separacin del ciclo de vida del Bean


<bean name="cycleA" class="org.jboss.demos.ioc.cycle.CyclePojo"> <property name="dependency"><inject bean="cycleB"/></property> </bean> <bean name="cycleB" class="org.jboss.demos.ioc.cycle.CyclePojo"> <constructor><parameter><inject bean="cycleA" state="Instantiated"/></parameter></ constructor> </bean> <bean name="cycleC" class="org.jboss.demos.ioc.cycle.CyclePojo"> <property name="dependency"><inject bean="cycleD"/></property> </bean> <bean name="cycleD" class="org.jboss.demos.ioc.cycle.CyclePojo"> <property name="dependency"><inject bean="cycleC" state="Instantiated"/></property> </bean>

7.12. Oferta y demanda


Algunas veces as como con una inyeccin, es posible que una dependencia entre dos beans no sea aparente. Tales dependencias se deben expresar de manera clara tal como se puede ver en Ejemplo 7.22, Uso esttico del cdigo. Ejemplo 7.22. Uso esttico del cdigo
<bean name="TMDemand" class="org.jboss.demos.ioc.demandsupply.TMDemander"> <demand>TM</demand> </bean> <bean name="SimpleTMSupply" class="org.jboss.demos.ioc.demandsupply.SimpleTMSupplyer"> <supply>TM</supply> </bean>

7.13. Instalaciones
A medida que el bean se mueve a travs de diferentes estados es posible que quiera invocar algunos mtodos en otros beans o en el mismo bean. Ejemplo 7.23, Invocacin de mtodos en diferentes estados muestra cmo Entry invoca a los mtodos add y removeEntry del RepositoryManager pararegistrar y desregistrarse a s mismo. Ejemplo 7.23. Invocacin de mtodos en diferentes estados
<bean name="RepositoryManager" class="org.jboss.demos.ioc.install.RepositoryManager"> <install method="addEntry"> <parameter><inject fromContext="name"/></parameter> <parameter><this/></parameter> </install> <uninstall method="removeEntry"> <parameter><inject fromContext="name"/></parameter> </uninstall> </bean> <bean name="Entry" class="org.jboss.demos.ioc.install.SimpleEntry"> <install bean="RepositoryManager" method="addEntry" state="Instantiated"> <parameter><inject fromContext="name"/></parameter> <parameter><this/></parameter> </install>

59

Captulo 7. Inyeccin avanzada de dependencias y ldC


<uninstall bean="RepositoryManager" method="removeEntry" state="Configured"> <parameter><inject fromContext="name"/></parameter> </uninstall> </bean>

7.14. Imitacin perezosa


Es posible que tenga una dependencia en un bean que se utilice con muy poca frecuencia, pero toma mucho tiempo en configurar. Puede utilizar la imitacin perezosa del bean que se demuestra en Ejemplo 7.24, Imitacin perezosa para resolver la dependencia. Cuando de hecho necesita el bean, invoque y use el bean destino esperando que para ese momento ya se haya instalalado. Ejemplo 7.24. Imitacin perezosa
<bean name="lazyA" class="org.jboss.demos.ioc.lazy.LazyImpl"> <constructor> <parameter> <lazy bean="lazyB"> <interface>org.jboss.demos.ioc.lazy.ILazyPojo</interface> </lazy> </parameter> </constructor> </bean> <bean name="lazyB" class="org.jboss.demos.ioc.lazy.LazyImpl"> <constructor> <parameter> <lazy bean="lazyA"> <interface>org.jboss.demos.ioc.lazy.ILazyPojo</interface> </lazy> </parameter> </constructor> </bean> <lazy name="anotherLazy" bean="Pojo" exposeClass="true"/> <bean name="Pojo" class="org.jboss.demos.ioc.lazy.Pojo"/>

7.15. Ciclo de vida


Por defecto el microcontenedor usa los mtodos create, start y destroy cuando avanza a travs de los variados estados. Sin embargo, es posible que no quiera que el microcontenedor los invoque. Por esta razn, se encuentra disponible una etiqueta ignore. Ejemplo 7.25. Ciclos de vida del Bean
<bean name="FullLifecycleBean-3" class="org.jboss.demos.ioc.lifecycle.FullLifecycleBean"/> <bean name="FullLifecycleBean-2" class="org.jboss.demos.ioc.lifecycle.FullLifecycleBean"> <create ignored="true"/> </bean> <bean name="FullLifecycleBean-1" class="org.jboss.demos.ioc.lifecycle.FullLifecycleBean"> <start ignored="true"/> </bean>

60

El sistema virtual de archivos


El duplicado del cdigo de manejo de recursos es un problema comn para los desarrolladores. En la mayora de los casos, el cdigo ayuda a determinar la informacin sobre un recurso en particular, el cual puede ser un archivo, un directorio o en el caso de una JAR, una URL remota. Otro problema de duplicacin es el cdigo para el procesamiento de ficheros anidados. Ejemplo 8.1, Problema de duplicacin de recursos ilustra el problema. Ejemplo 8.1. Problema de duplicacin de recursos
public static URL[] search(ClassLoader cl, String prefix, String suffix) throws IOException { Enumeration[] e = new Enumeration[]{ cl.getResources(prefix), cl.getResources(prefix + "MANIFEST.MF") }; Set all = new LinkedHashSet(); URL url; URLConnection conn; JarFile jarFile; for (int i = 0, s = e.length; i < s; ++i) { while (e[i].hasMoreElements()) { url = (URL)e[i].nextElement(); conn = url.openConnection(); conn.setUseCaches(false); conn.setDefaultUseCaches(false); if (conn instanceof JarURLConnection) { jarFile = ((JarURLConnection)conn).getJarFile(); } else { jarFile = getAlternativeJarFile(url); } if (jarFile != null) { searchJar(cl, all, jarFile, prefix, suffix); } else { boolean searchDone = searchDir(all, new File(URLDecoder.decode(url.getFile(), "UTF-8")), suffix); if (searchDone == false) { searchFromURL(all, prefix, suffix, url); } } } } return (URL[])all.toArray(new URL[all.size()]); } private static boolean searchDir(Set result, File file, String suffix) throws IOException { if (file.exists() && file.isDirectory()) { File[] fc = file.listFiles(); String path; for (int i = 0; i < fc.length; i++) { path = fc[i].getAbsolutePath(); if (fc[i].isDirectory())

61

Captulo 8. El sistema virtual de archivos


{ searchDir(result, fc[i], suffix); } else if (path.endsWith(suffix)) { result.add(fc[i].toURL()); } } return true; } return false; }

Tambin hay muchos problemas con el bloqueo de archivos en los sistemas Windows, lo cual ha forzado a los desarrolladores a copiar todos los ficheros de implementacin en vivo a otra ubicacin para prevenir el bloqueo de aquellos que se encuentran en las carpetas de implementacin (lo cual evitara el borrarlos y el borrado de la implementacin con base en el sistema de archivos). El bloqueo de archivos es un problema importante, cuya nica solucin sola ser el centralizar todo el cdigo de carga de recursos en un lugar. El proyecto VFS se cre para resolver todos estos problemas. VFS son las siglas en ingles de Virtual File System - sistema virtual de archivos.

8.1. API pblica VFS


VFS se utiliza para dos propsitos principales tal como se puede ver en Usos para VFS. Usos para VFS navegacin simple de recursos API (del ingls Application Programmer Interface) del patrn del visitante Como se mencion anteriormente, en JDK simple, el manejo y navegacin de recursos es complejo. Siempre debe chequear el tipo de recurso y estos chequeos pueden llegar engorrosos. VFS abstrae los recursos en un solo tipo de recurso, VirtualFile. Ejemplo 8.2. El tipo de recurso VirtualFile
public class VirtualFile implements Serializable { /** * Get certificates. * * @return the certificates associated with this virtual file */ Certificate[] getCertificates() /** * Get the simple VF name (X.java) * * @return the simple file name * @throws IllegalStateException if the file is closed */ String getName() /** * Get the VFS relative path name (org/jboss/X.java) * * @return the VFS relative path name * @throws IllegalStateException if the file is closed */

62

API pblica VFS


String getPathName() /** * Get the VF URL (file://root/org/jboss/X.java) * * @return the full URL to the VF in the VFS. * @throws MalformedURLException if a url cannot be parsed * @throws URISyntaxException if a uri cannot be parsed * @throws IllegalStateException if the file is closed */ URL toURL() throws MalformedURLException, URISyntaxException /** * Get the VF URI (file://root/org/jboss/X.java) * * @return the full URI to the VF in the VFS. * @throws URISyntaxException if a uri cannot be parsed * @throws IllegalStateException if the file is closed * @throws MalformedURLException for a bad url */ URI toURI() throws MalformedURLException, URISyntaxException /** * When the file was last modified * * @return the last modified time * @throws IOException for any problem accessing the virtual file system * @throws IllegalStateException if the file is closed */ long getLastModified() throws IOException /** * Returns true if the file has been modified since this method was last called * Last modified time is initialized at handler instantiation. * * @return true if modifed, false otherwise * @throws IOException for any error */ boolean hasBeenModified() throws IOException /** * Get the size * * @return the size * @throws IOException for any problem accessing the virtual file system * @throws IllegalStateException if the file is closed */ long getSize() throws IOException /** * Tests whether the underlying implementation file still exists. * @return true if the file exists, false otherwise. * @throws IOException - thrown on failure to detect existence. */ boolean exists() throws IOException /** * Whether it is a simple leaf of the VFS, * i.e. whether it can contain other files * * @return true if a simple file. * @throws IOException for any problem accessing the virtual file system * @throws IllegalStateException if the file is closed */ boolean isLeaf() throws IOException /**

63

Captulo 8. El sistema virtual de archivos


* Is the file archive. * * @return true if archive, false otherwise * @throws IOException for any error */ boolean isArchive() throws IOException /** * Whether it is hidden * * @return true when hidden * @throws IOException for any problem accessing the virtual file system * @throws IllegalStateException if the file is closed */ boolean isHidden() throws IOException /** * Access the file contents. * * @return an InputStream for the file contents. * @throws IOException for any error accessing the file system * @throws IllegalStateException if the file is closed */ InputStream openStream() throws IOException /** * Do file cleanup. * * e.g. delete temp files */ void cleanup() /** * Close the file resources (stream, etc.) */ void close() /** * Delete this virtual file * * @return true if file was deleted * @throws IOException if an error occurs */ boolean delete() throws IOException /** * Delete this virtual file * * @param gracePeriod max time to wait for any locks (in milliseconds) * @return true if file was deleted * @throws IOException if an error occurs */ boolean delete(int gracePeriod) throws IOException /** * Get the VFS instance for this virtual file * * @return the VFS * @throws IllegalStateException if the file is closed */ VFS getVFS() /** * Get the parent * * @return the parent or null if there is no parent * @throws IOException for any problem accessing the virtual file system

64

API pblica VFS


* @throws IllegalStateException if the file is closed */ VirtualFile getParent() throws IOException /** * Get a child * * @param path the path * @return the child or <code>null</code> if not found * @throws IOException for any problem accessing the VFS * @throws IllegalArgumentException if the path is null * @throws IllegalStateException if the file is closed or it is a leaf node */ VirtualFile getChild(String path) throws IOException /** * Get the children * * @return the children * @throws IOException for any problem accessing the virtual file system * @throws IllegalStateException if the file is closed */ List<VirtualFile> getChildren() throws IOException /** * Get the children * * @param filter to filter the children * @return the children * @throws IOException for any problem accessing the virtual file system * @throws IllegalStateException if the file is closed or it is a leaf node */ List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException /** * Get all the children recursively<p> * * This always uses {@link VisitorAttributes#RECURSE} * * @return the children * @throws IOException for any problem accessing the virtual file system * @throws IllegalStateException if the file is closed */ List<VirtualFile> getChildrenRecursively() throws IOException /** * Get all the children recursively<p> * * This always uses {@link VisitorAttributes#RECURSE} * * @param filter to filter the children * @return the children * @throws IOException for any problem accessing the virtual file system * @throws IllegalStateException if the file is closed or it is a leaf node */ List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws IOException /** * Visit the virtual file system * * @param visitor the visitor * @throws IOException for any problem accessing the virtual file system * @throws IllegalArgumentException if the visitor is null * @throws IllegalStateException if the file is closed */ void visit(VirtualFileVisitor visitor) throws IOException

65

Captulo 8. El sistema virtual de archivos


}

Todas las operaciones del sistema de archivos de slo lectura estn disponibles adems de unas pocas opciones para limpiar o borrar el recurso. El manejo de la limpieza o el borrado se necesita al tratar con algunos archivos internos temporales tal como archivos creados para manejar jars anidadas. Para cambiar el manejo de recursos File o URL de JDK al nuevo VirtualFile necesita un VirtualFile raz, el cual los proporciona la clase VFS con la ayuda de la URL o el parmetro URI. Ejemplo 8.3. Uso de la clase VFS
public class VFS { /** * Get the virtual file system for a root uri * * @param rootURI the root URI * @return the virtual file system * @throws IOException if there is a problem accessing the VFS * @throws IllegalArgumentException if the rootURL is null */ static VFS getVFS(URI rootURI) throws IOException /** * Create new root * * @param rootURI the root url * @return the virtual file * @throws IOException if there is a problem accessing the VFS * @throws IllegalArgumentException if the rootURL */ static VirtualFile createNewRoot(URI rootURI) throws IOException /** * Get the root virtual file * * @param rootURI the root uri * @return the virtual file * @throws IOException if there is a problem accessing the VFS * @throws IllegalArgumentException if the rootURL is null */ static VirtualFile getRoot(URI rootURI) throws IOException /** * Get the virtual file system for a root url * * @param rootURL the root url * @return the virtual file system * @throws IOException if there is a problem accessing the VFS * @throws IllegalArgumentException if the rootURL is null */ static VFS getVFS(URL rootURL) throws IOException /** * Create new root * * @param rootURL the root url * @return the virtual file * @throws IOException if there is a problem accessing the VFS * @throws IllegalArgumentException if the rootURL */ static VirtualFile createNewRoot(URL rootURL) throws IOException

66

API pblica VFS


/** * Get the root virtual file * * @param rootURL the root url * @return the virtual file * @throws IOException if there is a problem accessing the VFS * @throws IllegalArgumentException if the rootURL */ static VirtualFile getRoot(URL rootURL) throws IOException /** * Get the root file of this VFS * * @return the root * @throws IOException for any problem accessing the VFS */ VirtualFile getRoot() throws IOException }

Los tres mtodos diferentes se ven similares. getVFS createNewRoot getRoot getVFS retorna una instancia VFS pero todava no crea una instancia VirtualFile. Esto es importante ya que hay mtodos que ayudan con la configuracin de una instancia VFS (consulte la clase VFS API javadocs) antes de ordenarle que cree una raz VirtualFile. Por otro lado, los otros dos mtodos usan configuraciones predeterminadas para la creacin de root. La diferencia entre createNewRoot y getRoot es en los detalles de cach, los cuales abordaremos ms adelante. Ejemplo 8.4. Uso de getVFS
URL rootURL = ...; // get root url VFS vfs = VFS.getVFS(rootURL); // configure vfs instance VirtualFile root1 = vfs.getRoot(); // or you can get root directly VirtualFile root2 = VFS.crateNewRoot(rootURL); VirtualFile root3 = VFS.getRoot(rootURL);

Otra cosa til de la API VFS es su implementacin de un patrn visitante apropiado. Es muy simple el reunir recursos de manera recursiva, una tarea dificil de realizar con la carga de recursos JDK simple. Ejemplo 8.5. Reunin de recursos de manera recursiva
public interface VirtualFileVisitor { /** * Get the search attribues for this visitor * * @return the attributes */ VisitorAttributes getAttributes(); /**

67

Captulo 8. El sistema virtual de archivos


* Visit a virtual file * * @param virtualFile the virtual file being visited */ void visit(VirtualFile virtualFile); } VirtualFile root = ...; // get root VirtualFileVisitor visitor = new SuffixVisitor(".class"); // get all classes root.visit(visitor);

8.2. Arquitectura VFS


Aunque la API pblica es bastante is quite intuitiva, los detalles de la implementacin real agregan complejidad. Es necesario explicar algunos conceptos en ms detalle. Cada vez que crea una instancia VFS tambin se crea su instancia correspondiente VFSContext. Esta creacin se realiza por medio de VFSContextFactory. Protocolos diferentes mapean a diferentes instancias VFSContextFactory. Por ejemplo, file/vfsfile mapea a FileSystemContextFactory mientras que zip/vfszip mapea a ZipEntryContextFactory. Cada vez que se crea una instancia VirtualFile tambin se crea su VirtualFileHandler correspondiente. Esta instancia VirtualFileHandler sabe cmo manejar diferentes tipos de recursos apropiadamente; el API VirtualFile solo delega invocaciones a su referencia VirtualFileHandler. La instancia VFSContext sabe cmo crear instancias VirtualFileHandler de acuerdo con el tipo de recurso. Por ejemplo, ZipEntryContextFactory crea ZipEntryContext, el cual luego crea ZipEntryHandler.

8.3. Implementaciones existentes


Aparte de archivos, directorios (FileHandler) y ficheros zip (ZipEntryHandler), el microcontenedor tambin soporta otros casos ms avanzados. El primero es Assembled, el cual es similar a lo que Eclipse llama Linked Resources. Su propsito es tomar recursos ya existentes de diferentes rboles y "simular" un slo rbol de recursos. Ejemplo 8.6. Implementacin de VirtualFileHandlers reunidos
AssembledDirectory sar = AssembledContextFactory.getInstance().create("assembled.sar"); URL url = getResource("/vfs/test/jar1.jar"); VirtualFile jar1 = VFS.getRoot(url); sar.addChild(jar1); url = getResource("/tmp/app/ext.jar"); VirtualFile ext1 = VFS.getRoot(url); sar.addChild(ext); AssembledDirectory metainf = sar.mkdir("META-INF"); url = getResource("/config/jboss-service.xml"); VirtualFile serviceVF = VFS.getRoot(url); metainf.addChild(serviceVF); AssembledDirectory app = sar.mkdir("app.jar"); url = getResource("/app/someapp/classes"); VirtualFile appVF = VFS.getRoot(url); app.addPath(appVF, new SuffixFilter(".class"));

68

Ganchos de extensin Otra implementacin son los archivos en-memoria. Esta implementacin surgi de la necesidad de manejar fcilmente bytes generados por AOP. En lugar de utilizar archivos temporales, puede poner bytes en VirtualFileHandlers en la memoria. Ejemplo 8.7. Implementacin de VirtualFileHandlers en memoria
URL url = new URL("vfsmemory://aopdomain/org/acme/test/Test.class"); byte[] bytes = ...; // some AOP generated class bytes MemoryFileFactory.putFile(url, bytes); VirtualFile classFile = VFS.getVirtualFile(new URL("vfsmemory://aopdomain"), "org/acme/ test/Test.class"); InputStream bis = classFile.openStream(); // e.g. load class from input stream

8.4. Ganchos de extensin


Es fcil extender VFS con un nuevo protocolo, similar a lo que hicimos con Assembled y Memory. Todo lo que necesita es una combinacin de las implementaciones VFSContexFactory, VFSContext, VirtualFileHandler, FileHandlerPlugin y URLStreamHandler. La VFSContextFactory es trivial mientras que las otras dependen de la complejidad de su tarea. Puede implementar el acceso rar, tar, gzip, o incluso remote. Despus de implementar un nuevo protocolo, registre el nuevo VFSContextFactory con VFSContextFactoryLocator.

8.5. Funcionalidades
Uno de los problemas principales que los desarrolladores del microcontenedor enfrentaron fue el uso apropiado de los recursos anidados, ms especificamente de los archivos jar anidados: por ejemplo, implementaciones ear normales: gema.ear/ui.war/WEB-INF/lib/struts.jar. Con el fin de leer el contenido de struts.jar tenemos dos opciones: manejar los recursos en la memoria crear copias temporales de jars a nivel superior de manera recursiva La primera opcin es ms fcil de implementar, pero consume mucha memoria, lo cual requiere potencialmente que las aplicaciones grandes residan en la memoria. El otro enfoque deja atrs un gran nmero de archivos temporales, los cuales deben ser invisibles para el usuario y por lo tanto deben desaparecer despus del borrado de la implementacin. Considere el siguiente escenario: un usuario accede uns intstancia URL VFS, la cual apunta a algun recurso anidado. La manera en que el VFS simple manejara esto es re-creando toda la ruta desde el principio: desempacara los recursos anidados y de nuevo. Esto crea un gran nmero de archivos temporales. El microcontenedor evita esto utilizando VFSRegistry, VFSCache y TempInfo. Cuando solicita VirtualFile sobrer VFS (getRoot no createNewRoot), VFS le pide a la implementacin VFSRegistry que proporcione el archivo. El DefaultVFSRegistry existente primero chequea si extiste un VFSContext raz que coincida para la URI dada. Si s existe entonces DefaultVFSRegistry primero trata de navigar al TempInfo existente (enlace a un archivo temporal), regresando a la navegacin normal si no existe dicho archivo temporal. De esta manera reutiliza completamente cualuqier archivo temporal que ya hayan sido desempacados, ahorrando 69

Captulo 8. El sistema virtual de archivos tiempo y espacio en el disco. Si no se encuentra un VFSContext que coincida en el cach entonces el cdigo crear una nueva entrada VFSCache y continuar con la navegacin predeterminada. El determinar la manera en que el VFSCache maneja las entradas VFSContext en cach depende de la implementacin utilizada. VFSCache es configurable por medio de VFSCacheFactory. Por defecto, nada va en el cach, pero hay unas pocas implementaciones VFSCache tiles existentes, utilizando algoritmos tal como Least Recently Used (LRU) o timed cache.

70

La capa ClassLoading
JBoss siempre ha tenido una manera nica de tratar con la carga de clase y la nueva capa classloading que viene junto con el microcontenedor no es la excepcin. ClassLoading es una funcionalidad agregada que puede utilizar cuando prefiera la carga de clase no predeterminada. Con una mayor demanda por la carga de clase de estilo OSGi y un nmero de especificaciones nuevas de carga de clase Java en el horizonte, los cambios a la capa ClassLoading de EAP 5.1 son tiles y muy oportunos. La capa ClassLoading del microcontenedor es una capa de abstraccin. La mayora de los detalles se esconden detrs de mtodos privados y de paquetes privados sin comprometer la extensibilidad y funcionalidad disponibles por medio de las clases y mtodos pblicos que hacen el API. Esto significa que usted escribe cdigo frente a la poltica y no frente a los detalles del cargador de clase. El proyecto ClassLoader se divide en 3 sub-proyectos el cargador de clase - classloader la carga de la clase - classloading classloading-vfs classloader contiene una extensin java.lang.ClassLoader personalizada sin ninguna poltica de carga de clase especfica. Una poltica de carga de clase incluye el saber desde dnde carga y cmo cargar. Classloading es una extensin de los mecanismos de dependencia del microcontenedor. Su implementacin respaldada por VFS es classloading-vfs. Consulte Captulo 8, El sistema virtual de archivos para obtener mayor informacin sobre VFS.

9.1. ClassLoader
La implementacin ClassLoader soporta polticas enchufables y es una clase final, se supone que no se debe alterar. Para escribir sus propias implementaciones ClassLoader, escriba una ClassLoaderPolicy, la cual proporciona una API ms simple para ubicar las clases y recursos y para especificar otras reglas asociadas con el cargador de clase. Para personalizar la carga de clase, instance una ClassLoaderPolicy y regstrela con un ClassLoaderSystem para crear un ClassLoader personalizado. Tambin puede crear un ClassLoaderDomain para realizar la particin en el ClassLoaderSystem. La capa ClassLoader tambin incluye la implementacin de cosas como el modelo DelegateLoader, la carga de clase, filtros de recursos y polticas de delegacin padre-hijo. El tiempo de ejecucin est habilitado para JMX para exponer la poltica utilizada para cada cargador de clase. Tambin proporciona estadsticas de carga de clase y mtodos de depuracin para ayudar a determinar desde dnde se cargan las cosas. Ejemplo 9.1. La clase ClassLoaderPolicy La ClassLoaderPolicy controla la manera en que funciona la carga de clase.
public abstract class ClassLoaderPolicy extends BaseClassLoaderPolicy { public DelegateLoader getExported() public String[] getPackageNames()

71

Captulo 9. La capa ClassLoading


protected List<? extends DelegateLoader> getDelegates() protected boolean isImportAll() protected boolean isCacheable() protected boolean isBlackListable() public abstract URL getResource(String path); public InputStream getResourceAsStream(String path) public abstract void getResources(String name, Set<URL> urls) throws IOException; protected ProtectionDomain getProtectionDomain(String className, String path) public PackageInformation getPackageInformation(String packageName) public PackageInformation getClassPackageInformation(String className, String packageName) protected ClassLoader isJDKRequest(String name) } }

Los siguientes dos ejemplos de ClassLoaderPolicy. El primero recupera los recursos con base en expresiones regulares, mientras que el segundo maneja los recursos encriptados. Ejemplo 9.2. ClassLoaderPolicy con soporte para expresiones regulares
public class RegexpClassLoaderPolicy extends ClassLoaderPolicy { private VirtualFile[] roots; private String[] packageNames; public RegexpClassLoaderPolicy(VirtualFile[] roots) { this.roots = roots; } @Override public String[] getPackageNames() { if (packageNames == null) { Set<String> exportedPackages = PackageVisitor.determineAllPackages(roots, null, ExportAll.NON_EMPTY, null, null, null); packageNames = exportedPackages.toArray(new String[exportedPackages.size()]); } return packageNames; } protected Pattern createPattern(String regexp) { boolean outside = true; StringBuilder builder = new StringBuilder(); for (int i = 0; i < regexp.length(); i++) { char ch = regexp.charAt(i); if ((ch == '[' || ch == ']' || ch == '.') && escaped(regexp, i) == false) { switch (ch) { case '[' : outside = false; break; case ']' : outside = true; break; case '.' : if (outside) builder.append("\\"); break; }

72

ClassLoader
} builder.append(ch); } return Pattern.compile(builder.toString()); } protected boolean escaped(String regexp, int i) { return i > 0 && regexp.charAt(i - 1) == '\\'; } public URL getResource(String path) { Pattern pattern = createPattern(path); for (VirtualFile root : roots) { URL url = findURL(root, root, pattern); if (url != null) return url; } return null; } private URL findURL(VirtualFile root, VirtualFile file, Pattern pattern) { try { String path = AbstractStructureDeployer.getRelativePath(root, file); Matcher matcher = pattern.matcher(path); if (matcher.matches()) return file.toURL(); List<VirtualFile> children = file.getChildren(); for (VirtualFile child : children) { URL url = findURL(root, child, pattern); if (url != null) return url; } return null; } catch (Exception e) { throw new RuntimeException(e); } } public void getResources(String name, Set<URL> urls) throws IOException { Pattern pattern = createPattern(name); for (VirtualFile root : roots) { RegexpVisitor visitor = new RegexpVisitor(root, pattern); root.visit(visitor); urls.addAll(visitor.getUrls()); } } private static class RegexpVisitor implements VirtualFileVisitor { private VirtualFile root; private Pattern pattern; private Set<URL> urls = new HashSet<URL>(); private RegexpVisitor(VirtualFile root, Pattern pattern)

73

Captulo 9. La capa ClassLoading


{ this.root = root; this.pattern = pattern; } public VisitorAttributes getAttributes() { return VisitorAttributes.RECURSE_LEAVES_ONLY; } public void visit(VirtualFile file) { try { String path = AbstractStructureDeployer.getRelativePath(root, file); Matcher matcher = pattern.matcher(path); if (matcher.matches()) urls.add(file.toURL()); } catch (Exception e) { throw new RuntimeException(e); } } public Set<URL> getUrls() { return urls; } } }

RegexpClassLoaderPolicy usa un mecanismo simplistico para encontrar los recursos que coinciden. Las implementaciones del mundo real seran ms completas y elegantes.
public class RegexpService extends PrintService { public void start() throws Exception { System.out.println(); ClassLoader cl = getClass().getClassLoader(); Enumeration<URL> urls = cl.getResources("config/[^.]+\\.[^.]{1,4}"); while (urls.hasMoreElements()) { URL url = urls.nextElement(); print(url.openStream(), url.toExternalForm()); } } }

El servicio de expresiones regulares usa el patrn de la expresin regular config/[^.]+\\.[^.] {1,4} para listar los recursos bajo el directorio config// . La longitud del sufijo es limitado de tal manera que los nombres de archivos tal como excluded.properties se ignorarn. Ejemplo 9.3. ClassLoaderPolicy con soporte para codificacin
public class CrypterClassLoaderPolicy extends VFSClassLoaderPolicy { private Crypter crypter;

74

ClassLoader
public CrypterClassLoaderPolicy(String name, VirtualFile[] roots, VirtualFile[] excludedRoots, Crypter crypter) { super(name, roots, excludedRoots); this.crypter = crypter; } @Override public URL getResource(String path) { try { URL resource = super.getResource(path); return wrap(resource); } catch (IOException e) { throw new RuntimeException(e); } } @Override public InputStream getResourceAsStream(String path) { InputStream stream = super.getResourceAsStream(path); return crypter.crypt(stream); } @Override public void getResources(String name, Set<URL> urls) throws IOException { super.getResources(name, urls); Set<URL> temp = new HashSet<URL>(urls.size()); for (URL url : urls) { temp.add(wrap(url)); } urls.clear(); urls.addAll(temp); } protected URL wrap(URL url) throws IOException { return new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile(), new CrypterURLStreamHandler(crypter)); } }

Ejemplo 9.3, ClassLoaderPolicy con soporte para codificacin muestra cmo encriptar JARs. Puede configurar cules recursos codificar especificando un filtro apropiado. Aqu todo est encriptado a excepcin del contenido del directorio META-INF/.
public class EncryptedService extends PrintService { public void start() throws Exception { ClassLoader cl = getClass().getClassLoader(); URL url = cl.getResource("config/settings.txt"); if (url == null) throw new IllegalArgumentException("No such settings.txt."); InputStream is = url.openStream(); print(is, "Printing settings:\n"); is = cl.getResourceAsStream("config/properties.xml"); if (is == null) throw new IllegalArgumentException("No such properties.xml."); print(is, "\nPrinting properties:\n");

75

Captulo 9. La capa ClassLoading


} }

Este servicio imprime el contenido de dos archivos de configuracin. Muestra que se esconde la decodificacin de cualquier recurso encriptado detrs de la capa de carga de clase. Para probar esto apropiadamente puede encriptar el mdulo de poltica usted mismo o puede utilizar uno que ya est encriptado. Para poner esto en accin es necesario que uan apropiadamente EncryptedService con ClassLoaderSystem y los programas de implementacin. Ms adelante en este captulo abrodamos el particionamiento del ClassLoaderSystem.

9.2. ClassLoading
En lugar de utilizar la abstraccin ClassLoader directamente puede crear mdulos ClassLoading, los cuales contienen declaraciones de dependencias ClassLoader. Una vez se especifican las dependencias se construyen las ClassLoaderPolicys y se conectan de manera respectiva. Para facilitar la definicin de los ClassLoaders antes de que existan, la abstraccin incluye un modelo ClassLoadingMetaData. El ClassLoadingMetaData se puede presentar como un objeto administrado dentro del nuevo servicio de perfil JBoss EAP. Esto le ayuda a los administradores de sistemas a tratar con los detalles de la poltica abstracta en lugar de los detalles de la implementacin. Ejemplo 9.4. ClassLoadingMetaData presentada como un objeto administrado
public class ClassLoadingMetaData extends NameAndVersionSupport { /** The serialVersionUID */ private static final long serialVersionUID = -2782951093046585620L; /** The classloading domain */ private String domain; /** The parent domain */ private String parentDomain; /** Whether to make a subdeployment classloader a top-level classloader */ private boolean topLevelClassLoader = false; /** Whether to enforce j2se classloading compliance */ private boolean j2seClassLoadingCompliance = true; /** Whether we are cacheable */ private boolean cacheable = true; /** Whether we are blacklistable */ private boolean blackListable = true; /** Whether to export all */ private ExportAll exportAll; /** Whether to import all */ private boolean importAll; /** The included packages */ private String includedPackages; /** The excluded packages */ private String excludedPackages;

76

ClassLoading

/** The excluded for export */ private String excludedExportPackages; /** The included packages */ private ClassFilter included; /** The excluded packages */ private ClassFilter excluded; /** The excluded for export */ private ClassFilter excludedExport; /** The requirements */ private RequirementsMetaData requirements = new RequirementsMetaData(); /** The capabilities */ private CapabilitiesMetaData capabilities = new CapabilitiesMetaData(); ... setters & getters

Ejemplo 9.5, API ClassLoading definida en XML y Ejemplo 9.6, API ClassLoading definida en Java muestran la API ClassLoading definida en XML y Java respectivamente. Ejemplo 9.5. API ClassLoading definida en XML
<classloading xmlns="urn:jboss:classloading:1.0" name="ptd-jsf-1.0.war" domain="ptd-jsf-1.0.war" parent-domain="ptd-ear-1.0.ear" export-all="NON_EMPTY" import-all="true" parent-first="true"/>

Ejemplo 9.6. API ClassLoading definida en Java


ClassLoadingMetaData clmd = new ClassLoadingMetaData(); if (name != null) clmd.setDomain(name + "_Domain"); clmd.setParentDomain(parentDomain); clmd.setImportAll(true); clmd.setExportAll(ExportAll.NON_EMPTY); clmd.setVersion(Version.DEFAULT_VERSION);

Puede agregar ClassLoadingMetaData a su implementacin ya sea programticamente o declarativamente por medio de jboss-classloading.xml. Ejemplo 9.7. Agregar ClassLoadingMetaData por medio de jboss-classloading.xml
<classloading xmlns="urn:jboss:classloading:1.0" domain="DefaultDomain" top-level-classloader="true" export-all="NON_EMPTY"

77

Captulo 9. La capa ClassLoading


import-all="true"> </classloading>

El DefaultDomain se comparte entre todas las aplicaciones que no definen sus propios dominios. Ejemplo 9.8. Aislamiento tpico a nivel de dominio
<classloading xmlns="urn:jboss:classloading:1.0" domain="IsolatedDomain" export-all="NON_EMPTY" import-all="true"> </classloading>

Ejemplo 9.9. Aislamiento con un padre especfico


<classloading xmlns="urn:jboss:classloading:1.0" domain="IsolatedWithParentDomain" parent-domain="DefaultDomain" export-all="NON_EMPTY" import-all="true"> </classloading>

Ejemplo 9.10. No cumple con los requerimientos de j2seClassLoadingCompliance


<classloading xmlns="urn:jboss:classloading:1.0" parent-first="false"> </classloading>

Las implementaciones .war usan este mtodo por defecto. En lugar de realizar buqeudas de padres primero por defecto primero chequea sus propios recursos. Ejemplo 9.11. Implementacin tpica OSGi
<classloading xmlns="urn:jboss:classloading:1.0"> <requirements> <package name="org.jboss.dependency.spi"/> </requirements> <capabilities> <package name="org.jboss.cache.api"/> <package name="org.jboss.kernel.spi"/> </capabilities> </classloading>

Ejemplo 9.12. Importing and Exporting Whole Modules and Libraries, Rather than Fine-Grained Packages
<classloading xmlns="urn:jboss:classloading:1.0"> <requirements> <module name="jboss-reflect.jar"/> </requirements>

78

ClassLoading
<capabilities> <module name="jboss-cache.jar"/> </capabilities> </classloading>

<classloading xmlns="urn:jboss:classloading:1.0"> <requirements> <package name="si.acme.foobar"/> <module name="jboss-reflect.jar"/> </requirements> <capabilities> <package name="org.alesj.cl"/> <module name="jboss-cache.jar"/> </capabilities> </classloading>

Tambin puede mezclar los requerimientos y los tipos de funcionalidades usando paquetes y mdulos. El sub-proyecto de carga de clase usa una implementacin muy pequea del patrn recurso-visitante. En el proyecto ClassLoader, la conexin entre implementacin y carga de clase se realiza por medio de la clase Module, la cual mantiene toda la informacin requerida para aplicar restricciones apropiadamente en el patrn del visitante tal como los filtros. Ejemplo 9.13. Las interfaces ResourceVisitor y ResourceContext
public interface ResourceVisitor { ResourceFilter getFilter(); void visit(ResourceContext resource); } public interface ResourceContext { URL getUrl(); ClassLoader getClassLoader(); String getResourceName(); String getClassName(); boolean isClass(); Class<?> loadClass(); InputStream getInputStream() throws IOException; byte[] getBytes() throws IOException; }

Para usar el mdulo, instancie su instancia ResourceVisitor y psela al mtodo Module::visit. Esta funcionalidad se utiliza en el marco d etrabajo de la implementacin para indexar los usos de anotacions en las implementaciones. 79

Captulo 9. La capa ClassLoading

9.3. Carga de clase VFS


Esros ejemplos proporcionan una implementacin de la ClassLoaderPolicy que usa un proyecto de sistema de archivos virtual JBoss para cargar clases y recursos. Puede utilizar esta idea directamente o en conjunto con un marco de trabajo de carga de clase. Opcionalmente puede configurar sus mdulos dentro de la configuracin del microcontenedor. Ejemplo 9.14. Programa de implementacin del mdulo de carga de clases
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <classloader name="anys-classloader" xmlns="urn:jboss:classloader:1.0" import-all="true" domain="Anys" parent-domain="DefaultDomain"> <capabilities> <package name="org.jboss.test.deployers.vfs.reflect.support.web"/> </capabilities> <root>${jboss.tests.url}</root> </classloader> <bean name="AnyServlet" class="org.jboss.test.deployers.vfs.reflect.support.web.AnyServlet"> <classloader><inject bean="anys-classloader:0.0.0"/></classloader> </bean> </deployment>

La clase VFSClassLoaderFactory transforma el programa de implementacin XML en un VFSClassLoaderPolicyModule, el cual luego crea la instacia real del ClassLoader. Luego puede utilizar directamente esta nueva instancia ClassLoader con sus beans.

Nota
VFSClassLoaderFactory extiende ClassLoadingMetaData as que todos los ejemplos relacionados con ClassLoadingMetaData aplican en este caso tambin.

80

Marco de trabajo de la implementacin virtual


El nuevo Marco d etrabajo de la implementacin virtual (VDF del ingls Virtual Deployment Framework) es una manera mejorada de administrar los programas de implementacin en el microcontenedor. Este captulo detalla algunas de sus funcionalidades ms tiles.

10.1. Manejo agnstico de tipos de implementacin


El tipo tradicional de implementacin virtual se basa en clases que ya existen en un espcio de clase o dominio compartido. En este caso, el producto final es un nuevo servicio instalado en el servidor desde el cliente principal. La manera tradicional de lograr esto es cargar un archivo del programa de implementacin. El nuevo VDF simplifica este proceso pasando los bytes y serialindolos en una instancia Deployment. El otro tipo de implementacin, el cual extiende el primero, es una implementancin basada en el sistema simple de archivos, respaldado po el microcontenedor VFS. Este enfoque se describe con ms detalle en Captulo 8, El sistema virtual de archivos.

10.2. Separacin del reconocimiento de la estructura de la lgica del ciclo de vida de la implementacin
Con el fin de realizar cualquier trabajo real encima de una implementacin primero debe comprender su estructura incluyendo sus rutas de clase y la ubicacin de sus metadatos. La ubicacin de los metadatos incluye los archivos de configuracin tal como my-jbossbeans.xml, web.xml, ejb-jar.xml. Las rutas de clase son races del cargador de clase tal como WEB-INF/classes o myapp.ear/lib. Teniendo esta estructura en mente puede proceder al manejo de la implementacin. Ciclo de vida de una implementacin tpica 1. El MainDeployer le pasa la implementacin al grupo de StructuralDeployers para un reconocimiento y recibe un contexto de implementacin. 2. Luego, el MainDeployer le pasa el contexto de implementacin que resulta a los Deployers para que el Deployer apropiado lo maneje. De esta manera, el MainDeployer es un agente con la responsibilidad de decidir qu programas de implementacin utilizar. En el caso de una implementacin virtual o programtica, una informacin StructureMetaData predeterminada ya existente lee la informacin de la estructura y la maneja de una de las maneras que se explic en Manejo de la informacin StructuredMetaData. Manejo de la informacin StructuredMetaData Implementaciones basadas en VFS el reconocimiento de la estructura se re-enva a un grupo de StructureDeployers. estructuras definidas de la especificacin JEE tenemos implementaciones StructureDeployer que coinciden: EarStructure 81

Captulo 10. Marco de trabajo de la implementacin virtual WarStructure JarStructure DeclarativeStructures busca el archivo META-INF/jboss-structure.xml dentro de su implementacin y lo analiza sintcticamente para construir un StructureMetaData apropiado. FileStructures solo reconoce los archivos de configuracin conocidos tal como -jboss-beans.xml o service.xml. Ejemplo 10.1. Un ejemplo de jboss-structure.xml
<structure> <context comparator="org.jboss.test.deployment.test.SomeDeploymentComparatorTop"> <path name=""/> <metaDataPath> <path name="META-INF"/> </metaDataPath> <classpath> <path name="lib" suffixes=".jar"/> </classpath> </context> </structure>

En el caso de EarStructure, primero reconozca una implementacin a nivel superior y luego procese recursivamente las sub-implementaciones. Puede implementar un StructureDeployer personalizado con la ayuda de la clase genrica GroupingStructure proporcionada por la interfaz genrica StructureDeployer. Despus de tener una estructura de implementacin reconocida se la puede pasar a los programas de implementacin reales. El objeto Deployers sabe cmo encargarse de los programas de implementacin reales, utilizando una cadena de programas de implementacin por DeploymentStage. Ejemplo 10.2. Etapas de la implementacin
public interface DeploymentStages { /** The not installed stage - nothing is done here */ DeploymentStage NOT_INSTALLED = new DeploymentStage("Not Installed"); /** The pre parse stage - where pre parsing stuff can be prepared; altDD, ignore, ... */ DeploymentStage PRE_PARSE = new DeploymentStage("PreParse", NOT_INSTALLED); /** The parse stage - where metadata is read */ DeploymentStage PARSE = new DeploymentStage("Parse", PRE_PARSE); /** The post parse stage - where metadata can be fixed up */ DeploymentStage POST_PARSE = new DeploymentStage("PostParse", PARSE); /** The pre describe stage - where default dependencies metadata can be created */ DeploymentStage PRE_DESCRIBE = new DeploymentStage("PreDescribe", POST_PARSE); /** The describe stage - where dependencies are established */ DeploymentStage DESCRIBE = new DeploymentStage("Describe", PRE_DESCRIBE); /** The classloader stage - where classloaders are created */

82

Separacin del reconocimiento de la estructura de la lgica del ciclo de vida de la implementacin


DeploymentStage CLASSLOADER = new DeploymentStage("ClassLoader", DESCRIBE); /** The post classloader stage - e.g. aop */ DeploymentStage POST_CLASSLOADER = new DeploymentStage("PostClassLoader", CLASSLOADER); /** The pre real stage - where before real deployments are done */ DeploymentStage PRE_REAL = new DeploymentStage("PreReal", POST_CLASSLOADER); /** The real stage - where real deployment processing is done */ DeploymentStage REAL = new DeploymentStage("Real", PRE_REAL); /** The installed stage - could be used to provide valve in future? */ DeploymentStage INSTALLED = new DeploymentStage("Installed", REAL); }

La etapas de implementacin pre-existentes se mapean a los estados del controlador incorporado del microcontenedor. Proporcionan una vista cntrica del ciclo de vida de la implementacin de los estados del controlador genrico. Dentro de los programas de implementacin, la implementacin se convierte en el componente DeploymentControllerContext del microcontenedor. La mquina de estado del microcontenedor maneja las dependencias. Las implementaciones se manejan secuencialmente por etapa de implementacin. Para cada porgrama de implementacin se maneja todo el orden de la jerarqua implementada usando la propiedad parent-first del programa de implementacin. Esta propiedad se configura como true por defecto. Tambin puede especificar los niveles de jerarqua que el programa de implementacin maneja. Puede seleccionar all, top level, components only o no components. La manera en que el microcontendor maneja los modelos de componentes y el manejo de las dependencias tambin aplica aqu. Si hay dependencias no resueltas entonces la implementacin empezar en el estado actual, potencialmente reportando un error si el estado actual no es el estado requerido. El agregar un nuevo programa de implementacin se logra extendiendo uno de los muchos programas de implementacin de ayuda que existen. Algunos programas de implementaciin de hecho necesitan una implementacin respaldada por VFS mientras que otros pueden utilizar una implementacin general. En la mayora de los casos los programas de instalacin de anlisis sintctico son los que necesitan respaldo de VFS.

Aviso
Tambin tenga en cuenta que los programas de implementacin ejecutan recursivamente en toda implementacin, sub-implementacin y componentes. Su cdigo necesita determinar tan pronto como sea posible en el proceso, si el programa de implementacin debe manejar la implementacin actual o no.

Ejemplo 10.3. Programa de implementacin simple, el cual presenta informacin sobre su implementacin
public class StdioDeployer extends AbstractDeployer {

83

Captulo 10. Marco de trabajo de la implementacin virtual


public void deploy(DeploymentUnit unit) throws DeploymentException { System.out.println("Deploying unit: " + unit); } @Override public void undeploy(DeploymentUnit unit) { System.out.println("Undeploying unit: " + unit); } }

Agregue esta descripcin en uno de los archivos -jboss-beans.xml en el directorio deployers/ en el servidor de aplicaciones JBoss y el bean MainDeployerImpl reconocer este programa de implementacin por medio del manejo callback loC del microcontenedor. Ejemplo 10.4. Descriptor de implementacin simple
<bean name="StdioDeployer" class="org.jboss.acme.StdioDeployer"/>

10.3. Control de flujo natural en forma de anexos


VDF incluye un mecanismo llamado anexos -attachments, el cual facilita el paso de la informacin de un programa de implementacin al siguiente. Los anexos se implementan como un java.util.Map con mejoras, cuyas entradas representan un anexo. Algunos programas de implementacin son productores mientras que otros son consumidores. El mismo programa de implementacin tambin puede realizar ambas funciones. Algunos programas de implementacin crean metadatos o instancias de funcionalidades ponindolos en el mapa de anexos. Otros programas de implementacin solo declaran su necesidad de estos anexos y toman los datos del mapa de anexos, antes de realizar trabajo adicional en esos datos. El orden natural se refiere a la manera en que los porgramas de implementacin se ordenan. Un orden natural comn usa los trminos relativos antes y despus. Sin embargo, con el mecanismo de anexos en uso puede ordenar los programas de implementacin de acuerdo a la manera en que producen y/o consumen los anexos. Cada anexo tiene una llave y los programas de implementacin pasan las llaves a los anexos que producen. Si el programa de implementacin produce un anexo entonces se llama a la llave output. Si el programa de implementacin consume un anexo entonces esa llave se llama input. Los programas de implementacin tienen entradas ordinarias y entradas requeridas. Las entradas ordinarias slo se utilizan para ayudar a determinar el orden natural. Las entradas requeridas tambin ayudan a determinar el orden, pero tambin tienen otra funcin. Ayudan a determinar si el programa de implementacin de hecho es relevante para la implementacin dada, chequeando a ver si existe un anexo correspondiente a esa entrada requerida en el mapa de anexos.

Aviso
Aunque se soporta el ordenamiento relativo, este se considera como mala prctica y es posible que no haya soporte para este en lanzamientos futuros.

84

Detalles de la implementacin y del cliente, usuario y uso del servidor

10.4. Detalles de la implementacin y del cliente, usuario y uso del servidor


Estas funcionalidades esconden los detalles de la implementacin, lo cual hace que el uso sea menos propenso a errores y al mismo tiempo optimiza el proceso de desarrollo. La meta es que los clientes solo vean una API de desarrollo mientras que los desarrolladores vean un DeploymentUnit y los detalles de la implementacin del servidor se encuentren en un DeploymentContext. Solo se presenta la informacin necesaria en un nivel en particular del ciclo de vida de la implementacin. Ya mencionamos los componentes como parte del manejo de la jerarqua de los desarrolladores. Aunque la implementacin y sub-implementacin a nivel superior son una representacin natural de la jerarqua de la estructura de la implementacin, los componentes son un nuevo concepto VDF. La idea de los componentes es que tengan un mapeo 1:1 con el ControllerContexts dentro del microcontenedor. Consulte Por qu los componentes mapean 1:1 con los ControllerContexts para ver las razones que respaldan esta afirmacin. Por qu los componentes mapean 1:1 con los ControllerContexts Nombrado El nombre de la unidad del componente es el mismo que el nombre del ControllerContext. get*Scope() and get*MetaData() retorna el mismo contexto MDR que el microcontenedor utilizar para esa instancia. IncompleteDeploymentException (IDE) Con el fin de que el IDE imprima las dependencias que faltan en una implementacin, necesita saber los nombres del ControllerContext. descubre el nombre reuniendo los nombres de las DeploymentUnit's componentes en los programas de implementacin de componentes que los especifican tal como los mtodos BeanMetaDataDeployer o setUseUnitName() en AbstractRealDeployer.

10.5. Mquina de estado nico


Todos los componentes del microcontenedor son manejados por un solo punto de entrada o una sola mquina de estado. Las implemtaciones no son la excepcin. Puede sacar ventaja de esta funcionalidad utilizando el archivo de configuracin jbossdependency.xml en sus implementaciones. Ejemplo 10.5. jboss-dependency.xml
<dependency xmlns="urn:jboss:dependency:1.0"> <item whenRequired="Real" dependentState="Create">TransactionManager</item> (1) <item>my-human-readable-deployment-alias</item> (2) </dependency>

Note las llamadas artificiales en el XML: (1) y (2). (1) muestra cmo describir la dependencia en otro servicio. Este ejemplo requiere el crear un TransactionManager antes de que la implementacin se encuentre en la etapa 'real'. (2) es un poco ms complejo ya que le falta informacin adicional. Por defecto, los nombres de las implementaciones dentro del microcontenedor son nombres URI, lo cual hace que el escribirlos a mano sea un proceso propenso a errores. As que con el fin de declarar dependencias fcilmente en otras implementaciones, necesita un mecanismo de alias para evitar nombres URI. Puede 85

Captulo 10. Marco de trabajo de la implementacin virtual agregar un archivo de texto simple llamado aliases.txt en su implementacin. Cada lnea del archivo contiene un alias, dndole al fichero de implementacin uno o ms nombres simples utilizados para referirse a este.

10.6. Escaneo de clases en busca de anotaciones


Las especificaciones JEE actuales reducen el nmero de archivos de configuracin, pero ahora se requiere que el contenedor realice la mayora del trabajo utilizando @annotations. Con el fin de obtener informacin sobre @annotation, los contenedores deben escanear las clases. Este escaneo crea una penalidad en el rendimiento. Sin embargo con el fin de reducir la cantidad de escaneo, el microcontenedor proporciona otro gancho descriptor por medio de jboss-scanning.xml. Ejemplo 10.6. jboss-scanning.xml
<scanning xmlns="urn:jboss:scanning:1.0"> <path name="myejbs.jar"> <include name="com.acme.foo"/> <exclude name="com.acme.foo.bar"/> </path> <path name="my.war/WEB-INF/classes"> <include name="com.acme.foo"/> </path> </scanning>

Este ejemplo muestra una descripcin simple de rutas relativas para incluir o excluir cuando se escanea en busca de informacin de metadatos anotados para Java Enterprise Edition versin 5y posteriores.

86

Apndice A. Historial de revisiones


Revisin 5-1 Wed Sep 15 2010 Misty Stanley-Jones mstanley@redhat.com JBPAPP-5076 - Arreglar los ejemplos y sus leyendas Se cambi el nmero de la versin en relacin con los requerimientos de la versin. Revisado para JBoss Enterprise Application Platform 5.1.0.GA.

87

88

You might also like