JBoss Enterprise Application Platform 5 Manual del usuario de

Anuncio
JBoss Enterprise Application
Platform 5
Manual del usuario de JBoss
Microcontainer
para uso con JBoss Enterprise Application Platform 5
Edición 5.1.0
Mark Newton
Aleš Justin
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss
Microcontainer
para uso con JBoss Enterprise Application Platform 5
Edición 5.1.0
Mark Newto n
Red Hat
mark.newto n@jbo ss.o rg
Aleš Justin
Red Hat
[email protected] m
Edited by
Misty Stanley-Jo nes
Red Hat
[email protected] m
Legal Notice
Copyright © 2011 Red Hat, Inc.
T his document is licensed by Red Hat under the Creative Commons Attribution-ShareAlike 3.0 Unported
License. If you distribute this document, or a modified version of it, you must provide attribution to Red
Hat, Inc. and provide a link to the original. If the document is modified, all Red Hat trademarks must be
removed.
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 T orvalds 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.
Node.js ® is an official trademark of Joyent. Red Hat Software Collections is not formally related to or
endorsed by the official Joyent Node.js open source or commercial project.
T he OpenStack ® Word Mark and OpenStack Logo are either registered trademarks/service marks or
trademarks/service marks of the OpenStack Foundation, in the United States and other countries and
are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or
sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
Abstract
Este manual está dirigido a aquellos desarrolladores Java que desean utilizar el microcontenedor
JBoss para implementar entornos Java modulares y personalizados para sus aplicaciones.
Table of Contents
Table of Contents
.Prefacio
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . . .
1. Convenciones del Documento
4
1.1. Convenciones tipográficas
4
1.2. Convenciones del documento
5
1.3. Notas y Advertencias
6
2. Cómo obtener ayuda y hacer sus comentarios
6
2.1. ¿Necesita ayuda?
6
2.2. ¡Necesitamos sus comentarios!
7
. . . . . . .I.. Introducción
Parte
. . . . . . . . . . . . . .al
. . tutorial
. . . . . . . . sobre
. . . . . . .el
. . Microcontainer
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8. . . . . . . . . .
.Capítulo
. . . . . . . . .1.
. . Prerequisitos
. . . . . . . . . . . . . . .para
. . . . .el
. . uso
. . . . .de
. . .este
. . . . .manual
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9. . . . . . . . . .
1.1. Instale Maven
9
1.2. Configuración especial de Maven para los ejemplos del microcontenedor
12
1.3. Descarga de los ejemplos
13
.Capítulo
. . . . . . . . .2.
. . Introducción
. . . . . . . . . . . . . .al. .microcontenedor
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
............
2.1. Funcionalidades
14
2.2. Definiciones
14
2.3. Instalación
15
.Capítulo
. . . . . . . . .3.. .Construcción
. . . . . . . . . . . . . . de
. . . servicios
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
............
3.1. Introducción al ejemplo de recusos humanos
16
3.2. Compilación del proyecto de ejemplo HRManager
17
3.3. Creación de POJOs
17
3.3.1. Descriptores de implementación XML
17
3.4. Conexión de POJOs
17
3.4.1. Consideraciones especiales
18
3.5. T rabajar con servicios
18
3.5.1. Configuración de un servicio
19
3.5.2. Probar un servicio
19
3.5.3. Empacar un servicio
21
.Capítulo
. . . . . . . . .4. .. Uso
. . . . .de
. . .los
. . . servicios
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23
...........
4.1. Bootstrap del microcontenedor
26
4.2. Implementación del servicio
27
4.3. Acceso directo
28
4.4. Acceso indirecto
30
4.5. Carga de clase dinámica
31
4.5.1. Problemas con cargadores de clase creados con los descriptores de implementación
36
.Capítulo
. . . . . . . . .5.
. . Agregar
. . . . . . . . .comportamiento
. . . . . . . . . . . . . . . . . con
. . . . .AOP
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .37
...........
5.1. Creación de un aspecto
37
5.2. Configuración del microcontenedor para AOP
39
5.3. Aplicación de un aspecto
41
5.4. Callbacks del ciclo de vida
43
5.5. Agregar búsquedas de servicios por medio de JNDI
45
. . . . . . .II.. .Conceptos
Parte
. . . . . . . . . . . .avanzados
. . . . . . . . . . . con
. . . . .el
. . microcontenedor
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. .7. . . . . . . . . .
.Capítulo
. . . . . . . . .6.
. . Modelos
. . . . . . . . . de
. . . componentes
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. .8. . . . . . . . . .
6.1. Interacciones permitidas con los modelos de componentes
48
6.2. Un Bean sin dependencias
48
6.3. Uso del microcontenedor con Spring
48
1
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
6.3. Uso del microcontenedor con Spring
6.4. Uso de Guice con el microcontenedor
6.5. MBeans de legado y mezcla de diferentes modelos de componentes
6.6. Exponer POJOs como MBeans
48
49
52
53
.Capítulo
. . . . . . . . .7.
. . Inyección
. . . . . . . . . . avanzada
. . . . . . . . . . .de
. . . dependencias
. . . . . . . . . . . . . . . y. .ldC
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
............
7.1. Fábrica de valores
56
7.2. Callbacks
58
7.3. Modo de acceso del Bean
60
7.4. Alias Bean
61
7.5. Soporte para anotaciones XML (o metadatos)
61
7.6. Autowire
64
7.7. Fábrica de beans
64
7.8. Constructor de metadatos Bean
67
7.9. ClassLoader personalizado
68
7.10. Modo controlador
69
7.11. Ciclo
70
7.12. Oferta y demanda
71
7.13. Instalaciones
71
7.14. Imitación perezosa
72
7.15. Ciclo de vida
73
.Capítulo
. . . . . . . . .8.
. . El
. . .sistema
. . . . . . . . virtual
. . . . . . . de
. . . .archivos
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
............
8.1. API pública VFS
77
8.2. Arquitectura VFS
86
8.3. Implementaciones existentes
86
8.4. Ganchos de extensión
87
8.5. Funcionalidades
87
.Capítulo
. . . . . . . . .9.
. . La
. . . capa
. . . . . .ClassLoading
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
............
9.1. ClassLoader
89
9.2. ClassLoading
96
9.3. Carga de clase VFS
101
.Capítulo
. . . . . . . . .10.
. . . Marco
. . . . . . . de
. . . trabajo
. . . . . . . . de
. . . .la. .implementación
. . . . . . . . . . . . . . . . .virtual
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
.............
10.1. Manejo agnóstico de tipos de implementación
103
10.2. Separación del reconocimiento de la estructura de la lógica del ciclo de vida de la
implementación
103
10.3. Control de flujo natural en forma de anexos
106
10.4. Detalles de la implementación y del cliente, usuario y uso del servidor
107
10.5. Máquina de estado único
108
10.6. Escaneo de clases en busca de anotaciones
108
. . . . . . . . . .de
Historial
. . .revisiones
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
.............
2
Table of Contents
3
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Prefacio
1. Convenciones del Documento
Este manual utiliza varias convenciones para resaltar algunas palabras y frases y llamar la atención
sobre ciertas partes específicas de información.
En ediciones PDF y de papel, este manual utiliza tipos de letra procedentes de Liberation Fonts.
Liberation Fonts también se utilizan en ediciones de HT ML si están instalados en su sistema. Si no, se
muestran tipografías alternativas pero equivalentes. Nota: Red Hat Enterprise Linux 5 y siguientes
incluyen Liberation Fonts predeterminadas.
1.1. Convenciones tipográficas
Se utilizan cuatro convenciones tipográficas para llamar la atención sobre palabras o frases
específicas. Dichas convenciones y las circunstancias en que se aplican son las siguientes:
Negrita m onoespaciado
Utilizado para resaltar la entrada del sistema, incluyendo los comandos de shell, nombres de archivos y
rutas. T ambién sirve para resaltar teclas y combinaciones de teclas. Por ejemplo:
Para ver el contenido del archivo m y_next_bestselling_novel en su directorio actual
de trabajo, escriba el comando cat m y_next_bestselling_novel en el intérprete 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 . T odo se presenta
en negrita-monoespaciado y distinguible gracias al contexto.
Las combinaciones de teclas se pueden distinguir de las individuales con el signo más que conecta
cada partee de la combinación de tecla. Por ejemplo:
Pulse Enter para ejecutar el comando.
Pulse Ctrl+Alt+F2 para pasar a una terminal virtual.
El primer ejemplo resalta una tecla particular a pulsar. El segundo ejemplo, resalta una combinación de
teclas: un set de tres teclas pulsadas simultáneamente.
Si se discute el código fuente, los nombres de las clase, los métodos, las funciones, los nombres de
variables y valores de retorno mencionados dentro de un párrafo serán presentados en Negritam onoespaciado. Por ejemplo:
Las clases de archivo relacionadas incluyen filenam e 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 aplicación, texto de
cuadro de diálogo, botones etiquetados, etiquetas de cajilla de verificación y botón de radio; títulos de
menú y títulos del submenú. Por ejemplo:
Seleccione Sistema → Preferencias → Ratón desde la barra del menú principal para
lanzar Preferencias de ratón. En la pestaña de Botones, seleccione la cajilla de ratón
4
Prefacio
de m ano izquierda y luego haga clic en Cerrar para cambiar el botón principal del
ratón de la izquierda a la derecha (adecuando el ratón para la mano izquierda).
Para insertar un carácter especial en un archivo gedit, seleccione Aplicaciones →
Accesorios → Mapa de caracteres de la barra del menú. Luego, seleccione Búsqueda
→ Buscar… de la barra del menú de Mapa de caracteres, escriba el nombre del
carácter en el campo de Búsqueda y haga clic en Siguiente. El carácter que buscó será
resaltado en la T abla de caracteres. Haga doble clic en ese carácter resaltado para
colocarlo en el campo de T exto a copiar y luego haga clic en el botón Copiar. Ahora
regrese al documento y elija Modificar → Pegar de la barra de menú de gedit.
El texto anterior incluye nombres de aplicación; nombres y elementos del menú de todo el sistema;
nombres de menú de aplicaciones específicas y botones y texto hallados dentro de una interfaz gráfica
de usuario, todos presentados en negrita proporcional y distinguibles por contexto.
Itálicas-negrita monoespaciado o Itálicas-negrita proporcional
Ya sea negrita monoespaciado o negrita proporcional, la adición de itálicas indica texto reemplazable o
variable. Las itálicas denotan texto que usted no escribe literalmente o texto mostrado que cambia
dependiendo de la circunstancia. Por ejemplo:
Para conectar a una máquina remota utilizando ssh, teclee ssh nombre de
usuario@ dominio.nombre en un intérprete de comandos de shell. Si la máquina remota
es exam ple.com y su nombre de usuario en esa máquina es john, teclee ssh
john@ exam ple.com .
El comando m ount -o rem ount file-system remonta el sistema de archivo llamado.
Por ejemplo, para volver a montar el sistema de archivo /hom e, el comando es m ount -o
rem ount /hom e.
Para ver la versión de un paquete actualmente instalado, utilice el comando rpm -q
paquete. Éste entregará el resultado siguiente: paquete-versión-lanzamiento.
Observe que las palabras resaltadas en itálicas — nombre de usuario, dominio.nombre, sistema de
archivo, paquete, versión y lanzamiento. Cada palabra es un marcador de posición, ya sea de texto a
ingresar cuando se ejecuta un comando o para un texto ejecutado por el sistema.
Aparte del uso estándar para presentar el título de un trabajo, las itálicas denotan el primer uso de un
término nuevo e importante. Por ejemplo:
Publican es un sistema de publicación de DocBook.
1.2. Convenciones del documento
Los mensajes de salida de la terminal o fragmentos de código fuente se distinguen visualmente del
texto circundante.
Los mensajes de salida enviados a una terminal se muestran en rom ano m onoespaciado y se
presentan así:
books
books_tests
Desktop
Desktop1
documentation
downloads
drafts
images
mss
notes
photos
scripts
stuff
svgs
svn
Los listados de código fuente también se muestran en rom ano m onoespaciado, pero se presentan
y resaltan de la siguiente manera:
5
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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 atención sobre la información que de otro
modo se podría pasar por alto.
Nota
Una nota es una sugerencia, atajo o enfoque alternativo para una tarea determinada. Ignorar una
nota no debería tener consecuencias negativas, pero podría perderse de algunos trucos que
pueden facilitarle las cosas.
Importante
Los cuadros con el título de importante dan detalles de cosas que se pueden pasar por alto
fácilmente: cambios de configuración únicamente aplicables a la sesión actual, o servicios que
necesitan reiniciarse antes de que se aplique una actualización. Ignorar estos cuadros no
ocasionará pérdida de datos, pero puede causar enfado y frustración.
Aviso
Las advertencias no deben ignorarse. Ignorarlas muy probablemente ocasionará pérdida de
datos.
2. Cómo 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 través del portal del cliente, usted podrá:
6
Prefacio
buscar o navegar a través de la base de artículos de soporte técnico sobre productos de Red Hat.
enviar un caso de soporte a Servicios de Soporte Global de Red Hat (GSS)
acceder a otra documentación del producto.
Red Hat alberga una lista grande de correos electrónicos para discutir sobre software de Red Hat y
tecnología. Encontrará un listado de las listas de correo disponibles al público 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 encantaría 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://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
rápidamente.
URL del documento:
Número de la sección y nombre:
Describa el problema:
Sugerencias para mejorar:
Información adicional:
Asegúrese de darnos su nombre para poder darle todo el crédito por reportar el problema.
7
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Parte I. Introducción al tutorial sobre el Microcontainer
8
Capítulo 1. Prerequisitos para el uso de este manual
Capítulo 1. 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 código 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 página 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 también es un
requerimiento para la plataforma empresarial.
Asegúrese 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 información con relación a la configuración 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 ubicación sugerida en su
sistema operativo. Maven, como cualquier otra aplicación 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-m aven-2.2.1-bin.zip
Seleccione un espejo de descarga de la lista.
Para usuarios de Linux
Guarde el fichero zip en su directorio hom e.
Para usuarios de Windows
Guarde el fichero zip en su directorio C:\Docum ents and Settings\user_name.
3. Instale Maven
Para usuarios de Linux
Extraiga el archivo zip en su directorio hom e. Si seleccionó el fichero zip en el paso 2 y no vuelve
a nombrar el directorio, el directorio extraído se llama apache-m aven-version.
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 extraído se llama apachem aven-version.
4. Configure las variables del entorno
9
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Para usuarios de Linux
Agregue las siguientes líneas a su ~/.bash_profile. Asegúrese de cambiar el [username] a
su nombre de usuario real y verifique que el directorio Maven es de hecho el nombre del
directorio. El número de la versión puede ser diferente del que se lista a continuación.
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 versión Maven que acabó de instalar será la versión
predeterminada utilizada. Puede que también quierar establecer la ruta de su variable de entorno
JAVA_HOME con la ubicación del JDK en su sistema.
Para usuarios de Windows
Agregue las variables de entorno M2_HOME, M2 y JAVA_HOME.
a. Oprima Start+Pause|Break. Se presenta la ventana de propiedades del sistema.
b. Haga clic en la pestaña Advanced y luego haga clic en el botón Environm ent
Variables.
c. Bajo System Variables, seleccione Path.
d. 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-m aven-2.2.1.
Agregue la variable M2 y configure el valor como %M2_HOME%\bin.
e. En la misma ventana, cree la variable de entorno JAVA_HOME:
Agregue la variable %JAVA_HOME% y establezca el valor con la ubicación de su JDK. Por
ejemplo C:\Program Files\Java\jdk1.6.0_02.
f. 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 línea de
comandos.
Agregue la variable %JAVA_HOME%\bin para establecer la ruta con la instalación
correcta de Java.
g. Haga clic en OK hasta que la ventana System Properties se cierre.
5. Implemente los cambios en .bash_profile
Solo para los usuarios de Linux
Para actualizar los cambios realizados al .bash_profile en la sesión 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.
10
Capítulo 1. Prerequisitos para el uso de este manual
a. Haga clic en Edit → Profiles
b. Seleccione Default y luego haga clic en el botón Edit.
c. En la ventana Editing Profile, haga clic en la pestaña T itle and Com m and.
d. Seleccione la opción Run com m and as login shell.
e. Cierre todas las terminales que tenga abiertas.
7. Verifique los cambios en las variables de entorno y en la instalación 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 $PAT H y verifique que el directorio Maven /bin está incluído.
[localhost]$ echo $PATH /home/username/apache-maven-2.2.1/bin
Ejecute which m vn, el cual debe presentar la ruta al Maven ejecutable.
[localhost]$ which mvn ~/apache-maven-2.2.1/bin/mvn
Ejecute m vn -version, la cual debe presentar la versión de Maven, la versión Java
relacionada y la información relacionada con el sistema operativo.
[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 línea de comandos ejecute m vn -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.
11
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
1.2. Configuración especial de Maven para los ejemplos del
microcontenedor
Maven es un sistema modular de construcción que llama las dependencias cuando se necesitan. Los
ejemplos en este manual asumen que ha incluído el bloque de XML en Ejemplo 1.1, “Archivo
settings.xm l de ejemplo” en su ~/.m 2/settings.xm l (Linux) o C:\Docum ents and
Settings\username\.m 2\settings.xm l (Windows). Si el archivo no existe entonces créelo
primero.
Ejemplo 1.1. Archivo settings.xm l 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>
</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>
12
Capítulo 1. Prerequisitos para el uso de este manual
1.3. Descarga de los ejemplos
Los ejemplos en este manual le muestran cómo crear un proyecto maven que dependa del JBoss
Microcontainer utilizando Maven. Puede descargarlos de images/examples.zip . Esta ubicación cambiará
pero la hemos incluído para su conveniencia.
Después de descargar el archivo Z IP que contiene los ejemplos, extraiga su contenido en un lugar
conveniente y mire los ejemplos para familiarizarse con su estructura.
13
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Capítulo 2. Introducción al microcontenedor
El microcontenedor JBoss es un rediseño del JBoss JMX Microkernel para soportar la implementación
POJO directa y el uso autónomo fuera del servidor de aplicaciones JBoss.
El microcontenedor está diseñado para llenar las necesidades especificas de los desarrolladores Java
que querían utilizar técnicas de programación orientadas a objetos para implementar software de
manera rápida. Además permite implementar software en un amplio rango de dispositivos desde
plataformas de computación móviles, entornos de computación de grande escala y lo que se encuentre
entre estos dos.
2.1. Funcionalidades
T odas las funcionalidades del microkernel JMX
Implementación POJO directa (no hay necesidad de estándar/XMBean o MBeanProxy)
Inyección directa de dependencias de estilo IOC
Administración mejoarada del ciclo de vida
Control adicional sobre las dependencias
Integración transparente AOP
Sistema virtual de archivos
Marco de trabajo de implementación virtual
Carga de clase OSGi
2.2. Definiciones
Este manual usa algunos términos que puede que no le sean familiares. Algunos de ellos se definen en
Lista de definición del mMicrocontenedor.
Lista de definición del mMicrocontenedor
Microkernel JMX
JBoss JMX Microkernel es un entorno Java modular. Es diferente de los entornos estándar
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 inglés 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 término 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 lógica 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 construcción.
Un bean Java es un pedazo de código independiente. No requiere herencias de ninguna clase
o interfaz base en particular. Aunque los beans Java se crean principalmente en IDEs gráficos
también se pueden desarrollar en simples editores de texto.
14
Capítulo 2. Introducción al microcontenedor
AOP
Aspect-Oriented Programming (AOP) es un paradigma de programación en el cual las
funciones secundarias o de soporte se aislan de la lógica empresarial del programa principal.
Es un sub-grupo de la programación orientada a objetos.
2.3. Instalación
El microcontenedor es una parte integral de la plataforma empresarial. En el manual de configuración y
administración encontrará mayor información sobre la instalación y configuración de la plataforma
empresarial.
15
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Capítulo 3. Construcción de servicios
Los servicios son pedazos de código que realizan tareas que múltiples clientes necesitan. Poara
nuestro propósito pondremos algunas restricciones adicionales en la definición 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 programación orientada a objetos (OOP del inglés object-oriented
programming). En OOP, cada objeto es independente y ningún otro objeto necesita saber cómo 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 ejecución 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 métodos y campos y el acceso a ellos no sea restringido, no hay
necesidad de recompilar los clientes para utilizar un POJO recién 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 método no cambien.
El resto de este manual consiste de la creación del servicio de recursos humanos utilizando el
microcontenedor para capturar y modularizar la lógica empresarial de la aplicación. Después de que el
microcontenedor esté instalado, el código de ejemplo se encuentra en
exam ples/User_Guide/gettingStarted/hum anResourcesService.
3.1. Introducción al ejemplo de recusos humanos
Al familiarizarse con la estructura del directorio de los archivos en el ejemplo note que usa la estructura
del directorio estándar Maven.
Los archivos fuente Java se encuentran en los paquetes debajo del directorio
exam ples/User_Guide/gettingStarted/hum anResourcesService/src/m ain/java/org/j
boss/exam ple/service después de extraer el archivo Z IP. Cada una de estas clases representa un
POJO simple que no implementa ninguna interfaz especial. La clase más importante es HRManager, la
cual representa el punto de entrada del servicio proporcionando todos los métodos públicos que los
clientes llamarán.
Métodos que la clase HRManager proporciona
addEm ployee(Employee employee)
rem oveEm ployee(Employee employee)
getEm ployee(String firstName, String lastName)
getEm ployees()
getSalary(Employee employee)
setSalary(Employee employee, Integer newSalary)
16
Capítulo 3. Construcción de servicios
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 límites mínimos y máximos en los salarios para
diferentes roles de empleados.
3.2. Compilación del proyecto de ejemplo HRManager
Para compilar el código fuente, escriba m vn com pile desde el directorio
hum anResourcesService/. 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
m vn clean.
3.3. Creación 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 ejecución.
3.3.1. Descriptores de implementación XML
Después de compilar las clases, use un descriptor de implementación 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 ejecución. 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 implementación XML asociado con el microcontenedor en tiempo
de ejecución, el cual realiza la implementación real e instancia los beans.
3.4. Conexión 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. ¿Cómo
puede conectar POJOs para seleccionar diferentes implementaciones de estrategia de salarios?
El siguiente descriptor de implementación XML hace justamente eso:
17
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
<?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 implementación de la estrategia de salario incluyendo un elemento
<bean> adicional. Esta vez, se selecciona AgeBasedSalaryStrategy. Luego el código inyecta una
referencia a este bean en la instancia de HRManager creada utilizando el bean HRService. La
inyección es posible ya que la clase HRManager contiene un método
setSalaryStrategy(SalaryStrategy strategy). Mientras tanto detrás de bastidores el
microcontenedor JBoss llama a este método en la instancia HRManager recién creada y le pasa una
referencia a la instancia AgeBasedSalaryStrategy.
El descriptor de implementación XML causa la misma secuencia de eventos como si hubiera escrito el
siguiente código:
HRManager hrService = new HRManager();
AgeBasedSalaryStrategy ageBasedSalary = new AgeBasedSalaryStrategy();
hrService.setSalaryStrategy(ageBasedSalary);
Además de realizar la inyección por medio de los métodos setter de las propiedades, el
microcontenedor JBoss también puede realizar la inyección por medio de parámetros del constructor si
es necesario. Para obtener mayores detalles consulte el capítulo sobre 'Inyección' 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
implementación, no siempre es la mejor manera. Por ejemplo, el crear instancias de las clases
Em ployee y Address es innecesario ya que el cliente crea estas en respuesta a la entrada del
usuario. T odavía son parte del servicio pero no se referencian en el descriptor de implementación.
Realice comentarios en su código
Puede definir múltiples beans dentro de un descriptor de implementación 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 múltiples beans. Un bean usualmente representa el
punto de entrada del servicio y contiene los métodos públicos que los clientes llaman. En este ejemplo,
el punto de entrada es el bean HRService. El descriptor de implementación XML no indica si un bean
representa un servicio o si un bean es el punto de entrada del servicio. Es una buena idea 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
Después de crear POJOs y conectarlos para formar servicios, necesita configurar los servicios,
18
Capítulo 3. Construcción de servicios
probarlos y empacarlos.
3.5.1. Configuración de un servicio
Los servicios se pueden configurar de dos maneras:
Inyección de referencias entre instancias POJO
Inyección de valores en propiedades POJO
En este ejemplo se utiliza el segundo método. El siguiente descriptor de implementación configura la
instancia de HRManager de la siguiente manera:
Se implementa una congelación en la contratación
La AgeBasedSalaryStrategy implementa un nuevo valor de salario mínimo y máximo.
El inyectar referencias enter instancias POJO es una manera de configurar un servicio; sin embargo,
también podemos inyectar valores en propiedades POJO. El siguiente descriptor de implementación
muestra cómo podemos configurar la instancia HRManager para que realice una congelación en la
contratación y para que la AgeBasedSalaryStrategy tenga un valor de salario mínimo y máximo:
<?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 métodos setter públicos para las propiedades relevantes de manera que los
valores se puedan inyectar. Por ejemplo, la clase HRManager tiene un método
setHiringFreeze(boolean hiringFreeze) y la clase AgeBasedSalaryStrategy tiene los
métodos setMinSalary(int m inSalary) y setMaxSalary(int m axSalary).
Los valores en el descriptor de implementación 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 estándar, pero puede crear los propios si es necesario. Consulte el capítulo de
propiedades en la parte II 'Desarrollo POJO' para obtener mayores detalles.
3.5.2. Probar un servicio
Después 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 MicrocontainerT est.
La clase org.jboss.test.kernel.junit.MicrocontainerT est hereda de
junit.fram ework.T estCase, configurando cada prueba realizando bootstrap en JBoss
19
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Microcontainer y agregando un BasicXMLDeployer. Luego busca la ruta de clase para un descriptor de
implementación XML con el mismo nombre que la clase de prueba terminado en .xm l 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
método conveniente llamado getBean(String nam e).
Puede encontrar ejemplos de estos descriptores de implementación 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 código 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 HRManagerT est extiende MicrocontainerT est con el fin de configurar un número de
empleados a utilizar como base para la prueba. Ejemplos individuales luego crean sub-clases en
HRManagerT est para realizar el trabajo en sí. T ambién se includyen un par de clases T estSuite
que se utilizan para agrupar ejemplos individuales por comodidad.
Para ejecutar las pruebas escriba m vn test desde el directorio hum anResourcesService/. Debe
ver alguna salida de registro DEBUG, el cual muestra a JBoss Microcontainer inicando e implementando
los desde el archivo XML relevante antes de ejecutar cada prueba. Al final de la prueba se borra la
implementación de los beans y se apaga el microcontenedor.
20
Capítulo 3. Construcción de servicios
Nota
Algunas de las pruebas tal como HRManagerT estCase, AgeBasedSalaryT estCase y
LocationBasedSalaryT estCase prueban POJOs individuales. Otras pruebas tal como
HRManagerAgeBasedT estCase y HRManagerLocationBasedT estCase prueban servicios
enteros. De cualquier manera, las pruebas se ejecutan de la misma manera. El utilizar la clase
MicrocontainerT est facilita el configurar y conducir pruebas completas de cualquier parte de su
código.
Las clases Address y Em ployee no se anidan aquí. El escribir pruebas para ellas queda de su
parte.
3.5.3. Empacar un servicio
Después de probar su servicio es hora de empacarlo de manera que otros puedan utilizarlo. La manera
más simple de hacer esto es crear una JAR que contenga todas las clases. Puede escoger el incluir el
descriptor de implementación si hay una manera predeterminada sensible de configurar el servicio, pero
es opcional.
Procedimiento 3.1. Empacar un servicio
1. Ponga el descriptor de implementación en el directorio MET A-INF (opcional)
Si decide incluir el descriptor de implementación por convención se debe llamar jbossbeans.xm l y se debe poner en un directorio MET A-INF. Esta es la distribución predeterminada
para la plataforma empresarial así que el programa de implementación JAR reconoce esta
distribución y realiza la implementación de manera automática.
El descriptor de implementación 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. Generación de la JAR
Para generar una JAR que contenga todas las clases compiladas introduzca m vn package
desde el directorio hum anResourcesService/.
3. Hacer la JAR disponible para otros proyectos Maven
Para hacer la JAR disponible para los otros proyectos Maven introduzca m vn install con el fin
de copiarlo a su repositorio Maven local. La distribución final de la JAR se puede ver en
Ejemplo 3.3, “Listado de los directorios org/jboss/exam ple/service y MET A-INF”.
21
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 3.3. Listado de los directorios org/jboss/exam ple/service y MET A-INF
`-- org
`-- jboss
`-- example
`-- service
|-- Address.java
|-- Employee.java
|-- HRManager.java
`-- util
|-- AgeBasedSalaryStrategy.java
|-- LocationBasedSalaryStrategy.java
`-- SalaryStrategy.java
`--META-INF
`-- MANIFEST.MF
`-- maven
`-- org.jboss.micrcontainer.examples
`-- humanResourceService
Nota
Maven crea automáticamente el directorio MET A-INF/m aven y no estará presente si está
utilizando uns sistema de construcción diferente.
22
Capítulo 4. Uso de los servicios
Capítulo 4. Uso de los servicios
El capítulo anterior le mostró cómo 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 tamaño y complejidad del código ejemplo.
T odos los archivos necesarios se encuentran en el directorio
exam ples/User_Guide/gettingstarted/com m andLineClient, el cual sigue la estructura del
directorio estándar Maven, como se puede ver en Ejemplo 4.1, “Listar el directorio
exam ples/User_Guide/gettingstarted/com m andLineClient”.
Ejemplo 4 .1. Listar el directorio
exam ples/User_Guide/gettingstarted/com m andLineClient
├──
├──
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
└──
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
23
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
org/jboss/exam ple/client.
UserInterface describe los métodos que el cliente llama en tiempo de ejecución para solicitar lla
entrada del usuario. ConsoleInput es una implementación de UserInterface que crea un T UI que
el usuario utiliza para interactuar con el cliente. La ventaja de este diseño es que puede crear fácilmente
una implementación Swing de UserInterface en una fecha posterior y puede reemplazar el T UI con
un GUI. T ambién puede simular el proceso de ingreso de datos con un script. Luego puede chequear el
comportamiento del cliente automáticamente usando ejemplos JUnit convencionales que se encuentran
en Ejemplo 3.2, “Listado del directorio src/test/java”.
Para que la construcción funcione primero debe construir e instalar auditAspect.jar desde el
directorio exam ples/User_Guide/gettingStarted/auditAspect usando el m vn install
com m and. Se crean un número 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ó m vn install desde el directorio
exam ples/User_Guide/gettingStarted entonces hum anResourcesService.jar y
auditAspect.jar ya se han construído y empacado junto con el cliente así que este paso no será
necesario.
Para compilar el código fuente, se realizan todos los pasos que se encuentran en Procedimiento 4.1,
“Compilación del código fuente” al emitir el comando m vn package desde el directorio
com m andLineClient.
Procedimiento 4 .1. Compilación del código fuente
1. Ejecute las pruebas de las unidades.
2. construya una JAR cliente.
3. Ensamble una distribución que contenga todos los archivos necesarios.
Después de compilar y empacar el cliente, la estructura del directorio en el diretcorio
com m andLineClient/target incluye los subdirectorios descritos en Ejemplo 4.2, “Los
subdirectorios del directorio com m andLineClient/target”.
Ejemplo 4 .2. Los subdirectorios del directorio com m andLineClient/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 Capítulo 5, Agregar comportamiento con AOP para obtener
mayores detalles.
Cada sub-directorio representa una distribución diferente con todos los scripts shell, JARs y
descriptores de implementación XML que se necesitan para ejecutar el cliente en diferentes
configuraciones. El resto de este capítulo usea la distribución client-pojo que se encuentra en el
24
Capítulo 4. Uso de los servicios
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
|-- 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, cámbiese al directorio client-pojo y escriba ./run.sh. Aparecerá el T he
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 implementación 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 congelación de la contratación
m) Ver el menú
p) Imprimir el estatus del servicio
q) Salir
>
Para seleccionar una opción, introduzca la letra que se muestra en el lado izquierdo y oprima RET URN.
Por ejemplo para ver lsa opciones del menú introduzca m y luego presione RET URN. El introducir más
de una letra o el introducir una opción inválida genera un mensaje de error.
25
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Importante
El script run.sh establece el entorno de ejecución agregando todas las JARs que se
encuentran en el directorio lib/ a la ruta de clase usando la propiedad del sistema java.ext.dirs.
T ambién agrega el directorio actual y la client-1.0.0.jar usando la eiqueta -cp de manera
que el descriptor de implementación jboss-beans.xm l se encuentre en tiempo de ejecución
junto con la clase org.jboss.exam ple.client.Client, la cual se llama para iniciar la
aplicación.
4.1. Bootstrap del microcontenedor
Antes de utilizar el cliente para implementar y llamar a su servicio, mire detalladamente lo que pasó
durante la construcción:
public Client(final boolean useBus) throws Exception {
this.useBus = useBus;
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 implementación jboss-beans.xm l.
Esto se necesita luego de manera que el programa de implementación XML pueda implementar y borrar
la implementación de los beans declarados en el archivo. El método getResource() del cargador de
clase de la aplicación se utiliza ya que se incluye el archivo jboss-beans.xm l en la ruta de clase.
esto es opcional; el nombre y ubicación del descriptor de implementación no son importantes en tanto la
URL sea válida y se pueda llegar a ella.
Luego se crea una instancia de JBoss Microcontainer junto con un programa de implementación XML.
Este proceso se llama bootstrapping y se proporciona una clase llamada BasicBootstrap como parte
del microcontenedor para tener en cuenta la configuración programática. Para agregar un programa de
implementación XML, extienda BasicBootstrap para crear una clase Em beddedBootstrap y
sobrescriba el método protegido bootstrap() así:
26
Capítulo 4. Uso de los servicios
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();
}
}
}
El gancho shutdown se asegura de que cuando la MVJ termina, se borra la implementación de todos
los beans en el orden correcto. Los métodos públicos deploy/undeploy delegan al
BasicXMLDeployer de manera que los beans declarados en jboss-beans.xm l 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. Implementación del servicio
Después de crear el cliente puede implementar el servicio de recursos humanos. Esto se logra
introduciendo la opción d del T UI. La salida indica que el BasicXMLDeployer ha analizado
sintácticamente el archivo jboss-beans.xm l usando la URL y ha instanciado los beans que se
encuentran adentro.
27
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Nota
El microcontenedor puede instanciar los beans ya que sus clases están disponibles en la ruta
de clase de extensión dentro del archivo lib/hum anResourcesService.jar. T ambién
puede poner estas clases en una estructura de directorio expandido y agregarla a la ruta de
clase de la aplicación, pero el empacarlos en una JAR usualmente es más conveniente.
El descriptor de implementación es completamente separado del archivo
hum anResourcesService.jar. Esto permite modificarlo para propósitos de pruebas. El archivo
jboss-beans.xm l 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>
Importante
Dependiendo de la manera en que acceda el servicio en tiempo de ejecución es posible que
necesite apagar la aplicación y re-iniciarla para volver a implementar el servicio y ver sus
cambios. Esto reduce la flexibilidad de la aplicación, pero incrementa el rendimiento en tiempo de
ejecución. Opcionalmente puede simplemente volver a implementar el servicio mientras que la
aplicación esté ejecutando. Esto incrementa la flexibilidad pero disminuye el rendimiento en
tiempo de ejecución. Mantenga estas opciones en consideración al diseñar sus aplicaciones.
4.3. Acceso directo
Si no se le pasan parámetros al script run.sh cuando se inicia el cliente entonces se busca una
28
Capítulo 4. Uso de los servicios
referencia al bean HRService usando el controlador del microcontenedor después 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 método getT arget(). 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_INST ALADO
DESCRIT O
INST ANCIADO
CONFIGURADO
INST ALADO
Para mantener el registro de en qué estado se encuentra el bean, envuélvalo 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 INST ALADO entonces el bean que representa se considera
implementado.
Después de crear una referencia a la instancia del bean que representa el punto de entrada del
servicio, puede llamar a los métodos en este para realizar tareas:
@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
29
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
del bean real. El rendimiento es bueno ya que cada llamada de método va directamente al bean. Sin
embargo, ¿Qué pasa si desea re-configurar el servicio y volver a implementarlo mientras la aplicación
está ejecutando?
La re-configuración se logra realizando cambios al descriptor de implementación XML y guardando el
archivo. Con el fin de volver a implementar el servicio, se debe borrar la implementación de la instancia
actual. Al borrar la implementación el controlador del microcontenedor libera su referencia a la instancia
del bean, junto con los beans dependientes. Posteriormente estos beans se harán disponibles para el
servicio de recolección de basura ya que la aplicación ya no los necesita más. El volver a implementar el
servicio crea nuevas instancias del bean representando la nueva configuración. Cualquier búsqueda
posterior de parte de los clientes recuperará las referencias a estas nuevas instancias y podrán 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 implementación del
servicio no tienen ningún efecto ya que la instancia del bean todavía 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 búsqueda ya que el cliente ya tiene una referencia en
caché. Por lo tanto continuará utilizando la instancia del bean representando la configuración del
servicio inicial.
Puebe probar este comportamiento escribiendo u seguido de RET URN para borrar la implementación del
servicio actual. Debe poder acceder el servicio todavía desde el cliente aunque haya 'borrado' la
implementación. Luego, realice algunos cambios a la configuración utilizando el archivo jbossbeans.xm l, guarde el archivo y vuelva a implementarlo usando la opción d. Puede imprimir el estatus
del servicio utilizando la opción p, la cual muestra que el cliente todavía 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
implementación se puede presentar el mismo problema de caché.
Para volver a implementar el servicio reconfigurado de manera confiable, apague la aplicación
completamente utilizando la opción 'q' y reinícela usando el script run.sh. Para servicios empresariales
tal como transacciones, mensajería y persistencia este es un comportamiento completamente aceptable
ya que generalmente se utilizan. No se pueden volver a implementar en tiempo de ejecución y también
se benefician del alto rendimiento dado por el uso del acceso directo. 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 parámetro 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 método invoke() en el bus, pasando el
nombre del bean, el nombre del método, los argumentos del método y los tipos de método. El bus usa
esta información para llamar al bean de parte del cliente.
30
Capítulo 4. Uso de los servicios
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 método seleccionado usando la
reflexión. 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 configuración del servicio y se puede volver a implementar en tiempo
de ejecución. Las llamadas posteriores por parte del cliente utilizarán 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 opción p para
imprimir el estatus. Borre la implementación del servicio utilizando la opción u y observe que es
inaccesible. Luego realice algunos cambios al archivo jboss-beans.xm l, guarde los cambios e
implemente de nuevo usando la opción d. Imprima el estatus de nuevo usando la opción p. El
cliente está accediendo la nueva configuración del servicio.
Ya que el bus usa la refleción para llamar instancias del bean, es un poco más 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 un servicio en
tiempo de ejecución. 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 reducción en el rendimiento es superior a la flexibilidad que proporciona.
4.5. Carga de clase dinámica
Hasta ahora ha utilizado los cargadores de clase de aplicación y extensión para cargar todas las
clases en la aplicación. La ruta de clase de la aplicación 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í:
31
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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 extensión 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 después de la etiqueta -cp. Ya que la extensión classloader es padre de la
aplicación classloader, las clases del cliente pueden encontrar todas las clases del microcontenedor
y las clases del servicio de recursos humanos en tiempo de ejecución.
Nota
Con las versiones de Java 6 y posteriores puede utilizar un comodín para incluir todas las JARs
en un directorio con la etiqueta -cp: java -cp `pwd`/lib/* :.:client-1.0.0.jar
org.jboss.exam ple.client.Client $1
Aquí todas las clases en la aplicació se agregarán a la ruta de clase del cargador de clase de la
aplicación y extensión de la ruta de clase del cargador de clase retendrá su valor
predeterminado.
¿Qué pasa si necesita implementar un servicio adicional en tiempo de ejecución? 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 aplicación (y el cargador de clase de extensión) en el arranque, no es fácil el agregar la URL de la
JAR. La misma situación 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 aplicación) entonces el cargador de clase de la aplicación 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 ubicación 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 implementación para lograr esto.
La distribución client-cl contiene el archivo listado en el Ejemplo 4.5, “Listado del directorio
com m andLineClient/target/client-cl” .
32
Capítulo 4. Uso de los servicios
Ejemplo 4 .5. Listado del directorio com m andLineClient/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 hum anResourcesService.jar a un nuevo sub-directorio llamado
otherLib. Ya no está disponible para los cargadores de clase de extensión o de la aplicación, 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 implementación del servicio, cárguela
en las clases del servicio y cree instancias de los beans. Para ver cómo se logra esto vea el contenido
del archivo jboss-beans.xm l:
33
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
<?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_Gui
de/gettingStarted/commandLineClient/target/clientcl.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>
<!-- <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 inyección de parámetros
en el constructor para especificar la ubicaci´on del archivo hum anResourcesService.jar en
el sistema local de archivos.
2. Luego, cree una instancia de un URLClassLoader inyectando el bean URL en el constructor
como único elemento en el array.
3. Incluya un elemento <classloader> en su definición de bean HRService e inyecte el bean
custom CL. Esto especifica que la clase HRManager necesita ser cargada por el cargador de
clase customCL.
34
Capítulo 4. Uso de los servicios
Necesita una manera de decidir cuál cargador de clase utilizar para los otros beans en la
implementación. T odos los beans en la implementación utilizan el cargador de clase del contexto del hilo
actual. En este caso el hilo que maneja la implementación es el hilo principal de la aplicación, el cual
tiene su cargador de clase de contexto establecido para el cargador de clase de la aplicación durnate el
arranque. Si desea puede especificar un cargador de clase diferente para toda la implementación
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_G
uide/gettingStarted/commandLineClient/target/clientcl.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>
...
</deployment>
Esto sería necesario para permitir la reconfiguración 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 implementación. Para sobreescribir el cargador
de clase a nivel de implementación y utilizar el cargador de clase predeterminado para un bean, use el
valor <null/> así:
35
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
<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
implementación
Si crea un nuevo cargador de clase para su servicio utilizando el descriptor de implementación es
posible que no pueda acceder las clases cargadas por este desde el cargador de clase de la
aplicación. 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 excepción java.lang.NoClassDefFoundError y la aplicación 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 aplicación. En este ejemplo, las clases
afectadas son Address, Em ployee y SalaryStrategy.
36
Capítulo 5. Agregar comportamiento con AOP
Capítulo 5. Agregar comportamiento con AOP
La programación orientada a objetos (OOP del inglés Object Oriented Programming) tiene muchas
técnicas útiles para el desarrollo de software incluyendo la encapsulación, herencia y polimorfismo. Sin
embargo, no soluciona el problema de la lógica de direccionamiento que con frecuencia se repite en
muchas clases diferentes. Ejemplos de esto incluye los registros, seguridad y lógica transaccional, la
cual es tradicionalmente codificada a fuego en cada clase. Este tipo de lógica se llama un asunto de
corte transversal.
La programación orientada a aspectos (AOP del ingles Aspect Oriented Programming funciona para
permitir el aplicar asuntos de corte transversal a las clases después de que se han compilado. Esto
mantiene el código fuente libre de lógica, lo cual no es una parte central del propósito principal de la
clase y optimiza el mantenimiento. El método depende de la implementación AOP. Usualmente si una
clase implementa una interfaz, cada llamada de método 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 código byte java de la clase compilada se modifica: los métodos
originales se re-nombran y se reemplazan con métodos que implementan la lógica de corte transversal.
Luego estos nuevos métodos llaman a los métodos originales después de haber ejecutado la lógica de
corte transversal. Otro método para lograr el mismo resultado es modificar el código byte para crear una
subclase de la clase original que sobreescribe sus métodos. Los métodos sobreescritos luego ejecutan
la lógica de corte transversal antes de llamar los métodos correspondiente de la super clase.
JBoss AOP es un marco de trabajo para AOP. Utilizándolo puede crear asuntos de corte transversal
utilizando métodos 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 métodos dentro del aspecto llamado consejos. Estos consejos siguen ciertas reglas
para su parámetro y retornan tiposy cualquier excepción que presenten. Dentro de este marco de
trabajo puede utilizar nociones convencionales orientadas a objetos tal como la herencia, encapsulación
y composición para hacer que sus asuntos de corte transversal sean fáciles de mantener. Los
aspectos se aplican al código utilizando un lenguaje de expresiones que le permite especificar los
constructores, los métodos e incluso los campos de destino. Puede cambiar rápidamente el
comportamiento de múltiples clases modificando el archivo de configuración.
Este capítulo contiene ejemplos, los cuales demuestran cómo utilizar JBoss AOP junto con el
microcontenedor para crear y aplicar un aspecto de auditoría al servicio de recursos humanos. El
código de auditoría se puede poner dentro de la clase HRManager, pero llenaría la clase con código
que no es relevante para su propósito principal, expandiéndola y haciendo más dificil el mantenerla. El
diseño del aspecto también proporciona modularidad, facilitando el auditar otras clases en el futuro, si el
ámbito del proyecto cambia.
AOP también se puede utilizar para aplicar comportamiento adicional durante la fase de implementación.
Este ejemplo creará y enlazará un proxy a una instancia bean en un servicio básico JNDI, permitiendo
accederlo utilizando una búsqueda JNDI en lugar del controlador del microcontenedor.
5.1. Creación de un aspecto
El directorio exam ples/User_Guide/gettingStarted/auditAspect contiene todos los archivos
necesarios para crear el aspecto.
pom .xm l
src/m ain/java/org/jboss/exam ple/aspect/AuditAspect.java
37
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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;
}
}
38
Capítulo 5. Agregar comportamiento con AOP
Procedimiento 5.1. Creación 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.
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 métodos realizadas en diferentes instancias de la clase destino en archivos
separados.
3. Finalmente se define otro aviso. Este aviso aplica a cada llamada de método realizada en la clase
destino.El nombre del método y los argumentos se almacenan junto con el valor de retorno. Esta
información se utiliza para construir un registro de auditoría y escribirlo en el archivo de registro
actual. Cada aviso llama a inv.invokeNext(), el cual encadena los avisos si se ha aplicado
más de un asunto de corte transversal o para llamar el constructor/método destino.
Nota
Cada aviso se implementa utilizando un método que toma un objeto de invocación como
parámetro, presenta T hrowable y retorna Object. En el momento del diseño no se sabe a qué
constructores o métodos se aplicarán estos avisos así que haga los tipos tan genéricos como
sea posible.
Para compilar la clase y crear un archivo auditAspect.jar que lo puedan utilizar otros ejemplos,
escriba m vn install desde el directorio auditAspect.
5.2. Configuración del microcontenedor para AOP
Antes de aplicar el aspecto de auditoría al servicio de recursos humanos, se debe agregar un número
de JARs a la ruta de clase de la extensión. Se encuentran en el sub-directorio lib de la distribución
client-aop que se encuentra en el directorio
exam ples/User_Guide/gettingStarted/com m andLineClient/target/client-aop.dir:
39
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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
Primero, se necesita lib/auditAspect-1.0.0.jar para crear una instancia del aspecto en tiempo
de ejecución con el fin de ejecutar la lógica. Luego el archivo jar para JBoss AOP (jboss-aop.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 definición de esquema XML que le permite definir aspectos dentro
de un descriptor de implementación XML. T ambién contiene código de integración para crear
dependencias entre beans normales y beans de aspecto dentro del microcontenedor, permitiéndole
agregar comportamiento durante las fases de implementación y de borrado de la implementación.
Ya que está utilizando Maven2 para montar la distribución cliente-aop, debe agregar estos archivos JAR
declarando las dependencias apropiadas en su archivo pom .xm l y creando un descriptor de
ensamblaje válido. Puede ver un ejemplo de pom .xm l en Ejemplo 5.3, “Extracto de ejemplo pom .xm l
para AOP”. Para realizar su construcción utilizando Ant, el procedimiento será diferente.
40
Capítulo 5. Agregar comportamiento con AOP
Ejemplo 5.3. Extracto de ejemplo pom .xm l 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. Aplicación de un aspecto
Ahora que tiene una distribución válida que contiene todo lo que necesitad, puede configurar jbossbeans.xm l para aplicar el aspecto de auditoría. Se encuentra en
exam ples/User_Guide/gettingStarted/com m andLineClient/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>
...
</deployment>
41
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Procedimiento 5.2. Explicación del código 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 método de
fábrica en lugar de llamar un constructor convencional ya que solo es necesario una instancia del
AspectManager en la MVJ en tiempo de ejecución.
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, también tiene los atributos method y pointcut que
puede utilizar para aplicar o enlazar un consejo dentro del aspecto para los constructores y
métodos dentro de otras clases. Estos atributos enlazan el consejo de auditoría a todos los
constructores y métodos públicos dentro de la clase HRManager. Sólo es necesario especificar
el método audit ya que ha sido sobrecargado dentro de la clase AuditAspect con diferentes
parámetros. JBoss AOP sabe cuál seleccionar en tiempo de ejecución dependiendo de si se está
realizando una invocación de método o constructor.
Esta configuración adicional es todo lo que se necesita para aplicar el aspecto de auditoría en tiempo
de ejecución agregando un comportamiento de auditoría 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 implementación 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 auditoría, comente los fragmentos relevantes de XML en el descriptor
de implementación y re-inicie la aplicación.
Aviso
El orden de la implementación 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 código byte de la
clase bean para agregar la lógica 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.
42
Capítulo 5. Agregar comportamiento con AOP
5.4. Callbacks del ciclo de vida
Además de aplicar aspectos a los beans que instanciamos utilizando el microcontenedor también
podemos agregar comportamiento durante el proceso de implementación y de borrado de la
implementación. T al como lo mencinamos en Sección 4.3, “Acceso directo”, un bean atravieza varios
estados diferentes cuando se implementa. Estos incluyen:
NOT _INST ALLED
el descriptor de implementación que contiene el bean ha sido analizado sintácticamente junto
con cualquier anotación en el bean mismo.
DESCRIBED
cualquier dependencia que AOP ha creado ha sido agregada al bean y se han procesado las
anotaciones personalizadas.
INST ANT IAT ED
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.
CREAT E
se ha llamado al método create, si está definido en el bean.
ST ART
se ha llamado al método start, si está definido en el bean.
INST ALLED
cualquier acción de instalación personalizada que se definió en el descriptor de
implementación se ha ejecutado y está listo para acceder al bean.
Importante
Los estados CREAT E y ST ART están incluídos 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 ningún método crear/inicar correspondientes en su bean, pasará
derecho por estos estados.
Estos estados representan el ciclo de vida del bean. Puede definir un número 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
43
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
<aop:lifecycle-instantiate>
aplicado al entrar/salir del estado INST ANT IAT ED
<aop:lifecycle-configure>
aplicado al entrar/salir del estado CONFIGURED
<aop:lifecycle-create>
aplicado al entrar/salir del estado CREAT E
<aop:lifecycle-start>
aplicado al entrar/salir del estado ST ART
<aop:lifecycle-install>
aplicado al entrar/salir del estado INST ALLED
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,
nombrándola de manera que se pueda utilizar cuando los beans entren o salgan del estado relevante
durante la implementación y durante el borrado de la implementación. Puede especificar cuáles 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 código especifica que la lógica 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 INST ALLED.
Para que la clase callback funcione, debe contener los métodos install y uninstall que toman
ControllerContext como parámetro, como se puede ver en Ejemplo 5.6, “Métodos de instalación y
desinstalación”.
44
Capítulo 5. Agregar comportamiento con AOP
Ejemplo 5.6. Métodos de instalación y desinstalación
import org.jboss.dependency.spi.ControllerContext;
public class LifecycleCallback {
public void install(ControllerContext ctx) {
System.out.println("Bean " + ctx.getName() + " is being installed";
}
public void uninstall(ControllerContext ctx) {
System.out.println("Bean " + ctx.getName() + " is being uninstalled";
}
}
El método install se llama durante la implementación del bean y se llama al método uninstall
durante el borrado de la implementación.
Nota
Aunque se está agregando comportamiento al proceso de implementación y de borrado de la
implementación utilizando callbacks, AOP de ehcho no se utiliza aquí. La funcionalidad pointcut
expression de JBoss AOP se utiliza para determinar a cuáles clases bean se aplican los
comportamientos.
5.5. Agregar búsquedas 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, “Búsqueda de referencias a
los Beans”.
45
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 5.7. Búsqueda de referencias a los Beans
private
private
private
private
private
HRManager manager;
EmbeddedBootstrap bootstrap;
Kernel kernel;
KernelController controller;
final static String HRSERVICE = "HRService";
...
// 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(); }
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 configuración del microcontenedor. Para mayor seguridad
aplique el patrón ServiceLocator y utilice una clase para realizar búsquedas de parte de los clientes.
Incluso puede pasar las referencias del bean junto con sus nombres al ServiceLocator en el momento
de la implementación utilizando un callback del ciclo de vida. En ese escenario, el ServiceLocator puede
buscarlos sin llegar a saber del microcontenedor. El borrado de la implementación posteriormente
borraría las referencias del bean del ServiceLocator para evitar más búsquedas.
No sería dificil es escribir su propia implementación ServiceLocator. En integrar una ya existente tal
como JBoss Naming Service (JBoss NS) es incluso más rápido y tiene el beneficio adicional de cumplir
con la especificación de JNDI - Java Naming and Directory Interface. JNDI habilita a los clientes para
acceder diferentes y posiblemente múltiples servicios de nombrado utilizando una API común.
Procedimiento 5.3. Escritura de su propia implementación ServiceLocator
1. Primero cree una instancia de JBoss NS usando el microcontenedor.
2. Luego, agregue un callback del ciclo de vida para realizar el enlace y des-enlace de las
referencias bean durante la implementación y durante el borrado de la implementación.
3. Marque las clases bean a las que desea enlazar sus referencias, utilizando anotaciones.
4. Ahora puede ubicar los beans en tiempo de ejecución utilizando la expresión como se mostró
anteriormente.
46
Parte II. Conceptos avanzados con el microcontenedor
Parte II. Conceptos avanzados con el microcontenedor
Esta sección aborda conceptos avanzados y muestra algunas funcionalidades interesantes del
microcontenedor. Se asume que los ejemplos de código en el resto del manual son ejemplos
incompletos y es responsabilidad del programador el extrapolarlos y extenderlos como sea necesario.
47
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Capítulo 6. 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 fácilmente
para crear aplicaciones sofisticadas. Una de las metas clave del microcontenedor es la integración
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 interacción 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 ejecución de operaciones MBean, referencia a atributos, el
configurar atributos y la declaración explícita de dependencias entre las MBeans nombradas.
Las interacciones y comportamientos predeterminados en el microcontenedor son lo que normalmente
obtiene de cualquier otro contenedor Inversión de Control (IoC del inglés >Inversion of Control) y es
similar a la funcionalidad que los MBeans proporcionan, incluyendo simples invocaciones de método
para operaciones, setters/getters para los atributos y dependencias explícitas.
6.2. Un Bean sin dependencias
Ejemplo 6.1, “Descriptor de implementación para un POJO simple” muestra un descriptor de
implementación para un POJO simple sin dependencias. Este es el punto inicial para integrar el
microcontenedor con Spring o Guice.
Ejemplo 6.1. Descriptor de implementación 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
48
Capítulo 6. Modelos de componentes
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>
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 versión del puerto del esquema Spring, el
cual describe el estilo Spring de su bean. El microcontenedor implementa los beans a manera
opuesta de la noción de fábrica 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
implementación de la interfaz BeanNameAware, su único propósito es exponer e imitar algo del
comportamiento del callback de Spring.
49
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
El enfoque de Guice es el acomplamiento de tipos. Los beans Guice se generan y se configuran usando
módulos.
Ejemplo 6.4 . Descriptor de implementación para la integración 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>
Dos partes importantes de observar en este archivo son PojoModule y
GuiceKernelRegistryEntryPlugin. PojoModule configura sus beans tal como en Ejemplo 6.5,
“Configuración de Beans para Guice”. GuiceKernelRegistryEntryPlugin proporciona integración
con el microcontenedor tal como se puede ver en Ejemplo 6.6, “Integración mock con el
microcontenedor”.
50
Capítulo 6. Modelos de componentes
Ejemplo 6.5. Configuración 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"));
}
}
51
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 6.6. Integración 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)
{
}
return entry;
}
}
Nota
Se crea un Injector desde la clase Modules luego realiza una búsqueda en este para ver si
hay beans que coincidan. Consulte Sección 6.5, “MBeans de legado y mezcla de diferentes
modelos de componentes” para encontrar mayor información sobre la declaración y uso de
MBeans de legado.
6.5. MBeans de legado y mezcla de diferentes modelos de
componentes
El ejemplo más simple de mezclar diferentes modelos de contenido se puede ver en Ejemplo 6.7,
52
Capítulo 6. Modelos de componentes
“Inyección de un POJO en un MBean”.
Ejemplo 6.7. Inyección 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 -jm x-beans.xm l para obtener mayores
detalles. El código de este archivo se encuentra en el código 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.jb
oss.demos.models.mbeans.PojoMBean.class, registerDirectly=true)</annotation>
</bean>
<bean name="ExposedPojo" class="org.jboss.demos.models.jmx.Pojo"/>
<bean name="AnnotatedExposePojo"
class="org.jboss.demos.models.jmx.ExposePojo">
<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 finalícelo con una anotación @JMX asumiendo que ha
importado org.jboss.aop.m icrocontainer.aspects.jm x.JMX. El bean se puede exponer
directamente o en su propiedad.
53
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 6.9. Presentación 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 búsqueda de inyección ya sea buscando un POJO simple u
obteniendo un MBean del servidor MBean. Una de las opciones de inyección es utilizar la inyección 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>
El bean FromGuice inyecta el bean Guice por medio de la correspondencia de tipos, en donde
PlainPojo se inyecta con una inyección de nombres común. Ahora puede probar a ver si el enlace
54
Capítulo 6. Modelos de componentes
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 implementación se pueden ver en Ejemplo 6.12, “Código fuente de AbstractController”.
Ejemplo 6.12. Código 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 implementación del bean se vuelve
menos importante. El alias espera en un estado no-instalado hasta que el bean real lo dispara.
55
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Capítulo 7. Inyección avanzada de dependencias y ldC
Hoy en día la Inyección de Dependencias (ID), también llamada Inversión de Control (IdC), se encuentra
en la parte central de muchos marcos de trabajo que adoptan la noción de un contenedor o un modelo
de componentes. En un capítulo 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 capítulo muestra la manera en que puede aplicar diferentes conceptos ID con la ayuda del
microcotenedor JBoss. Estos conceptos se expresarán por medio del código XML pero también puede
aplicar la mayoría de estas funcionalidades utilizando las anotaciones.
7.1. Fábrica de valores
Una fábrica de valores es un bean, el cual tiene uno o más métodos dedicados a generar valores por
usted. Consulte Ejemplo 7.1, “Fábrica de valores”.
56
Capítulo 7. Inyección avanzada de dependencias y ldC
Ejemplo 7.1. Fábrica 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>
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 invocación del método getPort.
57
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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 número de beans que coincidan.
Junto con el descriptor en Ejemplo 7.3, “Callbacks para reunir y filtrar beans”, el código Java que se
puede ver en Ejemplo 7.4, “Un analizador sintáctico para reunir todos los editores” muestra un Parser,
el cual reune todos los Editores.
58
Capítulo 7. Inyección avanzada de dependencias y ldC
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"/>
</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 sintáctico 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 método para buscar.
59
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
<incallback method="addEditor" cardinality="4..n"/>
<uncallback method="removeEditor"/>
Un límite inferior controla cuántos editores de hecho hacen que el bean progrese de un estado
configurado: cardinality=4 ..n/>
Eventualmente se crea Checker y corrige el analizador sintáctico. Esto se ilustra en Ejemplo 7.5, “El
corrector para el analizador sintáctico”.
Ejemplo 7.5. El corrector para el analizador sintáctico
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, “Configuración de BeanAccessMode” y Ejemplo 7.8, “La clase FieldsBean” para una
implementación.
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:
60
Capítulo 7. Inyección avanzada de dependencias y ldC
Ejemplo 7.7. Configuración de BeanAccessMode
<bean name="FieldsBean" class="org.jboss.demos.ioc.access.FieldsBean" accessmode="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 número 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 explícita 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>
7.5. Soporte para anotaciones XML (o metadatos)
Una de las funcionalidades principales en el microcontenedor de JBoss es el soporte para AOP. Puede
61
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
utilizar aspectos AOP y beans simples combinadas de cualquier manera. Ejemplo 7.10, “Interceptar un
método basado en una anotación” trata de interceptar una invocación de método con base en una
anotación. La anotación puede provenir de cualquier lado. Puede ser una anotación de clase verdadera
o puede ser una anotación agregada por medio de la configuración xml.
Ejemplo 7.10. Interceptar un método basado en una anotación
<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.
62
Capítulo 7. Inyección avanzada de dependencias y ldC
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();
}
}
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));
}
}
Después de agregar los beans invocadores del ejecutor, puede ver los ejecutores en acción durante el
empleo, buscando salidas del registro tal como Ejemplo 7.13, “Salida del registro del ejecutor”.
63
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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 inyección contextual, es una funcionalidad común con con marcos de trabajo IdC.
Ejemplo 7.14, “Incluir y excluir con autowiring” le muestra cómo 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"/>
En ambos casos - ShapeUser y ShapeChecker - solo Circle se debe utilizar ya que Square se excluye
en el enlace contextual.
7.7. Fábrica de beans
Cuando quiere más de una instancia de un bean en particular, necesita utilizar el patrón de fábrica del
bean. El trabajo del microcontenedor es configurar e instalar la fábrica de beans como si fuera un bean
simple. Luego necesita invocar el método createBean de la fábrica de beans.
Por defecto, el microcontenedor crea una instancia GenericBeanFactory, pero puede configurar su
propia fábrica. La única limitación es que su firma y ganchos de configuración son similares al de
AbstractBeanFactory.
64
Capítulo 7. Inyección avanzada de dependencias y ldC
Ejemplo 7.15. Fábrica de beans genéricas
<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.
65
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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
{
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);
}
}
}
66
Capítulo 7. Inyección avanzada de dependencias y ldC
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 código, use BeanMetaDataBuilder para crear y configurar los
metadatos de su bean.
67
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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>
Utilizando este concepto no expone su código a ninguno de los detalles de implementación 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 implementación, asegúrese de no crear una dependencia cíclica -- por ejemplo, un
cargador de clase recién definido que dependa de sí mismo.
68
Capítulo 7. Inyección avanzada de dependencias y ldC
Ejemplo 7.18. Definición 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 {
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 AUT O. 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
69
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
bean dependa explícitamente de este. En el modo MANUAL, el usuario microcontenedor debe llevar al
bean hacia adelante y atrás 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
representación de componentes del microcontenedor inmodificables.
Revise el código de OptionalServiceUser y ManualServiceUser para ver cómo 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 construcción,
pero B depende de A durante la configuración. Debido a la separación del ciclo de vida del estado
detallado del microcontenedor, este problema se puede resolver fácilmente.
70
Capítulo 7. Inyección avanzada de dependencias y ldC
Ejemplo 7.21. Separación 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 inyección, es posible que una dependencia entre dos beans no sea
aparente. T ales dependencias se deben expresar de manera clara tal como se puede ver en
Ejemplo 7.22, “Uso estático del código”.
Ejemplo 7.22. Uso estático del código
<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 través de diferentes estados es posible que quiera invocar algunos
métodos en otros beans o en el mismo bean. Ejemplo 7.23, “Invocación de métodos en diferentes
estados” muestra cómo Entry invoca a los métodos add y rem oveEntry del RepositoryManager
pararegistrar y desregistrarse a sí mismo.
71
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 7.23. Invocación de métodos 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>
<uninstall bean="RepositoryManager" method="removeEntry" state="Configured">
<parameter><inject fromContext="name"/></parameter>
</uninstall>
</bean>
7.14. Imitación 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 imitación perezosa del bean que se demuestra en
Ejemplo 7.24, “Imitación 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.
72
Capítulo 7. Inyección avanzada de dependencias y ldC
Ejemplo 7.24 . Imitación 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 métodos create, start y destroy cuando avanza a través
de los variados estados. Sin embargo, es posible que no quiera que el microcontenedor los invoque.
Por esta razón, 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>
73
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Capítulo 8. El sistema virtual de archivos
El duplicado del código de manejo de recursos es un problema común para los desarrolladores. En la
mayoría de los casos, el código ayuda a determinar la información 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
duplicación es el código para el procesamiento de ficheros anidados. Ejemplo 8.1, “Problema de
duplicación de recursos” ilustra el problema.
74
Capítulo 8. El sistema virtual de archivos
Ejemplo 8.1. Problema de duplicación de recursos
75
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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())
{
searchDir(result, fc[i], suffix);
}
else if (path.endsWith(suffix))
{
76
Capítulo 8. El sistema virtual de archivos
result.add(fc[i].toURL());
}
}
return true;
}
return false;
}
T ambién 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 implementación en vivo a otra ubicación
para prevenir el bloqueo de aquellos que se encuentran en las carpetas de implementación (lo cual
evitaría el borrarlos y el borrado de la implementación con base en el sistema de archivos). El bloqueo
de archivos es un problema importante, cuya única solución solía ser el centralizar todo el código 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 pública VFS
VFS se utiliza para dos propósitos principales tal como se puede ver en Usos para VFS.
Usos para VFS
navegación simple de recursos
API (del inglés Application Programmer Interface) del patrón del visitante
Como se mencionó anteriormente, en JDK simple, el manejo y navegación 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.
77
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 8.2. El tipo de recurso VirtualFile
78
Capítulo 8. El sistema virtual de archivos
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
*/
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
79
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
*/
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
/**
* 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
*/
80
Capítulo 8. El sistema virtual de archivos
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
* @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
81
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
/**
* 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
}
T odas las operaciones del sistema de archivos de sólo lectura están disponibles además 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 raíz, el
cual los proporciona la clase VFS con la ayuda de la URL o el parámetro URI.
82
Capítulo 8. El sistema virtual de archivos
Ejemplo 8.3. Uso de la clase VFS
83
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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
/**
* 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
84
Capítulo 8. El sistema virtual de archivos
/**
* Get the root file of this VFS
*
* @return the root
* @throws IOException for any problem accessing the VFS
*/
VirtualFile getRoot() throws IOException
}
Los tres métodos diferentes se ven similares.
getVFS
createNewRoot
getRoot
getVFS retorna una instancia VFS pero todavía no crea una instancia VirtualFile. Esto es importante ya
que hay métodos que ayudan con la configuración de una instancia VFS (consulte la clase VFS API
javadocs) antes de ordenarle que cree una raíz VirtualFile.
Por otro lado, los otros dos métodos usan configuraciones predeterminadas para la creación de root. La
diferencia entre createNewRoot y getRoot es en los detalles de caché, los cuales abordaremos más
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 implementación de un patrón visitante apropiado. Es muy simple el
reunir recursos de manera recursiva, una tarea dificil de realizar con la carga de recursos JDK simple.
85
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 8.5. Reunión de recursos de manera recursiva
public interface VirtualFileVisitor {
/**
* Get the search attribues for this visitor
*
* @return the attributes
*/
VisitorAttributes getAttributes();
/**
* 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 pública es bastante is quite intuitiva, los detalles de la implementación real agregan
complejidad. Es necesario explicar algunos conceptos en más detalle.
Cada vez que crea una instancia VFS también se crea su instancia correspondiente VFSContext. Esta
creación se realiza por medio de VFSContextFactory. Protocolos diferentes mapean a diferentes
instancias VFSContextFactory. Por ejemplo, file/vfsfile mapea a
FileSystem ContextFactory mientras que zip/vfszip mapea a ZipEntryContextFactory.
Cada vez que se crea una instancia VirtualFile también se crea su VirtualFileHandler
correspondiente. Esta instancia VirtualFileHandler sabe cómo manejar diferentes tipos de recursos
apropiadamente; el API VirtualFile solo delega invocaciones a su referencia VirtualFileHandler.
La instancia VFSContext sabe cómo crear instancias VirtualFileHandler de acuerdo con el tipo de
recurso. Por ejemplo, Z ipEntryContextFactory crea ZipEntryContext, el cual luego crea
ZipEntryHandler.
8.3. Implementaciones existentes
Aparte de archivos, directorios (FileHandler) y ficheros zip (Z ipEntryHandler), el microcontenedor
también soporta otros casos más avanzados. El primero es Assembled, el cual es similar a lo que
Eclipse llama Linked Resources. Su propósito es tomar recursos ya existentes de diferentes árboles y
"simular" un sólo árbol de recursos.
86
Capítulo 8. El sistema virtual de archivos
Ejemplo 8.6. Implementación 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"));
Otra implementación son los archivos en-memoria. Esta implementación surgió de la necesidad de
manejar fácilmente bytes generados por AOP. En lugar de utilizar archivos temporales, puede poner
bytes en VirtualFileHandlers en la memoria.
Ejemplo 8.7. Implementación 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 extensión
Es fácil extender VFS con un nuevo protocolo, similar a lo que hicimos con Assem bled y Mem ory. T odo
lo que necesita es una combinación de las implementaciones VFSContexFactory, VFSContext,
VirtualFileHandler, FileHandlerPlugin y URLStream Handler. La VFSContextFactory
es trivial mientras que las otras dependen de la complejidad de su tarea. Puede implementar el acceso
rar, tar, gzip, o incluso rem ote.
Después 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
87
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
apropiado de los recursos anidados, más especificamente de los archivos jar anidados: por ejemplo,
implementaciones ear normales: gem a.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 opción es más fácil de implementar, pero consume mucha memoria, lo cual requiere
potencialmente que las aplicaciones grandes residan en la memoria. El otro enfoque deja atrás un gran
número de archivos temporales, los cuales deben ser invisibles para el usuario y por lo tanto deben
desaparecer después del borrado de la implementación.
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 manejaría esto es re-creando toda la ruta desde el principio:
desempacaría los recursos anidados y de nuevo. Esto crea un gran número de archivos temporales.
El microcontenedor evita esto utilizando VFSRegistry, VFSCache y T em pInfo.
Cuando solicita VirtualFile sobrer VFS (getRoot no createNewRoot), VFS le pide a la implementación
VFSRegistry que proporcione el archivo. El DefaultVFSRegistry existente primero chequea si
extiste un VFSContext raíz que coincida para la URI dada. Si sí existe entonces
DefaultVFSRegistry primero trata de navigar al T em pInfo existente (enlace a un archivo
temporal), regresando a la navegación normal si no existe dicho archivo temporal. De esta manera
reutiliza completamente cualuqier archivo temporal que ya hayan sido desempacados, ahorrando tiempo
y espacio en el disco. Si no se encuentra un VFSContext que coincida en el caché entonces el código
creará una nueva entrada VFSCache y continuará con la navegación predeterminada.
El determinar la manera en que el VFSCache maneja las entradas VFSContext en caché depende de la
implementación 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 tim ed cache.
88
Capítulo 9. La capa ClassLoading
Capítulo 9. 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 excepción. 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 número 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 abstracción. La mayoría de los detalles se
esconden detrás de métodos privados y de paquetes privados sin comprometer la extensibilidad y
funcionalidad disponibles por medio de las clases y métodos públicos que hacen el API. Esto significa
que usted escribe código frente a la política 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 extensión java.lang.ClassLoader personalizada sin ninguna política
de carga de clase específica. Una política de carga de clase incluye el saber desde dónde carga y cómo
cargar.
Classloading es una extensión de los mecanismos de dependencia del microcontenedor. Su
implementación respaldada por VFS es classloading-vfs. Consulte Capítulo 8, El sistema virtual de
archivos para obtener mayor información sobre VFS.
9.1. ClassLoader
La implementación ClassLoader soporta políticas 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 más 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 regístrela con un
ClassLoaderSystem para crear un ClassLoader personalizado. T ambién puede crear un
ClassLoaderDom ain para realizar la partición en el ClassLoaderSystem .
La capa ClassLoader también incluye la implementación de cosas como el modelo DelegateLoader, la
carga de clase, filtros de recursos y políticas de delegación padre-hijo.
El tiempo de ejecución está habilitado para JMX para exponer la política utilizada para cada cargador de
clase. T ambién proporciona estadísticas de carga de clase y métodos de depuración para ayudar a
determinar desde dónde se cargan las cosas.
89
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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()
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.
90
Capítulo 9. La capa ClassLoading
Ejemplo 9.2. ClassLoaderPolicy con soporte para expresiones regulares
91
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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;
}
}
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;
}
92
Capítulo 9. La capa ClassLoading
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)
{
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())
93
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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 serían más 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 patrón de la expresión 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
ignorarán.
94
Capítulo 9. La capa ClassLoading
Ejemplo 9.3. ClassLoaderPolicy con soporte para codificación
public class CrypterClassLoaderPolicy extends VFSClassLoaderPolicy {
private Crypter crypter;
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 codificación” muestra cómo encriptar JARs. Puede
configurar cuáles recursos codificar especificando un filtro apropiado. Aquí todo está encriptado a
excepción del contenido del directorio MET A-INF/.
95
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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");
}
}
Este servicio imprime el contenido de dos archivos de configuración. Muestra que se esconde la
decodificación de cualquier recurso encriptado detrás de la capa de carga de clase.
Para probar esto apropiadamente puede encriptar el módulo de política usted mismo o puede utilizar
uno que ya esté encriptado. Para poner esto en acción es necesario que uan apropiadamente
EncryptedService con ClassLoaderSystem y los programas de implementación.
Más adelante en este capítulo abrodamos el particionamiento del ClassLoaderSystem .
9.2. ClassLoading
En lugar de utilizar la abstracción ClassLoader directamente puede crear módulos 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 definición de los ClassLoaders antes de que existan, la abstracción 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 política abstracta en lugar de los detalles de la implementación.
96
Capítulo 9. La capa ClassLoading
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;
/** 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
97
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
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 implementación ya sea programáticamente o
declarativamente por medio de jboss-classloading.xm l.
Ejemplo 9.7. Agregar ClassLoadingMetaData por medio de jboss-classloading.xm l
<classloading xmlns="urn:jboss:classloading:1.0"
domain="DefaultDomain"
top-level-classloader="true"
export-all="NON_EMPTY"
import-all="true">
</classloading>
El DefaultDomain se comparte entre todas las aplicaciones que no definen sus propios dominios.
98
Capítulo 9. La capa ClassLoading
Ejemplo 9.8. Aislamiento típico 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 específico
<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 método por defecto. En lugar de realizar bśuqeudas de
padres primero por defecto primero chequea sus propios recursos.
Ejemplo 9.11. Implementación típica 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>
99
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 9.12. Importing and Exporting Whole Modules and Libraries, Rather than FineGrained Packages
<classloading xmlns="urn:jboss:classloading:1.0">
<requirements>
<module name="jboss-reflect.jar"/>
</requirements>
<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>
T ambién puede mezclar los requerimientos y los tipos de funcionalidades usando paquetes y módulos.
El sub-proyecto de carga de clase usa una implementación muy pequeña del patrón recurso-visitante.
En el proyecto ClassLoader, la conexión entre implementación y carga de clase se realiza por medio
de la clase Module, la cual mantiene toda la información requerida para aplicar restricciones
apropiadamente en el patrón del visitante tal como los filtros.
100
Capítulo 9. La capa ClassLoading
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 módulo, instancie su instancia ResourceVisitor y pásela al método Module::visit. Esta
funcionalidad se utiliza en el marco d etrabajo de la implementación para indexar los usos de
anotacions en las implementaciones.
9.3. Carga de clase VFS
Esros ejemplos proporcionan una implementación 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 módulos dentro de la configuración del microcontenedor.
101
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Ejemplo 9.14 . Programa de implementación del módulo de carga de clases
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<classloader name="anys-classloader" xmlns="urn:jboss:classloader:1.0" importall="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 implementación 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 también.
102
Capítulo 10. Marco de trabajo de la implementación virtual
Capítulo 10. Marco de trabajo de la implementación virtual
El nuevo Marco d etrabajo de la implementación virtual (VDF del inglés Virtual Deployment Framework)
es una manera mejorada de administrar los programas de implementación en el microcontenedor. Este
capítulo detalla algunas de sus funcionalidades más útiles.
10.1. Manejo agnóstico de tipos de implementación
El tipo tradicional de implementación 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
implementación. El nuevo VDF simplifica este proceso pasando los bytes y serialiándolos en una
instancia Deploym ent.
El otro tipo de implementación, el cual extiende el primero, es una implementanción basada en el
sistema simple de archivos, respaldado po el microcontenedor VFS. Este enfoque se describe con más
detalle en Capítulo 8, El sistema virtual de archivos.
10.2. Separación del reconocimiento de la estructura de la lógica
del ciclo de vida de la implementación
Con el fin de realizar cualquier trabajo real encima de una implementación primero debe comprender su
estructura incluyendo sus rutas de clase y la ubicación de sus metadatos.
La ubicación de los metadatos incluye los archivos de configuración tal como m y-jboss-beans.xm l,
web.xm l, ejb-jar.xm l. Las rutas de clase son raíces del cargador de clase tal como WEBINF/classes o m yapp.ear/lib.
T eniendo esta estructura en mente puede proceder al manejo de la implementación.
Ciclo de vida de una implementación típica
1. El MainDeployer le pasa la implementación al grupo de StructuralDeployers para un
reconocimiento y recibe un contexto de implementación.
2. Luego, el MainDeployer le pasa el contexto de implementación 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
implementación utilizar.
En el caso de una implementación virtual o programática, una información StructureMetaData
predeterminada ya existente lee la información de la estructura y la maneja de una de las maneras que
se explicó en Manejo de la información StructuredMetaData.
Manejo de la información StructuredMetaData
Implementaciones basadas en VFS
el reconocimiento de la estructura se re-envía a un grupo de StructureDeployers.
estructuras definidas de la especificación JEE
tenemos implementaciones StructureDeployer que coinciden:
EarStructure
103
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
WarStructure
JarStructure
DeclarativeStructures
busca el archivo MET A-INF/jboss-structure.xm l dentro de su implementación y lo
analiza sintácticamente para construir un StructureMetaData apropiado.
FileStructures
solo reconoce los archivos de configuración conocidos tal como -jboss-beans.xm l o service.xm l.
Ejemplo 10.1. Un ejemplo de jboss-structure.xm l
<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 implementación a nivel superior y luego procese
recursivamente las sub-implementaciones.
Puede implementar un StructureDeployer personalizado con la ayuda de la clase genérica
GroupingStructure proporcionada por la interfaz genérica StructureDeployer.
Después de tener una estructura de implementación reconocida se la puede pasar a los programas de
implementación reales. El objeto Deployers sabe cómo encargarse de los programas de implementación
reales, utilizando una cadena de programas de implementación por Deploym entStage.
104
Capítulo 10. Marco de trabajo de la implementación virtual
Ejemplo 10.2. Etapas de la implementación
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 */
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 implementación pre-existentes se mapean a los estados del controlador incorporado del
microcontenedor. Proporcionan una vista céntrica del ciclo de vida de la implementación de los estados
del controlador genérico.
Dentro de los programas de implementación, la implementación se convierte en el componente
Deploym entControllerContext del microcontenedor. La máquina de estado del microcontenedor
maneja las dependencias.
Las implementaciones se manejan secuencialmente por etapa de implementación. Para cada porgrama
de implementación se maneja todo el orden de la jerarquía implementada usando la propiedad parentfirst del programa de implementación. Esta propiedad se configura como true por defecto.
T ambién puede especificar los niveles de jerarquía que el programa de implementación maneja. Puede
seleccionar all, top level, com ponents only o no com ponents.
La manera en que el microcontendor maneja los modelos de componentes y el manejo de las
105
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
La manera en que el microcontendor maneja los modelos de componentes y el manejo de las
dependencias también aplica aquí. Si hay dependencias no resueltas entonces la implementación
empezará en el estado actual, potencialmente reportando un error si el estado actual no es el estado
requerido.
El agregar un nuevo programa de implementación se logra extendiendo uno de los muchos programas
de implementación de ayuda que existen.
Algunos programas de implementacióin de hecho necesitan una implementación respaldada por VFS
mientras que otros pueden utilizar una implementación general. En la mayoría de los casos los
programas de instalación de análisis sintáctico son los que necesitan respaldo de VFS.
Aviso
T ambién tenga en cuenta que los programas de implementación ejecutan recursivamente en
toda implementación, sub-implementación y componentes. Su código necesita determinar tan
pronto como sea posible en el proceso, si el programa de implementación debe manejar la
implementación actual o no.
Ejemplo 10.3. Programa de implementación simple, el cual presenta información sobre su
implementación
public class StdioDeployer extends AbstractDeployer {
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 descripción en uno de los archivos -jboss-beans.xm l en el directorio deployers/ en
el servidor de aplicaciones JBoss y el bean MainDeployerIm pl reconocerá este programa de
implementación por medio del manejo callback loC del microcontenedor.
Ejemplo 10.4 . Descriptor de implementación 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 información de un
programa de implementación al siguiente. Los anexos se implementan como un java.util.Map con
mejoras, cuyas entradas representan un anexo.
Algunos programas de implementación son productores mientras que otros son consumidores. El
106
Capítulo 10. Marco de trabajo de la implementación virtual
mismo programa de implementación también puede realizar ambas funciones. Algunos programas de
implementación crean metadatos o instancias de funcionalidades poniéndolos en el mapa de anexos.
Otros programas de implementación 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 implementación se ordenan. Un orden
natural común usa los términos relativos antes y después. Sin embargo, con el mecanismo de anexos
en uso puede ordenar los programas de implementación de acuerdo a la manera en que producen y/o
consumen los anexos.
Cada anexo tiene una llave y los programas de implementación pasan las llaves a los anexos que
producen. Si el programa de implementación produce un anexo entonces se llama a la llave output. Si el
programa de implementación consume un anexo entonces esa llave se llama input.
Los programas de implementación tienen entradas ordinarias y entradas requeridas. Las entradas
ordinarias sólo se utilizan para ayudar a determinar el orden natural. Las entradas requeridas también
ayudan a determinar el orden, pero también tienen otra función. Ayudan a determinar si el programa de
implementación de hecho es relevante para la implementación 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 práctica y es posible
que no haya soporte para este en lanzamientos futuros.
10.4. Detalles de la implementación y del cliente, usuario y uso del
servidor
Estas funcionalidades esconden los detalles de la implementación, 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 implementación del servidor se encuentren en un
DeploymentContext. Solo se presenta la información necesaria en un nivel en particular del ciclo de vida
de la implementación.
Ya mencionamos los componentes como parte del manejo de la jerarquía de los desarrolladores.
Aunque la implementación y sub-implementación a nivel superior son una representación natural de la
jerarquía de la estructura de la implementación, 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 afirmación.
¿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.
107
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
IncompleteDeploymentException (IDE)
Con el fin de que el IDE imprima las dependencias que faltan en una implementación, necesita
saber los nombres del ControllerContext. descubre el nombre reuniendo los nombres de las
DeploymentUnit's componentes en los programas de implementación de componentes que los
especifican tal como los métodos BeanMetaDataDeployer o setUseUnitNam e() en
AbstractRealDeployer.
10.5. Máquina de estado único
T odos los componentes del microcontenedor son manejados por un solo punto de entrada o una sola
máquina de estado. Las implemtaciones no son la excepción.
Puede sacar ventaja de esta funcionalidad utilizando el archivo de configuración jbossdependency.xm l 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 cómo describir la dependencia en otro servicio. Este ejemplo requiere el crear un
T ransactionManager antes de que la implementación se encuentre en la etapa 'real'.
(2) es un poco más complejo ya que le falta información 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 fácilmente en
otras implementaciones, necesita un mecanismo de alias para evitar nombres URI. Puede agregar un
archivo de texto simple llamado aliases.txt en su implementación. Cada línea del archivo contiene
un alias, dándole al fichero de implementación uno o más nombres simples utilizados para referirse a
este.
10.6. Escaneo de clases en busca de anotaciones
Las especificaciones JEE actuales reducen el número de archivos de configuración, pero ahora se
requiere que el contenedor realice la mayoría del trabajo utilizando @annotations. Con el fin de obtener
información 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.xm l.
108
Capítulo 10. Marco de trabajo de la implementación virtual
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 descripción simple de rutas relativas para incluir o excluir cuando se
escanea en busca de información de metadatos anotados para Java Enterprise Edition versión 5y
posteriores.
109
JBoss Enterprise Application Platform 5 Manual del usuario de JBoss Microcontainer
Historial de revisiones
Revisión 5.1.0-3.4 00
Rebuild with publican 4.0.0
2013-10-31
Rüdiger Landmann
Revisión 5.1.0-3
Rebuild for Publican 3.0
2012-07-18
Anthony T owns
Revisión 5-1
Wed Sep 15 2010
Misty Stanley-Jones
JBPAPP-5076 - Arreglar los ejemplos y sus leyendas
Se cambió el número de la versión en relación con los requerimientos de la versión.
Revisado para JBoss Enterprise Application Platform 5.1.0.GA.
110
Descargar