<rss version="2.0">
  <channel>
    <atom:link xmlns:atom="http://www.w3.org/2005/Atom" href="http://www.davidmarco.es/rss/blog.xml" rel="self" type="application/rss+xml"/>
    <title>davidmarco.es</title>
    <link>http://www.davidmarco.es/blog</link>
    <description>Programacion en Java: articulos, tutoriales, traducciones y mas</description>
    <language>es-es</language>
    <copyright>David Marco</copyright>
    <ttl>15</ttl>
    <lastBuildDate>Sun, 04 Mar 2012 20:29:21 +0100</lastBuildDate>
    <item>
      <title>Feeds RSS</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=215</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=215</guid>
      <pubDate>Thu, 01 Jul 2010 02:00:00 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Como anuncié hace unos dias en el blog, he estado preparando un sistema de feeds RSS para que podáis seguir más facilmente la actividad de la web. He tenido que actualizar la aplicación Spring MVC con la que gestiono el blog para que permitiera la publicación de las entradas también en formato RSS, publicación que es llevada a cabo en última instancia a traves de una sencilla clase (menos de 25 lineas de código) escrita en Groovy. Podéis suscribiros al blog a traves de la url &lt;a href=&quot;http://www.davidmarco.es/rss/blog.xml&quot;&gt;http://www.davidmarco.es/rss/blog.xml&lt;/a&gt;, o pinchando en el icono que encontrareis en la barra de direcciones de vuestro navegador. Por último, pero no por ello menos importante, quiero agradecer a Felix Ernesto Orduz la idea, hace ya muchas semanas, de este feed RSS.</description>
    </item>
    <item>
      <title>Introducción a Groovy (I)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=181</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=181</guid>
      <pubDate>Thu, 01 Jul 2010 13:14:07 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Con este entrega comienza una serie de artículos de introducción a Groovy, paso previo a la próxima publicación del tutorial de Grails. El tutorial estará formado por lo siguientes capítulos (podrían ser más en el futuro):
&lt;br&gt;
&lt;br&gt;1. Introducción a Groovy, reglas y características básicas del lenguaje
&lt;br&gt;2. Strings, GStrings y Closures
&lt;br&gt;3. Rangos y Colecciones
&lt;br&gt;4. POGO's
&lt;br&gt;5. Metaprogramación
&lt;br&gt;6. Usando el API (manejo de archivos, manejo de xml, groovelets)
&lt;br&gt;
&lt;br&gt;Para poder seguir el tutorial es necesario tener instalado Groovy en tu equipo, misión que puedes llevar a cabo de forma sencilla siguiendo los pasos del siguiente &lt;a href=&quot;http://www.davidmarco.es/tutoriales/anexo_introduccion_groovy.html&quot;&gt;anexo&lt;/a&gt;. Podrás acceder al resto de artículos de esta serie desde la pagina de &lt;a href=&quot;http://www.davidmarco.es/tutoriales/&quot;&gt;tutoriales&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.1 PERSPECTIVA GENERAL
&lt;br&gt;Groovy es un lenguaje dinámico, orientado a objetos, muy intimamente ligado a Java. EL 99% del código Java existente puede ser compilado mediante groovy, y el 100% del código Groovy es convertido en bytecode Java, y ejecutado en tu JVM de manera natural. Groovy simplifica la sintaxis de Java hasta lo realmente necesario para expresar lo que queremos hacer, y ademas añade una serie de metodos tremendamente utiles al JDK, convirtiendo multitud de tareas en un placer.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.2 SINTAXIS
&lt;br&gt;La sintaxis de Groovy es una especie de código Java minimalista, eliminando la mayor parte del código &quot;innecesario&quot; (por innecesario nos referimos al código que no es estrictamente necesario para ejecutar la acción que deseamos). Esto, que a priori podria parecernos una dificultad, haciendonos pensar que tenemos que aprender un nuevo lenguaje, no lo es, pues como se ha mencionado en la sección 1.1 casi todo el código Java puede ser compilado con Groovy. De esta manera, podemos introducirnos en Groovy poco a poco, utilizando su sintaxis exclusiva mientras la vamos aprendiendo y la sintaxis de Java el resto del tiempo. Esto es válido en una misma clase o método, de manera que la curva de aprendizaje del lenguaje es muy suave. Veamos un ejemplo
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println &quot;¡Hola Mundo!&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código de arriba podria considerarse el ejemplo más simple de Groovy. Esa unica linea muestra por pantalla el mensaje &quot;¡Hola Mundo!&quot;. No necesitamos escribir una clase contenedora, ni un método &lt;code&gt;public static void main(String[] args)&lt;/code&gt; que rodee el código (llamaremos a esto un script). No hay llamada a &lt;code&gt;System.out&lt;/code&gt;, hemos ignorado los paréntesis en la llamada al método &lt;code&gt;println&lt;/code&gt; así como el punto y coma al final de la linea. Aquí es donde estriba la sencillez de Groovy: reduciendo el código a lo estrictamente necesario. Si deseamos escribir los paréntesis, el punto y coma o ambos, podemos hacerlo: el código seguira funcionando.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.3 SCRIPTS
&lt;br&gt;Existen diversas maneras de ejecutar código Groovy. Una de ellas es mediante scripts. Puedes escribir el código de la sección 1.2 en un archivo con extensión .groovy (p.e. holamundo.groovy) y ejecutarlo desde linea de comandos así:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;groovy holamundo.groovy&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;
&lt;br&gt;Esto compilará el archivo en bytecode Java y sera ejecutado &quot;al vuelo&quot; en memoria. Este archivo será una clase con un metodo &lt;code&gt;main&lt;/code&gt;, dentro del cual se insertará el contenido del script que este fuera de cualquier metodo, más los métodos del script que se insertarán dentro de la propia clase.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.4 GROOVY SHELL
&lt;br&gt;Una segunda opción para ejecutar codigo Groovy es mediante groovy shell. Para lanzar el groovy shell escribimos en la linea de comandos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;groovysh
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Hecho esto, el prompt cambiara y podremos escribir código directamente en él. Para obtener ayuda, podemos escribir lo suguiente una vez que estamos dentro del shell:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;help
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Una caracteristica interesante del shell es que mantiene un historial de todos los comandos que hemos introducido anteriormente, incluso aquellos de una ejecucíon anterior del shell. Para movernos por ese historial, podemos usar las flechas arriba-abajo del cursor de nuestro teclado.
&lt;br&gt;
&lt;br&gt;Es necesario mencionar que el shell debe ser utilizado para ejecutar pequeños scripts, ya que algunas caracteristicas mas complejas del lenguage aún no están soportadas. Utilizalo como una manera rapida de probar un trozo de código que, tal vez, estas escribiendo dentro de tu IDE favorito.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.5 GROOVY CONSOLE
&lt;br&gt;Una opcion mas potente para ejecutar código Groovy es mediante la consola de Groovy. Esta consola funciona en modo grafico y permite opciones mas potentes que el shell, como guardar y cargar archivos, opciones de edición de texto, etc. Para lanzar la consola de Groovy ejecuta lo siguiente desde la linea de comandos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;groovyconsole
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;La consola no padece de las limitaciones del shell a la hora de ejecutar ciertas características complejas del lenguaje. Mi recomendación es que sigas todos los ejemplos restantes del tutorial desde la consola, a menos que se especifique lo contrario.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.6 COMPILAR ARCHIVOS
&lt;br&gt;Todo archivo .groovy, ya contenga una clase o un script, puede ser compilado en un archivo .class. Este archivo es una clase Java normal que, por tanto, puede ser cargada desde Java y Groovy como cualquier otra clase. Realicemos un sencillo ejemplo para comprobarlo. Compila el archivo que hemos escrito en la sección 1.3 de la siguiente manera:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;groovyc holamundo.groovy
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Si miramos en el sistema de archivos, veremos que junto al archivo 'holamundo.groovy' también aparece el recién creado archivo 'holamundo.class'. Ahora crea un script nuevo, en un fichero llamado 'ejecutor.groovy' y escribe dentro de él lo siguiente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;holamundo hm = new holamundo()
&lt;br&gt;hm.main()
&lt;br&gt;println &quot;este es otro archivo&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Si ahora ejecutamos este archivo desde linea de comandos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;groovy ejecutor.groovy
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Obtenemos la siguiente salida:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;¡Hola Mundo!
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;este es otro archivo
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Como puedes ver, hemos instanciado una clase que fué escrita y compilada en Groovy, resultando en una clase Java normal.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.7 IMPORTACIONES AUTOMATICAS
&lt;br&gt;Groovy importa por defecto varios paquetes y clases, de manera que pueden ser utilizados inmediatamente sin necesidad de escribir sus correspondientes sentencias &lt;code&gt;import&lt;/code&gt;. Dichos paquetes y clases son:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- groovy.lang
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- groovy.util
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- java.lang
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- java.util
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- java.net
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- java.io
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- java.math.BigInteger
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- java.math.BigDecimal
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;1.8 PUNTO Y COMA OPCIONAL
&lt;br&gt;Como ya hemos visto en los ejemplos anteriores, el caracter de punto y coma al final de cada linea es opcional. Solo debe ser usado al escribir varias sentencias en una única linea:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;println &quot;primera sentencia&quot;; println &quot;segunda sentencia&quot;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.9 PARÉNTESIS OPCIONAL
&lt;br&gt;El caracter de paréntesis para llamar a un metodo con argumentos también es opcional.
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;void metodo(String s1, String s2) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println s1 + s2
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;metodo &quot;uno&quot;, &quot;dos&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Los paréntesis si que son obligatorios cuando se llama a un método sin argumentos (ya que el compilador no podria saber si es un metodo o una variable lo que estamos llamando).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.10 RETURN OPCIONAL
&lt;br&gt;La sentencia &lt;code&gt;return&lt;/code&gt; al final de un método también es opcional en Groovy. Si se omite, el resultado devuelto por su última linea será implícitamente su valor de retorno (esto también aplica a scripts, que como vimos en el punto 1.3, en tiempo de ejecución son convertidos en una clase que se ejecuta en memoria):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;void cuadrado(int numero) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;devolviendo cuadrado de &quot; + numero
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;numero*numero
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El método anterior, cuando es ejecutado, escribe un mensaje por la salida estandar y devuelve el cuadrado del número pasado como argumento. La sentecia &lt;code&gt;return&lt;/code&gt; solo es necesario cuando, por ejemplo, necesitemos devolver un valor dentro de un bucle o un bloque &lt;code&gt;switch&lt;/code&gt; En caso de que la última sentencia de un método o script no devuelva ningún valor (por ejemplo una sentencia &lt;code&gt;println&lt;/code&gt; o la llamada a un método &lt;code&gt;void&lt;/code&gt;), se devolverá &lt;code&gt;null&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.11 DECLARACION DE TIPOS OPCIONAL
&lt;br&gt;En Groovy no tenemos que declarar el tipo de una variable cuando le asignamos un valor. Esto es debido a la naturaleza dinamica de Groovy, en contra de Java que es un lenguaje fuertemente tipado (o estático).
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;x = &quot;Esto es un String&quot;
&lt;br&gt;println x.class
&lt;br&gt;x = 12
&lt;br&gt;println x.class
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La variable &lt;code&gt;x&lt;/code&gt;, que no ha sido declarada previamente en el código, es inicializada con un &lt;code&gt;String&lt;/code&gt; primero y con un entero después. Las sentencias &lt;code&gt;println&lt;/code&gt; demuestran esto mostrando por pantalla el tipo actual de la variable después de cada asignación. Esta naturaleza dinámica es conocida como 'duck typing', un término que significaria algo como 'escritura de pato', y proviene de un dicho inglés que dice que &lt;i&gt;si anda como un pato, come como un pato y hace ruido como un pato, seguramente es un pato&lt;/i&gt;. En nuestro caso, si una variable contiene un &lt;code&gt;String&lt;/code&gt; y se comporta como tal, entonces es un &lt;code&gt;String&lt;/code&gt; (aunque no hayamos definido su tipo).
&lt;br&gt;
&lt;br&gt;El código anterior, que funciona bien en scripts, no puede ser usado dentro de una clase: o declaramos el tipo explicitamente (&lt;code&gt;String&lt;/code&gt; o &lt;code&gt;int&lt;/code&gt;) o declaramos la variable con &lt;code&gt;def&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class MiClase {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def x = &quot;Esto es un String&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void metodo() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println x.class&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x = 12
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println x.class
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;new MiClase().metodo()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Mi recomendación es utilizar siempre &lt;code&gt;def&lt;/code&gt;, incluso en scripts, puesto que así podemos determinar en que momento se crea la variable y en que momento se le esta reasignando un valor diferente.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.12 MANEJO DE EXCEPCIONES
&lt;br&gt;En Groovy todas las excepciones son de tipo no chequeadas, por lo que no tenemos que declararlas ni capturarlas. Esto nos da la liberad de manejarlas solo cuando creamos necesario hacerlo, en contra del sistema de manejo de excepciones en Java donde el compilador nos obliga a hacerlo siempre que un metodo declare lanzar una excepción de tipo chequeada. Veamos un ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;FileReader fr = new FileReader(&quot;actividad.log&quot;)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En el ejemplo anterior, si el archivo 'actividad.log' no existe se lanzará una excepción del tipo &lt;code&gt;FileNotFoundException&lt;/code&gt;. Pero imaginemos que esa linea se llama desde una aplicación donde ese archivo siempre existe (porque se ha creado 5 lineas de código antes o porque al iniciar la aplicación se crea automáticamente), o que estamos llamando a un archivo del sistema operativo que, de igual manera, debe estar siempre presente en disco. En estos dos casos los bloques &lt;code&gt;try-catch&lt;/code&gt; solo añaden &quot;ruido&quot; al código, pues son a todas luces innecesarios. Groovy nos permite no declarar ni capturar cualquier excepcion, sea del tipo que sea. Por supuesto que, cuando no podamos asegurar que una excepción no va a ser lanzada, deberemos gestionarla correctamente. Dejame recordarte que, sobre todo en una aplicación seria, NUNCA debes capturar una excepción en un bloque &lt;code&gt;catch&lt;/code&gt; vacio, pues tu aplicación podria estar funcionando mal y no ser consciente de ello.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.13 SOBRECARGA DE OPERADORES
&lt;br&gt;Groovy permite la sobrecarga de operadores, de manera que podemos definir un método (dentro de una de nuestras clases) que será llamado al usar cierto operador. La manera mas sencilla de entenderlo es, como siempre, viendo un ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class MiInteger {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private int valor = 0;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public MiInteger(int valor) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.valor = valor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int plus(MiInteger otro) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;valor + otro.valor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;def mc1 = new MiInteger(8)
&lt;br&gt;def mc2 = new MiInteger(7)
&lt;br&gt;println mc1 + mc2
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El ejemplo anterior es una clase wrapper simplificada de &lt;code&gt;Integer&lt;/code&gt;. En su interior hay un método llamado &lt;code&gt;plus()&lt;/code&gt; el cual sobrecarga el operador &lt;code&gt;+&lt;/code&gt; (caracter más). Debajo de la definición de la clase hemos instanciado dos objetos de dicha clase y los hemos &quot;sumado&quot; con el citado operador &lt;code&gt;+&lt;/code&gt;. El resultado ha sido la llamada al método &lt;code&gt;plus()&lt;/code&gt;, el cual ha devuelto la suma de los valores contenidos en ambas instancias (recuerda que la última linea de un método es implícitamente una sentencia &lt;code&gt;return&lt;/code&gt;. Puedes encontrar una lista con todos los operadores que pueden ser sobrecargados y sus métodos correspondientes &lt;a href=&quot;http://groovy.codehaus.org/Operator+Overloading&quot;&gt;aquí&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.14 REFERENCIACIÓN SEGURA
&lt;br&gt;El operador de referenciación segura (&lt;code&gt;?&lt;/code&gt;) evita que se lance la temida excepción de tipo &lt;code&gt;NullPointerException&lt;/code&gt; cuando llamamos a un método en un objeto con valor &lt;code&gt;null&lt;/code&gt;. En su lugar, la llamada al método devolverá &lt;code&gt;null&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;MiInteger mi
&lt;br&gt;mi?.plus(new MiInteger(10))
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior declara una instancia de la clase &lt;code&gt;MiInteger&lt;/code&gt; y llama a su método &lt;code&gt;plus()&lt;/code&gt; usando el operador de referenciación segura (el caracter de interrogación) antes del punto. Al ejecutar el código, obtenemos que la llamada al método devuelve &lt;code&gt;null&lt;/code&gt; en lugar de lanzar una excepción &lt;code&gt;NullPointerException&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;El operador de referenciación segura puede ser encadenado tantas veces se desee:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;empresa?.getEmpleado()?.getSueldo()?.getSalarioBase()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.15 AUTOBOXING
&lt;br&gt;En Groovy, TODO es un objeto. Incluso los tipos primitivos son tratados como objetos. Mira el siguiente código:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println println 2.floatValue()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior llama al método &lt;code&gt;floatValue()&lt;/code&gt; que está presente en la clase &lt;code&gt;Integer&lt;/code&gt;, a pesar de que &lt;code&gt;2&lt;/code&gt; es un tipo primitivo. La razón de este comportamiento tan sorprendente como potente es que Groovy convierte (cuando es necesario) cualquier variable de tipo primitivo en su correspondiente clase wrapper. 
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.16 DECIMALES
&lt;br&gt;En Groovy, todas las expresiones numéricas con decimales son por defecto de tipo &lt;code&gt;BigDecimal&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println 0.91.class
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Si ejecutas el código anterior, verás que la expresión decimal &lt;code&gt;0.91&lt;/code&gt; es una instancia de la clase &lt;code&gt;BigDecimal&lt;/code&gt;. Este comportamiento del lenguaje esta destinado a evitar la inexactitud de las clases &lt;code&gt;Float&lt;/code&gt; y &lt;code&gt;Double&lt;/code&gt;. Aunque dichas clases siguen estando disponibles, evidentemente deben ser instanciadas explícitamente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println new Double(0.91).class
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.17 VERDADERO Y FALSO
&lt;br&gt;En Java, solamente &lt;code&gt;true&lt;/code&gt; puede ser verdadero y solamente &lt;code&gt;false&lt;/code&gt; puede ser falso. En Groovy el concepto de verdadero y falso ha sido extendido a multitud de situaciones más, siempre con la intención de simplificar el código y hacerlo tremendamente expresivo. Siempre que se evalue un valor cero, &lt;code&gt;null&lt;/code&gt;, un String vacío, una coleccion vacía, un array de longitud cero o un StringBuilder/StringBuffer vacío, se obtendrá &lt;code&gt;false&lt;/code&gt;. En cualquier otra situación, se obtendrá &lt;code&gt;true&lt;/code&gt;. Esto nos permite, por ejemplo, lo siguiente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def lista = []
&lt;br&gt;// ...
&lt;br&gt;if(lista) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;ArrayList con elementos&quot;
&lt;br&gt;} else {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;ArrayList vacio&quot;
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La primera linea del código anterior declara un &lt;code&gt;ArrayList&lt;/code&gt; vacío, y despues de varias lineas que no mostramos (que podrían añadir o eliminar objetos del &lt;code&gt;ArrayList&lt;/code&gt;) se llama a una sentencia &lt;code&gt;if&lt;/code&gt; pasandole como condición booleana la lista previamente creada. Si la lista contiene elementos, el bloque &lt;code&gt;if&lt;/code&gt; será alcanzado; en caso contrario se ejecutará el bloque &lt;code&gt;else&lt;/code&gt;. 
&lt;br&gt;
&lt;br&gt;En el &lt;a href=&quot;http://localhost:8080/blog/form.do?id=211&quot;&gt;próximo capítulo&lt;/a&gt; veremos como trabajar con cadenas de texto en Groovy, lo que nos permitirá introducir la clase &lt;code&gt;GString&lt;/code&gt; (Groovy Strings) y los Heredocs. A continuación nos introduciremos en el concepto de Closure, una de las caracteristicas del lenguaje más potentes y totalmente necesaria para poder seguir con el resto del tutorial (ademas de elevar nuestro código hasta cotas inimaginables). Hasta entonces, ¡saludos!.</description>
    </item>
    <item>
      <title>Introducción a Groovy (II)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=211</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=211</guid>
      <pubDate>Thu, 01 Jul 2010 13:17:40 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>En esta segunda entrega del tutorial de introducción a Groovy vamos a ver como trabajar con cadenas de texto, así como el concepto de Closure. En la &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=181&quot;&gt;primera entrega&lt;/a&gt; vimos las características más basicas del lenguaje, así como las reglas de sintaxis. Esta entrega es una continuacíon de la anterior, pues muestra caracteristicas del lenguaje que son comunmente utilizadas.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.1 TIPOS DE CADENAS DE TEXTO
&lt;br&gt;Groovy soporta de forma nativa tres tipos de cadenas de texto: Strings, GStrings y Heredocs. Cual usar en cada momento es una decisión que surgirá de las necesidades de nuestro código, aunque en última instancia todas ellas son intercambiales por cualquier otra.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.2 STRINGS
&lt;br&gt;Un String en Groovy es similar a un String en Java, con la particularidad de que puede ser construido usando tanto comillas simples como dobles:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def cadena1 = &quot;Esto es válido en Java y Groovy&quot;
&lt;br&gt;def cadena2 = 'Esto es válido solo en Groovy'
&lt;br&gt;
&lt;br&gt;println cadena1.class
&lt;br&gt;println cadena2.class
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Si observamos la salida de ambas sentencias &lt;code&gt;println&lt;/code&gt; veremos que las dos variables definidas previamente, &lt;code&gt;cadena1&lt;/code&gt; y &lt;code&gt;cadena2&lt;/code&gt;, son de tipo &lt;code&gt;java.lang.String&lt;/code&gt;. Un tipo de comillado puede contener al otro en su interior, sin necesidad de (aunque está permitido) escapar el comillado interior:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def cadena3 = &quot;Hola 'Usuario'&quot;
&lt;br&gt;def cadena4 = 'Hola &quot;Usuario&quot;'
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.3 GSTRINGS
&lt;br&gt;GStrings (o Groovy Strings) es una cadena de texto que contiene expresiones embebidas. Un GStrings solo puede ser construido con comillas dobles o triples (las cuales veremos en el apartado 2.4). Veamos un ejemplo simple:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def saldo = 1821.14
&lt;br&gt;println &quot;El saldo es de ${saldo} euros&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior, vemos que dentro de la cadena de texto pasada a &lt;code&gt;println&lt;/code&gt; hemos insertado la variable &lt;code&gt;saldo&lt;/code&gt; como si fuera parte de la propia cadena de texto. Esta inserción se hace dentro del operador &lt;code&gt;${}&lt;/code&gt; y es evaluada en tiempo de ejecución. Como se indicaba en el párrafo anterior, podemos insertar cualquier expresión dentro de un GString:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def saldo = 1821.14
&lt;br&gt;def mensaje = &quot;El saldo a fecha ${new Date()} es de ${saldo} euros&quot;
&lt;br&gt;println mensaje
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Es evidente que el código anterior es mucho mas natural, tanto al escribirlo como al leerlo, que su homologo en Java (el cual necesitaria unir cada parte de texto con cada expresión mediante el operador &lt;code&gt;+&lt;/code&gt;). Es importante tener siempre presente que un GString no es un String, y que usarlos en combinación puede producir resultados inesperados:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def str = &quot;abc&quot;
&lt;br&gt;def gstr = &quot;${str}&quot;
&lt;br&gt;
&lt;br&gt;println str.equals(gstr)
&lt;br&gt;println str.equals(gstr.toString())
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La primera sentencia &lt;code&gt;println&lt;/code&gt; devuelve &lt;code&gt;false&lt;/code&gt;, ya que ambas clases implementan sus métodos &lt;code&gt;equals&lt;/code&gt; y &lt;code&gt;hashCode&lt;/code&gt; de forma diferente. El mismo problema puede surgir (y surgirá) si mezclamos &lt;code&gt;String&lt;/code&gt;'s y &lt;code&gt;GString&lt;/code&gt;'s en sitios tales como las claves de un &lt;code&gt;Map&lt;/code&gt;. Una forma de solventar este problema es invocar el método &lt;code&gt;toString()&lt;/code&gt; en el objeto &lt;code&gt;GString&lt;/code&gt;, como puede verse en la segunda sentencia &lt;code&gt;println&lt;/code&gt; del código anterior (la cual SI devuelve &lt;code&gt;true&lt;/code&gt; pues ambos objetos a comparar ahora si son del mismo tipo).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.4 HEREDOCS
&lt;br&gt;El último tipo de cadena de texto soportado en Groovy es el Heredoc, el cual se forma con tres comillas simples o dobles:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println &quot;&quot;&quot;Esto es un Heredoc&quot;&quot;&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Los Heredoc's nos permiten tanto almacenar cadenas de texto multilinea en una única variable como mezclar comillas simples y dobles en su interior sin necesidad de escaparlas:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def multilinea = &quot;&quot;&quot;
&lt;br&gt;Primera linea
&lt;br&gt;Segunda linea
&lt;br&gt;Tercera linea con &quot;comillas dobles&quot; y 'comillas simples'
&lt;br&gt;&quot;&quot;&quot;
&lt;br&gt;println multilinea
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Por las dos características arriba mencionadas, los Heredocs son tremendamente útiles para almacenar XML y HTML en una variable. Los Heredocs formados con comillas dobles permiten insertar cualquier expresión, resultando en un &lt;code&gt;GString&lt;/code&gt; multilinea. Realmente los Heredocs no son un tipo (de ahí que no aparece su nombre en otra fuente, como ocurre por ejemplo con los &lt;code&gt;String&lt;/code&gt;'s y &lt;code&gt;GString&lt;/code&gt;'s), sino más bien una caracteristica del lenguaje para escribir cadenas multilinea. Esto podemos comprobarlo de la siguiente manera:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println '''heredoc con comillas simples'''.class
&lt;br&gt;println &quot;&quot;&quot;heredoc con comillas dobles&quot;&quot;&quot;.class
&lt;br&gt;println &quot;&quot;&quot;heredoc con comillas dobles y expresión embebida: ${new Date()}&quot;&quot;&quot;.class
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Las dos primeras sentencias &lt;code&gt;println&lt;/code&gt; del código anterior devuelven &lt;code&gt;java.lang.String&lt;/code&gt; como tipo del heredoc, mientras que la tercera expresión devuelve &lt;code&gt;org.codehaus.groovy.runtime.GStringImpl&lt;/code&gt;, ya que detecta la expresión embebida y automaticamente trata la cadena como si fuera un &lt;code&gt;GString&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.5 CLOSURES
&lt;br&gt;Los closures son una de las caracteristicas mas potentes del Groovy, y para aquellos que solo han trabajado con Java tal vez la más dificil de comprender y utilizar correctamente (en otros lenguajes hay construcciones comparables a los closures de Groovy). Empecemos con su definición: un closure es un bloque de código autónomo (fuera de cualquier clase) que puede ser definido y usado en puntos distintos. Veamos el ejemplo más simple posible:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def saludar = { println '¡Hola Mundo de los Closures!' }
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior se define un closure, siempre entre llaves, y se asigna a una variable llamada &lt;code&gt;saludar&lt;/code&gt;. Para ejecutar este closure podemos invocarlo como si fuera un método (a efectos practicos lo es):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;saludar()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Un closure puede aceptar parametros:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def saludar2 = { println &quot;¡Hola ${it}!&quot; }
&lt;br&gt;saludar2 &quot;David&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, utilizamos dentro del closure la variable &lt;code&gt;it&lt;/code&gt;, la cual es implícita para todos los closures que no definen ningun parametro. Para cerrar el círculo y entender que significa esto, declaremos un closure con parametros explícitos:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def saludar3 = { nombre -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;¡Hola ${nombre}!&quot;
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;saludar3 &quot;David&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En este último ejemplo, al contrario del anterior, hemos definido un parámetro explícito llamado &lt;code&gt;nombre&lt;/code&gt; que sustituye a &lt;code&gt;it&lt;/code&gt; y hace el código más legible y consonante con su función final (saludar usando un nombre). Este parámetro debe declararse antes del código del closure y separarse de este con los caracteres &lt;/code&gt;-&amp;gt;&lt;/code&gt;. Por supuesto, podemos declarar más de un parámetro para un closure:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def saludar4 = { nombre, apellido -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;¡Hola ${nombre} ${apellido}!&quot;
&lt;br&gt;}
&lt;br&gt;saludar4 &quot;David&quot;, &quot;Marco&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Recuerda que, como se explicó en el punto 1.9 del &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=181&quot;&gt;capítulo anterior&lt;/a&gt;, Groovy permite omitir los parentesis al llamar a una función a la que le pasamos argumentos (y tal como hemos dicho unos parrafos mas arriba los closures son a efectos practicos funciones) de ahí que la llamada a los closures &lt;code&gt;saludar2&lt;/code&gt;, &lt;code&gt;saludar3&lt;/code&gt; y &lt;code&gt;saludar4&lt;/code&gt; puedan parecer un poco extrañas.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.6 CURRYING
&lt;br&gt;Currying es una técnica que nos permite pre-cargar valores en los parámetros de un closure. Veamos un ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def saludar5 = { nombre -&gt; println &quot;¡Hola ${nombre}!&quot; }
&lt;br&gt;def anonimo = saludar5.curry(&quot;Anonimo&quot;)
&lt;br&gt;anonimo()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior hemos pre-cargado el valor &quot;Anonimo&quot; para el unico parametro del closure &lt;code&gt;saludar5&lt;/code&gt;, y el closure resultante lo hemos almacenado en la variable &lt;code&gt;anonimo&lt;/code&gt;. A continuación hemos llamado a dicho closure, resultando en una llamada equivalente a:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;saludar5 &quot;Anonimo&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Este ejemplo, tan simple como estúpido (espero que estés de acuerdo conmigo) no muestra la verdadera potencia del currying; su unica misión es mostrarnos el concepto de la manera más simple posible. Ahora es el momento de ver algo más práctico:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def multiplicar = { valor1, valor2 -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;valor1 * valor2
&lt;br&gt;}
&lt;br&gt;def doble = multiplicar.curry(2)
&lt;br&gt;def triple = multiplicar.curry(3)
&lt;br&gt;
&lt;br&gt;println doble(7)
&lt;br&gt;println triple(7)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El currying muestra toda su potencia cuando trabajamos con múltiples parametros, ya que nos permite pre-cargar valores que serán siempre los mismos para una determinada función y pasar el resto en tiempo de ejecución. En el ejemplo anterior, hemos creado dos closures, &lt;code&gt;doble&lt;/code&gt; y &lt;code&gt;triple&lt;/code&gt; que hacen currying sobre el closure &lt;code&gt;multiplicar&lt;/code&gt;, pre-cargando los valores &lt;code&gt;2&lt;/code&gt; y &lt;code&gt;3&lt;/code&gt; respectivamente en su parametro más a la izquierda, &lt;code&gt;valor1&lt;/code&gt;. Así, al llamar a &lt;code&gt;doble(7)&lt;/code&gt; y &lt;code&gt;triple(7)&lt;/code&gt; lo que hacemos es asignar el valor &lt;code&gt;7&lt;/code&gt; al primer parametro sin definir de &lt;code&gt;multiplicar&lt;/code&gt;, en nuestro caso &lt;code&gt;valor2&lt;/code&gt; (ya que, vuelvo a insistir, &lt;code&gt;valor1&lt;/code&gt; fue asignado con un valor por defecto al hacer currying).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.7 CLOSURES COMO PARAMETROS
&lt;br&gt;Una de las caracteristicas más potentes de los closures es que pueden ser utilizadas como argumentos de una función:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def repetirClosure(int numRepeticiones, Closure closure) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i = 0; i &lt; numRepeticiones; i++) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;closure.call(i)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;def closure = { println it }
&lt;br&gt;repetirClosure(5, closure)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, hemos definido un método (&lt;code&gt;repetirClosure&lt;/code&gt;) que acepta como parámetro un closure. Dentro de dicho método, invocamos el closure dentro de un bucle mediante el método &lt;code&gt;call()&lt;/code&gt;, al cual podemos pasarle cualquier parámetro que sera enviado directamente al closure (esto es equivalente a ejecutar el closure directamente, como hemos hecho hasta ahora, pero necesario cuando trabajamos con un objeto &lt;code&gt;Closure&lt;/code&gt; en lugar de con la propia definición del closure). A continuación, y ya fuera de la definición del método, definimos un closure y se lo pasamos al metodo recién definido. Por otro lado, cuando el parámetro que acepta el closure es el situado más a la derecha en la definición del método (como ocurre en nuestro caso) podemos pasar el closure de la siguiente manera:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;repetirClosure(5) { println it }
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Esta última sintaxis la veremos de forma intensiva en el capitulo 3 cuando trabajemos con Rangos y Colecciones.
&lt;br&gt;
&lt;br&gt;Los closures permiten hacer cosas muchisimo más complejas (y por supuesto utiles) que las aquí mostradas, pero todo lo que necesitamos saber para continuar con el tutorial se encuentra en este capítulo. Es importante que escribas tus propios closures para ganar confianza con esta potentisima herramienta del lenguaje, y que busques información adicional a la aquí descrita si quieres explorar/explotar todas sus caracteristicas. En el próximo capítulo veremos que son los Rangos, y como Groovy ha simplificado el uso de Colecciones respecto a Java. Hasta entonces, ¡feliz currying!.</description>
    </item>
    <item>
      <title>Introducción a Groovy (III)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=225</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=225</guid>
      <pubDate>Mon, 12 Jul 2010 22:32:21 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>En los &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=181&quot;&gt;capítulos 1&lt;/a&gt; y &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=211&quot;&gt;2&lt;/a&gt; del tutorial de Groovy vimos los conceptos básicos del lenguage, asi como algunas estructuras de datos. En esta tercera entrega vamos a ver dos tipos nativos del lenguaje: Rangos y Colecciones.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.1 RANGOS
&lt;br&gt;Los rangos son un tipo de datos nativo, derivado de &lt;code&gt;List&lt;/code&gt;, que nos permite definir una lista de valores secuenciales. Veamos el ejemplo mas simple:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def rango = 1..5
&lt;br&gt;def rango = 1..&lt;5
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El primer rango arriba definido es una lista con los valores del 1 al 5, ambos inclusive. El segundo rango contiene una lista con los valores del 1 al 4, pues el último valor ha sido excluido. Ahora que sabemos como definir un rango, podemos iterarlo llamando al método &lt;code&gt;each()&lt;/code&gt;, el cual acepta un closure como argumento (recuerda que si el único o último parámetro de un método es un closure, podemos definir dicho closure a continuación de la llamada al método):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;rango.each {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println it
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior, iteramos a través del rango imprimiendo cada uno de sus valores. Si no vamos a reusar el rango, podemos definirlo &quot;al vuelo&quot;, insertandolo entre parentesis:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;(1..5).each {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println it
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Una forma alternativa de iterar a través de los valores de un rango es mediante un bucle &lt;code&gt;for&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;for(int contador in 1..5) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println contador
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Además de &lt;code&gt;each()&lt;/code&gt;, los rangos disponen de una serie de atributos y métodos que podemos llamar en nuestra aplicación:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def rango = 5..10
&lt;br&gt;println rango.from
&lt;br&gt;println rango.to
&lt;br&gt;println rango.contains(4)
&lt;br&gt;println rango.size()
&lt;br&gt;println rango.get(3)
&lt;br&gt;println rango[3]
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El atributo &lt;code&gt;from&lt;/code&gt; devuelve el valor de inicio del rango, mientras que el atributo &lt;code&gt;to&lt;/code&gt; devuelve el último valor. El método &lt;code&gt;contains()&lt;/code&gt; devuelve &lt;code&gt;true&lt;/code&gt; si su argumento está incluido en el rango, y &lt;code&gt;size()&lt;/code&gt; devuelve el tamaño del rango. Por último, podemos obtener el valor almacenado en un índice del rango (recuerda que es una lista) mediante el método &lt;code&gt;get(indice)&lt;/code&gt; o mediante notación de arrays (&lt;code&gt;rango[indice]&lt;/code&gt;). Otra opción permitida por un rango es la de invertirlo, gracias al método &lt;code&gt;reverse()&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def rango = 10..15
&lt;br&gt;def inverso = rango.reverse()
&lt;br&gt;inverso.each {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println it
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Hasta ahora hemos utilizado rangos que contenian valores enteros; sin embargo, cualquier clase que implemente el interface &lt;code&gt;Comparable&lt;/code&gt;, así como los métodos &lt;code&gt;next()&lt;/code&gt; y &lt;code&gt;previous&lt;/code&gt;, puede ser usado como valor de un rango. Este es el caso, por ejemplo, de &lt;code&gt;Date()&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def hoy = new Date()
&lt;br&gt;def dentroDeSieteDias = hoy + 7
&lt;br&gt;(hoy..dentroDeSieteDias).each { dia -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println dia
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Otro ejemplo de clase soportada en rangos es &lt;code&gt;String&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;('a'..'z').each { letra -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println letra
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Los rangos ofrecen mucho mas de lo aquí explicado, y como siempre te invito a que visites la &lt;a href=&quot;http://groovy.codehaus.org/Documentation&quot;&gt;documentación oficial&lt;/a&gt; de Groovy. Pero antes de terminar esta sección, veamos un último ejemplo que seguro te resulta util en el futuro: rangos como valores de comparación en un bucle &lt;code&gt;switch&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def sueldo = 1700;
&lt;br&gt;switch(sueldo) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 600..&lt;1200:
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println 'nivel 1'
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 1200..&lt;1800:
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println 'nivel 2'
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 1800..&lt;2400:
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println 'nivel 3'
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código es, sin duda, autoexplicativo.
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;3.2 COLECCIONES
&lt;br&gt;Groovy ofrece soporte nativo para colecciones de tipo &lt;code&gt;List&lt;/code&gt; y &lt;code&gt;Map&lt;/code&gt;, así como conversión explícita de listas en colecciones de tipo &lt;code&gt;Set&lt;/code&gt; y &lt;code&gt;Queue&lt;/code&gt;. Veamos uno por uno estos tipos.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.3 LISTAS
&lt;br&gt;Las listas son colecciones secuenciales cuyos elementos pueden ser accedidos mediante un índice. Veamos como crear una lista vacia en Groovy:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def lista = []
&lt;br&gt;println lista.class
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior define una lista sin elementos y la almacena en la variable &lt;code&gt;lista&lt;/code&gt;. A continuación imprime su tipo (&lt;code&gt;ArrayList&lt;/code&gt; en mi versión de Groovy, 1.7.2). Es posible insertar elementos en la lista en el momento de su creación:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def paises = [&quot;España&quot;, &quot;Mexico&quot;]
&lt;br&gt;println paises.size()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior hemos definido una lista con dos elementos de tipo &lt;code&gt;String&lt;/code&gt;. A continuación hemos llamado al método &lt;/code&gt;size()&lt;/code&gt; que nos devuelve el número de elementos de una lista. Ahora es el momento de añadir elementos a una lista previamente creada. Las dos maneras mas comunes de hacerlo son a traves del operador 'leftshift' (&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;, un operador sobrecargado como se explicó en la sección 1.13) y del metodo &lt;code&gt;add()&lt;/code&gt; del interface &lt;code&gt;List&lt;/code&gt;, como habriamos hecho hasta ahora en Java:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;paises &amp;lt;&amp;lt; &quot;Argentina&quot;
&lt;br&gt;paises.add(&quot;Ecuador&quot;)
&lt;br&gt;println paises
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Las dos primeras lineas del código anterior añaden un &lt;code&gt;String&lt;/code&gt; cada a la lista &lt;code&gt;paises&lt;/code&gt;. Ahora podemos obtener cualquier objeto de la lista por medio de su índice numérico, y también de dos maneras: mediante notación de arrays y mediante el método &lt;code&gt;getAt()&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def pais = paises[0]
&lt;br&gt;def otroPais = paises.getAt(1)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Recuerda que las posiciones de una lista están basadas en índice cero: el primer elemento está en la posición 0, el segundo elemento en la posición 1, etc. La notación de arrays nos permite, además de sobreescribir el valor de una posición, insertar un nuevo elemento en una posición explícita, añadiendo valores &lt;code&gt;null&lt;/code&gt; en todas las posiciones intermedias:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;paises[3] = &quot;Colombia&quot;
&lt;br&gt;paises[6] = &quot;Ecuador&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior sobreescribe la posición número 3 con el valor &lt;code&gt;Colombia&lt;/code&gt;, y a continuación define en la posición 6 el valor &lt;code&gt;Ecuador&lt;/code&gt;. Las posiciones 4 y 5, las cuales aún no han podido ser definidas pero deben existir para mantener la secuencialidad, son 'rellenadas' con valores &lt;code&gt;null&lt;/code&gt;; así mantenemos intacto el índice de la lista. Tras ejecutar el código anterior: nuestra lista de paises quedara de la siguiente manera:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[España, Mexico, Argentina, Colombia, null, null, Ecuador]
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Otra opción necesaria en una colección es la de eliminar objetos, operación que podemos llevar a cabo mediante el método &lt;code&gt;remove()&lt;/code&gt;, el cual admite como argumento tanto el índice de la posición como el objeto a eliminar, y devuelve el valor eliminado:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def eliminado1 = paises.remove(6)
&lt;br&gt;def eliminado2 = paises.remove(&quot;Ecuador&quot;)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Ambas lineas del código anterior realizar la misma operación para los valores concretos de nuestra lista: eliminar la posición 6 / eliminar el valor &quot;Ecuador&quot;. Es importante que tengas en cuenta que si eliminamos por índice, y este no existe, obtendremos una excepción de tipo &lt;code&gt;NullPointerException&lt;/code&gt;. Si eliminamos pasando un objeto que no existe obtendremos como resultado &lt;code&gt;null&lt;/code&gt;, pero sin que se lance ninguna excepción. Antes de continuar vamos a eliminar los dos valores &lt;code&gt;null&lt;/code&gt; que están embebidos en nuestra lista:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;2.times {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;paises.remove(null)
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior ejecuta el método &lt;code&gt;times&lt;/code&gt; de la clase &lt;code&gt;Number&lt;/code&gt; (y por tanto heredado por &lt;code&gt;Integer&lt;/code&gt;). Este método ejecuta el closure pasado como argumento tantas veces como el valor de la variable donde es invocado, en nuestro caso &lt;code&gt;2&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;Una tercera manera de eliminar un elemento de una lista es mediante el método &lt;code&gt;pop()&lt;/code&gt;, el cual devuelve y a elimina el último elemento de la lista (no el último elemento añadido, que podría haber sido insertado a traves de notación de arrays en medio de la lista, si no el elemento que tiene el índice más alto). Este método permite tratar una lista como una cola LIFO (Last In, First Out - El último en entrar, el primero en salir) aunque, como veremos después, existe una manera más adecuada de crear colas de datos:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def eliminado = paises.pop()
&lt;br&gt;println eliminado
&lt;br&gt;println paises
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Ahora el contenido de nuestra lista será el siguiente:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[España, Mexico, Argentina, Colombia]
&lt;br&gt;
&lt;br&gt;Veamos ahora como iterar a través de los elementos de una lista:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;paises.each {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println it.toUpperCase()
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior hemos llamado al método &lt;code&gt;each()&lt;/code&gt;, el cual acepta un closure que es ejecutado por cada elemento de la lista. Dentro del closure hemos imprimido en mayúsculas cada elemento (recuerda que está lista contiene elementos de tipo &lt;code&gt;String&lt;/code&gt;). Como explicamos en la sección 2.5, podemos utilizar una variable definida por nosotros cuando el closure acepta un unico parametro, sustituyendo así a la variable explicita &lt;code&gt;it&lt;/code&gt; y haciendo el código más expresivo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;paises.each { pais -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println pais.toUpperCase()
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Una segunda manera de iterar una lista es mediante el método &lt;code&gt;eachWithIndex&lt;/code&gt;, el cual acepta un closure con dos parámetros: uno para el valor de cada elemento iterado y otro para almacenar su posición (o número de iteración):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;paises.eachWithIndex { pais, indice -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;${pais} se encuentra en la posición ${indice}&quot;
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Existe una forma alternativa de iteración, que ejecuta una acción en cada elemento de la lista y devuelve una nueva lista conteniendo el resultado de dichas ejecuciones. Esto es llevado a cabo mediante el método &lt;code&gt;collect()&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def paisesMayusculas = paises.collect { pais -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pais.toUpperCase()
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior, hemos creado una nueva lista, llamada &lt;code&gt;paisesMayusculas&lt;/code&gt; que contiene el resultado de convertir en mayusculas todos los valores de la lista &lt;code&gt;paises&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[ESPAÑA, MEXICO, ARGENTINA, COLOMBIA]
&lt;br&gt;
&lt;br&gt;En determinadas ocasiones, necesitamos ordenar una lista de manera natural, esto es, en base a los objetos que están contenidos en ella. Por ejemplo, para nuestra lista conteniendo objetos &lt;code&gt;String&lt;/code&gt; la ordenación natural sería la alfabética:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;paises.sort()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El fragmento de código anterior ordena la lista &lt;code&gt;paises&lt;/code&gt;, modificando la lista original y dejando sus elementos (del tipo &lt;code&gt;String&lt;/code&gt;) en orden alfabético):
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[Argentina, Colombia, España, Mexico]
&lt;br&gt;
&lt;br&gt;Otro método de utilidad es &lt;code&gt;reverse()&lt;/code&gt; el cual devuelve una lista en sentido inverso, pero sin modificar la lista original. Por tanto, para capturar la nueva lista debemos asignarla a una variable:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def paisesInvertidos = paises.reverse()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Groovy nos permite añadir/sustraer una lista a/de otra mediante los operadores &lt;code&gt;+=&lt;/code&gt; y &lt;code&gt;-=&lt;/code&gt;. Veamos un ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def pares = [2, 4, 6, 8]
&lt;br&gt;def impares = [1, 3, 5, 7, 9]
&lt;br&gt;pares += impares
&lt;br&gt;pares.sort()
&lt;br&gt;pares -= impares
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Las dos primeras lineas del código anterior crean dos listas, una conteniendo números pares y otra conteniendo números impares. A continuación, en la tercera linea, añadimos la lista de números impares a la lista de números pares, y en la cuarta linea ordenamos la nueva lista mixta con &lt;code&gt;sort()&lt;/code&gt; (como la lista contiene números enteros, la ordenación se realiza por valor numérico, esto es: 1, 2, 3, 4, ...). En la quinta y última linea, eliminamos de la lista ordenada todos los valores de la lista de números impares, dejandola evidentemente solo con los valores pares originales.
&lt;br&gt;
&lt;br&gt;Otro método de gran utilidad es &lt;code&gt;join()&lt;/code&gt;, el cual une los valores de una lista en una cadena de texto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def letras = ['a', 'b', 'c']
&lt;br&gt;println letras.join()
&lt;br&gt;println letras.join(&quot;-&quot;)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La primera llamada a &lt;code&gt;join&lt;/code&gt; devuelve una cadena de texto conteniendo el valor &lt;code&gt;abc&lt;/code&gt;, mientras que la segunda llamada devuelve también una cadena de texto pero, esta vez, con los valores de la lista separados por el &lt;code&gt;String&lt;/code&gt; que hemos pasado como argumento; en nuestro caso, en el que hemos pasado como argumento un caracter de guión, el resultado es &lt;code&gt;a-b-c&lt;/code&gt;. Ninguno de las versiones de &lt;code&gt;join()&lt;/code&gt; modifica la lista original.
&lt;br&gt;
&lt;br&gt;Groovy añade todavía más métodos de utilidad en las listas: &lt;code&gt;max()&lt;/code&gt; y &lt;/code&gt;min&lt;/code&gt;, por ejemplo, devuelven los valores máximo y mínimo contenidos en una lista (como siempre, el concepto de máximo, mínimo, ordenación, etc. está relacionado con el tipo de objeto que almacena la lista):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println letras.max()
&lt;br&gt;println letras.min()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior, el método &lt;code&gt;max()&lt;/code&gt; devuelve el valor &lt;code&gt;c&lt;/code&gt;, ya que la ordenación de cadenas de texto en Java establece que &lt;code&gt;c&lt;/code&gt; es un caracter 'mayor' que &lt;code&gt;a&lt;/code&gt; o &lt;/code&gt;b&lt;/code&gt;. De igual manera, en la siguiente lista conteniendo números flotantes, el valor máximo corresponderia a 4.71 y el valor mínimo a 0.02:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def flotantes = [2.08, 0.02, 4.71, 3.99, 1.99]
&lt;br&gt;println flotantes.max()
&lt;br&gt;println flotantes.min()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Como puedes ver, el soporte de listas en Groovy es tremendamente util a la vez que sencillo. Aquí solo se han explicado algunos metodos de los muchos que provee el API, así que te recomiendo que estudies la documentación para encontrar información adicional.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.4 ARRAYS, SET's Y COLAS
&lt;br&gt;Por defecto, todas las listas en Groovy son implementaciones de la clase &lt;code&gt;ArrayList&lt;/code&gt;. Sin embargo, podemos coaccionar al lenguaje para que convierta una lista en una implementación de &lt;code&gt;Set&lt;/code&gt; (en la versión 1.7.2 &lt;code&gt;HashSet&lt;/code&gt;), de &lt;code&gt;Queue&lt;/code&gt; (&lt;code&gt;LinkedList&lt;/code&gt;) o en un array:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def setPaises = paises as Set
&lt;br&gt;def colaPaises = paises as Queue
&lt;br&gt;def arrayPaises = paises as String[]
&lt;br&gt;println setPaises.class
&lt;br&gt;println colaPaises.class
&lt;br&gt;println arrayPaises.class
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;También podemos aplicar la sintaxis anterior en el momento de la creación de la colección, para así trabajar con el tipo deseado desde el primer momento:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def paises = [&quot;España&quot;, &quot;Mexico&quot;] as Set
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Y por supuesto, podemos seguir instanciando nuestras colecciones mediante la antigua sintaxis de Java. Recuerda que el 99% del código Java es código Groovy válido:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Set lhs = new LinkedHashSet();
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.5 MAPS
&lt;br&gt;Los mapas son colecciones de valores que pueden ser referidas por una clave, o lo que es lo mismo, una colección de parejas clave-valor. Groovy ofrece soporte nativo también para mapas, con una sixtaxis que en gran medida es muy similar a la de las listas:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def mapa = [:]
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior crea un mapa vacio, en el cual podemos, por supuesto, ir añadiendo parejas clave-valor (posteriormente veremos como). Si deseas inicializar un mapa con valores predefinidos:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def capitales = ['España':'Madrid', 'Mexico':'Mexico D.F.']
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior define un mapa con 2 parejas clave-valor en su interior. Veamos ahora como realizar algunas operaciones básicas con mapas:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;capitales.get('España')
&lt;br&gt;capitales.España
&lt;br&gt;capitales['España']
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Las tres lineas de código anterior realizan la misma tarea, obtener un valor a partir de su clave. La primera utiliza el método &lt;code&gt;get(clave)&lt;/code&gt; para obtener el valor asociado a dicha clave. La segunda linea utiliza la notacion de puntos, en la forma &lt;code&gt;mapa.clave&lt;/code&gt;. La última versión utiliza la notación de arrays. Cual uses depende en gran medida de tus preferencias. Es importante subrayar que cuando utilices notación de puntos debes encerrar entre comillas el nombre de las claves que contengan ciertos caracteres especiales, por ejemplo, un caracter de punto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def datos = ['correo.electronico', 'programacion@davidmarco.es']
&lt;br&gt;println datos.'correo.electronico'
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El mapa definido en el código anterior contiene una clave que contiene un caracter de punto, de manera que al usar notación de puntos debemos encerrar el nombre de la clave entre comillas (tanto comillas simples como dobles están permitidas). Si no lo hacemos, obtendremos un error de compilación, ya que al haber más de un punto este no sabría donde comienza el nombre de la clave. Veamos ahora como añadir elementos a un mapa:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;capitales.put('Argentina', 'Buenos Aires')
&lt;br&gt;capitales.Argentina = 'Buenos Aires'
&lt;br&gt;capitales['Argentina'] = 'Buenos Aires'
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Las tres lineas de código anterior insertan una nueva pareja clave-valor en el mapa &lt;code&gt;capitales&lt;/code&gt;. Al igual que al obtener un valor, cuando insertamos mediante notación de puntos un valor que contiene un punto mediante debemos encerrar la clave entre comillas. La última operación básica que nos queda es la de borrar una pareja clave-valor mediante el método &lt;code&gt;remove(clave)&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;capitales.remove('Argentina')
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La forma de iterar las parejas clave-valor de un mapa es tan sencilla como en una lista:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;capitales.each {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println it
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior obtendria las parejas como tales. Si deseamos acceder a las claves y valores de forma independiente tenemos dos opciones: la primera consiste en usar los atributos &lt;code&gt;key&lt;/code&gt; y/o &lt;code&gt;value&lt;/code&gt; de la variable que almacena la pareja en cada iteración:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;capitales.each {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println it.key
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La segunda manera consiste en pasar como parámetro a &lt;code&gt;each()&lt;/code&gt; un closure con dos variables, la primera de ellas haciendo referencia a la clave correspondiente y la segunda a su valor:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;capitales.each { pais, capital -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;La capital de ${pais} es ${capital}&quot;
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Otros muchos métodos que vimos en la sección 3.3 (LISTAS) también están disponibles para mapas, como son &lt;code&gt;collect()&lt;/code&gt; y &lt;code&gt;sort()&lt;/code&gt;. Otros tienen una sintaxis ligeramente diferente (como &lt;code&gt;reverseEach(Closure)&lt;/code&gt; en lugar de &lt;code&gt;reverse()&lt;/code&gt;). Visita el API de Groovy para ver todos los métodos disponibles en &lt;code&gt;Map&lt;/code&gt;. Otras operaciones, como adición y sustraccion entre mapas estan, también soportadas, aunque de nuevo de una manera un tanto diferente a como las realizabamos con listas. Por ejemplo, la adición de una lista a otra funciona de manera igual, mediante el operador &lt;code&gt;+=&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def angloParlantes = ['EEUU':'Washington', 'Reino Unido':'Londres']
&lt;br&gt;capitales += angloParlantes
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Sin embargo, la sustracción mediante el operador &lt;code&gt;-=&lt;/code&gt; no está soportada en mapas, por lo que hay que realizar un poco de trabajo extra para llevar a cabo esta operación:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;angloParlantes.each {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;capitales.remove(it.key)
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior iteramos a traves del mapa que queremos eliminar, seleccionamos cada uno de las claves, y se las pasamos al método &lt;code&gt;remove&lt;/code&gt; del mapa del cual queremos sustraer los valores.
&lt;br&gt;
&lt;br&gt;Antes de terminar esta sección vamos a ver cuatro nuevos métodos. Los dos primeros métodos son &lt;code&gt;keySet()&lt;/code&gt; y &lt;code&gt;values()&lt;/code&gt;. El primero devuelve una lista con todas las claves de un mapa, mientras que el segundo devuelve una lista conteniendo todos los valores de un mapa:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def paises = capitales.keySet()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior almacenaria en la variable &lt;code&gt;paises&lt;/code&gt; una lista con las claves del mapa &lt;code&gt;capitales&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[España, Mexico, Argentina]
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Por ultimo, los métodos &lt;code&gt;containsKey()&lt;/code&gt; y &lt;code&gt;containsValue()&lt;/code&gt; devuelven &lt;code&gt;true&lt;/code&gt; o &lt;code&gt;false&lt;/code&gt; dependiendo de si el mapa donde los llamemos contiene cierta clave o cierto valor:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println capitales.containsKey('España')
&lt;br&gt;println capitales.containsValue('Roma')
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Para el código anterior, la primera linea devolverá &lt;code&gt;true&lt;/code&gt; mientras que la segunda devolverá &lt;code&gt;false&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;En este capítulo hemos visto diversos tipos de colecciones, como rangos, listas y mapas. El API de estos objetos es mucho mas amplio de lo que, por motivos de espacio, podemos (y tal vez debemos) mostrar aquí. Sin embargo, con lo aquí citado podemos comenzar a trabajar comodamente con todos estos tipos de colecciones. En posteriores capítulos las veremos y usaremos de estas y otras maneras. En el próximo capítulo veremos como trabajar con POGO's, el equivalente &quot;Grooviano&quot; del clasico POJO. Hasta entonces, ¡un saludo!.</description>
    </item>
    <item>
      <title>Introducción a Groovy (IV)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=226</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=226</guid>
      <pubDate>Sat, 31 Jul 2010 15:10:58 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>En esta &lt;a href=&quot;http://www.davidmarco.es/tutoriales/&quot;&gt;cuarta entrega&lt;/a&gt; del tutorial de introducción a Groovy vamos a ver que son y como funcionan los POGO's (Plain Old Groovy Objects). Los POGO's son el sustituto natural de Groovy a los POJO's de Java, tomando toda la funcionalidad y potencia de Groovy para construir objetos.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.1 POGO's
&lt;br&gt;Los POGO's, al igual que los POJO's en Java, son &lt;i&gt;clases simples que no dependen de un framework en especial&lt;/i&gt; (cita de la Wikipedia). Esto es, clases que no heredan ni implementan ninguna clase/interface de un API en concreto y externo a nuestra aplicación, y que por tanto pueden ser reusados una y otra vez entre aplicaciones. Este concepto de reuso de clases es uno de los pilares básicos de la programación orientada a objetos. A efectos practicos, un POGO es una clase normal y corriente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Libro {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String titulo
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String autor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int numPaginas
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La clase del código anterior define un libro con tres atributos que pueden ser leidos/escritos directamente, ya que Groovy generará los métodos getter/setter por nosotros en tiempo de compilación. Es más, a pesar de que dichos métodos estarán disponibles cuando compilemos y llamemos a la clase, podemos llamar a los atributos directamente por su nombre:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def libro = new Libro()
&lt;br&gt;libro.titulo = &quot;Introducción a Groovy&quot;
&lt;br&gt;libro.autor = &quot;David Marco&quot;
&lt;br&gt;libro.numPaginas = 0
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Esta sintaxis, basada en la notación de puntos (objeto.atributo) es también válida para leer valores:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println libro.titulo
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.2 GETTERS Y SETTERS
&lt;br&gt;En ciertas ocasiones, sin embargo, debemos controlar como se almacenan y leen los valores de los atributos. Nada tan sencillo como sobreescribir el getter/setter correspondiente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Libro {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String titulo
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String autor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int numPaginas
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String getTitulo() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return titulo.toUpperCase()
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;def libro = new Libro()
&lt;br&gt;libro.titulo = &quot;Introducción a Groovy&quot;
&lt;br&gt;libro.autor = &quot;David Marco&quot;
&lt;br&gt;libro.numPaginas = 0
&lt;br&gt;
&lt;br&gt;println libro.titulo
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En la definición de la clase &lt;code&gt;Libro&lt;/code&gt; del código anterior hemos proporcionado explícitamente un método setter para el atributo &lt;code&gt;titulo&lt;/code&gt;, de manera que todas las llamadas a &lt;code&gt;libro.titulo&lt;/code&gt; serán redirigidas a través de este método customizado. Es probable que hayas notado algo rato en la definición del método anterior (vuelve atrás y miralo bien...). ¿Ya? Como seguramente has observado, el método no es público, y la norma general es que los métodos getter/setter (sobre todo los getter) sean &lt;code&gt;public&lt;/code&gt;, ya que de otra manera nuestra clase sería muy poco usable. Esto nos lleva al siguiente punto de este artículo.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.3 NIVELES DE ACCESO
&lt;br&gt;En Groovy prima en cierta manera el concepto de &lt;i&gt;Convención sobre Configuración&lt;/i&gt;, esto es, que la sintaxis más simple refleja el comportamiento mas común de un componente. Lo vimos en el punto anterior con los getters y setters por defecto y tambíén aplica de la siguiente manera a los niveles de acceso por defecto en POGO's:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Todas las clases son públicas por defecto
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Todos los métodos son públicos por defecto
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Todos los atributos son privados por defecto
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Estas reglas, sin embargo, conllevan ciertas matizaciones que debemos comprender. Veamos un ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Libro {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String titulo
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String autor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private int numPaginas
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, hemos definido explícitamente el atributo &lt;code&gt;numPaginas&lt;/code&gt; como privado. Esto indica al compilador que no debe generar métodos getter/setter para este atributo, de manera que el atributo no será visible de ninguna manera para un cliente Java. Y digo solamente clientes Java porque Groovy puede seguir accediendo al atributo, para leerlo y escribirlo. Esto es debido a que Groovy tiene ciertos privilegios al usar otro código Groovy, llamemoslo &lt;i&gt;Despotismo Groovy&lt;/i&gt;. Incluso aunque proporcionemos métodos setter/getter privados para ese atributo, ¡Groovy podrá seguir accediendo a el!. Un efecto secundario de este comportamiento es que el nivel de visibilidad &lt;i&gt;default-package&lt;/i&gt; (el que se venia aplicando hasta ahora en Java a todo método, campo y clase interna sin un nivel de visibilidad concreto) no existe en Groovy. No voy a discutir aquí los motivos por los que el lenguaje funciona de esta manera ni mucho menos a opinar al respecto, ambos temas caen fuera de los propositos de este tutorial. Sin embargo, debes tener muy presente este comportamiento cuando uses el lenguaje. Y como he dicho antes, desde Java el código se comportará como lo ha venido haciendo hasta ahora, respetando los niveles de acceso (que para eso están ahí), por lo que aún puedes controlar la visibilidad de los miembros de una clase escrita en Groovy (salvo el ya mencionado &lt;i&gt;package-default&lt;/i&gt; que deja de existir) desde Java.
&lt;br&gt;
&lt;br&gt;Un privilegio extra de Groovy es que puede leer y escribir un atributo directamente, sin pasar por el método getter/setter correspondiente (sea este generado implícitamente por el compilador o explícitamente por nosotros):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println libro.@titulo
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En la sentencia anterior hemos utilizado el caracter &lt;code&gt;@&lt;/code&gt; para indicar que debemos acceder a la variable &lt;code&gt;titulo&lt;/code&gt; directamente.
&lt;br&gt;
&lt;br&gt;Por último, y aunque no está relacionado con la discusión sobre niveles de acceso, vamos a ver una tercera manera de leer y escribir atributos en un POGO:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def libro = new Libro()
&lt;br&gt;libro.setProperty('titulo', 'Introducción a Groovy')
&lt;br&gt;println libro.getProperty('titulo')
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La sintaxis anterior puede resultar muy útil en ciertos casos, por ejemplo cuando no disponemos en tiempo de compilación de los nombres de los atributos que tenemos que llamar, pero si en tiempo de ejecución.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.4 CONSTRUCTORES
&lt;br&gt;Groovy nos ofrece una sintaxis especial para crear on POGO en una única linea:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def libro = new Libro(titulo:'Introducción a Groovy', autor:'David Marco', numPaginas:0)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Si recuerdas el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=225&quot;&gt;capítulo 3&lt;/a&gt;, verás que los valores que se han pasado al constructor son en realizad una estructura de tipo &lt;code&gt;Map&lt;/code&gt;. Por tanto, también podemos pasar al constructor un mapa previamente definido:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def mapa = [titulo:'Introducción a Grails', autor:'David Marco', numPaginas:0]
&lt;br&gt;def libroGrails = new Libro(mapa)
&lt;br&gt;
&lt;br&gt;println mapa.titulo
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Pero, ¡aún hay más! Esta sintaxis es válida incluso para crear un POJO (un objeto Java), así que nos podemos beneficiar de ella cuando estemos usando objetos creados en Java. Ahora es el momento de preguntarnos: ¿Estamos obligados a pasar todos los atributos de un objeto al construir dicho objeto?. La respuesta es NO:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def libro = new Libro(titulo:'Introducción a Groovy')
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El resto de los atributos pueden ser establecidos en cualquier momento posterior a la creación del objeto y de cualquiera de las maneras que hemos visto hasta ahora. Así de simple. Esto nos lleva a otra pregunta: ¿Debemos pasar los atributos en algún tipo de orden? La respuesta es, de nuevo NO, cualquier orden es valido. 
&lt;br&gt;
&lt;br&gt;Otra poderosa característica de los constructores en Groovy es que podemos proporcionar a cualquier atributo un valor por defecto si ninguno es proporcionado:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Libro {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String titulo
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String autor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int numPaginas
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Libro(int numPaginas, String titulo='Sin título', String autor='Sin autor') {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.titulo = titulo
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.autor = autor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.numPaginas = numPaginas;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;def libro = new Libro(10)
&lt;br&gt;println libro.titulo
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, se ha definido un constructor que además de inicializar los valores de los atributos de la clase, declara dos de ellos como opcionales dandoles un valor por defecto (&lt;code&gt;titulo&lt;/code&gt; y &lt;code&gt;autor&lt;/code&gt;). Por tanto, si instanciamos un objeto &lt;code&gt;Libro&lt;/code&gt; y no proporcionamos los parámetros que corresponden a dichos atributos opcionales, se tomarán sus valores por defecto. Además, en la declaración del constructor, los parámetros opcionales deben aparecer después de los parámetros obligatorios para ese constructor. A la hora de diseñar el constructor debes ordenar cuidadosamente los parámetros opcionales, de manera que los que tienen más posibilidad de ser proporcionados deben aparecer primero (aunque esta anticipación al uso de la clase no es siempre posible). Nuestra nueva clase &lt;code&gt;Libro&lt;/code&gt; es perfecta para mostrarnos este asunto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def libro = new Libro(0, 'David Marco')
&lt;br&gt;println libro.titulo
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Mira bien el código anterior: ¿Que atributo estamos ajustando con el parámetro &lt;code&gt;'David Marco'&lt;/code&gt;? ¿&lt;code&gt;titulo&lt;/code&gt; o &lt;code&gt;autor&lt;/code&gt; (recuerda que ambos son &lt;code&gt;String&lt;/code&gt; y ambos son opcionales)?. En este caso concreto, es &lt;code&gt;titulo&lt;/code&gt;, aunque mi ingenua intención era ajustar el atributo &lt;code&gt;autor&lt;/code&gt;, y por tanto he construido un objeto que, cuando sea usado, no se comportará como yo espero. Piensa cuidadosamente en el orden de los parámetros opcionales y, más aún, usalos con mucho cuidado y en situaciones donde realmente son necesarios y/o útiles.
&lt;br&gt;
&lt;br&gt;Con este consejo termina la cuarta entrega del tutorial de introduccíón a Groovy (un poquito más corto de lo habitual, pero espero que igual de interesante). En la próxima entrega abordaremos la Metaprogramación en Groovy, un estilo de programar realmente increible. ¡Hasta pronto!</description>
    </item>
    <item>
      <title>Introducción a Groovy (V)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=227</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=227</guid>
      <pubDate>Thu, 05 Aug 2010 15:04:32 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>En esta quinta entrega del tutorial de Groovy, vamos a ver el concepto de Metaprogramación. Mediante metaprogramación podemos escribir código que genera o modifica otro código, por ejemplo otros programas, o incluso a si mismos (esto es, código que tiene la habilidad de cambiar su comportamiento en tiempo de ejecución). Esto nos puede permitir, entre otras cosas, a manejar situaciones que no estaban previstas cuando se escribió el código, y sin necesidad de recompilar.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.1 UN POCO DE REFLEXIÓN
&lt;br&gt;La metaprogramación en Groovy, al igual que en Java, se basa en la capacidad del lenguaje llamada Reflexión. Mediante reflexión podemos conocer los miembros de una clase:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;String.interfaces.each { println it }
&lt;br&gt;String.constructors.each { println it }
&lt;br&gt;String.methods.each { println it }
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Cada una de las lineas del código anterior muestran los interfaces que implementa una clase, sus constructores y sus métodos, respectivamente. Para los dos últimos casos, se muestran solo los miembros públicos (&lt;code&gt;public&lt;/code&gt;). Así mismo, todo objeto en Groovy tiene un método &lt;code&gt;getClass()&lt;/code&gt; que devuelve el objeto &lt;code&gt;Class&lt;/code&gt; asociado a su clase. Recuerda que podemos invocar la propiedad de una clase mediante su metodo getter, o directamente por su nombre (el getter es llamado en este caso implícitamente):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println String.class
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Y hablando de propiedades, veamos como mostrar todas las propiedades de un objeto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def s = new String(&quot;cadena de texto&quot;)
&lt;br&gt;s.properties.each { propiedad -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println propiedad
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El ejemplo anterior nos muestra que todo objeto &lt;code&gt;String&lt;/code&gt; contiene tres propiedades: &lt;code&gt;class&lt;/code&gt; (la cual vimos en acción en el ejemplo anterior), &lt;code&gt;bytes&lt;/code&gt; (un array de bytes que contiene el valor del &lt;code&gt;String&lt;/code&gt;) y &lt;code&gt;empty&lt;/code&gt; que como su nombre indica contiene un valor &lt;code&gt;true&lt;/code&gt; en caso de que la cadena de texto tenga longitud cero y &lt;code&gt;false&lt;/code&gt; en caso contrario. Ten presente que todas las propiedades de un objeto son deducidas por medio sus métodos getter/setter.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.2 METACLASS
&lt;br&gt;Toda clase Groovy dispone de un miembro llamado &lt;code&gt;metaClass&lt;/code&gt;. Este miembro nos permite, entre otras cosas, comprobar si la clase dispone de una propiedad concreta gracias a su método &lt;code&gt;hasProperty()&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Articulo {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String descripcion
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double precio
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;def boligrafo = new Articulo(descripcion:&quot;Boligrafo negro&quot;, precio:0.45)
&lt;br&gt;if(boligrafo.metaClass.hasProperty(boligrafo, &quot;precio&quot;)) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// hacer algo
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Así mismo, también podemos comprobar la existencia de un método con &lt;code&gt;respondsTo()&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;if(boligrafo.metaClass.respondsTo(boligrafo, &quot;getDescripcion&quot;)) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// hacer algo
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.3 EJECUTANDO UN MÉTODO MEDIANTE GSTRING's
&lt;br&gt;Una manera alternativa de invocar un método dinámicamente es construyendo la llamada con un objeto &lt;code&gt;GString&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def nombreDelMetodo = &quot;getPrecio&quot;
&lt;br&gt;boligrafo.&quot;${nombreDelMetodo}&quot;()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En la llamada al código anterior, cuando se ejecute el programa se sustituirá la expresión &lt;code&gt;${nombreDelMetodo}&lt;/code&gt; por su valor, produciendo así la llamada a &lt;code&gt;getPrecio()&lt;/code&gt; en el objeto &lt;code&gt;boligrafo&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.4 PUNTEROS
&lt;br&gt;En el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=226&quot;&gt;capítulo 4&lt;/a&gt; vimos como acceder directamente al valor de una variable (a una propiedad) mediante el operador &lt;code&gt;@&lt;/code&gt;. Este 'acceso directo' se llama puntero:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;println boligrafo.@precio
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;De manera parecida, mediante el operador &lt;code&gt;&amp;&lt;/code&gt;, podemos crear un puntero a un método:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def lista = []
&lt;br&gt;def insertar = lista.&amp;add
&lt;br&gt;insertar &quot;valor1&quot;
&lt;br&gt;insertar &quot;valor2&quot;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior, hemos creado un puntero (o alias) al método &lt;code&gt;add()&lt;/code&gt; del objeto &lt;code&gt;lista&lt;/code&gt; y lo hemos asignado a la variable &lt;code&gt;insertar&lt;/code&gt;. Desde ese momento, podemos ejecutar comandos como &lt;code&gt;insertar &quot;valor1&quot;&lt;/code&gt; y sería equivalente a ejecutar &lt;code&gt;lista.add(&quot;valor1&quot;)&lt;/code&gt;. Esto puede ser muy intuitivo de usar para alguien que no entiende sobre programación en general y Groovy en particular. Esto es, hemos creado un DSL (Domain Specific Language - Lenguaje Especifico de Dominio). Un DSL es un lenguaje que se adapta al dominio al cual se refiere y aplica (por ejemplo el lenguaje jurídico para la jurisprudencia), etc. Así podemos crear un lenguaje fácil de usar, ya que su sintaxis refleja la terminología del problema que se quiere resolver.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.5 EXPANDO
&lt;br&gt;Un objeto &lt;code&gt;Expando&lt;/code&gt; es como un objeto en blanco, al cual podemos añadir métodos y propiedades 'a la carta', y además de la forma más sencilla posible: dandoles un valor. Veamos un ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def posicion = new Expando()
&lt;br&gt;posicion.latitud = 15.47
&lt;br&gt;posicion.longitud = -3.11
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior, hemos definido un objeto &lt;code&gt;Expando&lt;/code&gt; llamado &lt;code&gt;posicion&lt;/code&gt; al cual le hemos proporcionado un valor para cada una de las propiedades &lt;code&gt;longitud&lt;/code&gt; y &lt;code&gt;longitud&lt;/code&gt;, propiedades que al no existir anteriormente para este &lt;code&gt;Expando&lt;/code&gt; han sido automáticamente. Dichas propiedades pueden ser después leidas como en un objeto normal. Pero vayamos un poquito más allá, vamos a definir un método para nuestro expando:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;posicion.diferencia = { nuevaLatitud, nuevaLongitud -&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;&quot;&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Existe una diferencia de:
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LATITUD: ${posicion.latitud - nuevaLatitud}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LONGITUD: ${posicion.longitud - nuevaLongitud}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;con respecto al la posición anterior: ${posicion.latitud} ${posicion.longitud}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;&quot;&quot;
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Para definir un metodo simplemente tenemos que definir su nombre (evidentemente) y asignarle un closure. En el código anterior, dicho closure contiene un Heredoc donde se realizan algunos calculos con las variables pasadas como argumento y las que ya contenia el &lt;code&gt;Expando&lt;/code&gt;, devolviendose finalmente una cadena de texto (recuerda que los Heredoc son cadenas de texto multilinea, y que al ser la última (y única) sentencia del closure es también su valor de retorno implícito). Ahora, podemos llamar al siguiente código:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;posicion.diferencia(10.0, 1.0)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Como puedes ver, &lt;code&gt;Expando&lt;/code&gt; es una herramienta tremendamente potente para crear nuevos objetos, y, como veremos un poco más adelante en este mismo artículo, para ayudarnos en nuestro camino a través de la metaprogramación.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.6 PROPIEDADES DINÁMICAS
&lt;br&gt;Aunque la clase &lt;code&gt;Expando&lt;/code&gt; nos permite añadir propiedades de manera dinámica a un objeto de su mismo tipo, ¿que ocurre cuando queremos disponer de dicho dinamismo en nuestras propias clases? Groovy, como siempre, al rescate:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Articulo {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String descripcion
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double precio
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def propiedades = [:]
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void setProperty(String nombre, Object valor) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;propiedades[nombre] = valor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object getProperty(String nombre) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;propiedades[nombre]
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Groovy nos permite definir los métodos &lt;code&gt;getProperty()&lt;/code&gt; y &lt;code&gt;setProperty()&lt;/code&gt;, y el truco consiste en almacenar los valores pasados a &lt;code&gt;setProperty()&lt;/code&gt; en un objeto &lt;code&gt;Map&lt;/code&gt; (al que hemos llamado &lt;code&gt;propiedades&lt;/code&gt;) para poder ser después leidos. Con esta infraestructura, ya podemos leer y escribir nuevas propiedades dinámicamente en nuestra clase &lt;code&gt;Articulo&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def articulo = new Articulo()
&lt;br&gt;articulo.codigoEAN = 84123445593
&lt;br&gt;println articulo.codigoEAN
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Cuando nuestro código llama a &lt;code&gt;getCodigoEAN()&lt;/code&gt; la llamada es 'redirigida' internamente mediante &lt;code&gt;getProperty('codigoEAN')&lt;/code&gt;, con total transparencia para nosotros y sin necesidad de que, en tiempo de compilación, exista esta propiedad ni sus correspondientes getters/setters. Un efecto secundario de definir propiedades dinámicas para una clase es que la lectura de una propiedad aún no definida (y por tanto inexistente) devolverá un valor &lt;code&gt;null&lt;/code&gt;, en lugar de lanzar una excepción (un comportamiento en cierto modo parecido al producido por el operador de referenciación segura, como vimos en el punto 1.14, pero aplicado a propiedades en lugar de a objetos).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.7 INTERCEPTANDO LLAMADAS A MÉTODOS
&lt;br&gt;Groovy nos permite interceptar las llamadas a métodos que no existen:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Articulo {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String descripcion
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double precio
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object invokeMethod(String nombre, Object args) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;Invocado método ${nombre}() con los argumentos ${args}&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;def articulo = new Articulo()
&lt;br&gt;articulo.operacionInexistente('abc', 123, true)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En la clase anterior hemos definido el método &lt;code&gt;invokeMethod()&lt;/code&gt;, el cual interceptará las llamadas a cualquier método no definido. Un efecto secundario de este comportamiento es que en tiempo de ejecución no se producirá una excepción informando de la no-existencia de dicho método. Sin embargo, la finalidad de &lt;code&gt;invokeMethod()&lt;/code&gt; no es evitar este tipo de errores (ni debería serlo) si no, por ejemplo, la construcción de clases con un comportamiento totalmente dinámico, como constructores de XML y HTML (en los que los nombres de los métodos que pasemos pueden ser usados para darles nombre a los nodos XML-HTML del documento que estamos construyendo, y el cuerpo de cada método ser interpretado como un subnodo que será procesado de la misma manera).
&lt;br&gt;
&lt;br&gt;Si lo que deseamos es interceptar las llamadas a métodos que si existen, además de definir el método &lt;code&gt;invokeMethod()&lt;/code&gt; nuestra clase debe implementar la interface GroovyInterceptable. Dentro de &lt;code&gt;invokeMethod()&lt;/code&gt; tenemos que obtener el método interceptado (a traves de su metamétodo) e invocarlo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def invokeMethod(String nombre, args) {&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def metaMetodo = Articulo.metaClass.getMetaMethod(nombre, args)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metaMetodo.invoke(this, args)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Esto nos permite realizar algunas cosas interesante, como implementar un around-advice al mas puro estilo de la Programación Orientada a Aspectos:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class SimpleLogger {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def logInicio(String metodo, args) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;Iniciado el método ${metodo}() con los argumentos ${args}&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def logFin(String metodo, resultado) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;println &quot;$Finalizando el método ${metodo}() con el resultado ${resultado}&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;class Articulo implements GroovyInterceptable {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String descripcion
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double precio
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SimpleLogger logger
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void añadirDescuento(double porcentajeDescuento){
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;precio = (precio * (100 - porcentajeDescuento) / 100)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def invokeMethod(String nombre, args) {&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.logInicio(nombre, args) 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def metaMetodo = Articulo.metaClass.getMetaMethod(nombre, args)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def resultado = metaMetodo.invoke(this, args)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.logFin(nombre, resultado)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;def logger = new SimpleLogger()
&lt;br&gt;def articulo = new Articulo(descripcion:'Libreta', precio:1.40)
&lt;br&gt;articulo.logger = logger
&lt;br&gt;
&lt;br&gt;articulo.añadirDescuento(15)
&lt;br&gt;println articulo.precio
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior define una sencilla clase de logging con dos métodos que muestran por pantalla información sobre el inicio o fin de un método. Ambos métodos son llamados en la primera y última linea dentro de &lt;code&gt;invokeMethod()&lt;/code&gt;, de manera que cada vez que llamemos a un método de la clase &lt;code&gt;Articulo&lt;/code&gt; se mostrará el mensaje correspondiente a su inicio y fin. Un tercera opción sería disponer de un método para loggear cualquier excepción que se produzca, pero este pequeño ejercicio lo dejo para tí. Una pregunta que podrías estar planteandote ahora es: ¿que ocurre si, con el código anterior, invocamos un método que no existe (como en nuestro primer ejemplo de este punto)? Pues que la variable &lt;code&gt;metaMetodo&lt;/code&gt; contendrá un valor &lt;code&gt;null&lt;/code&gt; (ya que &lt;code&gt;getMetaMethod()&lt;/code&gt; no va a encontrar dicho método al no existir), y por tanto &lt;code&gt;metaMetodo.invoke(this, args)&lt;/code&gt; producirá una excepción de tipo &lt;code&gt;NullPointerException&lt;/code&gt;. La manera de evitar esto es tan simple como hacer uso del operador de referenciación segura:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;def resultado = metaMetodo?.invoke(this, args)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Con la inclusion del operador de referenciación segura nuestra pequeña clase es capaz de interceptar las llamadas a TODOS sus métodos, existan o no:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;articulo.noExiste()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.8 CATEGORÍAS
&lt;br&gt;Groovy permite la adición de nueva funcionalidad a una clase de la que, por ejemplo, no disponemos del código fuente. Esto es posible a traves de una Categoría, la cual implementa los métodos que deseamos añadir a dicha clase. Veamos un ejemplo aplicado a &lt;code&gt;Articulo&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Articulo {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String descripcion
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double precio
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;class ArticuloExtras {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static double conImpuestos(Articulo articulo) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return articulo.precio * 1.18
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;Articulo articulo = new Articulo(descripcion:'Grapadora', precio:4.50)
&lt;br&gt;use(ArticuloExtras) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;articulo.conImpuestos()
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el código anterior definimos una categoría llamada &lt;code&gt;ArticuloExtras&lt;/code&gt; que define un método extra para la clase &lt;code&gt;Articulo&lt;/code&gt;. Los metodos que deseamos añadir deben seguir la siguiente estructura:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static tipoDeRetorno nombre(ClaseDeDestino, argumento1, argumento2, ...)
&lt;br&gt;
&lt;br&gt;Finalmente, aplicamos la categoría dentro de un bloque &lt;code&gt;use&lt;/code&gt;, el cual requiere como parámetro el nombre de la categoría a usar. También podemos indicar más de una categoría dentro de un bloque &lt;code&gt;use&lt;/code&gt; separando sus nombres con comas. Recuerda que los nuevos métodos solo estarán disponibles dentro del bloque &lt;code&gt;use&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;5.9 EXPANDOMETACLASS
&lt;br&gt;El concepto de ExpandoMetaClass combina los conceptos de &lt;code&gt;metaClass&lt;/code&gt; y &lt;code&gt;Expando&lt;/code&gt;, permitiendo así añadir métodos a un cualquier clase. El concepto es el mismo que ya hemos aplicado con las Categorias, solo que esta vez los métodos están disponibles a nivel global, sin necesidad de ceñirnos a un bloque concreto. Un ejemplo típico del uso de ExpandoMetaClass es el siguiente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Integer.metaClass.numeroAleatorio = {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def random = new Random()
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;random.nextInt(delegate.intValue())
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;50.numeroAleatorio()
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El el código anterior añadimos el método &lt;code&gt;numeroAleatorio()&lt;/code&gt; al objeto &lt;code&gt;metaClass&lt;/code&gt; de la clase &lt;code&gt;Integer&lt;/code&gt;, asignandole un closure que contiene el cuerpo del método. La primera linea dentro del closure define un objeto &lt;code&gt;Random&lt;/code&gt; y lo asigna a una variable. Es en la segunda linea de código donde se genera la magia: llamamos al método &lt;code&gt;Random.nextInt()&lt;/code&gt; pasandole como parámetro el propio objeto donde se está realizando la llamada a &lt;code&gt;numeroAleatorio()&lt;/code&gt;, esto es, &lt;code&gt;delegate&lt;/code&gt; (en este caso concreto será una instancia de &lt;code&gt;Intgeger&lt;/code&gt;), y a continuación se llama a su método &lt;code&gt;intValue()&lt;/code&gt; que devuelve un &lt;code&gt;int&lt;/code&gt; en lugar del &lt;code&gt;Integer&lt;/code&gt; original. Puesto que la capacidad de Java de hacer autoboxing y autounboxing tambíen está disponible en Groovy, podemos escribir el código de la siguiente manera:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;random.nextInt(delegate)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Lo importante es que tengas presente que &lt;code&gt;delegate&lt;/code&gt; hace referencia al objeto 'delegado', el objeto que estará disponible en tiempo de ejecución y desde el que se ejecutara el bloque de código con el que estamos tratando. Otro objeto que podemos alcanzar desde dentro del closure es el propio closure, en este caso con la palabra &lt;code&gt;this&lt;/code&gt;. Espero que resulte sencillo de comprender (yo tuve mis problemas en su momento, aunque no lo parezca por su sencillez).
&lt;br&gt;
&lt;br&gt;Hay todavía mucho que decir sobre metaprogramación, sobre todo ver ejemplos más complejos que los aquí mostrados, pero todos los temas estan tratados y dejo en tu mano profundizar más en el tema. La metaprogramación puede ser dificil de entender para los que venimos de lenguajes estáticos como Java, donde apenas se hace uso de las librerias de reflexión (si alguien las usa habitualmente que me perdone por ese comentario) y todo se deja más bien atado en tiempo de compilación. Sea como sea, la metaprogramación nos permite hacer cosas realmente increibles, y nunca esta de más tener unos conocimientos básicos sobre ella. En el próximo capítulo de este tutorial (que tal vez sean dos o más por su longitud) se verá como usar el lenguaje para tareas cotidianas, como parsear y generar XML, leer y escribir archivos, y algunos temas más; en resumen, un 'manos a la obra' con todo lo que hemos aprendido hasta ahora y algunas cositas nuevas.</description>
    </item>
    <item>
      <title>Spring Expression Language</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=228</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=228</guid>
      <pubDate>Fri, 20 Aug 2010 23:05:21 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Desde la versión 3.0, Spring ofrece un lenguaje dinámico llamado Spring Expression Language (SpEL). SpEL permite la consulta y manipulación de objetos en tiempo real (de manera similar a Expression Language en JSP/JSF) además de otras interesantes características como la invocación de metodos. SpringSource Tool Suite (una variación de Eclipse altamente customizada para trabajar con Spring) provee soporte para SpEL, permitiendo autocompletado de expresiones además de otras caracteristicas realmente útiles para trabajar con el lenguaje. SpEL puede ser utilizado:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- de forma nativa en una aplicación Spring (insertado en archivos XML o anotaciones)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- a través de un parser, creando explicitamente toda la infraestructura necesaria para interpretarlo
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;REQUISITOS
&lt;br&gt;Si usas Maven en tus proyectos, la única dependencia necesaria para usar empezar a usar SpEL es:
&lt;br&gt;
&lt;br&gt;&amp;lt;dependency&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;lt;version&amp;gt;3.0.3.RELEASE&amp;lt;/version&amp;gt;
&lt;br&gt;&amp;lt;/dependency&amp;gt;
&lt;br&gt;
&lt;br&gt;Si deseas gestionar tus librerías sin Maven, además de todos los JAR's necesarios para levantar una aplicación Spring 3.0 (&lt;i&gt;org.springframework.context-3.0.X.RELEASE.jar, org.springframework.beans-3.0.X.RELEASE.jar, ...&lt;/i&gt;)  necesitas incluir en tu classpath el siguiente JAR que encontrarás en el directorio &lt;code&gt;dist&lt;/code&gt; de tu distribución de Spring 3:
&lt;br&gt;
&lt;br&gt;org.springframework.expression-3.0.X.RELEASE.jar
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;SINTAXIS
&lt;br&gt;La sintaxis de SpEL toma la siguiente forma cuando es usada de forma nativa:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{EXPRESION}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Cuando la expresión es usada por un parser, debemos omitir el caracter de almohadilla y la pareja de llaves:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;EXPRESION
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;A lo largo de este artículo, al introducir cada tipo de expresión se utilizara la primera versión, de manera que se enfatice su naturaleza y se diferencie más facilmente del resto del contenido. Solo cuando una expresión se utilice a través de un parser se utilizará la versión correspondiente, sin almohadilla ni llaves.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;CONSTRUYENDO EXPRESIONES (1ª PARTE)
&lt;br&gt;Comencemos viendo los tipos mas básicos de expresión para realizar una toma de contacto con el lenguaje, de manera que en las dos próximas secciones (SPEL DE FORMA NATIVA y SPEL A TRAVES DE UN PARSER) entendamos el 100% del código y no nos perdamos. El primer tipo de expresión que vamos a ver, y la más simple, es la de tipo literal:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{12.7}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La expresión anterior es un literal del número flotante &lt;code&gt;12.7&lt;/code&gt;. Otro tipo de literal frecuentemente utilizado es la cadena de texto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{'Hola SpEL'}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Como puedes ver, las expresiones literales de tipo cadena de texto son construidas dentro una pareja de comillas simples. Ambas expresiones literales devuelven 'literalmente' su valor (de ahi su nombre).
&lt;br&gt;
&lt;br&gt;El siguiente tipo de expresión es la de tipo booleano:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{7 &amp;gt; 9}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El significado de la expresión anterior es totalmente obvio, y el resultado devuelto al evaluar la expresión sería &lt;code&gt;false&lt;/code&gt;. 
&lt;br&gt;
&lt;br&gt;La siguiente de la lista es la llamada 'expresión estandar', la cual nos permite acceder a las propiedades de un bean o javabean mediante notación de puntos:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{usuario.nombre}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La expresión anterior devolverá el valor de la propiedad &lt;code&gt;nombre&lt;/code&gt; del bean llamado &lt;code&gt;usuario&lt;/code&gt; que, evidentemente, debera estar registrado dentro del contexto de la aplicación Spring actual. Si lo que queremos es evaluar un bean en si mismo, nada tan facil como usar su nombre como expresión:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{usuario}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Antes de continuar viendo más tipos de expresiones, veamos como y donde pueden ser usadas. Esto, además de completar el binomio 'sintaxis-uso' te permitirá experimentar con las expresiones mientras continuas leyendo el artículo. 
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;SPEL DE FORMA NATIVA
&lt;br&gt;Como se indicó al inicio de este artículo, SpEL puede ser usado de forma nativa en una aplicación Spring 3.0 mediante anotaciones o en archivos de configuración XML. Veamos algunos ejemplos:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class Login {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Value(&quot;#{usuario.nombre}&quot;)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String nombreUsuario;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La anotación &lt;code&gt;@Value&lt;/code&gt; puede ser aplicada tanto en variables como metodos setter, así como en parámetros de un método o constructor. El valor devuelto por la expresion será el valor por defecto del campo donde se aplique, en el caso del ejemplo anterior la variable &lt;code&gt;nombreUsuario&lt;/code&gt;. Para que Spring pueda detectar la presencia de la anotación &lt;code&gt;@Value&lt;/code&gt; en nuestras clases debemos activar la configuración mediante anotaciones en el fichero de configuración de Spring:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http://www.springframework.org/schema/context
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http://www.springframework.org/schema/context/spring-context-3.0.xsd&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;context:annotation-config /&amp;gt;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Para usar la misma expresión en un archivo de configuración de Spring 3.0:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;&amp;lt;bean class=&quot;Login&quot; id=&quot;login&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;property name=&quot;nombreUsuario&quot; value=&quot;#{usuario.nombre} /&amp;gt;
&lt;br&gt;&amp;lt;/bean&amp;gt;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El resultado es el mismo que al utilizar la anotación &lt;code&gt;@Value&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;SPEL A TRAVES DE UN PARSER
&lt;br&gt;SpEl puede ser usado fuera de un archivo XML o anotación &lt;code&gt;@Value&lt;/code&gt; mediante un parser. Este parser requiere el ensamblaje de cierta infraestructura:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;ExpressionParser parser = new SpelExpressionParser();
&lt;br&gt;Expression expresion = parser.parseExpression(&quot;'Hola SpEL'&quot;);
&lt;br&gt;String nombreUsuario = expresion.getValue(String.class);
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior es bastante simple. Primero crea un parser de la clase &lt;code&gt;SpelExpressionParser&lt;/code&gt;. A continuación crea una expresión llamando al método &lt;code&gt;parseExpression(EXPRESION)&lt;/code&gt; del recien creado parser. Por último, obtenemos el resultado de la evaluación de la expresión a traves del objeto &lt;code&gt;expresion&lt;/code&gt;. Cuando la expresión hace referencia a un objeto, debemos crear un contexto de ejecución para dicho objeto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Usuario usuario = new Usuario(&quot;David Marco&quot;);
&lt;br&gt;EvaluationContext contexto = new StandardEvaluationContext(usuario);
&lt;br&gt;ExpressionParser parser = new SpelExpressionParser();
&lt;br&gt;Expression expresion = parser.parseExpression(&quot;nombre&quot;);
&lt;br&gt;String nombreUsuario = expresion.getValue(contexto, String.class);
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior hemos creado un objeto &lt;code&gt;usuario&lt;/code&gt; así como un contexto de evaluación para dicho objeto. En el momento de crear la expresión, solo indicamos la propiedad que queremos evaluar del objeto que hemos pasado al contexto (en lugar del binomio 'objeto.propiedad' que se utilizaría con la anotación &lt;code&gt;@Value&lt;/code&gt; o en un archivo de configuración XML). Finalmente, pasamos el contexto de evaluación a &lt;code&gt;expresion.getValue()&lt;/code&gt; de manera que la expresión (la propiedad &lt;code&gt;nombre&lt;/code&gt;) es aplicada contra el contexto (el objeto &lt;code&gt;usuario&lt;/code&gt;) resultando en la evaluación de &lt;code&gt;usuario.nombre&lt;/code&gt;. En caso de que el contexto de evaluación tienda a cambiar entre ejecuciones es preferible sustituir el contexto de evaluación que hemos creado explicitamente por el objeto que subyace a dicho contexto, y Spring creará por nosotros un nuevo contexto de evaluación en cada llamada a &lt;code&gt;getValue()&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;List&amp;lt;Usuario&amp;gt; usuarios = new ArrayList&amp;lt;Usuario&amp;gt;();
&lt;br&gt;// Inicializar la lista de usuarios
&lt;br&gt;ExpresionParser parser = new SpelExpressionParser();
&lt;br&gt;Expression expresion = parser.parseExpression(&quot;nombre&quot;);
&lt;br&gt;for(Usuario usuario: usuarios) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String nombreUsuario = expresion.getValue(usuario, String.class);
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;CONSTRUYENDO EXPRESIONES (2ª PARTE)
&lt;br&gt;Ahora que ya hemos visto como y donde podemos escribir expresiones, sigamos viendo más tipos. Empecemos con las expresiones de clase:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{T(java.lang.Math)}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El caracter &lt;code&gt;T&lt;/code&gt; indica que queremos actuar sobre el tipo de una clase (en nuestro caso &lt;code&gt;java.lang.Math&lt;/code&gt;), en lugar de sobre una instancia. Una vez obtenido el tipo, podemos asignarlo a una variable mediante &lt;code&gt;@Value&lt;/code&gt;, XML o con el parser. También podemos actuar sobre el tipo devuelto por la expresión llamando a cualquiera de sus métodos estáticos dentro de la expresión:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{T(java.lang.Math).random()}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;SpEL nos permite definir expresiones para gestionar colecciones. Para acceder a un array o a un objeto de tipo &lt;code&gt;List&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{empresa.empleados[1]}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El acceso a listas y arrays se realiza mediante su índice, puesto que son colecciones indizadas. El acceso a una colección de tipo &lt;code&gt;Map&lt;/code&gt; se realiza, como ya habras imaginado, mediante sus claves:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{empresa.telefonosDepartamentos['Ventas']}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En ambos casos, se utiliza la notación de corchetes ya sea para obtener el índice en array y listas como la clave en mapas.
&lt;br&gt;
&lt;br&gt;El siguiente tipo de expresión es la invocación de un método. Lo vimos en acción anteriormente al invocar &lt;code&gt;random()&lt;/code&gt; en una expresión de clase, pero por su importancia merece un nuevo ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{'Hola SpEL'.toUpperCase()}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La expresión anterior es muy interesante, consistiendo en la invocación de un método sobre una expresión literal. Por supuesto, dicha invocación de método puede realizarse sobre cualquier expresión, clase, u objeto.
&lt;br&gt;
&lt;br&gt;SpEL nos permite invocar el constructor de una clase con el siguiente tipo de expresión:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{new Date()}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El siguiente tipo de expresión de nuestra lista es la expresión con operador ternario, que funciona exactamente igual de como lo haría en Java:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{usuario.edad &amp;gt; 18 ? true : false}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Recuerda que cuando evaluamos una expresión sobre un objeto, y utilizamos el parser, omitimos el nombre del objeto puesto que dicho objeto ha sido o será pasado como contexto de evaluación:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Usuario usuario = new Usuario(&quot;David Marco&quot;, 30&quot;);
&lt;br&gt;ExpressionParser parser = new SpelExpressionParser();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Expression expresion = parser.parseExpression(&quot;edad &amp;gt; 18 ? true : false&quot;);
&lt;br&gt;Boolean mayorDeEdad = expresion.getValue(usuario, Boolean.class);
&lt;br&gt;System.out.println(&quot;Es mayor de edad? &quot; + mayorEdad);
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;También podemos hacer referencia al contexto de evaluación mediante una expresión de variable:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Expression expresion = parser.parseExpression(&quot;#this.edad &amp;gt; 18 ? true : false&quot;);
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En la expresión anterior, &lt;code&gt;#this&lt;/code&gt; hace referencia al objeto que conforma el contexto actual de evaluación, en nuestro caso &lt;code&gt;usuario&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;Los dos últimos tipos de expresión que vamos a mostrar en este artículo estan relacionadas con la manipulación de colecciones. La primera es proyección de colección:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{usuarios.![nombre]}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En la expresión anterior, &lt;code&gt;usuarios&lt;/code&gt; es una coleccion que contiene objetos de tipo &lt;code&gt;Usuario&lt;/code&gt;. Una vez evaluada la expresión, el resultado devuelto es una lista que contiene los nombres (mediante la propiedad &lt;code&gt;nombre&lt;/code&gt;) de todos los usuarios de la primera lista. El segundo tipo de expresión para manipular colecciones es selección de colección:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;#{usuarios.?[nombre.startsWith('D')]}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Selección de colección permite, como muy bien expresa la sintaxis anterior, filtrar los objetos de una colección (&lt;code&gt;usuarios&lt;/code&gt; y devolver una nueva colección que contiene solo aquellos objetos que cumplian las condiciones de filtrado.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;CONCLUSIONES
&lt;br&gt;Como puedes ver, Spring Expression Language provee un lenguaje rico y dinámico que te permitirá configurar los beans de tu aplicación Spring 3.0 de manera aún más flexible que en versiones anteriores, además de proveer un lenguaje de scripting que puedes usar dentro de tus clases a traves del parser.</description>
    </item>
    <item>
      <title>Integración de Eclipse y SpringSource Tool Suite</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=229</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=229</guid>
      <pubDate>Thu, 30 Sep 2010 19:24:31 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>SpringSource Tool Suite (STS) es un IDE basado en la versión Java EE de Eclipse, pero altamente customizado para trabajar con Spring Framework. Entre las características más destacadas que STS proporciona se encuentran:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- soporte para Spring 3
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- asistentes para la creación de proyectos Spring
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- herramientas para la gestión de beans
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- editores gráficos de archivos de configuración de Spring
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- herramientas de desarrollo para Spring Web Flow y Spring Batch
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;STS puede descargarse desde &lt;a href=&quot;http://www.springsource.com/landing/best-development-tool-enterprise-java&quot;&gt;aquí&lt;/a&gt; como un IDE completo, pero también puede integrarse sobre una instalación previa de Eclipse. Sobre esta última opción trata este artículo.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;INSTALANDO ECLIPSE
&lt;br&gt;Lo primero que necesitamos es tener Eclipse instalado en nuestro equipo. La versión que vamos a utilizar es la última en el momento de escribir este artículo: Eclipse IDE 3.6 for Java EE Developers (nombre en clave Helios), la cual incluye todas las dependencias necesarias para instalar STS. También se dan las instrucciones necesarias para Eclipse 3.5 (Galileo). Los pasos para instalar STS en otras versiones de Eclipse pueden ser diferentes, por lo que no puedo garantizar que este artículo sea 100% funcional para dichas versiones.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;PREPARANDO ECLIPSE
&lt;br&gt;Ya dentro del IDE, el primer paso es desactivar todas sitios desde los que Eclipse puede descargar actualizaciones y nuevo software. Desde la barra de menús del IDE accede a:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Windows &gt; Preferences &gt; Install/Update &gt; Available Software Sites
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Desactiva todas los sitios de descarga que se encuentren activados desmarcando su casilla correspondiente. Comprueba que el status de cada uno de ellos ha cambiado de Enabled (Activado) a Disabled (Desactivado). No cierres esta ventana aún.
&lt;br&gt;
&lt;br&gt;El siguiente paso es configurar los sitios de descarga específicos de STS. La manera más simple es descargando un fichero XML donde se encuentra dicha configuración. Descarga y guarda en tu equipo el archivo correspondiente a tu versión de Eclipse:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http://dist.springsource.com/snapshot/TOOLS/composite/e3.6/bookmarks.xml&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(para Eclipse 3.6)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http://dist.springsource.com/snapshot/TOOLS/composite/e3.5/bookmarks.xml&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(para Eclipse 3.5)
&lt;br&gt;
&lt;br&gt;Ahora es el momento de volver a la pantalla de configuración de sitios de descarga, que aún deberias tener abierta. Si la has cerrado, recuerda que puedes volver a ella desde:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Windows &gt; Preferences &gt; Install/Update &gt; Available Software Sites
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Pulsa el botón 'Import' y selecciona el archivo XML previamente descargado. Verás que aparecen dos nuevos sitios de descarga, y que ambos han sido automáticamente activados (Enabled). De manera adicional, uno de los sitios de descarga de Eclipse también ha sido activado automáticamente. En total, deberemos tener exactamente tres sitios de descarga activados (si estas utilizando Eclipse 3.5 verás que cambia 'Helios' por 'Galileo', así como los números de versión):
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Helios
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- SpringSource Update Site for Eclipse 3.6 (Snapshot)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- SpringSource Update Site for Eclipse 3.6 (Snapshot, Dependencies)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Pulsa OK para guardar los cambios.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;INSTALANDO STS
&lt;br&gt;El último paso es instalar los componentes que conforman STS. Para ello, accede al gestor de instalación de nuevo software de Eclipse:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Help &gt; Install New Software
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En el menú desplegable superior selecciona el sitio:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Work with &gt; SpringSource Update Site for Eclipse 3.6 (Snapshot)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Ahora te aparecerán los componentes que están disponibles desde el sitio seleccionado. Que componentes seleccionar y cuales no es una decisión que dejo en tus manos. Hay quienes prefieren instalarlos todos, y hay quienes (como en mi caso) siempre customizan la instalación, de manera que solamente se instalen los componentes necesarios para una determinada tarea. Además, siempre puedes entrar al gestor de instalación de nuevo software y seleccionar componentes que aún no has instalado. Como guía, estos son los componentes que yo he seleccionado (ten presente que algunos de ellos son obligatorios):
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Core / Spring IDE (COMPLETO)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Core / STS (COMPLETO)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Extensions (Incubation) / Spring IDE (COMPLETO)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Extensions / Spring IDE (PARCIAL)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Grails Support
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Maven Support
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Runtime Error Analysis Support
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Integrations / Spring IDE (COMPLETO)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Resources / Spring IDE (COMPLETO)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Una vez seleccionados los componentes a instalar, pulsamos 'Next' y llegamos a la ventana donde se muestran los detalles de la instalación que estamos a punto de realizar. Volvemos a pulsar 'Next', aceptamos las condiciones de la licencia marcando la casilla 'I accept the terms...' y pulsamos 'Finish'. 
&lt;br&gt;
&lt;br&gt;Si has realizado los pasos correctamente, verás como se abre una ventana donde se muestra la descarga e instalación de los componentes seleccionados (operación que suele durar varios minutos). Durante el proceso de descarga/instalación aparecerá una ventana con una alerta de seguridad (Security Warning), donde se nos informa que se está instalando software sin firmar; pulsa OK para continuar con la instalación. Finalmente, aparecerá una nueva ventana donde se nos informa que debemos reiniciar Eclipse para que los cambios tomen efecto. Por tanto, pulsamos 'Restart Now' para reiniciar (asegúrate de haber guardado todo el trabajo que pudieras haber estado realizando antes de instalar STS) o 'Not Now' si deseamos reiniciar más tarde.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;DESACTIVANDO EL DASHBOARD
&lt;br&gt;Una vez instalado STS y reiniciado Eclipse, veremos que al cargar el IDE nos aparece el Dashboard de STS. El dashboard (o tablero de mandos) es una ventana en la que:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- podemos gestionar proyectos Spring
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- se muestran actualizaciones de STS
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- se muestran feeds de notícias que son actualizadas períodicamente
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- se pueden instalar nuevas extensiones para STS (plug-ins, soporte para otros lenguajes de programación, ...)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Para mantener el IDE lo más limpio posible y acelerar el arranque de Eclipse, recomiendo desactivar el dashboard. Lo primero es ir a la configuración del dashboard:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Window &gt; Preferences &gt; Spring &gt; Dashboard
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Una vez alli, desactiva la casilla 'Show Dashboard On Startup'. Pulsa OK y de nuevo en la pantalla principal de Eclipse cierra el dashboard si aún continua abierto (pulsando sobre la X de la pestaña superior). La próxima vez que inicies Eclipse el dashboard no aparecerá. Si en algún momento deseas mostrarlo, nada tan simple como ir a:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Help &gt; Dashboard
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;
&lt;br&gt;UN EJEMPLO SIMPLE
&lt;br&gt;La mejor manera de explicar que es y que ofrece STS es, como no, mediante un ejemplo muy sencillo. Vamos a crear un proyecto Spring y a continuacion su archivo de configuración. Para crear el proyecto Spring:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File &gt; New &gt; Other &gt; Spring &gt; Spring Project
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Le damos un nombre al proyecto y pulsamos 'Finish'. Ahora, en la ventana del 'Project Explorer', expandimos el recien creado proyecto, pulsamos con el boton derecho del ratón sobre la carpeta 'src' y seleccionamos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;New &gt; Other &gt; Spring &gt; Spring Bean Configuration File
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Pulsamos 'Next', le damos un nombre al archivo de configuración (no olvides incluir la extensión XML o STS no sabrá gestionarlo) y pulsamos 'Finish'. El nuevo archivo de configuración se abrirá, y mediante sus pestañas inferiores (Source, Namespaces, ...) podremos gestionar el código fuente XML, los namespaces incluidos, crear nuevos beans mediante un asistente, ver representaciones gráficas de los beans así como sus relaciones, etc.
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;
&lt;br&gt;RESUMEN
&lt;br&gt;SpringSource Tool Suite es una fantástica herramienta que te ayudará a manejar de manera muy potente tus proyectos Spring, con multitud de asistentes, editores, opciones y configuraciones. Aquellos que trabajan con Spring encontrarán en SpringSource Tool Suite un entorno desde el que desarrollar más eficazmente sus aplicaciones Spring, sin olvidar que también trae soporte para otras tecnologías como &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=181&quot;&gt;Groovy&lt;/a&gt;, Grails, OGSI, y más.</description>
    </item>
    <item>
      <title>Sigueme también en Twitter</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=230</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=230</guid>
      <pubDate>Fri, 14 Oct 2010 22:30:00 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Desde ahora podeis seguir la actividad de la web a través de Twitter, accediendo a la dirección &lt;a href=&quot;http://twitter.com/davidmarcoes&quot;&gt;http://twitter.com/davidmarcoes&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;¡Os espero!</description>
    </item>
    <item>
      <title>Primer año de davidmarco.es</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=232</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=232</guid>
      <pubDate>Mon, 20 Dec 2010 12:05:00 +0100</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Hoy se cumple un año desde la puesta en marcha de la web. Las más de 187.000 visitas y 560.000 páginas vistas desde 42 paises distintos dan sentido al humilde esfuerzo con el que empecé esta aventura, a mi misión primera y última: compartir mis conocimientos con el resto de la comunidad, al tiempo que aprendo de ella. Las traducciones a Español de los tutoriales de Spring e Hibernate han tenido una aceptación extraordinaria, además de servir de base para diferentes modificaciones que algunos habéis realizado de ellos. También ha tenido gran acogida mi blog personal, dentro del cual he publicado los tutoriales de JPA, Groovy, y diversos artículos relacionados con Java.
&lt;br&gt;
&lt;br&gt;Los cientos de correos que he recibido agradeciendo mi trabajo han sido un gran motor para seguir adelante. Muchos de vosotros me habeís pedido también ayuda por email, ayuda que no siempre es facil de proporcionar pues cada problema que os surge con un proyecto concreto es un mundo. De cualquier modo, he contestado a todos y cada uno de los correos sin escatimar tiempo ni esfuerzo, y os invito a que os sigáis poniendo en contacto conmigo siempre que lo consideréis oportuno.
&lt;br&gt;
&lt;br&gt;Para este nuevo año espero poder escribir mejores artículos y, espero (aunque no sean tan importante), en mayor cantidad. Algunos ya están planificados (como un tutorial de EJB 3.1 que algunos me habéis solicitado y que comenzaré a escribir en Febrero) y otros irán surgiendo sobre la marcha. También tengo en mente algunas modificaciones en la presentación de la página (como el prometido sistema de búsqueda de contenido que hace tiempo que debería de estar en marcha), y tal vez un lavado de cara a la presentacion visual.
&lt;br&gt;
&lt;br&gt;No hay nada que me motive más que saber que aún quedan muchas cosas por hacer, tener delante un largo camino para unos pies que no se van a rendir porque disfrutan a cada paso que dan, por duro que sea. Un año de gracias a todos, y feliz 2011.
&lt;br&gt;
&lt;br&gt;David Marco.</description>
    </item>
    <item>
      <title>Usando buenos nombres</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=238</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=238</guid>
      <pubDate>Fri, 04 Feb 2011 22:45:46 +0100</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Actualmente me encuentro leyendo una joya de la literatura informática de los últimos años, &lt;a href=&quot;http://www.amazon.co.uk/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=sr_1_1?ie=UTF8&amp;qid=1296827685&amp;sr=8-1&quot;&gt;Clean Code: A Handbook of Agile Software Craftsmanship&lt;/a&gt;, de Robert C. Martin. Sin enrollarme demasiado, el libro muestra como mejorar nuestro código (y como no empeorarlo) siguiendo algunas técnicas que, en los dos últimas decadas, han demostrado ser efectivas para mantener un proyecto de software funcionando de la mejor manera posible durante el mayor tiempo posible.
&lt;br&gt;
&lt;br&gt;Este artículo trata sobre una de esas técnicas, una tan sencilla como poderosa, y que podemos empezar a aplicar desde ya a todo el código que pase por nuestras manos: &lt;i&gt;usar buenos nombres&lt;/i&gt;. Vamos al lio.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;INTRODUCCIÓN: ¿POR QUE USAR BUENOS NOMBRES?
&lt;br&gt;Usar buenos nombres es esencial para mantener el código legible. Como programadores, pasamos más tiempo leyendo código (propio y ajeno) que escribiéndolo (según algunos estudios ¡en un ratio de 10:1!); toda nueva funcionalidad se basa en funcionalidad anterior, y si esa funcionalidad anterior no es legible nuestra tarea se ralentizará y, en el peor de los casos, puede convertirse en una pesadilla. Más aún, prácticamente todo tiene un nombre (constantes, variables, métodos, clases, paquetes, ...) así que entidades bien definidas con un nombre apropiado y no ambiguo nos harán el trabajo mucho más sencillo. Usar buenos nombres nos va a ayudar a desarrollar más rápido, cometer/producir menos errores, y sobre todo a ser profesionales y sinceros con nuestro trabajo. Comencemos con las reglas.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;TEN CUIDADO AL ELEGIR LOS NOMBRES Y CAMBIALOS CUANDO ENCUENTRES UNO MEJOR
&lt;br&gt;Sin llegar a convertir esta regla en una obsesión, pues puede haber más de una manera igual de adecuada de nombrar una entidad, es la base de todo lo que se va a exponer. Debes aceptar esta regla de manera natural y acometerla sin poner excusas. La forma de llevarla a cabo está explicada en el resto de reglas.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;NOMBRANDO CLASES
&lt;br&gt;Clases y objetos deben ser nombrados usando sustantivos como &lt;code&gt;Cliente&lt;/code&gt;, &lt;code&gt;Usuario&lt;/code&gt; y &lt;code&gt;Empleado&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;NOMBRANDO MÉTODOS
&lt;br&gt;Métodos deben ser nombrados usando verbos o frases con verbos como &lt;code&gt;pagarSalario&lt;/code&gt;, &lt;code&gt;borrarArchivo&lt;/code&gt;, etc. Métodos que actuan como accesores según el estandar Javabean deben seguir las reglas típicas (getXxx, setXxx, isXxx).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;USA NOMBRES QUE REVELEN UNA INTENCIÓN
&lt;br&gt;El nombre de una variable, un método, o una clase debe decir porqué existe, que hace, y que representa, respectivamente. Si una variable, clase o método necesita un comentario que responda a una de esas tres cuestiones es que su nombre no está revelando su intención:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;int dias; // dias transcurridos desde la última comprobación
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior es ambiguo, y esa variable usada 100 lineas más abajo no nos estará diciendo quien es, porqué está ahí y porqué debe ser usada de la forma en que lo está siendo. Lo más probable es que tengamos que retroceder buscando el lugar donde ha sido declarada (y tal vez viendo cómo ha sido usada anteriormente) para responder a las tres preguntas anteriores. Una manera mucho más correcta de declararla sería así:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;int diasDesdeUltimaComprobacion;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Ahora, la misma variable leida las mismas 100 lineas más abajo expresa claramente su razón de ser y la del código que la usa. 
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;EVITA LA DESINFORMACIÓN
&lt;br&gt;La desinformación oscurece el código, llevandote a seguir falsas pistas y a perderte entre ellas. No uses nombres del tipo &lt;code&gt;usuariosList&lt;/code&gt; para un objeto que no represente realmente una colección de tipo &lt;code&gt;List&lt;/code&gt; (mejor usa &lt;code&gt;conjuntoDeUsuarios&lt;/code&gt; o aún mejor &lt;code&gt;usuarios&lt;/code&gt;).
&lt;br&gt;
&lt;br&gt;Otra fuente de desinformación resulta de nombres muy largos y muy similares:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;public class ControladorParaManejoEficienteDeEntradas { }
&lt;br&gt;public class ControladorParaGuardadoEficienteDeEntradas { }
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Para este último caso no hay solución sencilla (ambas clases están nombradas de manera adecuada) y lo mejor es tener presente la similaridad de sus nombres, prestando atención a si estamos usando la clase adecuada en cada momento.
&lt;br&gt;
&lt;br&gt;Un caso extremo de desinformación se produce al usar los caracteres &lt;code&gt;l&lt;/code&gt; (ele minúscula) y &lt;code&gt;O&lt;/code&gt; (o mayúscula), que son fácilmente confundidos por &lt;code&gt;1&lt;/code&gt; (uno) y &lt;code&gt;0&lt;/code&gt; (cero).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;REALIZA DISTINCIONES DE SIGNIFICADO
&lt;br&gt;Que el compilador entienda y compile todo el código que le proporcionamos no nos convierte en buenos programadores. Una de mis citas favoritas sobre programación (y que tengo pinchada en la pared delante de mi) es de Martin Fowler y dice lo siguiente:
&lt;br&gt;
&lt;br&gt;&lt;i&gt;&quot;Any fool can write code that a computer can understand. Good programmers write code that humans can understand.&quot;&lt;/i&gt;
&lt;br&gt;
&lt;br&gt;Que traducido viene a decir:
&lt;br&gt;
&lt;br&gt;&lt;i&gt;&quot;Cualquier tonto puede escribir código que un ordenador puede entender. Los buenos programadores escriben código que los seres humanos pueden entender.&quot;&lt;/i&gt;
&lt;br&gt;
&lt;br&gt;Que nuestro compilador entienda la diferencia inherente entre dos variables &lt;code&gt;array1&lt;/code&gt; y &lt;code&gt;array2&lt;/code&gt; no le va a importar lo más mínimo a quien, seis meses después de haber sido escritas, tenga que usarlas (y ese alguien podriamos ser nosotros) y no sepa por donde empezar porque sus nombres no significan nada. Ese dia seremos maldecidos:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;void copiarCaracteres(char[] array1, char[] array2) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i = 0; i &lt; array1.length; i++) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;array2[i] = array1[i];
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Aunque el método anterior tiene un nombre adecuado, el algoritmo que contiene en su interior es confuso. Y si en lugar de contener solamente 2 lineas de código tuviera 20, sería un caos. La solución es hacer una distinción de significado entre los nombres de los argumentos del método, renombrandolos para que tengan un significado explícito y claro:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;void copiarCaracteres(char[] origen, char[] destino) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i = 0; i &lt; origen.length; i++) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;destino[i] = origen[i];
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Otra fuente de indistinción de significado nace del uso de ciertas palabras en los nombres que damos a una entidad. ¿Acaso no resultan tremendamente similares en significado las variables &lt;code&gt;cliente&lt;/code&gt; y &lt;code&gt;clienteInfo&lt;/code&gt;? ¿Que representa cada una de ellas cuando ambas aparecen en el mismo contexto? Por este motivo, palabras como &lt;code&gt;info&lt;/code&gt; y &lt;code&gt;datos&lt;/code&gt; deben ser evitadas.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;USA NOMBRE PRONUNCIABLES
&lt;br&gt;Imagina el siguiente ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Date genAmdhms() { }
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El ejemplo anterior es un caso claro, tal vez un poco extremo (aunque recuerdo haber hecho cosas no mucho mejores en algunos proyectos...), de nombre impronunciable, y está relacionado con una de las primeras reglas que vimos: USA NOMBRES QUE REVELEN UNA INTENCIÓN. Probablemente el método vaya acompañado de un comentario que clarifique cual es su función, ya que de otra manera sería prácticamente imposible deducir cual es esta (función que, dicho sea de paso, es generar el año, mes, dia, hora, minuto, y segundo actual). ¿Acaso no habría sido más sencillo hacer lo siguiente?:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Date generarTimestamp() { }
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Otro problema que surje al usar nombres impronunciables aparece cuando tenemos que comunicarnos verbalmente con un compañero o socio. Imagínate por un momento la siguiente conversación:
&lt;br&gt;
&lt;br&gt;&lt;i&gt;Durante la última batería de tests ha aparecido un bug que apunta al método gen a eme de ache eme ese, ¿puedes echarle un vistazo?&lt;/i&gt;
&lt;br&gt;
&lt;br&gt;Creo que las palabras sobran.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;USA NOMBRES QUE PUEDAN SER BUSCADOS
&lt;br&gt;Nombres con un solo carácter (o extremadamente cortos) y el uso de literales numéricos sufren de un mal común: son difíciles de buscar. El el primer caso (nombres con un solo carácter) su uso debería ser reducido a métodos más bien cortos y algunos casos especiales (por ejemplo la famosa variable &lt;code&gt;i&lt;/code&gt; dentro de un bucle &lt;code&gt;for&lt;/code&gt;) y nunca en ningún otro lugar. Una variable llamada &lt;code&gt;e&lt;/code&gt; para representar a un &lt;code&gt;Empleado&lt;/code&gt; es una atrocidad que no debes cometer jamás. En el segundo caso (literales numéricos) deberían ser sustituidos por constantes con un nombre bien definido. Veamos un ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;if(empleado.getHorasTrabajadasUltimaSemana() &gt; 40) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pagarHorasExtra(empleado);
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el método anterior, se está usando un literal numérico (40) donde debería utilizarse una constante con un nombre bien definido. Si en el futuro decidimos que las horas base por semana deben ser 35 en lugar de 40, nos veremos obligados a buscar cada linea donde aparece el valor 40 (problema 1: es dificil de buscar) y determinar en cada una de ellas si dicho valor 40 hace referencia a las horas trabajadas, puesto que si hace referencia a otro contexto (por ejemplo el número máximo de empleados por departamento) y lo cambiamos por error, estaremos introduciendo un bug que será dificil de encontrar cuando la aplicación comience a funcionar mal (problema 2: propensión a introducir errores). La solución ya se ha mencionado dos veces: declarar una constante con un nombre adecuado:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;final static int HORAS_BASE_POR_SEMANA = 40;
&lt;br&gt;...
&lt;br&gt;if(empleado.getHorasTrabajadasUltimaSemana() &gt; HORAS_BASE_POR_SEMANA) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pagarHorasExtra(empleado);
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Ojala algún dia a todos nos paguen las horas extra con la misma facilidad :)
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;ELIGE UNA ÚNICA PALABRA POR CADA CONCEPTO
&lt;br&gt;Elige una palabra para cada concepto abstracto y úsala siempre. Imagina tres clases, cada una con un método que obtiene información de forma similar desde una base de datos. En la primera clase el método se llama &lt;code&gt;leerDatosDesdeBBDD&lt;/code&gt;, en la segunda &lt;code&gt;obtenerDatosDesdeBBDD&lt;/code&gt; y en la tercera &lt;code&gt;recuperarDatosDesdeBBDD&lt;/code&gt;. Esto solo puede crear confusión, además de ser muy poco elegante. 
&lt;br&gt;
&lt;br&gt;Quiero reconocer que este error (o más exactamente &lt;i&gt;violación de buenas prácticas&lt;/i&gt;) lo he cometido a menudo en el pasado, por ejemplo diseñando una interface DAO con métodos llamados &lt;code&gt;leerXxx&lt;/code&gt;, &lt;code&gt;leerYyy&lt;/code&gt;, ... y una interface de servicio con métodos llamados &lt;code&gt;obtenerXxx&lt;/code&gt;, &lt;code&gt;obtenerYyy&lt;/code&gt;, ... . Esta última interface se limitaba a llamar a los métodos del DAO, y a pesar de trabajar conectadas, cada una utilizaba su propia nomenclatura, resultando en código feo y muy poco estético.
&lt;br&gt;
&lt;br&gt;Quienquiera que lea código de este tipo se empezará a hacer preguntas totalmente innecesarias como &lt;i&gt;¿que diferencia hay entre &lt;i&gt;leer&lt;/i&gt; datos y &lt;i&gt;recuperar&lt;/i&gt; datos? ¿Lee desde un archivo y recupera desde una base de datos? ¿O lee desde una base de datos y recupera desde un archivo?&lt;/i&gt; Entonces tendrá que revisar código fuente, documentación y/o especificaciones para descubrir que ambos métodos hacen lo mismo, aunque han sido nombrados según convenciones diferentes. El código debe ser (dentro de sus/nuestras posibilidades) como la prosa, como un libro que cuenta una historía que puedes comprender frase a frase. Nunca como una adivinanza ni como un juego de palabras. No dejes nada al azar.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;EVITA USAR LA MISMA PALABRA PARA DOS CONCEPTOS
&lt;br&gt;Esta regla es hermana de la regla anterior. Imagina otras tres clases, cada una con un método llamado &lt;code&gt;añadir&lt;/code&gt;. En la primera clase, dicho método &lt;i&gt;añade&lt;/i&gt; un registro a una base de datos, en la segunda &lt;i&gt;añade&lt;/i&gt; un objeto a un array, y en la tercera &lt;i&gt;añade&lt;/i&gt; una cadena de texto a otra previamente almacenada en una variable. Esos tres métodos, si son utilizados &quot;cara a cara&quot; en una misma aplicación (como la interface de servicio y la interface DAO de la regla anterior) producirán confusión al lector, ya que los tres se llaman igual pero hacen cosas completamente distintas (ten presente que intento hacer una distinción sutil del &lt;i&gt;que hace&lt;/i&gt; y no del &lt;i&gt;cómo lo hace&lt;/i&gt;, siguiendo el más que importante principio de encapsulación). La solución a este problema es ser consistente con los nombres que usamos, o en su defecto o imposibilidad, usar nombres apropiados:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class SimpleDao {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void añadirRegistroEnBBDD(Registro registro) { }
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Facil, ¿verdad?.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;USA NOMBRES QUE REFLEJEN LA SOLUCIÓN
&lt;br&gt;Quien lee tu código es también programador, por lo debes usar terminos que reflejen la solución que estás usando. Un ejemplo visto anteriormente es &lt;code&gt;usuariosList&lt;/code&gt;, que rápidamente se interpreta como &lt;i&gt;una colección de tipo List que contiene usuarios&lt;/i&gt;. Quienquiera que tenga que usar dicha variable tendrá conciencia inmediata de &lt;i&gt;que&lt;/i&gt; es y &lt;i&gt;cómo&lt;/i&gt; debe usarla. Otro ejemplo de nombre que refleja la solución que está tratando sería &lt;code&gt;UsuarioFacade&lt;/code&gt;: una clase que implementa el patrón de diseño &lt;i&gt;Facade&lt;/i&gt;. Es más fácil nombrar bien una entidad que acompañarla con un comentario de 15 palabras.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;USA NOMBRES QUE REFLEJEN EL DOMINIO
&lt;br&gt;Esta regla complementa a la anterior. Cuando tratamos problemas de un dominio especifico, debemos usar nombres que reflejen ese dominio. Un método &lt;code&gt;actualizarInventario&lt;/code&gt; está hablando sobre algo llamado &lt;i&gt;inventario&lt;/i&gt;, que es parte del dominio de la aplicación que estamos escribiendo. Esto nos va a ayudar tanto a escribir el código necesario para implementar el método (puesto que el nombre deja claro el &lt;i&gt;que&lt;/i&gt;) como a entender su función cuando sea usado o leido por nosotros mismos o por otro programador.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;AÑADE UN CONTEXTO
&lt;br&gt;La última regla, &lt;i&gt;añade un contexto&lt;/i&gt;, nos puede ayudar en ciertos momentos a evitar ambigüedades y por tanto confusión. Imagina que tenemos un conjunto de variables llamadas &lt;code&gt;calle&lt;/code&gt;, &lt;code&gt;numero&lt;/code&gt;, &lt;code&gt;ciudad&lt;/code&gt; y &lt;code&gt;codigoPostal&lt;/code&gt;. Todas ellas, cuando se usan conjuntamente, reflejan claramente que estamos tratando con una dirección postal y que sus nombres son perfectamente válidos. Sin embargo, ¿que ocurre si una de ellas, por ejemplo &lt;code&gt;numero&lt;/code&gt;, es usada de manera independiente dentro de un método? Para el lector de dicho método, &lt;code&gt;numero&lt;/code&gt; puede significar un montón de cosas, o tal vez no significar nada, convirtiendo el método o ciertas partes de él en (como dije unas reglas más arriba) una adivinanza: sabemos el &lt;i&gt;que&lt;/i&gt;, pero no sabemos el &lt;i&gt;porqué&lt;/i&gt;. Esto no es código legible.
&lt;br&gt;
&lt;br&gt;Existen dos soluciones a este problema. La primera es añadir un prefijo a las variables, lo que les proporciona un contexto y elimina de un plumazo cualquier ambigüedad presente y futura:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;String direccionCalle;
&lt;br&gt;String direccionNumero;
&lt;br&gt;String direccionCiudad;
&lt;br&gt;String direccionCodigoPostal;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La segunda solución, y en cualquier lenguaje orientado a objetos la preferida, es crear una clase que sea en si misma el contexto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;public class Direccion {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String calle;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String numero;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String ciudad;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String codigoPostal;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// getters y setters
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;De esta manera dejamos de llamar a &lt;code&gt;numero&lt;/code&gt; para llamar a &lt;code&gt;direccion.getNumero()&lt;/code&gt;, provocando que el significado de la antes ambigua variable se descubra ahora por si mismo.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;RESUMEN
&lt;br&gt;Todo el código que no es legible y claro en sus intenciones es dicifil de entender y de mantener. Programar debe ser un placer, dentro de su dificultad y otras peculiaridades que no vienen a cuento, y nunca una pesadilla. El código debe fluir, y ningún programador desea ahogarse en un rio desbordado de dificultades. Usar buenos nombres en clases, métodos, variables, etc. es una muy buena manera de empezar a mejorar nuestro código, ayudándonos a nosotros mismos y ayudando también a otros. Y además, es tremendamente sencillo (dentro de su dificultad y otras peculiaridades que no vienen a cuento, again). Te animo a que adoptes los principios que se han expuesto en este artículo; si no te gustan siempre puedes volver a tu estilo habitual, pero lo más posible es que una vez los pruebes y veas como crece la calidad de tu trabajo, nunca des marcha atrás.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;SOBRE EL LIBRO &lt;i&gt;CLEAN CODE: A HANDBOOK OF AGILE SOFTWARE CRAFTMANSHIP&lt;/i&gt;
&lt;br&gt;Este artículo está basado en los apuntes que he ido tomando al leer el libro &lt;a href=&quot;http://www.amazon.co.uk/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=sr_1_1?ie=UTF8&amp;qid=1296827685&amp;sr=8-1&quot;&gt;Clean Code: A Handbook of Agile Software Craftsmanship&lt;/a&gt;, de Robert C. Martin (más precisamente el capítulo 2: &lt;i&gt;Meaningful Names&lt;/i&gt;). La mayoría de los principios que se han expuesto los he venido usando desde mucho antes de tener en mis manos el libro, pues no son desconocidos para la mayoría.
&lt;br&gt;
&lt;br&gt;Este artículo no es una traducción ni tampoco un resumen del libro, es una recopilación y  traslación de algunas reglas que en él se exponen, escritas por mi con mis propias palabras. Unos pocos fragmentos de código son muy similares a los que aparecen en la obra mientras que la mayoría son mios; así mismo, unas pocas frases me han inspirado por su simplicidad y energía, y las he incluido en el texto (siempre evitando la literalidad). No pretendo con esto quitarle a Robert C. Martin el enorme mérito que merece, pues este artículo es hijo de su obra, ni tampoco colgarmelo yo, pues la forma en como lo he escrito (el nombre de los principios y, salvo excepciones, el orden en que son presentados) está inspirada sin recelos en las páginas de dicha obra. Os recomiendo que os hagaís con ella, personalmente me parece una lectura tremendamente recomendable, divertida e inspiradora, escrita en un inglés muy fácil de leer.</description>
    </item>
    <item>
      <title>Introducción a EJB 3.1 (I)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=239</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=239</guid>
      <pubDate>Tue, 08 Mar 2011 23:05:40 +0100</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Con este artículo comienza un tutorial que describe el estandar EJB 3.1 de manera introductoria. El tutorial contiene tanto material teórico como práctico, de manera que según se vayan introduciendo nuevos conceptos se irán reflejando en código. Es muy recomendable que antes de seguir leyendo visites el siguiente &lt;a href=&quot;http://www.davidmarco.es/tutoriales/anexos/anexo_introduccion_ejb31.html&quot;&gt;anexo&lt;/a&gt; donde se explica como poner en marcha un entorno de desarrollo compatible con EJB 3.1, de manera que puedas seguir todos los ejemplos que se van a presentar en el tutorial, así como desarrollar los tuyos propios.
&lt;br&gt;
&lt;br&gt;La siguiente lista muestra el contenido de los primeros 6 artículos de los que constará el tutorial. Esta lista se actualizará si se publica contenido adicional:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- 1. Introducción a EJB y primer ejemplo
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- 2. Stateless Session Beans y Stateful Session Beans
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- 3. Singletons y Message-Driven Beans
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- 4. Persistencia
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- 5. Servicios que ofrece el contenedor (1ª parte)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- 6. Servicios que ofrece el contenedor (2ª parte)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Con todo esto dicho, ¡comencemos!
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.1 ¿QUE SON LOS ENTERPRISE JAVABEANS?
&lt;br&gt;EJB (Enterprise JavaBeans) es un modelo de programación que nos permite construir aplicaciones Java mediante objetos ligeros (como POJO's). Cuando construimos una aplicación, son muchas las responsabilidades que se deben tener en cuenta, como la seguridad, transaccionalidad, concurrencia, etc. El estandar EJB nos permite centrarnos en el código de la lógica de negocio del problema que deseamos solucionar y deja el resto de responsabilidades al contenedor de aplicaciones donde se ejecutará la aplicación.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.2 EL CONTENEDOR DE APLICACIONES
&lt;br&gt;Un contenedor de aplicaciones es un entorno (en si mismo no es más que una aplicación) que provee los servicios comunes a la aplicacion que deseamos ejecutar, gestionándolos por nosotros. Dichos servicios incluyen la creación/mantenimiento/destrucción de nuestros objetos de negocio, así como los servicios mencionados en el punto anterior, entre otros. Aunque el contenedor es responsable de la gestión y uso de dichos recursos/servicios, podemos interacturar con él para que nuestra aplicación haga uso de los servicios que se ofrecen (normalmente mediante metadados, como se verá a lo largo del tutorial).
&lt;br&gt;
&lt;br&gt;Una vez escrita nuestra aplicación EJB, podemos desplegarla en cualquier contenedor compatible con EJB, beneficiandonos de toda el trabajo tras bastidores que el contenedor gestiona por nosotros. De esta manera la lógica de negocio se mantiene independiente de otro código que pueda ser necesario, resultando en código que es más fácil de escribir y mantener (además de ahorrarnos mucho trabajo).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.3 LA ESPECIFICACIÓN EJB 3.1
&lt;br&gt;La especificación EJB 3.1 es parte de la plataforma JavaEE 6, desarrollada y mantenida por Sun Microsystems (ahora parte de Oracle Corporation). JavaEE 6 provee diversas API's para la construcción de aplicaciones empresariales, entre ellas EJB, JPA, JMS, y JAX-WS. Cada una de ellas se centra en un area específica, resolviendo así problemas concretos. Además, cada API/especificación está preparada para funcionar en compañia de las demás de forma nativa, y por tanto en su conjunto son una solución perfectamente válida para desarrollar una aplicación end-to-end (de principio a fin).
&lt;br&gt;
&lt;br&gt;Desde la versión 3.0, EJB no impone ninguna restricción ni obligación a nuestros objetos de negocio de implementar una API en concreto. Dicho de otro modo, podemos escribir dichos objetos de negocio usando POJO's, facilitando entre otras cosas la reutilización de componentes y la tarea de testearlos.
&lt;br&gt;
&lt;br&gt;Como se ha dicho, los POJO's son faciles de testear (siempre que estén bien diseñados). Al final de este primer artículo se verá un sencillo ejemplo de programación de un EJB mediante Test-Driven Development (Desarrollo Dirigido por Tests). TDD es una metodología de desarrollo en la cual cada bloque de código está respaldado por uno o más tests que han sido escritos con anterioridad. De manera muy resumida, TDD nos permite enfocar de manera efectiva el problema que deseamos resolver de la siguiente manera:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Escribimos un test que define &lt;i&gt;que&lt;/i&gt; queremos hacer. 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Ejecutamos el test y este falla (puesto que aún no hay lógica de negocio, o lo que es lo mismo, &lt;i&gt;como&lt;/i&gt; queremos hacerlo).
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Escribimos la lógica de negocio que hace pasar el test (la solución más simple posible).
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Mejoramos la lógica de negocio gradualmente, ejecutando el test después de cada mejora para verificar que no hemos &lt;i&gt;roto&lt;/i&gt; nada.
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Escribir el test antes que la lógica de negocio y mantenerlo lo más simple posible nos obliga a escribir código independiente de otro código, con responsabilidades bien definidas (en resumen, buen código). Usado de forma correcta, TDD permite crear sistemas que son escalables, y con niveles de bugs muy bajos. TDD es un tema tan amplio en si mismo que no tiene cabida en este tutorial (a excepción del citado ejemplo que veremos al final del artículo y que servirá solamente para demostrar que el modelo EJB es un buen modelo de programación), y en el que te animo que profundices si no lo conoces; las ventajas que ofrece para escribir código de calidad son muchas, independientemente del uso de EJB o no.
&lt;br&gt;
&lt;br&gt;Por otro lado, el uso de POJO's para encapsular nuestra lógica de negocio nos proporciona un modelo simple que es altamente reutilizable (recuerda que la reutilización de clases es un concepto básico y esencial en programación orientada a objetos). Debes tener en cuenta que un POJO no actuará como un componente EJB hasta que haya sido empaquetado, desplegado en un contenedor EJB y accedido por dicho contenedor (por ejemplo a petición de un usuario). Una vez que un POJO definido como EJB haya sido desplegado en el contenedor, se convertirá en uno de los tres siguientes componentes (dependiendo del como lo hayamos definido):
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Session Bean 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Message-Driven Bean
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Entity Bean
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Veamos una breve descripción de cada tipo de componente (en capítulos posteriores se explicará cada tipo de componente con más detalle).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.4 SESSION BEANS
&lt;br&gt;Los Session Beans (Beans de Sesión) son los componentes que contienen la lógica de negocio que requieren los clientes de nuestra aplicación. Son accedidos a través de un proxy (también llamado &lt;i&gt;vista&lt;/i&gt;, término que utilizaré en adelante) tras realizar una solicitud al contenedor. Tras dicha solicitud, el cliente obtiene una vista del Session Bean, pero no el Session Bean real. Esto permite al contenedor realizar ciertas operaciones sobre el Session Bean real de forma transparente para el cliente (como gestionar su ciclo de vida, solicitar una instancia a otro contenedor trabajando en paralelo, etc).
&lt;br&gt;
&lt;br&gt;Los componentes Session Bean pueden ser de tres tipos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Stateless Session Beans
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Stateful Session Beans
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Singletons
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Stateless Session Beans (SLSB - Beans de Sesión sin Estado) son componentes que no requieren mantener un estado entre diferentes invocaciones. Un cliente debe asumir que diferentes solicitudes al contenedor de un mismo SLSB pueden devolver vistas a objetos diferentes. Dicho de otra manera, un SLSB puede ser compartido (y probablemente lo será) entre varios clientes. Por todo esto, los SLSB son creados y destruidos a discrección del contenedor, y puesto que no mantienen estado son muy eficientes a nivel de uso de memoria y recursos en el servidor.
&lt;br&gt;
&lt;br&gt;Stateful Session Beans (SFSB - Beans de Sesión con Estado), al contrario que SLSB, si que mantienen estado entre distintas invocaciones realizadas por el mismo cliente. Esto permite crear un estado conversacional (como el carrito de la compra en una tienda online, que mantiene los objetos que hemos añadido mientras navegamos por las diferentes páginas), de manera que acciones llevadas a cabo en invocaciones anteriores son tenidas en cuenta en acciones posteriores. Un SFSB es creado justo antes de la primera invocación de un cliente, mantenido ligado a ese cliente, y destruido cuando el cliente invoque un método en el SFSB que esté marcado como finalizador (también puede ser destruido por timeout de sesión). Son menos eficientes a nivel de uso de memoria y recursos en el servidor que los SLSB.
&lt;br&gt;
&lt;br&gt;Los Singleton son un nuevo tipo de Session Bean introducido en EJB 3.1. Un Singleton es un componente que puede ser compartido por muchos clientes, de manera que una y solo una instancia es creada. A nivel de eficiencia en uso de memoria y recursos son indiscutíblemente los mejores, aunque su uso está restringido a resolver ciertos problemas muy específicos.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.5 MESSAGE-DRIVEN BEANS
&lt;br&gt;Message-Driven Beans (MDB - Beans Dirigidos por Mensajes) son componentes de tipo listener que actuan de forma asíncrona. Su misión es la de consumir mensajes (por ejemplo eventos que se producen en la aplicación), los cuales pueden gestionar directamente o enviar (derivar) a otro componente. Los MDB actuan sobre un proveedor de mensajería, por ejemplo Java Messaging System (JMS es además soportado de forma implícita por la especificacion EJB).
&lt;br&gt;
&lt;br&gt;Al igual que los Stateless Session Beans, los Message-Driven Beans no mantienen estado entre invocaciones.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.6 ENTITY BEANS
&lt;br&gt;Los Entity Beans (EB - Beans de Entidad) son representaciones de datos almacenados en una base de datos, siempre en forma de POJO's. El encargado de gestionar los EB es &lt;code&gt;EntityManager&lt;/code&gt;, un servicio que es suministrado por el contenedor y que está incluido en la especificación Java Persistence API (JPA - API de Persistencia en Java). JPA es parte de EJB desde la versión 3.0 de esta última. Para saber más sobre JPA, puedes visitar un tutorial anterior publicado en esta misma web en la &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=144&quot;&gt;siguiente dirección&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;Al contrario que los Session Beans y los Message-Driven Beans, los Entity Beans no son componentes del lado del servidor. En otras palabras, no trabajamos con una vista del componente, si no con el componente real.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.6 EJB Y TEST-DRIVEN DEVELOPMENT
&lt;br&gt;Para terminar este primer artículo, dejemos de lado la teoría y escribamos una sencilla aplicación EJB para ir abriendo el apetito. Para poder seguir este y futuros ejemplos, debes tener en marcha un entorno compatible con EJB 3.1 (aunque la mayoría de los ejemplos, incluido este, funcionarán en un contenedor compatible con EJB 3.0). Por otro lado, todo el código se ajusta al estandard EJB 3.1 (no se usarán extensiones exclusivas de un contenedor concreto). Sin embargo, ten presente que las indicaciones relativas a la creación del proyecto, despliegue, y ejecución de los ejemplos estarán condicionadas por el entorno concreto que se ha puesto en marcha mediante el &lt;a href=&quot;http://www.davidmarco.es/tutoriales/anexos/anexo_introduccion_ejb31.html&quot;&gt;anexo&lt;/a&gt; que acompaña este tutorial; si tu entorno es diferente, ciertas acciones (como los opciones de menús a ejecutar en tu IDE) serán otras.
&lt;br&gt;
&lt;br&gt;Como se ha indicado en el punto 1.3, este ejemplo de desarrollará de manera puntual mediante Test-Driven Development. En los próximos artículos solo se mostrará código EJB, que es al fin y al cabo el tema a tratar en este turorial. Así mismo, los pasos para crear un proyecto o como desplegarlo en el contenedor EJB se omitirán en artículos posteriores.
&lt;br&gt;
&lt;br&gt;Para comenzar inicia Eclipse (si aún no lo has hecho) y crea un nuevo proyecto EJB:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File &gt; New &gt; EJB Project
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Dale un nombre al nuevo proyecto y asegúrate tanto de seleccionar en el desplegable 'Target runtime' un contenedor compatible con EJB como de seleccionar la versión 3.1 en el desplegable 'EJB module version'. Haz click en el botón 'Finish' para crear el proyecto.
&lt;br&gt;
&lt;br&gt;Ahora es el momento de crear un test que defina y respalde nuestro primer EJB. Lo primero es crear una carpeta dentro del proyecto donde almacenaremos todos los tests que escribamos. En la pestaña 'Project Explorer' haz click con el botón derecho sobre el proyecto EJB y selecciona:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;New &gt; Source Folder
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Introduce el nombre del directorio en el campo 'Folder name' (utiliza un nombre descriptivo, como 'tests') y haz click en el botón 'Finish'. Si expandes el proyecto EJB (con la flecha negra que hay a la izquierda del nombre) verás que el nuevo directorio se ha creado correctamente. Ahora vamos a crear la clase donde escribiremos los tests para nuestro EJB. Haz click con el botón derecho sobre el directorio de tests y selecciona:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;New &gt; Other
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En la ventana que te aparecerá selecciona:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Java &gt; JUnit &gt; JUnit Test Case
&lt;br&gt;
&lt;br&gt;En la ventana de creación de un test de JUnit selecciona la opción 'New JUnit 4 test', introduce el nombre del paquete donde deseas alojar la clase en el campo 'Package' (muy recomendado) y escribe un nombre para la clase de tests. En mi caso, el nombre del paquete será 'es.davidmarco.ejb.slsb' y el nombre de la clase de tests
&lt;br&gt;'PrimerEJBTest'. Haz click en el botón 'Finish'; si es el primer tests que escribes para el proyecto (como es nuestro caso) aparecerá una ventana donde Eclipse nos informa que la librería JUnit no está incluida en el classpath. Seleccionamos la opción 'Perform the following action: Add JUnit4 library to the build path' (Realizar la siguiente acción: añadir la libreria JUnit 4 al path de construcción) y haz click en el botón 'OK'. Hecho esto, ya podemos escribir nuestro primer (y de momento único) test:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;import org.junit.Test;
&lt;br&gt;import static org.junit.Assert.*;
&lt;br&gt;
&lt;br&gt;public class PrimerEJBTest {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void testSaluda() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrimerEJB ejb = new PrimerEJB();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertEquals(&quot;Hola usuario&quot;, ejb.saluda(&quot;usuario&quot;));
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El test (un método que debe ser &lt;code&gt;void&lt;/code&gt;, no aceptar parámetros, y estar anotado con la anotación de JUnit &lt;code&gt;@Test&lt;/code&gt;) declara las intenciones (el contrato) del código que estamos diseñando: crear un objeto de la clase &lt;code&gt;PrimerEJB&lt;/code&gt; con un método &lt;code&gt;saluda()&lt;/code&gt; que acepte un argumento de tipo &lt;code&gt;String&lt;/code&gt; y devuelva un mensaje con el formato 'Hola argumento'. Aquí empezamos a ver las ventajas de EJB: podemos testear nuestro código de negocio directamente, sin tener que desplegar el componente EJB en un contenedor y entonces hacer una llamada a este, con toda la parafernalia que esto requiere. 
&lt;br&gt;
&lt;br&gt;Y ahora si (por fin) vamos a escribir nuestro primer EJB. Nuestra clase de negocio ira en un paquete con el mismo nombre que el utilizado para almacenar las clase de tests, pero en una carpeta diferente. De esta manera mantenemos ambos tipos de clases separadas físicamente en disco (por motivos de organización y por claridad), pero accesibles gracias a que virtualmente pertenecen al mismo paquete, y por tanto entre ellos hay visibilidad de tipo package-default (esto puede resultarnos útil si necesitamos, por ejemplo, acceder desde la clase de tests a métodos en las respectivas clases de negocio que han sido declarados como 'protected'). En la pestaña 'Project Explorer' haz click con el botón derecho en la carpeta 'ejbModule' (la carpeta por defecto que crea Eclipse en un proyecto EJB para almacenar nuestras clases) y selecciona:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;New &gt; Class
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Introduce en el campo 'Package' el nombre del paquete donde vamos a almacenar la clase de negocio (en mi caso 'es.davidmarco.ejb.slsb') y en el campo 'Name' el nombre de la clase de negocio; para este último caso es conveniente usar el nombre de la clase de tests sin el sufijo 'Test' (en mi caso 'PrimerEJB') de manera que podamos asociar visualmente en el explorador del IDE cada clase de negocio ('Xxx') con su clase de tests ('XxxTest'). Haz click en el botón 'Finish' para crear la clase de negocio y añade la lógica de negocio (comienza con la solución mas simple posible):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;public class PrimerEJB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String saluda(String nombre) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Si en este punto ejecutamos el test que hemos escrito (haciendo click con el botón derecho sobre el editor donde tenemos el código del test y seleccionando 'Run As &gt; JUnit Test') este fallará (verás una barra de color rojo que indica que al menos un tests no ha pasado correctamente). Si observas la ventana 'Failure trace' (seguimiento de fallos) de la pestaña de resultados de JUnit, verás un mensaje que, traducido a español, indica que se esperaba como respuesta 'Hola Usuario' pero se recibió 'null'. Debajo de este mensaje puedes ver la pila de llamadas que ha generado el error, en nuestro caso ha sido la función estática &lt;code&gt;AssertEquals&lt;/code&gt; de JUnit. Volvamos al editor donde tenemos la clase de negocio y arreglemos el código que está fallando:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;public class PrimerEJB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String saluda(String nombre) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;Hola usuario&quot;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Si ahora ejecutamos el test, veremos en la pestaña de JUnit que la barra es ahora de color verde, lo cual indica que todos los tests se han ejecutado sin fallos (la ventana 'Failure Trace' esta ahora vacía, evidentemente). Ahora decidimos que, cuando un cliente pase un argumento de tipo &lt;code&gt;null&lt;/code&gt; a nuestra función, esta deberá devolver un saludo por defecto. Renombremos el nombre del primer test que hemos escrito y escribamos un segundo test que pruebe esta nueva condición (desde ahora y hasta el final de esta sección omitiré en ambas clases las sentencias &lt;code&gt;package&lt;/code&gt; e &lt;code&gt;import&lt;/code&gt; por claridad):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;public class PrimerEJBTest {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void testSaludaConNombre() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrimerEJB ejb = new PrimerEJB();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertEquals(&quot;Hola usuario&quot;, ejb.saluda(&quot;usuario&quot;));
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void testSaludaConNull() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrimerEJB ejb = new PrimerEJB();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertEquals(&quot;Hola desconocido&quot;, ejb.saluda(null));
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Como se dijo previamente, mediante TDD estamos dejando claras las intenciones de nuestro código antes incluso de escribirlo, como se puede ver en el segundo tests. En él, esperamos recibir como respuesta la cadena de texto 'Hola desconocido' cuando invoquemos el método &lt;code&gt;saluda()&lt;/code&gt; con un argumento de tipo &lt;code&gt;null&lt;/code&gt;. Y mientras tanto, el primer test (que hemos renombrado para darle más claridad y expresividad a nuestros tests) debe seguir pasando, por supuesto. Ejecutamos los tests ('Run As &gt; JUnit Test') y el nuevo test que hemos escrito falla (podemos ver en la ventana a la izquierda de la pestaña de JUnit el/los test/s que ha/n fallado marcados con una cruz blanca sobre fondo azul). Volvamos al editor donde estamos escribiendo la lógica de negocio e implementemos la nueva funcionalidad:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;public class PrimerEJB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String saluda(String nombre) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(nombre == null) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;Hola desconocido&quot;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;Hola usuario&quot;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Ahora ambos tests pasan. Para terminar, ¿que ocurriría si en lugar de la cadena de texto 'usuario' pasamos al método &lt;code&gt;saluda()&lt;/code&gt; una cadena de texto distinta?. Añadamos un test que pruebe esta condición:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;public class PrimerEJBTest {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void testSaludaConNombre() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrimerEJB ejb = new PrimerEJB();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertEquals(&quot;Hola usuario&quot;, ejb.saluda(&quot;usuario&quot;));
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void testSaludaConOtroNombre() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrimerEJB ejb = new PrimerEJB();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertEquals(&quot;Hola Pedro&quot;, ejb.saluda(&quot;Pedro&quot;));
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void testSaludaConNull() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrimerEJB ejb = new PrimerEJB();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertEquals(&quot;Hola desconocido&quot;, ejb.saluda(null));
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Este último test demuestra, al ejecutarse y fallar, que nuestra lógica de negocio contiene un bug: siempre que invocamos el método &lt;code&gt;saluda()&lt;/code&gt; con un parámetro de tipo &lt;code&gt;String&lt;/code&gt; (diferente de &lt;code&gt;null&lt;/code&gt;) obtenemos la cadena de texto 'Hola usuario', ignorando así el parametro que le hemos pasado. He aquí otra ventaja más que surje del uso de TDD: descubrir bugs lo antes posible. Cuanto más tiempo tardemos en descubrir un bug, más dificil nos resultará encontrarlo y solucionarlo. Vamos a resolver este último error en nuestra lógica de negocio:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;public class PrimerEJB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String saluda(String nombre) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(nombre == null) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;Hola desconocido&quot;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;Hola &quot; + nombre;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Ahora todos los tests pasan. Aunque aún nos quedaría la tarea de refactorizar los tres métodos de tests (hay código redundante en todos ellos) y tal vez añadir algún test más (o eliminar...), vamos a dejar las cosas aquí. TDD es un tema demasiado amplio y complejo que está fuera del propósito de este tutorial. Aunque este ejemplo ha sido extremadamente simple/tonto/llamalo-como-quieras, nos ha servido para demostrar lo facil que es diseñar un componente EJB paso a paso y libre de errores. Nadie quiere software que falle, y por tanto debes tomarte la tarea de testear el código que escribes muy en serio. Test-Driven Development es una manera muy sencilla y divertida de diseñar software de calidad.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.7 DESPLEGANDO NUESTRO PRIMER EJB
&lt;br&gt;Hasta ahora hemos tratado la clase &lt;code&gt;PrimerEJB&lt;/code&gt; como si fuera un componente EJB. Pero lo cierto es que no es así (en otras palabras, te he mentido, aunque espero que puedas perdonarme...). Para que nuestro POJO sea reconocido por nuestro contenedor como un componente EJB verdadero tenemos que decirle que lo es:
&lt;br&gt; 
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;import javax.ejb.Stateless;
&lt;br&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class PrimerEJB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La anotación &lt;code&gt;@Stateless&lt;/code&gt; define nuestro POJO como un Session Bean de tipo Stateless y una vez desplegado en un contenedor EJB, este lo reconocerá como un componente EJB que podremos usar. ¡Así de simple!. Sin embargo, debemos añadir una segunda anotación a nuestro (ahora si) componente EJB:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;import javax.ejb.Remote;
&lt;br&gt;import javax.ejb.Stateless;
&lt;br&gt;
&lt;br&gt;@Remote
&lt;br&gt;@Stateless
&lt;br&gt;public class PrimerEJB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String saluda(String nombre) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(nombre == null) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;Hola desconocido&quot;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;Hola &quot; + nombre;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La anotación &lt;code&gt;@Remote&lt;/code&gt; permite a nuestro EJB ser invocado remotamente (esto es, desde fuera del contenedor). Si omitimos esta anotación, el EJB sería considerado como 'Local' (concepto que veremos en el próximo artículo) y solo podría ser invocado por otros componentes ejecutandose dentro del mismo contenedor. Nosotros la hemos incluido pues en la próxima sección vamos a escribir un cliente Java externo al contenedor que solicitará a este el componente que estamos diseñado. De manera adicional, todos los componentes que sean de tipo remoto (como este) deben extender una interface (o de lo contrario se producirá un error durante el despliegue):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;public interface MiInterfaceEJB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String saluda(String nombre);
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Por último modificamos nuestro EJB para que implemente la interface y el despliegue sea correcto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Remote
&lt;br&gt;@Stateless
&lt;br&gt;public class PrimerEJB implements MiInterfaceEJB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La necesidad de una interface para componentes de tipo remoto, aunque que a priori pueda parecer una restricción (o una limitación), es necesaria para que el contenedor pueda construir la vista/proxy que será enviada a los clientes remotos (externos al contenedor) por motivos que no vienen al caso. Además, se considera una buena práctica que nuestras clases y métodos de negocio se construyan sobre interfaces: de esta manera los clientes que usan nuestro código trabajan con la interface, ignorando la implementación concreta. De esta manera podemos cambiar dicha implementación en el futuro sin &lt;i&gt;romper&lt;/i&gt; el código de nuestros clientes. 
&lt;br&gt;
&lt;br&gt;Ahora ya podemos desplegar nuestra primera aplicación EJB en el contenedor. En la pestaña 'Project Explorer' haz click con el botón derecho sobre el nombre del proyecto, y selecciona:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Run As &gt; Run on Server
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Durante el primer despliegue nos aparecerá una ventana donde podemos seleccionar el servidor donde deseamos realizar el despliegue (aparecerá por defecto el que definimos al crear el proyecto). Seleccionamos la casilla 'Always use this server when running this project' (Usar siempre este servidor cuando se ejecute este proyecto) y hacemos click en el botón 'Finish'. La pestaña 'Console' se volverá activa y en ella veremos multitud de información relativa al proceso de arranque del servidor (puesto que no estaba arrancado). Tras unos momentos (30-40 segundos en mi equipo) el contenedor se habra levantado, y con él nuestra aplicación EJB. Entre los últimos mensajes de arranque del servidor puedes ver los siguientes:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrimerEJB/remote - EJB3.x Default Remote Business Interface
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrimerEJB/remote-es.davidmarco.ejb.slsb.InterfaceEJB - EJB3.x Remote Business Interface
&lt;br&gt;
&lt;br&gt;Esas dos lineas nos indican dos referencia JNDI válidas al componente EJB que hemos desplegado, y las necesitaremos cuando escribamos el cliente para que el contenedor nos devuelva el objeto correcto.
&lt;br&gt;
&lt;br&gt;
Antes de finalizar esta sección, veamos un último asunto relativo al despliegue. Una vez que ya tenemos desplegada nuestra aplicación en JBoss, si realizamos un cambio en nuestra lógica de negocio y deseamos volver a desplegar la aplicación en el contenedor, debemos hacerlo desde la pestaña 'Servers' de Eclipse (y no desde la pestaña 'Project Explorer' como hicimos la primera vez que desplegamos la aplicación). Para ello, primero abrimos la pestaña 'Servers' si no es visible en el Workbench de Eclipse:&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Window &gt; Show Views &gt; Servers&lt;br&gt;
&lt;br&gt;
Si miramos a la recién abierta pestaña 'Servers' veremos la instancia de JBoss asociada a nuestro proyecto, y junto a ella una flecha. Pinchamos en esta flecha para expandir el servidor y veremos nuestro proyecto EJB. Hacemos click con el botón derecho sobre el nombre del proyecto y seleccionamos 'Full Publish'. En unos segundos nuestro proyecto estará re-desplegado (puedes ver el proceso en la pestaña 'Console').
&lt;br&gt;
&lt;br&gt;
Por otro lado, cuando iniciemos el IDE y queramos acceder a una aplicación desplegada con anterioridad (por ejemplo desde un cliente como el que vamos a construir en la próxima sección) debemos iniciar primero el servidor, evidentemente. Para ello, haz click con el botón derecho sobre el nombre del servidor en la pestaña 'Servers' y selecciona 'Start'.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.8 EL CLIENTE JAVA
&lt;br&gt;Ahora es el momento de escribir el cliente Java, el cual va a hacer una solicitud al contenedor mediante JNDI para obtener el Stateless Session Bean que hemos creado en la sección 1.6 y desplegado en la sección 1.7. Con esto veremos como el contenedor gestiona todo el ciclo de vida de una aplicación EJB así como de sus componentes, mientras los clientes solo tienen que preocuparse de solicitar el componente que necesiten y usarlo. Lo primero es crear un nuevo proyecto Java:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File &gt; New &gt; Other
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Seleccionamos 'Java Project', hacemos click en 'Next', le damos un nombre al proyecto y hacemos click en 'Finish'. En la pestaña 'Project Explorer' expandimos el proyecto pinchando en la flecha que aparece a la izquierda de su nombre y en la carpeta 'src' creamos un nuevo paquete (muy recomendado) haciendo click con el botón derecho y seleccionando:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;New &gt; Package
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Le damos un nombre al paquete (en mi caso 'es.davidmarco.ejb.cliente') y hacemos click en 'Finish'. Volvemos a hacer click con el botón derecho sobre el paquete recién creado y seleccionamos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;New &gt; Class
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En la ventana que nos aparecerá le damos un nombre a la clase (en mi caso 'Cliente') y marcamos la casilla 'public static void main(String[] args)' para que nos cree un método &lt;code&gt;main()&lt;/code&gt; automáticamente, y hacemos click en el botón 'Finish'.
&lt;br&gt;
&lt;br&gt;Antes de mostrar el código del cliente es preciso mencionar que para ejecutarlo se necesitan ciertas librerias que, por motivos de simplicidad, vamos a obtener del primer proyecto (la aplicación EJB). Para ello, en la pestaña 'Project Explorer' haz click con el botón derecho sobre el nombre del proyecto que hace de cliente y selecciona:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Build Path &gt; Configure Build Path
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En la ventana que se abrirá seleccionamos la pestaña 'Projects', hacemos click en el botón 'Add', y marcamos la casilla correspondiente al proyecto donde está la aplicación EJB que hemos desplegado (y que, repito, contiene todas las librerias que necesita el cliente). Para finalizar, hacemos click en el botón 'OK', y de nuevo hacemos click en el botón 'OK'. El código del cliente es el siguiente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.cliente;
&lt;br&gt;
&lt;br&gt;import java.util.Properties;
&lt;br&gt;import javax.naming.Context;
&lt;br&gt;import javax.naming.InitialContext;
&lt;br&gt;import javax.naming.NamingException;
&lt;br&gt;import es.davidmarco.ejb.slsb.MiInterfaceEJB;
&lt;br&gt;
&lt;br&gt;public class Cliente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private static final String JNDI_PRIMER_EJB = &quot;PrimerEJB/remote&quot;;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws NamingException {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Properties properties = new Properties();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.factory.initial&quot;, &quot;org.jnp.interfaces.NamingContextFactory&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.factory.url.pkgs&quot;, &quot;org.jboss.naming:org.jnp.interfaces&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.provider.url&quot;, &quot;jnp://localhost:1099&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Context context = new InitialContext(properties);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MiInterfaceEJB bean = (MiInterfaceEJB) context.lookup(JNDI_PRIMER_EJB);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String respuesta = bean.saluda(&quot;Cliente Java&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(respuesta);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El cliente contiene una constante llamada &lt;code&gt;JNDI_PRIMER_EJB&lt;/code&gt; a la que le hemos dado el valor de la referencia JNDI a nuestro componente (recuerda que este valor nos los dio el contenedor cuando desplegó la aplicación, como vimos al final de la sección 1.7). Dentro del método &lt;code&gt;main()&lt;/code&gt; creamos un objeto de propiedades, introducimos los valores necesarios para acceder al contexto del contenedor EJB, y creamos dicho contexto mediante un objeto &lt;code&gt;InitialContext&lt;/code&gt; y el objeto de propiedades que acabamos de crear y configurar.
&lt;br&gt;
&lt;br&gt;A continuación viene lo realmente interesante: no obtenemos un objeto de tipo &lt;code&gt;InterfaceEJB&lt;/code&gt; mediante el constructor &lt;code&gt;new&lt;/code&gt; (como haríamos en una aplicación Java normal), si no que se lo solicitamos al contenedor EJB a traves del método &lt;code&gt;lookup()&lt;/code&gt; del contexto que acabamos de crear. A este método le hemos pasado el nombre de la referencia JNDI del componente que queremos obtener. Recuerda que cuando solicitamos al contenedor un componente de tipo Session Bean (ya sea Stateless, Stateful, o Singleton) lo que obtenemos no es una instancia del componente EJB (en nuestro caso &lt;code&gt;PrimerEJB&lt;/code&gt;), si no una vista (un objeto proxy) que sabe como alcanzar el objeto real dentro del contenedor.
&lt;br&gt;
&lt;br&gt;Una vez que tenemos la vista podemos ejecutar cualquiera de los métodos que definimos en su interface asociada (&lt;code&gt;MiInterfaceEJB&lt;/code&gt;). Para ejecutar el cliente nada tan sencillo como hacer click con el botón derecho sobre el editor donde lo tenemos y seleccionar:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Run As &gt; Java Application
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En la pestaña 'Console' aparecera el resultado de la ejecución del cliente. A modo de &lt;i&gt;experimento&lt;/i&gt; puedes cambiar la invocación al método &lt;code&gt;saluda()&lt;/code&gt;, pasarle un valor &lt;code&gt;null&lt;/code&gt; en lugar de una cadena de texto, volver a ejecutar el cliente, y ver la respuesta del componente EJB.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;1.9 RESUMEN
&lt;br&gt;Este primer artículo del tutorial de introducción a EJB 3.1 ha sido muy fructífero. En el hemos visto de manera superficial los conceptos básicos de la especificación EJB, una breve introducción al contenedor EJB, los tipos de componentes que podemos producir, un sencillo ejemplo de Test-Driven Development + EJB, la forma de desplegar dicho ejemplo en un contenedor compatible con EJB, y como acceder al componente (a través del contenedor) desde un cliente Java.
&lt;br&gt;
&lt;br&gt;En el próximo artículo veremos en profundidad dos de los tres tipos de componentes de tipo Session Bean: Stateless Session Beans y Stateful Session Beans. Hasta entonces, ¡felices despliegues!.</description>
    </item>
    <item>
      <title>Introducción a EJB 3.1 (II)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=240</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=240</guid>
      <pubDate>Fri, 18 Mar 2011 11:55:00 +0100</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>En el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=239&quot;&gt;artículo anterior&lt;/a&gt; del tutorial de EJB 3.1 vimos de manera superficial que representa la especificación EJB, que es un contenedor, los tipos de componentes dentro de una aplicación EJB, y por último un sencillo ejemplo de desarrollo de una aplicación EJB 3.1 mediante Test-Driven Development. En este segundo artículo vamos a empezar a profundizar en algunos de esos temas, viendo dos de los tres tipos de Session Beans: Stateless y Stateful. Sin embargo, antes es necesario comprender algunos conceptos relacionados con la tecnología EJB, como el funcionamiento del pool, el uso de metadatos, componentes locales vs componentes remotos, inyección de dependencias, y contexto de sesión dentro de una aplicación EJB. Comencemos.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.1 METADATOS
&lt;br&gt;Como vimos en la &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=239&quot;&gt;primer artículo&lt;/a&gt; del tutorial, para declararar nuestros POJO's como verdaderos componentes EJB necesitamos usar metadatos. Estos metadatos pueden ser de dos tipos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Anotaciones
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- XML
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;El uso de anotaciones es, a priori, el más sencillo y expresivo. Esta forma de aplicar información a nuestros componentes está disponible en la plataforma JavaEE desde su versión 5, y por tanto disponible también en JavaEE 6 (plataforma de la cual forma parte la especificación EJB 3.1). El único punto en contra del uso de anotaciones es que, si deseamos cambiar el comportamiento de un componente, debemos recompilar nuestro código (ya que la anotación acompaña al código Java). Por motivos de simplicidad, esta será la forma de metadatos que se utilizará durante todo el tutorial. Puedes consultar la referencia completa (en inglés) de las anotaciones soportadas en la especificación EJB 3.0 en la &lt;a href=&quot;http://download.oracle.com/docs/cd/E11035_01/wls100/ejb30/annotations.html&quot;&gt;siguiente dirección&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;El uso de XML para añadir metadatos a nuestro código es la forma heredada de versiones anteriores de la especificación JavaEE. Para ello, debemos incluir un archivo llamado &lt;code&gt;ejb-jar.xml&lt;/code&gt; dentro del directorio &lt;code&gt;META-INF&lt;/code&gt; del archivo jar/ear a desplegar. La ventaja del uso de XML como fuente de metadatos reside en que no es necesario recompilar nuestro código para cambiar el comportamiento de nuestros componentes, con todas las ventajas que esto puede suponer una vez que un proyecto se encuentra en producción. De manera adicional, al encontrarse los metadatos en un archivo externo, nuestro código Java no contiene ningún tipo de información relativa a la especificación EJB, y por tanto es más portable. Por contra, además de tener que mantener dos fuentes de información a la vez (el código Java y el archivo XML), el propio archivo XML puede ser dificil de mantener y entender cuando alcanza cierta longitud y complejidad. En este tutorial no se verán ejemplos de metadados en XML por motivos de simplicidad, aunque si deseas ampliar información puedes visitar el capítulo 19 de la especificación EJB 3.1, la cual puedes descargar desde la &lt;a href=&quot;http://jcp.org/aboutJava/communityprocess/final/jsr318/index.html&quot;&gt;siguiente dirección&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;Por último, debes tener muy presente que los metadatos en formato XML sobreescriben cualquier comportamiento ya expresado mediante anotaciones, siempre que ambos hagan referencia a un mismo componente. Por ello, una combinación de ambos tipos de metadatos sería perfectamente legal, aunque salvo honrosas excepciones, poco recomendable (puede inducir a la confusión, y por tanto a cometer errores).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.2 EL POOL
&lt;br&gt;Un pool es, expresado de forma básica, un almacén de objetos. El contenedor EJB mantiene uno o varios pools donde almacena componentes que están listos para ser servidos a un cliente que los solicite. De esta manera, el contenedor gestiona la creación, mantenimiento, y destrucción de componentes en segundo plano y de manera transparente a la aplicación EJB (mejorando así el rendimiento de esta última y de sus clientes).
&lt;br&gt;
&lt;br&gt;Cuando un cliente obtiene una referencia, ya sea local (mediante &lt;code&gt;@EJB&lt;/code&gt;, como veremos en la sección 2.5), o remota (mediante JNDI, como vimos en el ejemplo al final del &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=239&quot;&gt;artículo anterior&lt;/a&gt;), esta no apunta a ninguna instancia del componente en cuestión. Solamente cuando se invoca un método en dicha referencia, el contenedor extrae una instancia del pool y la asigna a dicha referencia, de manera que la invocación pueda tener efecto.
&lt;br&gt;
&lt;br&gt;El comportamiento de multitud de aspectos del pool es configurable, aunque en este tutorial no necesitamos hacerlo en ningún momento. Los detalles concretos del funcionamiento del pool es algo que tampoco necesitamos saber de antemano para seguir el tutorial; cuando se necesite comprender un aspecto concreto de dicho funcionamiento, se explicará en la sección correspondiente.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.3 LOCAL VS REMOTO
&lt;br&gt;Como se explicó muy brevemente en el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=239&quot;&gt;primer artículo&lt;/a&gt; del tutorial, un Session Bean puede ser declarado de tipo local o remoto. Un Session Bean declarado como local estará destinado a servir solicitudes de otros componentes dentro de la misma Java Virtual Machine (JVM - Máquina Virtual Java) donde está desplegado (dicho con otras palabras, dentro del contenedor donde se ejecuta la aplicación). El contenedor pasará la referencia que apunta al objeto en cuestión al cliente, pues dentro de la misma JVM está referencia es válida. Por contra, un Session Bean declarado como remoto está destinado a servir peticiones de clientes externos al propio contenedor (como vimos en el ejemplo al final del &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=239&quot;&gt;artículo anterior&lt;/a&gt;). En este caso, lo que se pasa es una copia del objeto en cuestión, pues para una JVM externa no tendrá ningun sentido una referencia a un objeto que no se encuentre en ella misma. Recuerda que esa copia no es una copia del componente EJB (una instancia del POJO desplegado en el contenedor), si no una vista/proxy que sabe como acceder a través de una red al objeto real.
&lt;br&gt;
&lt;br&gt;La especificación EJB no permite que la interface (en el sentido de &lt;i&gt;contrato&lt;/i&gt;) de un Session Bean sea declarada local y remota al mismo tiempo. Por tanto, lo siguiente no es válido y producirá un error al ser desplegado:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Local
&lt;br&gt;@Remote
&lt;br&gt;@Stateless
&lt;br&gt;public class MiBean implements MiInterfaceRemote {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// esta clase produce un error al desplegar
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, la clase &lt;code&gt;MiBean&lt;/code&gt; actua como interface local y remota al mismo tiempo, lo cual no está permitido. Sin embargo, lo siguiente si que es válido:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Local
&lt;br&gt;public interface MiBeanLocalInterface {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// declaración de métodos locales
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;@Remote
&lt;br&gt;public interface MiBeanRemoteInterface {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// declaración de métodos remotos
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class MiBean implements MiBeanLocalInterface, MiBeanRemoteInterface {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// implementación de métodos locales y remotos
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, declaramos una interface local y otra remota, y las implementamos en un Session Bean de tipo Stateless. De esta manera, el Session Bean podrá servir solicitudes de ambos tipos (cada una a través de la interface correspondiente). Otra forma de expresar lo mismo sería de la siguiente manera:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;public interface MiBeanLocalInterface {}
&lt;br&gt;
&lt;br&gt;public interface MiBeanRemoteInterface {}
&lt;br&gt;
&lt;br&gt;@Local(PrimerBeanLocalInterface.class)
&lt;br&gt;@Remote(PrimerBeanRemoteInterface.class)
&lt;br&gt;@Stateless
&lt;br&gt;public class MiBean implements MiBeanRemoteInterface {}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, hemos eliminado las anotaciones en las interfaces y las hemos aplicado a la clase &lt;code&gt;MiBean&lt;/code&gt;. Añadiendo los argumentos correspondientes en &lt;code&gt;@Local&lt;/code&gt; y &lt;code&gt;@Remote&lt;/code&gt; le indicamos al contenedor que interface actuará como local y cual como remota. Seguimos teniendo que implementar la interface remota en la declaración de la clase (&lt;code&gt;implements MiBeanRemoteInterface&lt;/code&gt;), pues como se vio en el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=239&quot;&gt;artículo anterior&lt;/a&gt;, todo Session Bean declarado como remoto necesita implementar una interface de manera obligatoria (dicha interface es necesaria para la creación del proxy/vista).
&lt;br&gt;
&lt;br&gt;Por supuesto también podemos aprovechar las características de polimorfismo y herencia en Java para crear nuestros componentes:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;public interface MiInterfaceBase {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// contrato general para todas las interfaces que hereden de esta
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;public interface MiInterfaceLocal extends MiInterfaceBase {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// contrato concreto para acceso local
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;public interface InterfaceRemote extends MiInterfaceBase {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// contrato concreto para acceso remoto
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;public abstract class MiBeanBase implements MiInterfaceBase {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// implementación general para todas las clases que hereden de esta
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;@Stateless
&lt;br&gt;@Local(MiInterfaceLocal.class)
&lt;br&gt;public class MiBeanLocal extends MiBeanBase implements MiInterfaceLocal {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// implementación concreta para acceso local
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;@Stateless
&lt;br&gt;@Remote(MiInterfaceRemote.class)
&lt;br&gt;public class MiBeanRemote extends MiBeanBase implements MiInterfaceRemote {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// implementación concreta para acceso remoto
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;En este tutorial los ejemplos se mantendrán siempre lo más simple posibles, pues a efectos lectivos toda la parafernalia del ejemplo anterior no es necesaria (de hecho es contraproducente). El aspecto clave a recordar estriba en no declarar una misma interface (repito, en el sentido de &lt;i&gt;contrato&lt;/i&gt;) de tipo local y remota al mismo tiempo.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.4 EJB CONTEXT Y SESSION CONTEXT
&lt;br&gt;A veces, necesitamos acceder al contexto de ejecución del componente que se está usando. &lt;code&gt;EJBContext&lt;/code&gt; (Contexto de EJB) es una interface que provee acceso al contexto de ejecución asociado a cada instancia de un componente EJB. A través de él podemos acceder, por ejemplo, al servicio de seguridad: imaginemos que invocamos un método en un Session Bean dentro de una aplicación donde hay restricciones de seguridad, de manera que el Session Bean necesita comprobar si el cliente que lo está invocándo está autorizado o no a hacerlo. A través del contexto de ejecución de dicho Session Bean podemos acceder al servicio de seguridad y realizar dicha comprobación. Otros ejemplos del uso del contexto de ejecución son el acceso a transacciones, u obtener el Timer Service (Servicio de Reloj, necesario para programar eventos mediante unidades de tiempo, como veremos en un artículo posterior).
&lt;br&gt;
&lt;br&gt;&lt;code&gt;SessionContext&lt;/code&gt; (Contexto de Sesión) es una interface que implementa &lt;code&gt;EJBContext&lt;/code&gt;, añadiendo métodos que permiten el uso de servicios adicionales. A través de él podemos, por ejemplo, obtener una referencia al Session Bean actual para poder pasarla a otro Session Bean como argumento de un método; esto es necesario, pues el contenedor no permite pasar el Session Bean actual usando una referencia de tipo &lt;code&gt;this&lt;/code&gt; (los detalles de porqué esto es así no son necesarios para entender el material, y por tanto los omito). Podemos acceder al contexto de sesión asociado a la instancia del componente actual mediante inyección de dependencia (asunto que se explicará en la sección 2.5):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Local
&lt;br&gt;@Stateless
&lt;br&gt;public class MiBean {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Resource
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private SessionContext contexto;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Mediante la anotación &lt;code&gt;@Resource&lt;/code&gt; (Recurso) indicamos al contenedor que debe inyectar el contexto de sesión asociado a dicha instancia en la variable &lt;code&gt;contexto&lt;/code&gt; (cuando veamos el ciclo de vida de los componentes EJB se verá cómo y cuándo se realiza esta operación). Otra manera de acceder al contexto de sesión es usando la misma anotación, pero sobre un método setter que siga el estandar JavaBean (no confundir con Enterprise JavaBean):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Local
&lt;br&gt;@Stateless
&lt;br&gt;public class MiBean {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private SessionContext contexto;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Resource
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setContexto(SessionContext contexto) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.contexto = contexto;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Puesto que &lt;code&gt;SessionContext&lt;/code&gt; extiende &lt;code&gt;EJBContext&lt;/code&gt;, podemos acceder a ambas interfaces desde la primera. Es muy importante que tengas presente que ciertos métodos en &lt;code&gt;EJBContext&lt;/code&gt; están marcados como &lt;i&gt;deprecated&lt;/i&gt;, y además lanzarán una excepción de tipo &lt;code&gt;RuntimeException&lt;/code&gt; si son invocados. Te recomiendo que, por este motivo, consultes la API de &lt;code&gt;EJBContext&lt;/code&gt; en la &lt;a href=&quot;http://download.oracle.com/javaee/6/api/javax/ejb/EJBContext.html&quot;&gt;siguiente dirección&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.5 INYECCIÓN DE DEPENDENCIAS
&lt;br&gt;La inyección de dependencias (Dependency Injection) es un proceso por el cual el contenedor puede &lt;i&gt;inyectar&lt;/i&gt; en un componente recursos que son necesarios. Un ejemplo de inyección de dependencia lo vimos en la sección anterior, donde usamos la anotación &lt;code&gt;@Resource&lt;/code&gt; para inyectar una instancia de &lt;code&gt;SessionContext&lt;/code&gt; en un SLSB. Otro ejemplo de inyección de dependencia surje cuando uno de nuestros componentes necesita de otro componente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class UnComponente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private OtroComponente dependencia;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String metodo() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return dependencia.otroMetodo();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, el Session Bean &lt;code&gt;UnComponente&lt;/code&gt; requiere otro Session Bean de tipo &lt;code&gt;OtroComponente&lt;/code&gt;. Puesto que, como ya se ha explicado, el contenedor EJB gestiona el ciclo de vida de todos los componentes (toda la aplicación EJB funciona en un entorno gestionado), una instanciación del tipo &lt;code&gt;new OtroComponente()&lt;/code&gt; sería incorrecta (esta instancia no tendría, por ejemplo, un contexto de sesión asociado, pues ha sido inicializada manualmente). La solución consiste en informar al contenedor de dicha dependencia mediante la anotación &lt;code&gt;@EJB&lt;/code&gt;, dejando así en sus manos esta tarea:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Local
&lt;br&gt;@Stateless(name=&quot;otroComponente&quot;)
&lt;br&gt;public class OtroComponente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String otroMetodo() { 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ... 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class UnComponente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@EJB(beanName=&quot;otroComponente&quot;)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private OtroComponente dependencia;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String metodo() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return dependencia.otroMetodo();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Gracias a la anotación &lt;code&gt;@EJB&lt;/code&gt; el contenedor sabe que componente instanciar, inicializar, y finalmente inyectar en la variable &lt;code&gt;dependencia&lt;/code&gt;. En el ejemplo anterior, se registra un Session Bean con nombre &lt;code&gt;otroComponente&lt;/code&gt; (gracias a &lt;code&gt;@Stateless(name=&quot;otroComponente&quot;)&lt;/code&gt;), el cual puede ser accedido mediante inyección de dependencia gracias a &lt;code&gt;@EJB(beanName=&quot;otroComponente&quot;)&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;La inyección de dependencias es una poderosa carecterística de EJB que libera al programador de muchas responsabilidades, ademas de resultar en código poco acoplado y apto para unit testing (entre otras buenas cualidades). Puedes encontrar más información sobre la anotación &lt;code&gt;@EJB&lt;/code&gt; en la &lt;a href=&quot;http://download.oracle.com/docs/cd/E11035_01/wls100/ejb30/annotations.html#wp1416481&quot;&gt;aquí&lt;/a&gt; y sobre la anotación &lt;code&gt;@Resource&lt;/code&gt; &lt;a href=&quot;http://download.oracle.com/javaee/5/tutorial/doc/bncjk.html&quot;&gt;aquí&lt;/a&gt; (ambas páginas en inglés).
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;
&lt;br&gt;2.6 COMPONENTES DEL LADO DEL SERVIDOR
&lt;br&gt;La primera pregunta que nos debemos hacer es: ¿Que es un componente del lado del servidor?. No es ni más ni menos que un componente que es gestionado de manera integra por el contenedor. Esto es, el cliente del componente no interacciona con el componente en si, si no con una representación (referencia/proxy/vista) del componente real. Los componentes del lado del servidor son dos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Todos los Session Bean (Stateless, Stateful, y Singleton)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Message-Driven Beans
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En este artículo veremos los dos primeros tipos de Session Beans, y dejaremos el componente Singleton y los Message-Driven Beans para el próximo artículo. Ahora otra buena pregunta sería: ¿Que NO es un componente del lado del servidor? La respuesta es: Entity Beans (EB - entidades). Los EB viajan entre el cliente y el servidor siendo siempre la representación del mismo objeto Java en ambos lados. Todo lo relacionado con EB se tratará en el capítulo relacionado con persistencia (si estás interesado en este tema puedes visitar un tutorial sobre Java Persistent API (JPA - API de Persistencia en Java) publicado en esta misma web en la &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=144&quot;&gt;siguiente dirección&lt;/a&gt;).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.7 STATELESS SESSION BEANS: CONCEPTOS BÁSICOS
&lt;br&gt;Como vimos brevemente en el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=239&quot;&gt;primer artículo&lt;/a&gt; del tutorial, los Stateless Session Bean (SLSB - Session Bean Sin Estado) son aquellos que no mantienen estado entre diferentes invocaciones de sus métodos. Podriamos considerar cada método dentro de un SLSB como un servicio en si mismo, que realiza una tarea y devuelve un resultado (puede no hacerlo) sin depender de invocaciones anteriores o posteriores sobre él mismo o sobre otro método. Debido a este comportamiento, el contenedor puede utilizar un número relativamente bajo de SLSB's para servir llamadas de muchos clientes (ya que ninguno de estos clientes estará asociado a un SLSB en concreto), y por ello son muy eficientes. El hecho de no mantener un estado entre invocaciones los hace aún más eficientes.
&lt;br&gt;
&lt;br&gt;Es importante destacar que un SLSB si puede mantener un estado interno, aunque este no debe escapar nunca hacia el cliente. Un ejemplo de este estado interno sería una variable que almacenara el número de veces que una instancia en concreto ha sido invocada: un cliente que dependa del valor de esta variable podría obtener un resultado distinto en cada llamada al SLSB, ya que el contenedor no garantiza devolver la misma instancia al mismo cliente. La regla es: si un SLSB mantiene estado, este debe ser interno (invisible para el cliente).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.8 STATELESS SESSION BEANS: EL CICLO DE VIDA
&lt;br&gt;El ciclo de vida de un componente describe los distintos estados (gestionados íntegramente por el contenedor) por los que puede pasar cada instancia del componente desde que es creada hasta que es destruida. Para los SLSB, este ciclo de vida es muy simple y consta únicamente de dos estados (incluyo el término original en inglés):
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No existe (Does not exists)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Preparado en pool (Method-ready pool)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;El primer estado, &lt;i&gt;no existe&lt;/i&gt;, es autoexplicativo: la instancia del SLSB no ha sido creada aún.  El segundo estado, &lt;i&gt;Preparado en pool&lt;/i&gt;, representa una instancia del SLSB que ha sido instanciada y construida por el contenedor, y se encuentra en el pool lista para recibir invocaciones por parte de un cliente (cuando esta invocación sucede, la instancia es extraida el pool y asociada a una referencia que es pasada al cliente). A este estado se llega durante el arranque del contenedor (el pool es poblado con cierto número de instancias), y cuando no existan suficientes instancias en el pool para servir llamadas de clientes (y por tanto se deban crear más). En resumen, siempre que una nueva instancia del SLSB sea creada.
&lt;br&gt;
&lt;br&gt;Durante la transición entre el primer estado y el segundo, el contenedor realizará tres operaciones (en este orden):
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Instanciación del SLSB
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Inyección de cualquier recurso necesario y de dependencias
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Ejecución de un método dentro del SLSB marcado con la anotación &lt;code&gt;@PostConstruct&lt;/code&gt;, si existe
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;La instanciación del SLSB se lleva a cabo mediante reflexión, a traves de &lt;code&gt;Class.newInstance()&lt;/code&gt;. Por tanto, el SLSB debe tener un constructor por defecto (sin argumentos), ya sea de forma implícita o explícita.
&lt;br&gt;
&lt;br&gt;La inyección de recursos y de dependencias se vio en las secciones 2.4 y 2.5, donde se utilizaron las anotaciones &lt;code&gt;@Resource&lt;/code&gt;  y &lt;code&gt;@EJB&lt;/code&gt; para tales efectos. Estos y otros recursos son inyectados en el SLSB de forma automática por el contenedor durante esta operación. De manera adicional, cada vez que un SLSB sea invocado por un nuevo cliente, todos los recursos son inyectados de nuevo.
&lt;br&gt;
&lt;br&gt;Por último, el contenedor ejecutará un método dentro del SLSB que esté anotado con &lt;code&gt;@PostConstruct&lt;/code&gt; (Post construcción), si existe. Esta anotación declara dicho método (que puede ser uno y solo uno) como un &lt;i&gt;método callback&lt;/i&gt;, esto es, un método que reacciona ante cierto evento (en este caso, a la construcción de la instancia, como su propio nombre indica). Dentro de este método tenemos la oportunidad de adquirir recursos adicionales necesarios para el SLSB, como una conexión de red o de base de datos. Este método debe ser &lt;code&gt;void&lt;/code&gt;, no aceptar parámetros, y no lanzar ninguna excepción de tipo &lt;i&gt;checked&lt;/i&gt;. Al contrario que la inyección de recursos, la ejecución del método &lt;code&gt;@PostConstruct&lt;/code&gt; se ejecuta una y solo una vez (al final de la instanciación del componente).
&lt;br&gt;
&lt;br&gt;Cuando el contenedor no necesita una instancia de SLSB, ya sea porque decide reducir el número de instancias en el pool, o porque se está produciendo un shutdown del servidor, se realiza una transición en sentido inverso: del estado &lt;i&gt;preparado en pool&lt;/i&gt; al estado &lt;i&gt;no existe&lt;/i&gt;. Durante esta transición se ejecutará, si existe, un método anotado con &lt;code&gt;@PreDestroy&lt;/code&gt; (Pre destrucción), el cual es también un &lt;i&gt;método callback&lt;/i&gt;, y el cual nos da la oportunidad de liberar cualquier recurso adquirido durante la construcción de la instancia (adquisición que hicimos en &lt;code&gt;@PostConstruct&lt;/code&gt;). Al igual que ocurría con &lt;code&gt;@PostConstruct&lt;/code&gt;, un método anotado con &lt;code&gt;@PreDestroy&lt;/code&gt; es opcional, debe ser &lt;code&gt;void&lt;/code&gt;, no aceptar parámetros, no lanzar ninguna excepción de tipo &lt;i&gt;checked&lt;/i&gt;, solo puede ser usado en un único método, y es ejecutado una y solo una vez (durante la destrucción de la instancia).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.9 STATELESS SESSION BEANS: UN SENCILLO EJEMPLO
&lt;br&gt;Supongamos que estamos desarrollando una aplicación de banca, y entre otras cosas necesitamos escribir código que represente los conceptos de ingreso, retirada, y transferencia de efectivo. Estos tres conceptos son operaciones que no requieren mantener un estado dentro de la aplicación (esto es, una vez invocadas y terminadas no dependen de otras operaciones) y por tanto son excelentes candidatas para ser representadas mediante un Session Bean de tipo Stateless. Como ya hemos visto en multitud de ejemplos, para declarar un Session Bean de tipo Stateless utilizamos la anotación &lt;code&gt;@Stateless&lt;/code&gt; (se omiten otras anotaciones como &lt;code&gt;@Remote&lt;/code&gt; o &lt;code&gt;@Local&lt;/code&gt;, así como todo código no estrictamente necesario para explicar el tema tratado; desde este momento se dará por hecho esto en la mayoría de los ejemplos que veamos):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;import javax.ejb.Stateless;
&lt;br&gt;import es.davidmarco.ejb.modelo.Cuenta;
&lt;br&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class OperacionesConEfectivo {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void ingresarEfectivo(Cuenta cuenta, double cantidad) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ingresar cantidad en cuenta
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void retirarEfectivo(Cuenta cuenta, double cantidad) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//retirar cantidad de cuenta
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void transferirEfectivo(Cuenta cuentaOrigen, Cuenta cuentaDestino, double cantidad) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// transferir cantidad de cuenta origen a cuenta destino
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La clase &lt;code&gt;Cuenta&lt;/code&gt; representa una cuenta bancaria, y teóricamente lo representaríamos mediante un componente de tipo Entity Bean (Bean de Entidad), los cuales veremos en el cuarto artículo de este tutorial. Lo realmente importante del ejemplo anterior es el concepto de operaciones que no requieren estado, y por tanto pueden ser representadas mediante Session Beans de tipo Stateless.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.10 STATEFUL SESSION BEANS: CONCEPTOS BÁSICOS
&lt;br&gt;Al contrario que los Session Bean de tipo Stateless, los Stateful Session Bean (SFSB - Session Bean con Estado) mantienen estado entre distintas invocaciones de un mismo cliente. Podríamos considerar un SFSB como una extensión del cliente en el contenedor, ya que cada SFSB está dedicado de manera exclusiva a un único cliente durante todo su ciclo de vida. Otra diferencia entre SLSB y SFSB es que estos últimos no son almacenados en un pool, pues no son reusados, como veremos en la sección 2.11 cuando expliquemos su ciclo de vida.
&lt;br&gt;
&lt;br&gt;¿A que nos referimos cuando decimos que un SFSB mantiene un estado? La cuestión es simple: un SFSB almacena información a consecuencia de las operaciones que realiza en él su cliente asociado, y dicha información (estado) debe estar disponible en invocaciones posteriores. De esta manera, un SFSB puede realizar una acción compleja mediante multiples invocaciones. Un ejemplo muy común es el carrito de la compra de una tienda online; añadimos y eliminamos artículos del carrito en diferentes invocaciones, lo cual sería imposible de realizar con un SLSB.
&lt;br&gt;
&lt;br&gt;A pesar de mantener estado, un SFSB no es persistente, de manera que dicho estado se pierde cuando la sesión del cliente asociado termina. Su misión es servir como lógica de negocio (misión de todos los Session Bean) y nada más. Para persistir dicha información deberemos usar otro tipo de componente EJB (Entity Bean) el cual veremos en el artículo sobre persistencia.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.11 STATEFUL SESSION BEANS: EL CICLO DE VIDA
&lt;br&gt;El ciclo de vida de un SFSB es ligeramente más complejo que el de su hermano pequeño SLSB, y consta de tres estados:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No existe (Does not exists)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Preparado (Method-ready)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Pasivo (Passive)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;El primer estado, &lt;i&gt;no existe&lt;/i&gt;, es similar al de un SLSB: la instancia del SFSB no ha sido creada aún. El segundo estado, &lt;i&gt;preparado&lt;/i&gt;, representa una instancia del SFSB que ha sido construida e inicializada, y está lista para servir llamadas de su cliente asociado (recuerda que esta asociación perdura durante toda la vida del SFSB). El tercer estado, &lt;i&gt;pasivo&lt;/i&gt;, representa un SFSB que, después de un periodo de inactividad, es persistido temporalmente para liberar recursos del servidor.
&lt;br&gt;
&lt;br&gt;Durante la transición entre el primer estado y el segundo, el contenedor realizará las siguientes tres operaciones:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Instanciación del SFSB
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Inyección de cualquier recurso necesario y de dependencias, y asociación con el cliente
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Ejecución de un método dentro del SFSB marcado con la anotación &lt;code&gt;@PostConstruct&lt;/code&gt;, si existe
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;La instanciación del SFSB se lleva a cabo mediante reflexión, a traves de &lt;code&gt;Class.newInstance()&lt;/code&gt;. Por tanto, el SFSB debe tener un constructor por defecto (sin argumentos), ya sea de forma implícita o explícita.
&lt;br&gt;
&lt;br&gt;La inyección de recursos y de dependencias se vio en las secciones 2.4 y 2.5, donde se utilizaron las anotaciones &lt;code&gt;@Resource&lt;/code&gt;  y &lt;code&gt;@EJB&lt;/code&gt; para tales efectos. Estos y otros recursos son inyectados en el SFSB de forma automática por el contenedor durante esta operación. Una vez finaliza la inyección de recursos y dependencias, el SFSB es asociado al cliente que ha generado su creación.
&lt;br&gt;
&lt;br&gt;Por último, el contenedor ejecutará un método dentro del SFSB que esté anotado con &lt;code&gt;@PostConstruct&lt;/code&gt; (Post construcción), si existe. Esta anotación declara dicho método (que puede ser uno y solo uno) como un &lt;i&gt;método callback&lt;/i&gt;, esto es, un método que reacciona ante cierto evento (en este caso, a la construcción de la instancia, como su propio nombre indica). Al igual que con un SLSB, la función de este método es adquirir recursos adicionales que sean necesarios para el SFSB, como una conexión de red o de base de datos. Y también al igual que su homónimo en un SLSB, este método debe ser &lt;code&gt;void&lt;/code&gt;, no aceptar parámetros, no lanzar ninguna excepción de tipo &lt;i&gt;checked&lt;/i&gt;, y no ser &lt;code&gt;static&lt;/code&gt; ni &lt;code&gt;final&lt;/code&gt;. La ejecución del método &lt;code&gt;@PostConstruct&lt;/code&gt; se ejecuta una y solo una vez, al final de la instanciación del componente. En este momento, el SFSB ya se encuentra en el estado &lt;i&gt;preparado&lt;/i&gt;, y procede a servir la llamada del cliente que ha generado la creación de la instancia.
&lt;br&gt;
&lt;br&gt;Por último, un SFSB en estado &lt;i&gt;preparado&lt;/i&gt; puede realizar una transición a cualquiera de los otros dos estados de su ciclo de vida: &lt;i&gt;no existe&lt;/i&gt; o &lt;i&gt;pasivo&lt;/i&gt;. La transición al estado &lt;i&gt;no existe&lt;/i&gt; ocurre cuando:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- El cliente ejecuta un método dentro del SFSB anotado con &lt;code&gt;@Remove&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- El SFSB sobrepasa un periodo de inactividad establecido (timeout)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En el primer caso, la ejecución de un método anotado con &lt;code&gt;@Remove&lt;/code&gt; informa al contenedor que el cliente ha terminado de usar su SFSB asociado y, por tanto, dicha instancia ya no es necesaria. En este momento la instancia es desasociada de su contexto de sesión y eliminada. Este método no es de tipo &lt;i&gt;callback&lt;/i&gt; (como &lt;code&gt;@PostConstruct&lt;/code&gt; o &lt;code&gt;@PreDestroy&lt;/code&gt;), pues no reacciona a un evento, si no que es ejecutado explicitamente por el cliente. En el segundo caso (timeout), el SFSB ha sobrepasado un periodo de tiempo establecido y el contenedor decide eliminarlo, previa ejecución de un método (uno y solo uno) anotado con &lt;code&gt;@PreDestroy&lt;/code&gt;, y con iguales reglas que en su homónimo en SLSB: opcional, void, sin parámetros, sin excepciones de tipo &lt;i&gt;checked&lt;/i&gt;, no &lt;code&gt;static&lt;/code&gt;, y no &lt;code&gt;final&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;Por otro lado, la transición al estado &lt;i&gt;pasivo&lt;/i&gt; se produce cuando el contenedor decide liberar recursos, persistiendo de manera temporal el estado del SFSB. La pasivación y posterior activación de un SFSB requiere una sección exclusiva que veremos enseguida.
&lt;br&gt;
&lt;br&gt;Por finalizar con el ciclo de vida de un componente SFSB, ten presente que si este lanza una excepción de sistema (cualquiera de tipo &lt;i&gt;unchecked&lt;/i&gt; cuya definición no esté anotada con &lt;code&gt;@ApplicationException&lt;/code&gt;), se producirá una transición al estado &lt;i&gt;no existe&lt;/i&gt; sin llamar a su método &lt;code&gt;@PreDestroy&lt;/code&gt;. Este comportamiento no está muy bien comprendido entre cierta parte de la comunidad, pues a todas luces no parece muy correcto, pero es así y debes tenerlo en cuenta.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.12 STATEFUL SESSION BEANS: PASIVACIÓN Y ACTIVACIÓN
&lt;br&gt;Durante la vida de un SFSB, el contenedor puede decidir liberar recursos persistiendo de manera temporal el estado de dicho SFSB, liberando de esta manera memoria del sistema (u otros recursos). A esto lo llamamos &lt;i&gt;pasivación&lt;/i&gt;. Si durante la pasivación el cliente realiza una llamada al SFSB, el contenedor recreará en memoria la instancia persistida y procedera con dicha llamada; a esto lo llamamos &lt;i&gt;activación&lt;/i&gt;. Todo el ciclo de activación-pasivación puede ocurrir múltiples veces en la vida de un SFSB, o ninguna en absoluto. Sea como sea, es un proceso gestionado por el contenedor y totalmente transparence al cliente, el cual no sabe en ningún momento si se ha producido una pasivación o activación del SFSB asociado a su sesión.
&lt;br&gt;
&lt;br&gt;No toda la información (estado) almacenada en un SFSB puede ser persistida. Los siguientes tipos son pasivados por defecto:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Todos los tipos primitivos
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Objetos que implementan la interface &lt;code&gt;Serializable&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Referencias a factorias de recursos gestionados por el contenedor (como &lt;code&gt;javax.sql.DataSource&lt;/code&gt;)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Referencias a otros componentes EJB
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- &lt;code&gt;javax.ejb.SessionContext&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- &lt;code&gt;javax.jta.UserTransaction&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- &lt;code&gt;javax.naming.Context&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- &lt;code&gt;javax.persistence.EntityManager&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- &lt;code&gt;javax.persistence.EntityManagerFactory&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Para todos los demás tipos, la especificación EJB nos proporciona dos métodos &lt;i&gt;callback&lt;/i&gt; para controlar la pasivación-activación de un SFSB cuando existen datos que no deben/pueden ser persistidos: &lt;code&gt;@PrePassivate&lt;/code&gt; (Pre-pasivación) y &lt;code&gt;@PostActivate&lt;/code&gt; (Post-activación). Ambas anotaciones son aplicadas en métodos dedicados a controlar cada uno de los procesos, según corresponda (en la sección 2.13 veremos un ejemplo de un SFSB con métodos de pasivación y activación).
&lt;br&gt;
&lt;br&gt;&lt;code&gt;@PrePassivate&lt;/code&gt; nos permite anotar un método (opcional) que deje el SFSB es un estado adecuado para su pasivación. Puesto que la pasivación se lleva a cabo mediante serialización, todas las referencias a objetos no serializables deben ser puestas a &lt;code&gt;null&lt;/code&gt;. Otra operacion llevada a cabo mediante &lt;code&gt;@PrePassivate&lt;/code&gt; es la liberación de recursos que no pertenezcan a la lista anterior. Una vez ejecutado el método &lt;code&gt;@PrePassivate&lt;/code&gt;, el SFSB es serializado y persistido temporalmente (tal vez en disco, en una cache, etc; esto es decisión de cada implementación de EJB). Es importante tener en cuenta que si un SFSB en estado &lt;i&gt;pasivo&lt;/i&gt; sobrepasa un periodo de inactividad establecido (timeout), el contenedor eliminará la instancia persistida sin ejecutar su método &lt;code&gt;@PreDestroy&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;Si durante la pasivación el cliente asociado realiza una llamada al SFSB, el contenedor realizará la activación del componente, deserializando la instancia desde el lugar donde se encuentra persistida, restaurándola al estado anterior a producirse la pasivación (inyección del contexto de sesión, inyección de referencias a otros componentes EJB, etc), y ejecutando un método anotado con &lt;code&gt;@PostActivate&lt;/code&gt; (también opcional). En este método podemos inicializar todos los objetos no serializables a unos valores adecuados (no debes confiar en los valores por defecto que el contenedor da a objetos no serializables, pues entre implementaciones pueden ser diferentes), así como restaurar cualquier recurso necesario para el correcto funcionamiento del SFSB. Una vez que la activación ha concluido, el SFSB puede gestionar la llamada del cliente que generó dicha activación.
&lt;br&gt;
&lt;br&gt;Tanto &lt;code&gt;@PrePassivate&lt;/code&gt; como &lt;code&gt;@PostActivate&lt;/code&gt; deben seguir las siguientes reglas:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- El tipo de retorno debe ser &lt;code&gt;void&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No puede aceptar ningún parámetro
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No puede lanzar ninguna excepción de tipo &lt;code&gt;checked&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No puede ser &lt;code&gt;static&lt;/code&gt; ni &lt;code&gt;final&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Estas reglas son las que se han aplicado a todos los métodos &lt;code&gt;callback&lt;/code&gt; vistos hasta ahora, por lo que una vez aprendidas podrás aplicarlas fácilmente cuando escribas cualquier método &lt;i&gt;callback&lt;/i&gt;.
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;
&lt;br&gt;2.13 STATEFUL SESSION BEANS: UN EJEMPLO SENCILLO
&lt;br&gt;Supongamos que estamos diseñando una aplicación de tienda online, con un carrito de la compra donde los clientes pueden añadir artículos, eliminarlos, vaciar el carrito, o realizar un pedido. Puesto que cada una de estas operaciones se lleva a cabo de manera independiente a las demas, pero los cambios de cada una de ellas pueden afectar al resto, necesitamos mantener un estado entre distintas invocaciones, y por tanto un componente Session Bean de tipo Stateful. Para declarar un SFSB usamos la anotación &lt;code&gt;@Stateful&lt;/code&gt; y hacemos que la clase en cuestión implemente la interface &lt;code&gt;Serializable&lt;/code&gt; (puesto que es este el mecanismo que utilizará el contenedor para la pasivación-activación). El ejemplo, como siempre, es una estructura básica sin apenas implementación: el objetivo del ejemplo es únicamente mostrar donde encaja cada pieza:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.sfsb;
&lt;br&gt;
&lt;br&gt;import java.io.Serializable;
&lt;br&gt;import java.util.HashMap;
&lt;br&gt;import java.util.Map;
&lt;br&gt;import javax.annotation.PostConstruct;
&lt;br&gt;import javax.annotation.PreDestroy;
&lt;br&gt;import javax.ejb.PostActivate;
&lt;br&gt;import javax.ejb.PrePassivate;
&lt;br&gt;import javax.ejb.Remove;
&lt;br&gt;import javax.ejb.Stateful;
&lt;br&gt;import es.davidmarco.ejb.modelo.Articulo;
&lt;br&gt;import es.davidmarco.ejb.util.BaseDeDatos;
&lt;br&gt;
&lt;br&gt;@Stateful
&lt;br&gt;public class Carrito implements Serializable {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Map&lt;Articulo, Integer&gt; articulosEnCarrito = new HashMap&lt;Articulo, Integer&gt;();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private BaseDeDatos bbdd;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void añadirArticulo(Articulo articulo, int cantidad) { 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// añadir la cantidad de cierto artículo al carrito
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void eliminarArticulo(Articulo articulo, int cantidad) { 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// eliminar la cantidad de cierto artículo del carrito
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void vaciarCarrito() { 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// vaciar el carrito
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Remove
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void finalizarCompra() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// procesar el pedido
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostConstruct
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostActivate
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void inicializar() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// obtener conexión con la base de datos
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PrePassivate
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PreDestroy
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void detener() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// liberar conexión con la base de datos
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Como puedes ver, la clase &lt;code&gt;Carrito&lt;/code&gt; está anotada con &lt;code&gt;@Stateful&lt;/code&gt; y marcada como &lt;code&gt;Serializable&lt;/code&gt;. Dentro de ella tenemos dos campos: &lt;code&gt;artículosEnCarrito&lt;/code&gt;, donde se almacena el estado requerido para el correcto funcionamiento del proceso de compra (&lt;code&gt;HashMap&lt;/code&gt; es de tipo &lt;code&gt;Serializable&lt;/code&gt; y por tanto es persistida de forma automática en caso de pasivación), y &lt;code&gt;BaseDeDatos&lt;/code&gt;, que es una clase ficticia que supuestamente nos permite realizar operaciones sobre una base de datos, pero no puede ser pasivada (supongamos que mantiene una conexión con una base de datos real que no puede permanecer abierta durante la pasivación). 
&lt;br&gt;
&lt;br&gt;Dentro de la clase, los cuatro primeros métodos nos permiten realizar operaciones de lógica de negocio, como añadir cierta cantidad de cierto artículo al carrito, vaciar el carrito completamente, o procesar el pedido una vez añadidos los artículos deseados. El cuarto método (&lt;code&gt;finalizarCompra&lt;/code&gt;), de manera adicional, indica al contenedor que hemos terminado de trabajar con el componente SFSB y que por tanto puede eliminarlo (gracias a la anotación &lt;code&gt;@Remove&lt;/code&gt;). Estos cuatro métodos son la interface que mostramos al cliente, y por tanto todos ellos son declarados &lt;code&gt;public&lt;/code&gt;. 
&lt;br&gt;
&lt;br&gt;Los dos últimos métodos (&lt;code&gt;inicializar&lt;/code&gt; y &lt;code&gt;detener&lt;/code&gt;) se encargar de obtener y liberar recursos en momentos clave del ciclo de vida del SFSB. Fíjate como &lt;code&gt;@PostConstruct&lt;/code&gt; y &lt;code&gt;@PostActivate&lt;/code&gt; anotan el mismo método, pues todas las operaciones que hay en él son comunes a los procesos de construcción del SFSB y una posible activación posterior. De igual manera, &lt;code&gt;@PrePassivate&lt;/code&gt; y &lt;code&gt;@PreDestroy&lt;/code&gt; acompañan al mismo método, por el mismo motivo. Ambos métodos, de tipo &lt;i&gt;callback&lt;/i&gt;, son gestionados por el contenedor en base a eventos, y por tanto el cliente del SFSB no necesita saber de su existencia (nosotros los hemos declarado &lt;code&gt;private&lt;/code&gt;, aunque cualquier nivel de visibilidad está permitido).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;2.14 RESUMEN
&lt;br&gt;En este segundo artículo del tutorial de EJB hemos visto conceptos relacionados con la tecnología EJB, como la definición del pool, local vs remoto, metadatos, inyección de dependencias, y contexto de sesión. Ademas, hemos visto en cierta profundidad los dos tipos de Session Bean más comunes: Stateless y Stateful.
&lt;br&gt;
&lt;br&gt;En el próximo artículo veremos el tercer y último tipo de Session Bean (Singleton) así como un nuevo tipo de componente: Message-Driven Beans. Hasta entonces, ¡feliz inyección de dependencias!</description>
    </item>
    <item>
      <title>Introducción a EJB 3.1 (III)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=241</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=241</guid>
      <pubDate>Mon, 28 Mar 2011 22:11:52 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>En el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=240&quot;&gt;artículo anterior&lt;/a&gt; vimos algunos conceptos comunes a los componentes de una aplicación EJB, como el contexto de sesión, o la diferencia entre remoto y local. Además, vimos en cierta profundidad los dos tipos de Session Bean más comunes en una aplicación EJB: Stateless y Stateful. En este artículo vamos a ver el último tipo de Session Bean (Singleton Session Bean), dos conceptos aplicables a todos los Session Bean y que son nuevos en la especificación EJB 3.1 (vista sin interface y llamadas asíncronas), y finalmente un nuevo tipo de componente: Message-Driven Bean. Comencemos.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.1 SINGLETON SESSION BEANS: CONCEPTOS BÁSICOS
&lt;br&gt;El Singleton Session Bean (no existe una traducción literal de la palabra &lt;i&gt;Singleton&lt;/i&gt;, pero viene a expresar el concepto de &lt;i&gt;instancia única&lt;/i&gt;; desde ahora nos referiremos a este componente como &lt;i&gt;Singleton&lt;/i&gt; a secas) es un nuevo tipo de Session Bean introducido en la especificación EJB 3.1. Este componente expresa claramente el patrón de diseño &lt;i&gt;Singleton&lt;/i&gt; definido por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides en su libro &lt;i&gt;Design Patterns: Elements of Reusable Object Oriented Software&lt;/i&gt;. Este patrón de diseño garantiza que de una clase dada solamente pueda crearse una instancia, con un punto de acceso global para acceder a dicha instancia. La naturaleza única de un componente Singleton conlleva un alto rendimiento dentro del contenedor para este tipo de Session Bean.
&lt;br&gt;
&lt;br&gt;Es importante tener en cuenta la sutil diferencia entre un componente de tipo Singleton y cualquiera de los otros dos tipos de Session Bean (SLSB y SFSB): cuando un cliente hace una llamada a un método de un SLSB o SFSB, puesto que la instancia del Session Bean está asociada a ese cliente en concreto (durante la invocación del metodo para un SLSB, y durante toda la duración de la sesión para un SFSB), un único thread (hilo de ejecución) es capaz de acceder a dicho método, y por tanto el componente es seguro en terminos de multi-threading (ejecución de múltiples hilos). Sin embargo, cuando trabajamos con un Singleton, multiples llamadas en paralelo pueden estar produciendose en un momento dado a su única instancia, y por tanto el componente debe garantizar que un hilo de ejecución no está interfiriendo con otro hilo de ejecución, produciendo resultados incorrectos. Dicho de otra manera, un componente Singleton debe ser &lt;i&gt;concurrente&lt;/i&gt;;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.2 SINGLETON SESSION BEANS: CONCURRENCIA BÁSICA
&lt;br&gt;Debido a la naturaleza de los Session Bean de tipo Singleton, tenemos que tener muy claros ciertos aspectos al diseñar este tipo de componente. Veamos un ejemplo de una clase donde no tenemos en cuenta la cuestión de concurrencia:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;class ClaseNoConcurrente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private int numeroDeInvocacionesDeEstaInstancia = 0;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int metodoUno() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// lógica de negocio
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return numeroDeEjecuciones++;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int metodoDos() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// lógica de negocio
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return numeroDeEjecuciones++;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En la clase del ejemplo anterior, no se ha tenido en cuenta el aspecto de concurrencia (lo cual, dependiendo de las especificaciones del problema de negocio que queremos resolver, puede ser perfectamente legal). Una consecuencia de esto es que, cuando intervienen múltiples hilos de ejecución en paralelo, una llamada al cualquiera de los métodos &lt;code&gt;metodoXxx&lt;/code&gt; puede devolver un resultado incorrecto. Veamos una posibilidad (entre muchas permitidas por la JVM) de la ejecución de esta clase por varios clientes:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1. Un cliente C-1 llama a &lt;code&gt;metodoUno()&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2. El cliente C-1 obtiene el valor 1 para el número de ejecuciones
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3. Un cliente C-2 llama a &lt;code&gt;metodoUno()&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4. Un cliente C-3 llama a &lt;code&gt;metodoDos()&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;6. El cliente C-3 obtiene el valor 2 para el número de ejecuciones
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;7. El cliente C-2 obtiene el valor 2 para el número de ejecuciones
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;¿Que ha ocurrido en el ejemplo anterior? El cliente C-2 cree que los métodos &lt;code&gt;metodoXxx&lt;/code&gt; han sido invocados dos veces (punto 7), cuando en realidad se han invocado tres veces (puntos 1, 3, y 4). Esto es debido a que la operación &lt;code&gt;numeroDeEjecuciones++&lt;/code&gt; no es atómica: cuando el código Java es convertido en código de bytes (.class), dicha operación se compone de muchas otras, de manera que la JVM puede para el hilo actual en &lt;i&gt;mitad del incremento&lt;/i&gt; y dar tiempo de ejecución a otro hilo. Incluso aunque la operación fuera atómica, la JVM podría seguir deteniendo un hilo durante la lógica de negocio (antes de realizar el incremento), dando tiempo de ejecución a otro hilo y produciendo de nuevo resultados incorrectos. Puesto que un Singleton es compartido por muchos clientes (accedido por muchos hilos de ejecución) este comportamiento no es aceptable: el Singleton debe ser concurrente.
&lt;br&gt;
&lt;br&gt;La especificación EJB 3.1 nos permite controlar la concurrencia de un Singleton de dos maneras:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Concurrencia Gestionada por el Contenedor (CMC - Contained-Managed Concurrency)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Concurrencia Gestionada por el Bean (BMC - Bean-Managed Concurrency)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Veamos cada una de ellas con cierto detalle.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.3 SINGLETON SESSION BEANS: CONTAINED-MANAGED CONCURRENCY&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Mediante CMC, el contenedor es responsable de gestionar toda la concurrencia en el Singleton mediante metadatos, liberando así al programador de la tarea de escribir código concurrente. Por defecto, todos los componentes Singleton son gestionados por el contenedor, aunque podemos especificarlo de manera explicita mediante la anotación &lt;code&gt;@ConcurrencyManagement&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import javax.ejb.ConcurrencyManagement;
&lt;br&gt;import javax.ejb.ConcurrencyManagementType;
&lt;br&gt;import javax.ejb.Singleton;
&lt;br&gt;
&lt;br&gt;@Singleton
&lt;br&gt;@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
&lt;br&gt;class MiSingleton { 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior hemos definido un componente Singleton mediante la anotación &lt;code&gt;@Singleton&lt;/code&gt;, y hemos indicado al contenedor de forma explícita que gestione por nosotros la concurrencia del componente mediante CMC (aunque, repito, este comportamiento es el ofrecido por defecto para todos los Singleton). Cuando usamos CMC, todos los métodos de la clase tienen por defecto un bloqueo de tipo &lt;i&gt;write&lt;/i&gt; (escritura). Este bloqueo es de utilidad cuando uno o varios métodos deben ser accedidos de manera secuencial (hasta que uno no termine, otro no puede comenzar) para evitar que se obtengan resultados incorrectos. Este acceso secuencial es necesario en casos como el del ejemplo de la sección 3.2, en el que varios métodos &lt;i&gt;escribían&lt;/i&gt; sobre el valor de una variable que después era devuelta al cliente. Como se puede deducir del comportamiento del bloqueo &lt;i&gt;write&lt;/i&gt;, este afecta a todo el objeto, y no a métodos concretos (todos los métodos &lt;i&gt;write&lt;/i&gt; del mismo Singleton deben compartir un único bloqueo).
&lt;br&gt;
&lt;br&gt;Por otro lado, cuando un método realiza solo operaciones de tipo &lt;i&gt;read&lt;/i&gt; (lectura), de manera que no se altera el estado del componente, podemos indicarle al contenedor que no bloquee ninguna invocación a dicho método. De esta manera, el método pueda ser accedido por múltiples hilos de ejecución simultaneamente (puesto que no modificamos el estado del componente, el acceso en paralelo es seguro). Tenemos que indicar que un método es de tipo &lt;i&gt;read&lt;/i&gt; mediante la anotación &lt;code&gt;@Lock&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import javax.ejb.Lock;
&lt;br&gt;import javax.ejb.LockType;
&lt;br&gt;
&lt;br&gt;// ...
&lt;br&gt; 
&lt;br&gt;@Lock(LockType.READ)
&lt;br&gt;public String metodo() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Aunque, como ya se ha dicho, el tipo de bloqueo &lt;i&gt;write&lt;/i&gt; se aplica por defecto, podemos expresarlo de forma explícita mediante &lt;code&gt;@Lock(LockType.WRITE)&lt;/code&gt;. Otra opción que nos brinda CMC es la liberación de un bloqueo automáticamente si este no ocurre tras un tiempo preestablecido (timeout):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import java.util.concurrent.TimeUnit;
&lt;br&gt;import javax.ejb.AccessTimeout;
&lt;br&gt;
&lt;br&gt;// ...
&lt;br&gt;
&lt;br&gt;@AccessTimeout(value=5, unit=TimeUnit.SECONDS)
&lt;br&gt;public String metodo() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.4 SINGLETON SESSION BEANS: BEAN-MANAGED CONCURRENCY
&lt;br&gt;En ocasiones, la concurrencia gestionada por el contenedor no es suficiente (tal vez no nos permite definir con suficiente detalle la manera en la que necesitamos que funcione la concurrencia de nuestra aplicación, por ejemplo). Bean-Managed Concurrency (BMC - Concurrencia Gestionada por el Bean) deja en manos del programador toda la gestión de la concurrencia. Esto puede realizarse utilizando bloques &lt;code&gt;synchronized&lt;/code&gt;, variables atómicas como &lt;code&gt;java.util.concurrent.atomic.AtomicInteger&lt;/code&gt;, etc. Podemos indicar que la concurrencia de un componente Singleton será gestionada íntegramente por el programador mediante la anotación &lt;code&gt;@ConcurrencyManagement&lt;/code&gt; (la cual usamos en la sección anterior para declarar explícitamente el comportamiento contrario, CMC):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import javax.ejb.ConcurrencyManagement;
&lt;br&gt;import javax.ejb.ConcurrencyManagementType;
&lt;br&gt;import javax.ejb.Singleton;
&lt;br&gt;
&lt;br&gt;@Singleton
&lt;br&gt;@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
&lt;br&gt;class OtraClaseConcurrente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Gestión explícita de la concurrencia
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La concurrencia en Java es un tema largo y complejo que no puede ser tratado en este tutorial. Un buen lugar para empezar (en inglés) es &lt;a href=&quot;http://download.oracle.com/javase/tutorial/essential/concurrency/&quot;&gt;The Java Tutorials&lt;/a&gt;. Estoy seguro que existen otras buenas fuentes de información en español, y si estás interesado tu buscador favorito te llevará hasta ellas.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.5 SINGLETON SESSION BEANS: EL CICLO DE VIDA
&lt;br&gt;El ciclo de vida de un Singleton muy parecido al de un SLSB, pues como en este último se compone de los dos mismos estados:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No Existe (Does not exists)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Preparado (Method-ready)
&lt;br&gt;
&lt;br&gt;La diferencia estriba en cuando se crea la única instancia del componente Singleton (tras el despliegue de la aplicación o tras la primera invocación al componente), y en su duración (a lo largo de toda la vida de la aplicación, esto es, hasta que la aplicación sea replegada o el servidor sea parado). Evidentemente, solo el primer comportamiento (el momento de creación) puede ser customizado, y para ello la especificación EJB nos ofrece, como siempre, metadatos. Aunque el contenedor puede decidir inicializar la única instancia de un Singleton en el momento que considere más oportuno, podemos forzar que dicho proceso ocurra durante el despliegue mediante la anotación &lt;code&gt;@Startup&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import javax.ejb.Singleton;
&lt;br&gt;import javax.ejb.Startup;
&lt;br&gt;
&lt;br&gt;@Singleton
&lt;br&gt;@Startup
&lt;br&gt;public class MiSingleton {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El código anterior fuerza al contenedor a crear la única instancia de &lt;code&gt;MiSingleton&lt;/code&gt; en el momento del despliegue de la aplicación EJB de la que forma parte. Esto comportamiento es llamado &lt;i&gt;eager initialization&lt;/i&gt; (inicialización temprana). Ahora supongamos que un Singleton debe ser inicializado antes que otro Singleton (tal vez este último necesite poner la aplicación en cierto estado necesario para el correcto funcionamiento del primero): podemos indicar esta dependencia en el orden de inicialización mediante la anotación &lt;code&gt;@DependsOn&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Singleton
&lt;br&gt;public class MiSingletonA {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;@Singleton
&lt;br&gt;@DependsOn(&quot;MiSingletonA&quot;)
&lt;br&gt;public class MiSingletonB {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, indicamos al contenedor que en el momento de inicializar la única instancia de &lt;code&gt;MiSingletonB&lt;/code&gt;, &lt;code&gt;MiSingletonA&lt;/code&gt; debe haber sido inicializado. De esta manera, el contenedor forzará la inicialización del Singleton dependiente si aún no se ha producido. Este comportamiento es totalmente ajeno al uso u omisión de &lt;code&gt;@Startup&lt;/code&gt;: si un Singleton depende de otro, este último se creará antes que el primero.
&lt;br&gt;
&lt;br&gt;Para terminar con el ciclo de vida de los componentes Singleton, indicar que, al igual que con los componentes SLSB y SFSB, disponemos de las anotaciones &lt;code&gt;@PostConstruct&lt;/code&gt; y &lt;code&gt;@PreDestroy&lt;/code&gt; para responder a los eventos de creación y destrucción (respectivamente) del componente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Singleton
&lt;br&gt;public class MiSingletonA {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostConstruct
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void inicializar() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Cualquier operación/es necesaria/s para la creación del componente,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// como obtención de recursos
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PreDestroy
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void detener() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Cualquier operación/es necesaria/s antes de la destrucción del componente,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// como liberación de recursos
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// lógica de negocio del Singleton
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.6 SINGLETON SESSION BEANS: UN EJEMPLO SENCILLO
&lt;br&gt;La utilidad del componente Singleton está limitada a ciertos problemas de negocio que podemos (o debemos) resolver mediante una única instancia de un objeto. Ejemplos válidos de componentes Singleton serían gestores de ventanas, sistemas de ficheros, colas de impresión, caches, etc. Para nuestro ejemplo de Singleton vamos a desarrollar un sistema de logging, el cual debe ser accedido por toda la aplicación a través de una única instancia:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.singleton;
&lt;br&gt;
&lt;br&gt;import java.io.FileWriter;
&lt;br&gt;import java.io.IOException;
&lt;br&gt;import java.text.SimpleDateFormat;
&lt;br&gt;import java.util.Date;
&lt;br&gt;import javax.annotation.PostConstruct;
&lt;br&gt;import javax.annotation.PreDestroy;
&lt;br&gt;import javax.ejb.Lock;
&lt;br&gt;import javax.ejb.LockType;
&lt;br&gt;import javax.ejb.Singleton;
&lt;br&gt;
&lt;br&gt;@Singleton
&lt;br&gt;public class SistemaDeLog {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private FileWriter writer;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private enum Nivel {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DEBUG, INFO, ERROR
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostConstruct
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected void inicializar() throws IOException {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer = new FileWriter(&quot;aplicacion.log&quot;, true);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PreDestroy
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected void detener() throws IOException {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer.flush();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer.close();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Lock(LockType.WRITE)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void debug(String mensaje) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;escribirMensajeEnArchivo(Nivel.DEBUG, mensaje);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Lock(LockType.WRITE)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void info(String mensaje) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;escribirMensajeEnArchivo(Nivel.INFO, mensaje);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Lock(LockType.WRITE)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void error(String mensaje) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;escribirMensajeEnArchivo(Nivel.ERROR, mensaje);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void escribirMensajeEnArchivo(Nivel nivel, String mensaje) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String cabecera = generarCabecera(nivel);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer.write(cabecera + mensaje + &quot;\n&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (IOException ioe) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new RuntimeException(ioe);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String generarCabecera(Nivel nivel) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String fechaMasHoraActual = new SimpleDateFormat(&quot;dd/MM/yyyy HH:mm:ss&quot;).format(new Date());
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringBuilder cabecera = new StringBuilder();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cabecera.append(&quot;[&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cabecera.append(nivel.name());
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cabecera.append(&quot;] &quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cabecera.append(fechaMasHoraActual);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cabecera.append(&quot; - &quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return cabecera.toString();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El ejemplo anterior, aunque más desarrollado que los vistos hasta ahora (es completamente funcional), sigue siendo un ejemplo &lt;i&gt;de juguete&lt;/i&gt;; sin embargo, es bastante interesante para explicar el componente Singleton. Existen verdaderos frameworks de logging que puedes (¡y debes!) usar en tus aplicaciones.
&lt;br&gt;
&lt;br&gt;Las primero que nos interesa del ejemplo son los métodos &lt;i&gt;callback&lt;/i&gt; &lt;code&gt;@PostConstruct&lt;/code&gt; y &lt;code&gt;@PreDestroy&lt;/code&gt;. En ellos se obtiene y libera (respectivamente) un recurso dado, en nuestro caso el acceso a un fichero en disco. Esto nos muestra la utilidad del componente Singleton: únicamente una instancia debe crear, editar, y finalmente cerrar el mismo fichero en disco. Y esta única instancia es la que obtendrán todos los clientes del Singleton. Ambos métodos se han marcado con visibilidad &lt;code&gt;protected&lt;/code&gt; para facilitar la tarea de testing (y por un motivo adicional que se explicará en la próxima sección).
&lt;br&gt;
&lt;br&gt;Lo segundo que nos interesa del ejemplo son los tres métodos que se exponen al cliente: &lt;code&gt;debug&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt;, y &lt;code&gt;error&lt;/code&gt;. A traves de ellos el cliente puede realizar las operaciones de logging. Los tres han sido marcados como métodos &lt;i&gt;write&lt;/i&gt; mediante &lt;code&gt;@Lock(LockType.WRITE)&lt;/code&gt;, y aunque este comportamiento es definido por defecto para todos los métodos de un Singleton (y por tanto la anotación es redundante), se han incluido para diferenciarlos del resto (siempre es aconsejable escribir código expresivo).
&lt;br&gt;
&lt;br&gt;Por último, los métodos de utilidad &lt;code&gt;escribirMensajeEnArchivo&lt;/code&gt; y &lt;code&gt;generarCabecera&lt;/code&gt; son métodos de utilidad usados por la lógica de negocio de nuestro componente.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.7 SESSION BEANS EN GENERAL: NO-INTERFACE VIEW
&lt;br&gt;Como se indicó en la sección anterior, el ejemplo del sistema de logging es completamente funcional. Sin embargo, el componente no ha sido declarado local ni remoto (ejemplos anteriores omitían este aspecto intencionadamente para mantener el código simple). En este momento es preciso introducir el concepto de &lt;i&gt;vista sin interface&lt;/i&gt;.
&lt;br&gt;
&lt;br&gt;Una vista sin interface (no-interface view) es una variación del concepto de componente local, e introducida en la especificación EJB 3.1. Como su nombre indica, se trata de un componente que no está anotado con &lt;code&gt;@Local&lt;/code&gt; ni &lt;code&gt;@Remote&lt;/code&gt;, ni implementa ninguna interface de negocio donde se hayan aplicado cualquiera de las anotaciones anteriores. Si no implementamos ninguna interface de negocio, ¿como sabe el contenedor que métodos del componente debe exponer a sus clientes? La respuesta es sencilla: todos aquellos declarados &lt;code&gt;public&lt;/code&gt;, incluyendo los de sus superclases y los de tipo &lt;i&gt;callback&lt;/i&gt; (en el ejemplo de la sección anterior hemos declarado los métodos &lt;i&gt;callback&lt;/i&gt; con un nivel de visibilidad menor a &lt;code&gt;public&lt;/code&gt; precisamente para evitar que sean expuestos). Aunque a efectos prácticos un componente de este tipo es tratado como uno local, puedes encontrar los detalles concretos sobre la vista sin interface en la &lt;a href=&quot;http://jcp.org/aboutJava/communityprocess/final/jsr318/index.html&quot;&gt;especificación EJB 3.1&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.8 SESSION BEANS EN GENERAL: LLAMADAS ASÍNCRONAS
&lt;br&gt;Otra de las novedades de la especificación EJB 3.1 es la posibilidad de llamar a los métodos de nuestros Session Bean de forma asíncrona. Hasta ahora, todas las llamadas que hemos realizado han sido sincronas, de manera que los clientes deben esperar hasta que el método invocado termine de ejecutarse para seguir ejecutando el resto de sus sentencias. Este es el comportamiento normal cuando invocamos un método en Java. Sin embargo, cuando realizamos una llamada asíncrona, el flujo de ejecución vuelve automáticamente a la aplicación que realiza la llamada, sin esperar el resultado de la llamada. Más tarde, podemos comprobar dicho resultado si existe y lo necesitamos.
&lt;br&gt;
&lt;br&gt;Las llamadas asíncronas son de gran utilidad en situaciones en las que un método realiza una operación que necesita un tiempo considerable para completarse, y no deseamos bloquear al cliente mientras dicha operación se realiza. Veamos primero el ejemplo más sencillo posible de llamada asíncrona:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;import javax.ejb.Asynchronous;
&lt;br&gt;import javax.ejb.Stateless;
&lt;br&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class ClaseAsincrona {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Asynchronous
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void metodoLento() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.sleep(15000);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch(InterruptedException ie) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new RuntimeException(ie);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, hemos declarado el método &lt;code&gt;metodoLento()&lt;/code&gt; como un método asíncrono mediante la anotación &lt;code&gt;@Asynchronous&lt;/code&gt;. Dicha anotación puede ser aplicada también a nivel de clase, en cuya caso todos los métodos de negocio (los declarados en una interface local, en una interface remota, o los de visibilidad &lt;code&gt;public&lt;/code&gt; en una vista sin interface) serán considerados como asíncronos. Dentro del método hemos simulado un proceso relativamente largo deteniendo durante quince segundos el hilo de ejecución que está procesando la instancia del SLSB. Cualquier cliente que llame a este método no tendrá que esperar esos quince segundos, ya que nada más realizar la llamada le será devuelto en control de ejecución, sin esperar a que el método asíncrono termine. Este comportamiento se conoce como &lt;i&gt;fire-and-forget&lt;/i&gt; (disparar y olvidar).
&lt;br&gt;
&lt;br&gt;Otra posibilidad es que necesitemos el resultado de una invocación asíncrona. Supongamos que necesitamos un método que realiza un cálculo intensivo y, cuando finalmente obtiene el resultado, lo devuelve en una variable de tipo &lt;code&gt;Double&lt;/code&gt;. La manera de declarar dicho método sería similar a esta:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import java.util.concurrent.Future;
&lt;br&gt;import javax.ejb.AsyncResult;
&lt;br&gt;import javax.ejb.Asynchronous;
&lt;br&gt;
&lt;br&gt;// ...
&lt;br&gt;
&lt;br&gt;@Asynchronous
&lt;br&gt;public Future&lt;Double&gt; metodoLentoConResultado() {&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.sleep(15000);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return new AsyncResult&lt;Double&gt;(Math.PI);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch(InterruptedException ie) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new RuntimeException(ie);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Como puedes ver, el método &lt;code&gt;metodoLentoConResultado()&lt;/code&gt; devuelve un objeto de tipo &lt;code&gt;Future&lt;/code&gt; (más concretamente de su implementación &lt;code&gt;AsyncResult&lt;/code&gt;) parametizado a &lt;code&gt;Double&lt;/code&gt;. Es sobre este objeto &lt;code&gt;Future&lt;/code&gt; sobre el que el cliente deberá comprobar si el método asíncrono ha terminado su ejecución, para obtener a continuación su resultado:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import java.util.concurrent.ExecutionException;
&lt;br&gt;import java.util.concurrent.Future;
&lt;br&gt;import javax.naming.NamingException;
&lt;br&gt;
&lt;br&gt;// ...
&lt;br&gt;
&lt;br&gt;Future&lt;Double&gt; resultado = bean.metodoLentoConResultado();
&lt;br&gt;System.out.println(&quot;Método asíncrono invocado&quot;);
&lt;br&gt;System.out.println(&quot;Realizando otras tareas mientras se ejecuta el método asíncrono...&quot;);
&lt;br&gt;// ...
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;while(true) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(!resultado.isDone()) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.sleep(2000);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;Método asincrono devuelve el resultado &quot; + resultado.get());
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El ejemplo anterior es parte de un cliente del SLSB asíncrono. En el, en un momento dado, se llama al método asíncrono, asignando el objeto &lt;code&gt;Future&lt;/code&gt; devuelto por dicho método en una variable. En este momento el resultado no está listo (recuerda que tardará quince segundos en producirse), pero el control de la ejecución del cliente continua sin esperar. Más adelante el cliente comprueba si el resultado está finalmente disponible mediante el método &lt;code&gt;isDone()&lt;/code&gt; de la clase &lt;code&gt;Future&lt;/code&gt;. Cuando esto ocurra, podemos obtener nuestro ansiado resultado mediante el método &lt;code&gt;get()&lt;/code&gt; (también de la clase &lt;code&gt;Future&lt;/code&gt;), el cual devuelve un objeto del mismo tipo al que usamos para parametizar la respuesta del método asíncrono (en nuestro caso, un objeto &lt;code&gt;Double&lt;/code&gt;). Es importante tener presente que el método &lt;code&gt;get()&lt;/code&gt; bloquea el hilo de ejecución del cliente hasta que el resultado esté listo, de manera que podemos omitir por completo el bucle &lt;code&gt;while&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Future&lt;Double&gt; resultado = bean.metodoLentoConResultado();
&lt;br&gt;System.out.println(&quot;Método asíncrono invocado&quot;);
&lt;br&gt;System.out.println(&quot;Realizando otras tareas mientras se ejecuta el método asíncrono...&quot;);
&lt;br&gt;// ...
&lt;br&gt;System.out.println(&quot;Método asíncrono devuelve resultado &quot; + resultado.get());
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;La interface &lt;code&gt;Future&lt;/code&gt; incluye otros métodos con los que podemos cancelar la ejecución del método asíncrono, o comprobar si dicha ejecución ha sido cancelada por el contenedor (por ejemplo en caso de excepción). Es recomendable que visites la &lt;a href=&quot;http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html&quot;&gt;API de &lt;code&gt;Future&lt;/code&gt;&lt;/a&gt; si vas a trabajar con ella.
&lt;br&gt;
&lt;br&gt;Antes de terminar con los métodos asíncronos, quiero hacer constar que en la implementación del contenedor EJB que estamos usando en este tutorial (JBoss 6.0.0 Final) las llamadas asíncronas aún no están completamente implementadas (el hilo de ejecución del cliente se bloquea al llamar al método asíncrono hasta que este ha terminado de ejecutarse; en otras palabras, las llamadas asíncronas se comportan como llamadas síncronas). En otros contenedores compatibles con EJB 3.1, como Glassfish v3, el comportamiento de las llamadas asíncronas si es el correcto (no lo he probado personalmente, pero así aparece indicado por usuarios de ambos servidores).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.9 SESSION BEANS EN GENERAL: RESUMEN
&lt;br&gt;Con esta sección terminamos de ver los componentes de tipo Session Bean, que son aquellos que contienen la lógica de negocio de una aplicación EJB que puede ser invocada por los clientes de dicha aplicación (ya sea en cualquiera de sus tres variaciones: Stateless, Stateful, o Singleton). Ahora es el momento de pasar a un nuevo tipo de componente con una misión totalmente diferente: Message-Driven Beans.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.10 MESSAGE-DRIVEN BEANS: CONCEPTOS BÁSICOS
&lt;br&gt;Los componentes de tipo Message-Driven Bean (MDB - Bean Dirigido por Mensajes) son componentes asíncronos de tipo &lt;i&gt;listener&lt;/i&gt; (oyente). Un MDB no es más que un componente que &lt;i&gt;espera&lt;/i&gt; a que se le envie un mensaje, y realiza cierta acción cuando finalmente recibe dicho mensaje (el MDB &lt;i&gt;escucha&lt;/i&gt; por si alguien le llama, de ahí su nombre). Algunas propiedades de los componentes MDB son:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No mantienen estado
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Son gestionados por el contenedor (transacciones, seguridad, concurrencia, etc)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Son clases puras que no implementan interfaces de negocio (puesto que son invocados por un cliente)
&lt;br&gt;
&lt;br&gt;Los componentes MDB forman parte de un sistema de mensajería, el cual se compone de los siguientes subsistemas:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Cliente (Productor)   ---&gt;   Broker   ---&gt;   Cliente (Consumidor)   ---&gt;   Message-Driven Bean
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En lo que refiere a este tutorial, el cliente consumidor será el propio contenedor EJB, el cual &lt;i&gt;distribuirá&lt;/i&gt; los mensajes que consuma a los MDB correspondientes. 
&lt;br&gt;
&lt;br&gt;Los tres primeros subsistemas (clientes y broker) forman parte del servicio de mensajería, que en la especificación EJB es gestionado por defecto mediante JMS. En este momento es preciso desviarnos del camino para explicar con un mínimo de detalle que es y cómo funciona JMS.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.11 JAVA MESSAGE SERVICE: CONCEPTOS BÁSICOS
&lt;br&gt;Java Message Service (JMS - Servicio de Mensajería en Java) es una API neutral que puede ser usada para acceder a sistemas de mensajería. Todos los contenedores EJB 3.x deben proporcionar un proveedor de JMS (el cual define su propia implementación de la API), de manera que podamos trabajar con mensajes sin necesidad de añadir librerías externas. Puesto que esta API es neutral, podemos cambiar en cualquier momento el proveedor JMS por uno que se adecue más a nuestras necesidades (o incluso usar un sistema de mensajería diferente a JMS).
&lt;br&gt;
&lt;br&gt;Una aplicación JMS se compone, generalmente, de múltiples clientes JMS y un único proveedor JMS. Un cliente JMS puede ser de dos tipos:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Productor: su misión es enviar mensajes
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Consumidor: su misión es recibir mensajes
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Por otro lado, la misión del proveedor JMS es dirigir y enviar los mensajes que le llegan a traves de un &lt;i&gt;broker&lt;/i&gt; (esto es algo bastante más complejo, pero por simplicidad vamos a pensar que tenemos un subsistema llamado &lt;i&gt;broker&lt;/i&gt; donde se almacenan los mensajes enviados hasta que son servidos a todos sus consumidores). JMS proporciona un tipo de mensajería asíncrona: los clientes JMS envían mensajes a traves del broker sin esperar una respuesta. Es responsabilidad del broker hacer llegar el mesaje a los clientes JMS que deban consumir el mensaje. De esta manera JMS proporciona un sistema de comunicación muy poco acoplado, pues el productor y el consumidor no saben el uno del otro en ningún momento.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.12 JAVA MESSAGE SERVICE: MODELOS DE MENSAJERÍA
&lt;br&gt;JMS proporciona dos modelos de mensajería, los cuales nos permiten definir el comportamiento de nuestro sistema de mensajería:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Publicar y Suscribir (pub/sub - Publish and Subscribe)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Punto a Punto (p2p - Point to Point)
&lt;br&gt;
&lt;br&gt;En el modelo pub/sub, un cliente JMS de tipo productor &lt;i&gt;publica&lt;/i&gt;sus mensajes en un canal virtual llamado &lt;i&gt;topic&lt;/i&gt; (tema). A su vez, uno o varios clientes JMS de tipo consumidor se &lt;i&gt;suscriben&lt;/i&gt; a dicho topic si desean recibir los mensajes que en él se publiquen. Si un suscriptor decide desconectarse del topic y más tarde reconectarse, recibirá todos los mensajes publicados durante su ausencia (aunque este comportamiento es configurable). Por todo esto, el modelo pub/sub es de tipo uno-a-muchos (un productor, muchos consumidores).
&lt;br&gt;
&lt;br&gt;En el modelo p2p, un cliente JMS de tipo productor publica sus mensajes en un canal virtual llamado &lt;i&gt;queue&lt;/i&gt; (cola). De manera similar al modelo pub/sub, pueden existir multiples consumidores conectados al queue. Sin embargo, el queue no enviará automáticamente los mensajes que le lleguen a todos los consumidores, si no que son estos últimos los que deben solicitarlos al queue. De manera adicional, solo un consumidor consumirá cada mensaje publicado: el primero en solicitarlo. Cuando esto ocurra, el mensaje se borrará del queue, y el resto de consumidores no será siquiera consciente de la anterior existencia del mensaje. Por todo esto, el modelo p2p es de tipo uno-a-uno (un productor, un consumidor).
&lt;br&gt;
&lt;br&gt;En versiones anteriores a JMS 1.1 cada uno de estos modelos usaba su propio conjunto de interfaces y clases para para el envio y recepción de mensajes. Desde la citada versión de JMS, sin embargo, está disponible una API unificada que es válida para ambos modelos de mensajería.
&lt;br&gt;
&lt;br&gt;Ahora es el momento de volver al camino que dejamos dos secciones atrás, y seguir con nuestros amados componentes MDB.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.13 MESSAGE-DRIVEN BEANS: EL CICLO DE VIDA
&lt;br&gt;Tal como vimos en la sección 3.10, los componentes MDB no mantienen estado entre invocaciones (son &lt;i&gt;stateless&lt;/i&gt;, pero no confundir con los componentes SLSB). Por tanto, su ciclo de vida es similar a los SLSB, constando de dos estados:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No existe (Does not exists)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Preparado en pool (Method-ready pool)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Un MDB en el primer estado es aquel que no ha sido creada aún, y por tanto no existe en memoria. Un MDB en el segundo estado representa una instancia que ha sido instanciada e inicializada por el contenedor. Se llega a este estado cuando se inicia el servidor (que puede decidir crear cierto número de instancias del MDB para procesar mensajes), o cuando el número de instancias en el pool sea insuficiente para atender todos los mensajes que se estén recibiendo. La especificación EJB no fuerza a que exista un pool de MDB's, de manera que una implementación concreta de contenedor EJB ppdría decidir crear una instancia cada vez que se reciba un mensaje (y eliminar esta instancia al terminar de procesar el mensaje) en lugar de mantener un pool de instancias ya preparadas. Este último aspecto, sea como sea, no nos afecta como programadores (al diseñar un MDB) ni como clientes; la forma en que sea gestionada nuestra aplicación es, a priori, responsabilidad exclusiva del contenedor.
&lt;br&gt;
&lt;br&gt;Durante la transición entre el primer estado y el segundo, el contenedor realizará tres operaciones (en este orden):
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Instanciación del MDB
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Inyección de cualquier recurso necesario y de dependencias
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Ejecución de un método dentro del MDB marcado con la anotación @PostConstruct, si existe
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;La instanciación del MDB se lleva a cabo mediante reflexión, a traves de Class.newInstance(). Por tanto, el MDB debe tener un constructor por defecto (sin argumentos), ya sea de forma implícita o explícita. 
&lt;br&gt;
&lt;br&gt;Durante la inyección de dependencias, el contenedor inyectará automáticamente cualquier recurso necesario para el MDB en base a los metadatos que hayamos proporcionado (como una anotación &lt;code&gt;@MessageDrivenContext&lt;/code&gt;, o una entrada en el descriptor XML de EJB). De manera adicional, cada vez que un MDB procese un nuevo mensaje, todas las dependencias se inyectarán de nuevo.
&lt;br&gt;
&lt;br&gt;Por último, el contenedor ejecutará, si existe, un método dentro del MDB anotado con &lt;code&gt;@PostConstruct&lt;/code&gt; (Post construcción). En este método podemos obtener recursos adicionales necesarios para el MDB (como conexiones de red, etc), recursos que permanecerán abiertos hasta la destrucción del MDB. Las reglas de declaración de los métodos &lt;i&gt;callback&lt;/i&gt; como &lt;code&gt;@PostConstruct&lt;/code&gt; se vieron una y otra vez en el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=240&quot;&gt;artículo anterior&lt;/a&gt;.
&lt;br&gt;
&lt;br&gt;Cuando el contenedor no necesita una instancia del MDB (ya sea porque decide reducir el número de instancias en el pool, o porque se esta produciendo un shutdown del servidor), se realiza una transición en sentido inverso: del estado &lt;i&gt;preparado en pool&lt;/i&gt; al estado &lt;i&gt;no existe&lt;/i&gt;.  Durante esta transición se ejecutará, si existe, un método anotado con &lt;code&gt;@PreDestroy&lt;/code&gt; (Pre destrucción), donde podemos liberar los recursos adquiridos en &lt;code&gt;@PostConstruct&lt;/code&gt;. Es importante tener presente que dentro del método &lt;code&gt;@PreDestroy&lt;/code&gt; todavía tenemos acceso al contexto del MDB (lo mismo es válido para todos los Session Bean).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.14 MESSAGE-DRIVEN BEANS: DEFINICIÓN
&lt;br&gt;Como ya hemos visto, los componentes de tipo MDB tienen como misión procesar mensajes enviados de forma asíncrona. Aunque todo contenedor compatible EJB 3.x debe incluir una implementación de JMS (de manera que tengamos un servicio de mensajería &lt;i&gt;on the box&lt;/i&gt;), MDB puede trabajar con otros servicios de mensajería diferentes. En este tutorial solo se usará JMS como servicio de mensajería (afectando este hecho, por ejemplo, a la interface que debe implementar el MDB, como veremos en el próximo párrafo). 
&lt;br&gt;
&lt;br&gt;Todo MDB debe implementar la interface &lt;code&gt;javax.jms.MessageListener&lt;/code&gt;, la cual define el método &lt;code&gt;onMessage()&lt;/code&gt;. Es dentro de este método donde se desarrolla toda la acción cuando el MDB procesa un mensaje, como veremos en el ejemplo de la próxima sección. De manera adicional, debemos indicar al contenedor que nuestra clase es un componente MDB. Para ello, utilizamos la anotación &lt;code&gt;@MessageDriven&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.mdb;
&lt;br&gt;
&lt;br&gt;import javax.ejb.MessageDriven;
&lt;br&gt;import javax.jms.Message;
&lt;br&gt;import javax.jms.MessageListener;
&lt;br&gt;
&lt;br&gt;@MessageDriven()
&lt;br&gt;public class PrimerMDB implements MessageListener {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void onMessage(Message message) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// procesar el mensaje
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El ejemplo anterior aún no es funcional (producirá un error de despliegue), ya que el MDB necesita saber el tipo de canal virtual (topic/queue) al que debe conectarse, así como el nombre de dicho canal virtual. Esta información forma parte de la configuración del MDB, configuración que proporcionamos al componente a través del atributo &lt;code&gt;activationConfig&lt;/code&gt; (configuración de activación) de la anteriormente vista anotación &lt;code&gt;@MessageDriven&lt;/code&gt;:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@MessageDriven(activationConfig={
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ActivationConfigProperty(propertyName=&quot;destinationType&quot;, propertyValue=&quot;javax.jms.Topic&quot;),
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ActivationConfigProperty(propertyName=&quot;destination&quot;, propertyValue=&quot;topic/MiTopic&quot;)})
&lt;br&gt;public class PrimerMDB implements MessageListener {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, hemos proporcionado al MDB la configuración necesaria mediante un array de anotaciones &lt;code&gt;@ActivationConfigProperty&lt;/code&gt;. Cada una de estas anotaciones contiene dos atributos: &lt;code&gt;propertyName&lt;/code&gt; y &lt;code&gt;propertyValue&lt;/code&gt;, en los cuales indicamos parejas &lt;i&gt;nombre-de-la-propiedad&lt;/i&gt;/&lt;i&gt;valor-de-la-propiedad&lt;/i&gt;, respectivamente. Volviendo a nuestro último ejemplo, hemos configurado el MDB con las siguientes propiedades:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- El tipo de canal virtual al que el MDB se conectará (&lt;code&gt;javax.jms.Topic&lt;/code&gt;)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- El nombre JNDI del canal virtual al que el MDB se conectará (&lt;i&gt;topic/MiTopic&lt;/i&gt;).
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Otra opción de configuración bastante interesante (aunque opcional) es la duración de la subscripción:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@ActivationConfigProperty(propertyName=&quot;subscriptionDurability&quot;, propertyValue=&quot;Durable&quot;)
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Añadiendo la anotación anterior al array de propiedades de configuración del MDB, nuestro componente recibirá todos los mensajes que se envien a su canal virtual mientras el contenedor EJB (y por tanto el propio componente MDB) esté offline. Esta situación puede ocurrir durante un shutdown del servidor, un problema de conectividad por red, etc. En otras palabras, el mensaje estará disponible hasta que todos sus suscriptores de tipo &lt;i&gt;durable&lt;/i&gt; lo hayan recibido y procesado. La opción contraria se aplica cambiando el valor del atributo &lt;code&gt;propertyValue&lt;/code&gt; a &lt;code&gt;NonDurable&lt;/code&gt; (no durable). La durabilidad de los mensajes solo afecta a los componentes MDB que trabajan con topics (modelo pub/sub), pues en un canal de tipo queue no tiene ningún sentido almacenar un mensaje para componentes MDB offline (en cuanto un MDB este online y lo consuma, el mensaje se eliminará).
&lt;br&gt;
&lt;br&gt;Al igual que los componentes Session Bean, los componentes MDB funcionan dentro de un contexto de ejecución. Y por tanto, al igual que los componentes Session Bean, nuestros MDB pueden acceder a su contexto de ejecución si necesitan comunicarse con el contenedor:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import javax.annotation.Resource;
&lt;br&gt;import javax.ejb.MessageDriven;
&lt;br&gt;import javax.ejb.MessageDrivenContext;
&lt;br&gt;
&lt;br&gt;@MessageDriven(/*...*/)
&lt;br&gt;public class PrimerMDB implements MessageListener {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Resource 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private MessageDrivenContext context;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior indicamos al contenedor que inyecte una instancia de &lt;code&gt;MessageDrivenContext&lt;/code&gt; mediante la anotación &lt;code&gt;@Resource&lt;/code&gt;. &lt;code&gt;MessageDrivenContext&lt;/code&gt; extiende la interface &lt;code&gt;EJBContext&lt;/code&gt;, sin añadir ningún método. Solamente los métodos transaccionales son útiles al MDB, como se verá cuando trabajemos con transacciones en artículos posteriores. El resto de métodos de la interface lanzará una excepción si son invocados, ya que no tiene sentido que un MDB pueda, por ejemplo, acceder al servicio de seguridad.
&lt;br&gt;
&lt;br&gt;Por otro lado, un MDB también puede referenciar un Session Bean para realizar el procesamiento del mensaje (mediante la anotación &lt;code&gt;@EJB&lt;/code&gt;, sección 2.5 del &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=240&quot;&gt;artículo anterior&lt;/a&gt;), así como enviar él mismo sus propios mensajes mediante JMS (al final de la próxima sección veremos un ejemplo de un MDB procesando mensajes, y a su vez enviando nuevos mensajes que serán procesador por otro MDB).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;3.15 MESSAGE-DRIVEN BEANS: UN SENCILLO EJEMPLO
&lt;br&gt;Ya hemos visto como los servicios de mensajería asíncronos desacoplan de forma completa al productor de un mensaje de su/s receptor/es: ninguno de ellos es consciente de la parte contraria. Esto debido a que, entre ellos, existe un &lt;i&gt;broker&lt;/i&gt; donde se realiza todo el proceso de almacenaje (ya sea en canales virtuales de tipo topic o queue) y reparto de los mensajes que se reciben.
&lt;br&gt;
&lt;br&gt;El ejemplo que vamos a ver consta de tres partes:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Creación de un canal virtual
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Creación de un componente MDB para consumir mensajes
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Creación de un cliente para enviar mensajes mediante JMS
&lt;br&gt;
&lt;br&gt;El primer paso lógico es crear un canal virtual donde poder enviar mensajes (un topic para modelos pub/sub o un queue para modelos p2p). En JBoss 6.0.0 Final (el servidor de aplicaciones que instalamos en el &lt;a href=&quot;http://www.davidmarco.es/tutoriales/anexos/anexo_introduccion_ejb31.html&quot;&gt;anexo&lt;/a&gt; que acompaña este tutorial), el proveedor JMS incorporado es HornetQ 2.1.2 Final. Para declarar un canal virtual de tipo topic, edita el archivo llamado &lt;i&gt;hornetq-jms.xml&lt;/i&gt; del directorio &lt;i&gt;server/default/deploy/hornetq/&lt;/i&gt; de tu instalación de JBoss y añade lo siguiente (&lt;i&gt;default&lt;/i&gt; es la configuración por defecto al crear el servidor en Eclipse; si seleccionaste otra configuración, modifica la ruta anterior a la que corresponda):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;&amp;lt;configuration xmlns=&quot;urn:hornetq&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xsi:schemaLocation=&quot;urn:hornetq /schema/hornetq-jms.xsd&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- ... --&amp;gt;
&lt;br&gt;   
&lt;br&gt;   &amp;lt;topic name=&quot;PrimerTopic&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name=&quot;/topic/PrimerTopic&quot; /&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/topic&amp;gt;
&lt;br&gt;
&lt;br&gt;&amp;lt;/configuration&amp;gt;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el archivo XML anterior hemos definido un canal virtual de tipo topic (mediante el elemento &amp;lt;topic&amp;gt;) con nombre &lt;code&gt;PrimerTopic&lt;/code&gt;, y lo hemos asociado a la dirección JNDI &lt;code&gt;/topic/PrimerTopic&lt;/code&gt; (es necesario reiniciar JBoss si se encuentra levantado). La forma de configurar un canal virtual puede ser diferente entre distintos contenedores (incluso entre distintas implementaciones de un mismo contenedor), por lo que si estás usando un servidor de aplicaciones diferente a JBoss 6.0.0 Final o un proveedor JMS diferente a HornetQ 2.1.2 Final, quizá necesites revisar la documentación correspondiente para declarar el canal virtual.
&lt;br&gt;
&lt;br&gt;Aunque este ejemplo se basará en un canal virtual de tipo topic, puedes declarar un queue (para montar un modelo de mensajería p2p) de la siguiente manera:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;&amp;lt;configuration xmlns=&quot;urn:hornetq&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xsi:schemaLocation=&quot;urn:hornetq /schema/hornetq-jms.xsd&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- ... --&amp;gt;
&lt;br&gt;   
&lt;br&gt;   &amp;lt;queue name=&quot;PrimerQueue&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name=&quot;/queue/PrimerQueue&quot; /&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/queue&amp;gt;
&lt;br&gt;
&lt;br&gt;&amp;lt;/configuration&amp;gt;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El siguiente paso lógico sería escribir un componente MDB que procese los mensajes del topic. Para ello, necesitamos crear un proyecto EJB en Eclipse y declarar una clase como la siguiente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.mdb;
&lt;br&gt;
&lt;br&gt;import javax.ejb.ActivationConfigProperty;
&lt;br&gt;import javax.ejb.MessageDriven;
&lt;br&gt;import javax.jms.JMSException;
&lt;br&gt;import javax.jms.Message;
&lt;br&gt;import javax.jms.MessageListener;
&lt;br&gt;import javax.jms.TextMessage;
&lt;br&gt;
&lt;br&gt;@MessageDriven(activationConfig={
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ActivationConfigProperty(propertyName=&quot;destinationType&quot;, propertyValue=&quot;javax.jms.Topic&quot;),
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ActivationConfigProperty(propertyName=&quot;destination&quot;, propertyValue=&quot;topic/PrimerTopic&quot;)})
&lt;br&gt;public class PrimerMDB implements MessageListener {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void onMessage(Message message) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(message instanceof TextMessage) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String contenidoDelMensaje = ((TextMessage)message).getText();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;PrimerMDB ha procesado el mensaje: &quot; + contenidoDelMensaje);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (JMSException jmse) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new RuntimeException(&quot;Error al procesar un mensaje&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior declaramos un componente MDB (con la anotación &lt;code&gt;@MessageDriven&lt;/code&gt;), lo configuramos para actuar como consumidor de los mensajes del topic registrado con dirección JNDI &lt;code&gt;topic/PrimerTopic&lt;/code&gt; (con las anotaciones &lt;code&gt;@ActivationConfigProperty&lt;/code&gt;), y finalmente añadimos dentro del método &lt;code&gt;onMessage()&lt;/code&gt; la lógica que procesará los mensajes. Recuerda que este método es el único declarado en la interface &lt;code&gt;MessageListener&lt;/code&gt;, la cual deben implementar todos los MDB basados en JMS.
&lt;br&gt;
&lt;br&gt;Es interesante explicar con un mínimo detalle las operaciones que se realizan dentro de nuestro método &lt;code&gt;onMessage&lt;/code&gt;. Este método requiere un parámetro de tipo &lt;code&gt;javax.jms.Message&lt;/code&gt;, que es una interface base de la cual extienden otras interfaces más específicas. Una de esas subinterfaces es &lt;code&gt;TextMessage&lt;/code&gt;, la cual provee de métodos para trabajar con mensajes cuyo contenido es texto. Por tanto, este MDB está diseñado para recibir mensajes desde el topic asociado, y procesarlos si son de tipo &lt;code&gt;TextMessage&lt;/code&gt; (en caso afirmativo, se imprime en el log del servidor el contenido del mensaje). Si durante dicho procesamiento se produce un error, el MDB lanzará una excepción. Lo ideal es que el topic asociado solo reciba este tipo de mensajes, y que mensajes con otro tipo de contenido sean almacenados en otros canales virtuales (de esta manera no se crearán instancias que finalmente no procesarán el mensaje). 
&lt;br&gt;
&lt;br&gt;Tras desplegar el proyecto EJB con nuestro primer componente MDB, el último paso lógico sería crear un cliente JMS que produjera mensajes y los enviara al topic. Este cliente podría ser, por ejemplo, un proyecto Java normal y corriente. Puesto que necesitamos las librerias de JMS (las cuales son parte de EJB 3.x), debemos incluirlas al crear nuestro proyecto. La forma más sencilla sería pulsando &lt;i&gt;Next&lt;/i&gt; en la pantalla de creación del proyecto Java en Eclipse, seleccionando la pestaña &lt;code&gt;Libraries&lt;/code&gt; y añadiendo las librerias del servidor JBoss:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Add Library &gt; Server Runtime &gt; Botón Next &gt; JBoss 6.0 Runtime &gt; Botón Finish &gt; Botón Finish
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Ahora ya estamos listos para escribir el cliente productor JMS:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.cliente;
&lt;br&gt;
&lt;br&gt;import java.util.Properties;
&lt;br&gt;import javax.jms.Connection;
&lt;br&gt;import javax.jms.ConnectionFactory;
&lt;br&gt;import javax.jms.JMSException;
&lt;br&gt;import javax.jms.MessageProducer;
&lt;br&gt;import javax.jms.Session;
&lt;br&gt;import javax.jms.TextMessage;
&lt;br&gt;import javax.jms.Topic;
&lt;br&gt;import javax.naming.Context;
&lt;br&gt;import javax.naming.InitialContext;
&lt;br&gt;import javax.naming.NamingException;
&lt;br&gt;
&lt;br&gt;public class ClienteJMS {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws NamingException, JMSException {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Properties propiedades = new Properties();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;propiedades.put(&quot;java.naming.factory.initial&quot;, &quot;org.jnp.interfaces.NamingContextFactory&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;propiedades.put(&quot;java.naming.factory.url.pkgs&quot;, &quot;org.jboss.naming:org.jnp.interfaces&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;propiedades.put(&quot;java.naming.provider.url&quot;, &quot;jnp://localhost:1099&quot;);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Context contexto = new InitialContext(propiedades);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ConnectionFactory factoria = (ConnectionFactory)contexto.lookup(&quot;ConnectionFactory&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Topic topic = (Topic)contexto.lookup(&quot;topic/PrimerTopic&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Connection conexion = factoria.createConnection();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Session sesion = conexion.createSession(false, Session.AUTO_ACKNOWLEDGE);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MessageProducer productor = sesion.createProducer(topic);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conexion.start();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TextMessage mensajeDeTexto = sesion.createTextMessage(&quot;Mensaje enviado desde Java&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;productor.send(mensajeDeTexto);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conexion.close();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En nuestro cliente JMS externo al contenedor lo primero que hacemos es crear un objeto de propiedades con los valores necesarios para conectar con el contenedor EJB (como hicimos en el cliente del &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=239&quot;&gt;primer artículo&lt;/a&gt;). A continuación creamos un contexto de ejecución desde el que poder acceder al contenedor, y mediante JNDI obtenemos un objeto factoría &lt;code&gt;ConnectionFactory&lt;/code&gt;, a través del cual podremos realizar conexiones para el envío de mensajes.
&lt;br&gt;
&lt;br&gt;Ahora viene la parte interesante: creamos un objeto &lt;code&gt;Topic&lt;/code&gt; que está asociado al canal virtual que hemos declarado en el primer paso lógico de esta sección (mediante su dirección JNDI), creamos una conexión con el broker mediante el objeto factoría, iniciamos una nueva sesión dentro de la conexión recién creada, creamos un objeto &lt;code&gt;MessageProducer&lt;/code&gt; asociado al objeto &lt;code&gt;Topic&lt;/code&gt;, iniciamos la conexión para poder enviar un mensaje, creamos un mensaje de tipo texto, lo enviamos, y finalmente cerramos la conexión.
&lt;br&gt;
&lt;br&gt;Al ejecutar el cliente, el mensaje se enviará al topic, y puesto que existen clientes consumidores asociados a ese topic, el contenedor EJB consumirá el mensaje, extraerá del pool MDB una instancia del componente MDB (o creará la instancia &lt;i&gt;en el aire&lt;/i&gt;; a nosotros nos es indiferente), y le pasará el mensaje al método &lt;code&gt;onMessage()&lt;/code&gt; de dicha instancia para que procese el mensaje. Si, tras ejecutar el cliente JMS, miras la pestaña &lt;i&gt;Console&lt;/i&gt; de Eclipse, verás el mensaje imprimido en el log de JBoss (tal como se definió al escribir el método &lt;code&gt;onMessage&lt;/code&gt;).
&lt;br&gt;
&lt;br&gt;¿Recuerdas el sencillo esquema de la sección 3.10?:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Cliente (Productor)   ---&gt;   Broker   ---&gt;   Cliente (Consumidor)   ---&gt;   Message-Driven Bean
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- El cliente Java es el cliente productor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- JMS (más concretamente su implementación HornetQ) es el broker
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- El contenedor EJB es el cliente consumidor
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Una instancia MDB es quien procesa el mensaje
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Lo interesante de un servicio de mensajería es que el cliente productor no sabe quien consumirá su mensaje, ni como lo hará. Podría ser un MDB, o podría ser otro componente en nada relacionado con la especificación EJB (tal vez ejecutándose en una máquina remota con un sistema operativo distinto).
&lt;br&gt;
&lt;br&gt;Por último, veamos como hacer que un MDB sea también productor:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.mdb;
&lt;br&gt;
&lt;br&gt;import javax.annotation.Resource;
&lt;br&gt;import javax.ejb.ActivationConfigProperty;
&lt;br&gt;import javax.ejb.MessageDriven;
&lt;br&gt;import javax.ejb.MessageDrivenContext;
&lt;br&gt;import javax.jms.Connection;
&lt;br&gt;import javax.jms.ConnectionFactory;
&lt;br&gt;import javax.jms.JMSException;
&lt;br&gt;import javax.jms.Message;
&lt;br&gt;import javax.jms.MessageListener;
&lt;br&gt;import javax.jms.MessageProducer;
&lt;br&gt;import javax.jms.Session;
&lt;br&gt;import javax.jms.TextMessage;
&lt;br&gt;import javax.jms.Topic;
&lt;br&gt;
&lt;br&gt;@MessageDriven(activationConfig={
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ActivationConfigProperty(propertyName=&quot;destinationType&quot;, propertyValue=&quot;javax.jms.Topic&quot;),
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ActivationConfigProperty(propertyName=&quot;destination&quot;, propertyValue=&quot;topic/PrimerTopic&quot;)})
&lt;br&gt;public class PrimerMDB implements MessageListener {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Resource
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private MessageDrivenContext contexto;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void onMessage(Message message) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(message instanceof TextMessage) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String contenidoDelMensaje = ((TextMessage)message).getText();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;PrimerMDB ha procesado el mensaje: &quot; + contenidoDelMensaje);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enviarMensaje(&quot;Mensaje enviado desde MDB&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (JMSException jmse) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new RuntimeException(&quot;Error al procesar un mensaje&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void enviarMensaje(String mensaje) throws JMSException {&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contexto.lookup(&quot;ConnectionFactory&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ConnectionFactory factoria = (ConnectionFactory)contexto.lookup(&quot;ConnectionFactory&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Topic topic = (Topic)contexto.lookup(&quot;topic/SegundoTopic&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Connection conexion = factoria.createConnection();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Session sesion = conexion.createSession(false, Session.AUTO_ACKNOWLEDGE);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MessageProducer productor = sesion.createProducer(topic);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conexion.start();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TextMessage mensajeDeTexto = sesion.createTextMessage(mensaje);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;productor.send(mensajeDeTexto);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conexion.close();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, dentro del método &lt;code&gt;onMessage()&lt;/code&gt; se llama a un método de utilidad que envia un nuevo mensaje a un segundo topic (que debemos haber declarado con anterioridad, por supuesto). La única diferencia entre el código del método de utilidad y el método &lt;code&gt;main()&lt;/code&gt; del cliente Java es que, puesto que el primero se está ejecutando dentro del contenedor EJB, podemos obtener el contexto de ejecución mediante inyección de dependencia, evitando así la necesidad de crear el objeto de propiedades y conectar por red al contenedor (lo cual sería bastante absurdo).
&lt;br&gt;
&lt;br&gt;Ahora podemos declarar un segundo MDB que procese los mensajes del segundo topic:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.mdb;
&lt;br&gt;
&lt;br&gt;import javax.ejb.ActivationConfigProperty;
&lt;br&gt;import javax.ejb.MessageDriven;
&lt;br&gt;import javax.jms.JMSException;
&lt;br&gt;import javax.jms.Message;
&lt;br&gt;import javax.jms.MessageListener;
&lt;br&gt;import javax.jms.TextMessage;
&lt;br&gt;
&lt;br&gt;@MessageDriven(activationConfig={
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ActivationConfigProperty(propertyName=&quot;destinationType&quot;, propertyValue=&quot;javax.jms.Topic&quot;),
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ActivationConfigProperty(propertyName=&quot;destination&quot;, propertyValue=&quot;topic/SegundoTopic&quot;)})
&lt;br&gt;public class SegundoMDB implements MessageListener {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void onMessage(Message message) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(message instanceof TextMessage) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String contenidoDelMensaje = ((TextMessage)message).getText();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;SegundoMDB ha procesado el mensaje: &quot; + contenidoDelMensaje);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (JMSException jmse) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new RuntimeException(&quot;Error al procesar un mensaje&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt; 
&lt;br&gt;Cuando &lt;code&gt;PrimerMDB&lt;/code&gt; reciba un mensaje, la consola de JBoss (pestaña &lt;i&gt;Console&lt;/i&gt; de Eclipse) mostrará como ambos MDB han procesado los mensajes de sus topics correspondientes:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;19:00:47,453 INFO  [STDOUT] PrimerMDB ha procesado el mensaje: Mensaje enviado desde Java
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;19:00:47,475 INFO  [STDOUT] SegundoMDB ha procesado el mensaje: Mensaje enviado desde MDB
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;3.16 RESUMEN
&lt;br&gt;En este tercer artículo del tutorial de EJB hemos terminado de ver los componentes de lado del servidor, además de algunas características interesantes que son nuevas en la especificación EJB 3.1: llamadas asíncronas y vista sin interface (ambas son aplicables a componentes Session Bean, pero no a Message-Driven Beans). En el próximo artículo veremos como integrar persistencia mediante Java Persistence API (JPA - API de persistencia en Java) con una aplicación EJB 3.1, en gran medida mediante ejemplos prácticos. En ningún caso se explicará a fondo JPA (ni que es, ni como funciona), así que si no conoces este framework te aconsejo que visites el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=144&quot;&gt;tutorial&lt;/a&gt; de cuatro artículos sobre JPA que se encuentra publicado en esta misma web.</description>
    </item>
    <item>
      <title>Revisión del tutorial de introducción a JPA</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=242</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=242</guid>
      <pubDate>Fri, 01 Apr 2011 20:32:48 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Hace ya algún tiempo que publiqué en el blog el tutorial de JPA (14 meses para ser más exactos), y por ser aquellos los primeros artículos técnicos que escribí y publiqué, llevaban consigo la impronta del &lt;i&gt;escritor novato&lt;/i&gt;. Hoy, después de haber escrito algunos artículos más, mi estilo es en cierto modo diferente, para mi gusto un poquito mejor, y tal vez ahora me veo capaz de expresar los mismos conceptos de forma más simple y comprensible, lo que yo llamo &lt;i&gt;más fácil de leer&lt;/i&gt;.
&lt;br&gt;
&lt;br&gt;El proposito de todo este rollo (que no creo que os importe demasiado) es que, aprovechando que el tutorial de EJB 3.1 se encuentra en plena efervescencia, y sobre todo que el último de sus artículos publicado hasta ahora termina haciendo un guiño (por no decir un grito) al tutorial de JPA, he revisado, reescrito, y corregido este último, acciones que, una vez concluidas, he comprobado que eran realmente necesarias. Como siempre espero que disfrutéis del &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=144&quot;&gt;material revisado&lt;/a&gt;, tanto aquellos que ya lo hicieron en su momento, como los que lo tengan ante si por primera vez.</description>
    </item>
    <item>
      <title>Introducción a EJB 3.1 (IV)</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=243</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=243</guid>
      <pubDate>Thu, 07 Apr 2011 17:48:14 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>En los &lt;a href=&quot;http://www.davidmarco.es/tutoriales/&quot;&gt;artículos anteriores&lt;/a&gt; del tutorial de introducción a EJB 3.1, hemos visto como declarar y trabajar con componentes de lado del servidor (Session Beans y Message-Driven Beans). El último componente que nos queda por ver es Entity Beans (EB - Beans de Entidad; a partir de ahora nos referiremos a ellos como &lt;i&gt;entidades&lt;/i&gt;).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.1 ENTIDADES: CONCEPTOS BÁSICOS
&lt;br&gt;Las entidades, a diferencia del resto de componentes EJB, son objetos Java reales que son manejados entre componentes (o entre un cliente y un componente) en su forma original, nunca a través de proxys/vistas. Podemos crearlos con sentencias &lt;code&gt;new&lt;/code&gt;, pasarlos como parámetros a un Session Bean, etc. Pero el verdadero valor de las entidades reside en que su estado puede ser almacenado en una base de datos, y más tarde recuperado en un nuevo objeto del tipo correspondiente. De manera adicional, los cambios que realicemos en el estado de una entidad serán sincronizados con la información que tenemos almacenada en la base de datos.
&lt;br&gt;
&lt;br&gt;Aunque las entidades se consideran componentes EJB, hasta la version JavaEE 1.4 pertenecían a una especificación independiente llamada Java Persistence API (JPA - API de Persistencia en Java). Fue a partir de la versión 5 de JavaEE que la especificación EJB &lt;i&gt;absorvió&lt;/i&gt; a la especificación JPA. Sin embargo, podemos trabajar con entidades en una aplicación no-EJB, aunque, tras bambalinas, se seguirán ejecutando dentro de un contenedor EJB. Desde ahora usaremos el término &lt;i&gt;aplicación JPA&lt;/i&gt; para referirnos a aplicaciones que realizan persistencia, y el término &lt;i&gt;aplicación EJB&lt;/i&gt; cuando exista integración de ambas tecnologías.
&lt;br&gt;
&lt;br&gt;En este artículo no vamos a tratar en profundidad la especificación JPA (ni la declaración ni el uso de entidades), si no como integrarla con una aplicación EJB 3.1. Si no conoces JPA, es prácticamente obligatorio que visites el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=144&quot;&gt;tutorial de JPA&lt;/a&gt; publicado en este mismo blog, de manera que puedas comprender todo el material que sigue a continuación.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.2 ENTIDADES: EL CICLO DE VIDA
&lt;br&gt;Como ya se ha mencionado, las entidades no son objetos del lado del servidor. Sin embargo, cuando son usadas dentro del contexto de un contenedor EJB, se convierten en objetos gestionados (gracias al servicio de persistencia, el cual es controlado mediante la interface &lt;code&gt;EntityManager&lt;/code&gt;). Esto nos lleva a los dos únicos estados de una entidad cuando se encuentra en el contexto de un contenedor EJB:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Gestionada (Attached)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- No gestionada (Detached)
&lt;br&gt;
&lt;br&gt;En el primer estado, la entidad se encuentra &lt;i&gt;gestionada&lt;/i&gt; por el servicio de persistencia: cualquier cambio que realicemos en su estado se verá reflejado en la base de datos subyacente. En el segundo estado, la entidad es un objeto Java regular, y cualquier cambio que realicemos en su estado no será sincronizado con la base de datos subyacente. En este último estado, la entidad puede ser, por ejemplo, enviada a traves de una red (mediante serialización).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.3 ENTIDADES: UNIDAD DE PERSISTENCIA
&lt;br&gt;Una &lt;i&gt;unidad de persistencia&lt;/i&gt; (persistence unit) representa un conjunto de entidades que pueden ser mapeadas a una base de datos, así como la información necesaria para que la aplicación JPA pueda acceder a dicha base de datos. Se define mediante un archivo llamado &lt;i&gt;persistence.xml&lt;/i&gt;, el cual debe acompañar a la aplicación donde se realizan las tareas de persistencia (recuerda que puede ser una aplicación EJB o una aplicación Java normal):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&lt;br&gt;&amp;lt;persistence xmlns=&quot;http://java.sun.com/xml/ns/persistence&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; version=&quot;2.0&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;persistence-unit name=&quot;introduccionEJB&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- configuración de acceso a la base de datos --&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- lista de entidades que pueden ser mapeadas --&amp;gt;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/persistence-unit&amp;gt;
&lt;br&gt;&amp;lt;/persistence&amp;gt; 
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Podemos definir más de una unidad de persistencia por aplicación, declarando cada una de ellas mediante el elemento XML &amp;lt;persistence-unit&amp;gt;. Cada unidad de persistencia debe seguir estas dos reglas:
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Debe proporcionar un nombre (identidad) a través del cual pueda ser llamado
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Debe conectar a una sola fuente de datos (data source)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Dependiendo del tipo de paquete que estemos construyendo (EAR, JAR, etc), el archivo &lt;i&gt;persistence.xml&lt;/i&gt; deberá encontrarse en una localización u otra. En la sección 4.6 veremos un ejemplo completo de este archivo, así como la información necesaria para su correcto despliegue dentro de una aplicación EJB.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.4 ENTIDADES: CONTEXTO DE PERSISTENCIA
&lt;br&gt;Otro concepto que tenemos que tener claro es el de &lt;i&gt;contexto de persistencia&lt;/i&gt;. Un contexto de persistencia representa un conjunto de instancias de entidades que se encuentran gestionadas en un momento dado. Existen dos tipos de contextos de persistencia:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Limitados a una transacción (Transaction-scoped)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Extendidos (Extended)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Cuando trabajamos dentro de un contexto de persistencia &lt;i&gt;limitado a una transancción&lt;/i&gt;, todas las entidades gestionadas pasarán a estar no gestionadas cuando dicha transacción finalice. Dicho con otras palabras, los cambios realizados tras finalizar la transacción no serán sincronizados con la base de datos.
&lt;br&gt;
&lt;br&gt;Cuando trabajamos dentro de un contexto de persistencia &lt;i&gt;extendido&lt;/i&gt;, las cosas funcionan de manera diferente: el contexto de persistencia sobrevivirá a la transacción donde se ejecuta, de manera que los cambios que realicemos en el estado de las entidades gestionadas por el contexto de persistencia se sincronizarán con la base de datos en el momento en que entremos en una nueva transacción. Este comportamiento es útil cuando trabajamos con SFSB, pues permite mantener un estado conversacional y mantener nuestras entidades sincronizadas.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.5 ENTIDADES: ENTITY MANAGER
&lt;br&gt;Mediante la interface &lt;code&gt;EntityManager&lt;/code&gt; (Gestor de entidades) tenemos acceso al servicio de persistencia de nuestro contenedor. Podemos obtener una instancia de &lt;code&gt;EntityManager&lt;/code&gt; en nuestros componentes EJB mediante inyección de dependencias:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import javax.ejb.Stateless;
&lt;br&gt;import javax.persistence.EntityManager;
&lt;br&gt;import javax.persistence.PersistenceContext;
&lt;br&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class MiSlsb {
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PersistenceContext(unitName=&quot;introduccionEJB&quot;)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private EntityManager em;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// operaciones del SLSB
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El ejemplo anterior inyecta una instancia de &lt;code&gt;EntityManager&lt;/code&gt; en el SLSB mediante la anotación &lt;code&gt;@PersistenceContext&lt;/code&gt;. A esta anotación hay que proporcionarle como atributo el nombre de la unidad de persistencia que &lt;code&gt;EntityManager&lt;/code&gt; usará para realizar la persistencia (y que hemos definido en el archivo &lt;i&gt;persistence.xml&lt;/i&gt;). Con los metadatos proporcionados obtendremos por defecto un contexto de persistencia limitado a una transacción (ver sección anterior); si deseamos obtener un contexto de persistencia extendido (solo válido en SFSB por su naturaleza conversacional), debemos añadir el atributo &lt;code&gt;type&lt;/code&gt; con el valor correspondiente para este comportamiento:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;import javax.persistence.PersistenceContextType;
&lt;br&gt;
&lt;br&gt;// ...
&lt;br&gt;
&lt;br&gt;@PersistenceContext(unitName=&quot;introduccionEJB&quot;, type=PersistenceContextType.EXTENDED)
&lt;br&gt;private EntityManager em;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En lo que se refiere a este tutorial, la integración de EJB con JPA termina aquí. Por tanto, podemos pasar a ver un ejemplo donde conectaremos todas las piezas para realizar persistencia mediante EJB 3.1.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.6 ENTIDADES: UN SENCILLO EJEMPLO
&lt;br&gt;Veamos un sencillo ejemplo de un componente EJB realizando persistencia sobre una base de datos. Al igual que algunos ejemplos anteriores, este consta de varias partes:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Una fuente de datos (data source) donde realizar la persistencia&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Una aplicación EJB donde se realiza las acciones de persistencia
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Un cliente EJB desde el que intercambiar entidades con la aplicación EJB
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Nuestro primer paso va a ser definir una fuente de datos que conectará nuestro contenedor EJB con nuestra base de datos. Siguiendo el entorno de desarrollo configurado en el &lt;a href=&quot;http://www.davidmarco.es/tutoriales/anexos/anexo_introduccion_ejb31.html&quot;&gt;anexo&lt;/a&gt; que acompaña este tutorial, escribimos un archivo llamado &lt;i&gt;derby-ds.xml&lt;/i&gt; y lo guardamos en el directorio &lt;i&gt;server\default\deploy&lt;/i&gt; de nuestra instalación de JBoss:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;br&gt;&amp;lt;datasources&amp;gt;
&lt;br&gt;   &amp;lt;local-tx-datasource&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;lt;jndi-name&amp;gt;DerbyDS&amp;lt;/jndi-name&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;lt;connection-url&amp;gt;jdbc:derby://localhost:1527/introduccionEJB;create=true&amp;lt;/connection-url&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;lt;driver-class&amp;gt;org.apache.derby.jdbc.ClientDataSource40&amp;lt;/driver-class&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;lt;user-name&amp;gt;&amp;lt;/user-name&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;lt;password&amp;gt;&amp;lt;/password&amp;gt;
&lt;br&gt;   &amp;lt;/local-tx-datasource&amp;gt;
&lt;br&gt;&amp;lt;/datasources&amp;gt;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el archivo XML anterior definimos una fuente de datos (data source) limitado a transacciones locales, esto es, dentro del propio contenedor (existe otro ambito de ejecución de una transacción llamado &lt;i&gt;extendido&lt;/i&gt;, capaz de realizar su trabajo a través de múltiples contenedores). A esta fuente de datos le hemos dado un nombre JNDI desde la que poder invocarla, así como los parámetros de conexión con nuestra base de datos subyacente (url, usuario, y password). Si JBoss 6.0.0 Final está arrancado, nada más guardar el archivo anterior la fuente de datos será activada y se producirá la conexión con Derby, así que deberás tener la base de datos iniciada o se producirá un error; nosotros vamos a considerar que en este preciso momento tanto JBoss como Derby están parados.
&lt;br&gt;
&lt;br&gt;El siguiente paso es crear un proyecto EJB 3.1 en Eclipse, y continuación levantar la base de datos Derby desde el propio IDE. Para ello, haz click con el botón derecho sobre el nombre del proyecto EJB en la pestaña &lt;i&gt;Proyect Explorer&lt;/i&gt; y selecciona:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Apache Derby &gt; Add Apache Derby nature
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;La operación anterior añade a nuestro proyecto las librerias del servidor embebido Derby, de manera que podamos conectar con él. A continuación levantamos la base de datos haciendo click con el botón derecho sobre el nombre del proyecto EJB en la pestaña &lt;i&gt;Proyect Explorer&lt;/i&gt; y seleccionando:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Apache Derby &gt; Start Derby Network Server
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Nos aparecerá una ventana donde se nos informa que la base de datos está siendo levantada, haz click en el botón &lt;i&gt;OK&lt;/i&gt; para finalizar este proceso. En un entorno en producción, todas estas operaciones serían innecesarias, pues teóricamente tendríamos una base de datos externa funcionando de manera continua.
&lt;br&gt;
&lt;br&gt;Ahora vamos a crear un componente SLSB remoto, de manera que podamos llamarlo desde un cliente Java normal. Como recordarás, un componente remoto requiere de manera obligatoria implementar una interface:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;import es.davidmarco.ejb.entidad.Cuenta;
&lt;br&gt;
&lt;br&gt;public interface OperacionesConCuentas {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void crearCuenta(Cuenta cuenta);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Cuenta obtenerCuenta(Long id);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void borrarCuenta(Cuenta cuenta);
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Ahora ya podemos implementar el componente remoto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.slsb;
&lt;br&gt;
&lt;br&gt;import javax.ejb.Remote;
&lt;br&gt;import javax.ejb.Stateless;
&lt;br&gt;import javax.persistence.EntityManager;
&lt;br&gt;import javax.persistence.PersistenceContext;
&lt;br&gt;import es.davidmarco.ejb.entidad.Cuenta;
&lt;br&gt;
&lt;br&gt;@Remote
&lt;br&gt;@Stateless
&lt;br&gt;public class OperacionesConCuentasRemote implements OperacionesConCuentas {
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PersistenceContext(unitName=&quot;introduccionEJB&quot;)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private EntityManager em;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void crearCuenta(Cuenta nuevaCuenta) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;em.persist(nuevaCuenta);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Cuenta obtenerCuenta(Long id) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return em.find(Cuenta.class, id);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void borrarCuenta(Cuenta cuenta) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;em.remove(cuenta);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El componente anterior es extremadamente sencillo: en él se inyecta una instancia de &lt;code&gt;EntityManager&lt;/code&gt;, la cual es usada en los métodos del Session Bean para realizar las tareas de persistencia. Estos métodos usan como parámetros o tipos de retorno instancias de la clase &lt;code&gt;Cuenta&lt;/code&gt; (la cual define cuentas bancarias) y que será nuestra entidad:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.entidad;
&lt;br&gt;
&lt;br&gt;import java.io.Serializable;
&lt;br&gt;
&lt;br&gt;import javax.persistence.Entity;
&lt;br&gt;import javax.persistence.GeneratedValue;
&lt;br&gt;import javax.persistence.Id;
&lt;br&gt;
&lt;br&gt;@Entity
&lt;br&gt;public class Cuenta implements Serializable {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private static final long serialVersionUID = 1L;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Id
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@GeneratedValue
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Long id;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String numeroDeCuenta;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String nombreDelTitular;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Double saldo;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Long getId() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return id;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setId(Long id) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.id = id;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getNumeroDeCuenta() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return numeroDeCuenta;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setNumeroDeCuenta(String numeroDeCuenta) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.numeroDeCuenta = numeroDeCuenta;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getNombreDelTitular() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return nombreDelTitular;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setNombreDelTitular(String nombreDelTitular) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.nombreDelTitular = nombreDelTitular;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Double getSaldo() {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return saldo;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setSaldo(Double saldo) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.saldo = saldo;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void aumentarSaldo(Double cantidad) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;saldo += cantidad;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void reducirSaldo(Double cantidad) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;saldo -= cantidad;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;Algunos detalles de la entidad definida en el ejemplo anterior merecen una pequeña explicación: para empezar, nuestra entidad implementa la interface &lt;code&gt;Serializable&lt;/code&gt;, necesaría cuando nuestra entidad va a viajar a través de una red (en nuestro caso entre el cliente Java y el contenedor EJB). Dentro de la entidad definimos 4 propiedades: una para la identidad de la entidad, y tres para representar su estado (&lt;code&gt;numeroDeCuenta&lt;/code&gt;, &lt;code&gt;nombreDelTitular&lt;/code&gt;, y &lt;code&gt;saldo&lt;/code&gt;), más sus correspondientes métodos getter/setter. De manera adicional, hemos añadido algunas operaciones de lógica de negocio (&lt;code&gt;aumentarSaldo()&lt;/code&gt; y &lt;code&gt;reducirSaldo&lt;/code&gt;) dentro de la entidad; es una buena práctica que las operaciones relacionadas con cuentas estén dentro de la clase que representa dichas cuentas.
&lt;br&gt;
&lt;br&gt;Ahora que tenemos un componente EJB y una entidad, vamos a crear la unidad de persistencía asociada a la fuente de datos y nuestra entidad. Crea un archivo llamado &lt;i&gt;persistence.xml&lt;/i&gt; en el directorio &lt;i&gt;META-INF&lt;/i&gt; del proyecto EJB:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&lt;br&gt;&amp;lt;persistence xmlns=&quot;http://java.sun.com/xml/ns/persistence&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd&quot;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; version=&quot;2.0&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;persistence-unit name=&quot;introduccionEJB&quot; transaction-type=&quot;JTA&quot;&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;provider&amp;gt;org.hibernate.ejb.HibernatePersistence&amp;lt;/provider&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;jta-data-source&amp;gt;java:/DerbyDS&amp;lt;/jta-data-source&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;class&amp;gt;es.davidmarco.ejb.entidad.Cuenta&amp;lt;/class&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;properties&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;property name=&quot;hibernate.dialect&quot;  value=&quot;org.hibernate.dialect.DerbyDialect&quot; /&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;property name=&quot;hibernate.hbm2ddl.auto&quot; value=&quot;update&quot;/&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/properties&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/persistence-unit&amp;gt;
&lt;br&gt;&amp;lt;/persistence&amp;gt;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el archivo XML anterior hemos declarado una unidad de persistencia con nombre &lt;code&gt;introduccionEJB&lt;/code&gt; (que fue el que usamos como parámetro de la anotación &lt;code&gt;@PersistenceContext&lt;/code&gt; en el componente SLSB que definimos previamente), así como transacciones de tipo JTA (gestionadas por el contenedor; los tipos de transacción se explicaron en las secciones 3.2 y 3.3 del &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=153&quot;&gt;tercer artículo&lt;/a&gt; del tutorial de JPA). 
&lt;br&gt;
&lt;br&gt;Ya dentro de la declaración de la unidad de persistencia, hemos declarado el proveedor de persistencia que usaremos (&lt;code&gt;HibernatePersistence&lt;/code&gt;), la dirección JNDI de la fuente de datos que declaramos en el archivo &lt;i&gt;derby-ds.xml&lt;/i&gt;, y las entidades que gestionaremos en esta unidad de persistencia (en nuestro caso solamente &lt;code&gt;Cuenta&lt;/code&gt;). Por último, hemos configurado algunos detalles relativos a la fuente de datos dentro del elemento &lt;code&gt;&amp;lt;properties&amp;gt;&lt;/code&gt;: el &lt;i&gt;dialecto&lt;/i&gt; que usará el contenedor para construir sentencias SQL adecuadas a nuestra base de datos, y la creación automática de los esquemas necesarios en base a los metadatos de nuestras entidades (de esta manera nos evitamos crear manualmente tanto las tablas como sus columnas, incluyendo la definición del tipo de dato de cada columna, restricciones de cada columna, etc). Ahora ya podemos desplegar la aplicación EJB en el contenedor.
&lt;br&gt;
&lt;br&gt;El último paso necesario para probar nuestro ejemplo es crear un cliente Java que pasará una instancia ya inicializada de la entidad &lt;code&gt;Cliente&lt;/code&gt; al componente EJB. Para ello, y para mantener las cosas sencillas, creamos un proyecto Java en Eclipse y le añadimos las librerias del proyecto EJB haciendo click con el botón derecho del ratón en el nombre del proyecto Java y seleccionando:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Build Path &gt; Configure Build Path
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;En la ventana que nos aparece, vamos a la pestaña &lt;i&gt;Proyects&lt;/i&gt;, hacemos click en el botón &lt;i&gt;Add&lt;/i&gt;, seleccionamos el proyecto EJB donde esta nuestro componente SLSB y nuestra entidad, hacemos click en el botón &lt;i&gt;OK&lt;/i&gt;, y de nuevo hacemos click en el botón &lt;i&gt;OK&lt;/i&gt;. Ahora ya podemos escribir el cliente:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;package es.davidmarco.ejb.cliente;
&lt;br&gt;
&lt;br&gt;import java.util.Properties;
&lt;br&gt;import javax.naming.Context;
&lt;br&gt;import javax.naming.InitialContext;
&lt;br&gt;import javax.naming.NamingException;
&lt;br&gt;import es.davidmarco.ejb.entidad.Cuenta;
&lt;br&gt;import es.davidmarco.ejb.slsb.OperacionesConCuentas;
&lt;br&gt;
&lt;br&gt;public class Cliente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private static final String JNDI_BEAN = &quot;OperacionesConCuentasRemote/remote&quot;;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws NamingException {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Properties properties = new Properties();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.factory.initial&quot;, &quot;org.jnp.interfaces.NamingContextFactory&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.factory.url.pkgs&quot;, &quot;org.jboss.naming:org.jnp.interfaces&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.provider.url&quot;, &quot;jnp://localhost:1099&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Context context = new InitialContext(properties);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Cuenta cuenta = new Cuenta();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cuenta.setNumeroDeCuenta(&quot;0000-0001&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cuenta.setNombreDelTitular(&quot;Nuevo cliente&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cuenta.setSaldo(2500D); */
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;OperacionesConCuentas occ = (OperacionesConCuentas)context.lookup(JNDI_BEAN);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;occ.crearCuenta(cuenta);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, creamos e inicializamos una cuenta, obtenemos un proxy/vista al componente EJB, e invocamos su método &lt;code&gt;crearCuenta()&lt;/code&gt; pasándole como parámetro la cuenta. Esta entidad será serializada, viajará a traves de la red hasta el contenedor, será deserializada, y dentro del componente EJB será persistida en la base de datos. Podemos comprobarlo ejecutando una sentencia SQL contra la base de datos: para ello, haz click con el botón derecho sobre el nombre del proyecto EJB en la pestaña &lt;i&gt;Proyect Explorer&lt;/i&gt; y selecciona:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Apache Derby &gt; ij (Interactive SQL)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;La consola de &lt;i&gt;ij&lt;/i&gt; se abrirá en la pestaña &lt;i&gt;Console&lt;/i&gt; de Eclipse, y desde el prompt de &lt;i&gt;ij&lt;/i&gt; nos conectamos a la base de datos mediante el comando:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;connect 'jdbc:derby://localhost:1527/introduccionEJB;'
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Cuando la conexión se realice, volveremos a ver el prompt de &lt;i&gt;ij&lt;/i&gt;. Ahora ya podemos realizar la consulta SQL mediante el comando:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;select * from cuenta;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;La consola de ij nos mostrará un registro en la tabla &lt;i&gt;Cuenta&lt;/i&gt;:
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|Nuevo cliente&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|0000-0001&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|2500.0
&lt;br&gt;
&lt;br&gt;Esto demuestra que nuestra entidad (un POJO Java) ha sido almacenado en una base de datos relacional (tablas y columnas) de manera transparente para nosotros. Misión cumplida. Si deseáramos realizar el proceso inverso (obtener un objeto Java desde la información almacenada en la base de datos):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;// ...
&lt;br&gt;
&lt;br&gt;public class Cliente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private static final String JNDI_BEAN = &quot;OperacionesConCuentasRemote/remote&quot;;
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws NamingException {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Properties properties = new Properties();
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.factory.initial&quot;, &quot;org.jnp.interfaces.NamingContextFactory&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.factory.url.pkgs&quot;, &quot;org.jboss.naming:org.jnp.interfaces&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties.put(&quot;java.naming.provider.url&quot;, &quot;jnp://localhost:1099&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Context context = new InitialContext(properties);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Cuenta cuenta = new Cuenta();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// cuenta.setNumeroDeCuenta(&quot;0000-0001&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// cuenta.setNombreDelTitular(&quot;Nuevo cliente&quot;);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// cuenta.setSaldo(2500D); */
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;OperacionesConCuentas occ = (OperacionesConCuentas)context.lookup(JNDI_BEAN);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// occ.crearCuenta(cuenta);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Cuenta cuenta = occ.obtenerCuenta(1L);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;Titular de la cuenta &quot; 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;+ cuenta.getNumeroDeCuenta() 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;+ &quot; con saldo &quot; 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;+ cuenta.getSaldo() 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;+ &quot;: &quot; 
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;+ cuenta.getNombreDelTitular());
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, hemos comentado las lineas que crean y persisten un cliente (de otra manera se insertará un nuevo registro con los misma información en la base de datos pero con &lt;i&gt;ID&lt;/i&gt; con valor 2), y en su lugar hemos llamado al método &lt;code&gt;obtenerCuenta()&lt;/code&gt; del SLSB, para así obtener una cuenta desde la base de datos en base a su &lt;i&gt;ID&lt;/i&gt;. Si una cuenta con ese &lt;i&gt;ID&lt;/i&gt; no existe, obtendremos como respuesta un valor &lt;code&gt;null&lt;/code&gt;. Te invito a que, a modo de práctica, elimines de la base de datos la cuenta que hemos creado llamando al método &lt;code&gt;borrarCuenta()&lt;/code&gt; del SLSB; para verificarlo, una vez hayas ejecutado esta operación vuelve a realizar la consulta SQL contra la base de datos a través de la consola de &lt;i&gt;ij&lt;/i&gt;:
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;select * from cuenta;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;Si has realizado correctamente el ejercicio, la tabla &lt;i&gt;Cuenta&lt;/i&gt; no deberá mostrar ninguna entidad (salvo que hayas insertado entidades adicionales).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;4.7 RESUMEN
&lt;br&gt;Como hemos visto en este artículo, podemos realizar persistencia de manera extremadamente sencilla en nuestras aplicaciones EJB. Las entidades son simples POJO's, la configuración con la base de datos se configura mediante archivos XML, y en nuestros componentes EJB solo tenemos que inyectar una unidad de persistencia y ejecutar sus métodos.
&lt;br&gt;
&lt;br&gt;En este punto ya hemos visto todos los componentes EJB (Session Beans, Message-Driven Beans, y Entities). Los dos próximos artículos estarán dedicados a los diversos servicios que ofrece el contenedor, servicios que nuestros componentes pueden usar para realizar taréas más complejas (y que son necesarias en aplicaciones reales).</description>
    </item>
    <item>
      <title>Cliente EJB para Glassfish v3</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=244</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=244</guid>
      <pubDate>Wed, 20 Apr 2011 14:34:36 +0200</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Para todos aquellos que estáis siguiendo el tutorial de introducción a EJB 3.1, pero habéis decidido usar Glassfish v3 como servidor de aplicaciones (en lugar de JBoss 6), aquí tenéis el código necesario para configurar el cliente Java que conecta con el contenedor EJB:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Properties props = new Properties();
&lt;br&gt;props.setProperty(&quot;java.naming.factory.initial&quot;, &quot;com.sun.enterprise.naming.SerialInitContextFactory&quot;);
&lt;br&gt;props.setProperty(&quot;java.naming.factory.url.pkgs&quot;, &quot;com.sun.enterprise.naming&quot;);
&lt;br&gt;props.setProperty(&quot;java.naming.factory.state&quot;, &quot;com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl&quot;);
&lt;br&gt; 
&lt;br&gt;// Opcional. Por defecto es localhost. Solo es necesario si el servidor se está ejecutando en una máquina distinta 
&lt;br&gt;props.setProperty(&quot;org.omg.CORBA.ORBInitialHost&quot;, &quot;localhost&quot;);
&lt;br&gt; 
&lt;br&gt;// Opcional. Por defecto es 3700. Solo es necesario si el puerto ORB es diferente de 3700&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;props.setProperty(&quot;org.omg.CORBA.ORBInitialPort&quot;, &quot;3700&quot;);
&lt;br&gt;
&lt;br&gt;Context ic = new InitialContext(props);
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;De manera adicional, la aplicación cliente puede necesitar que el módulo &lt;i&gt;gf-client.jar&lt;/i&gt; se encuentre en el classpath (puedes encontrar dicho módulo en el directorio &lt;i&gt;glassfish\modules&lt;/i&gt; de tu instalación de Glassfish v3).
&lt;br&gt;
&lt;br&gt;Muchísimas gracias a Antonio Querol por ponerse en contacto conmigo y compartir esta información.
&lt;br&gt;
&lt;br&gt;</description>
    </item>
    <item>
      <title>Retomando el blog</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=245</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=245</guid>
      <pubDate>Tue, 21 Feb 2012 19:14:50 +0100</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Para los que seguís mi blog, os será evidente que hace mucho tiempo que no publico nada; compromisos laborales y personales me tienen atado 24 horas al día, 7 días a la semana, dejándome apenas tiempo para sentarme delante del PC y escribir cualquiera de los muchos artículos que tengo en mente (o simplemente pendiente, como las dos últimas entregas del tutorial de EJB 3.1...).
&lt;br&gt;
&lt;br&gt;Puesto que sois muchos los que me animáis a través de correo electrónico a continuar publicando contenido (y por ello os doy las gracias), en los próximos días volveré a la carga con nuevos artículos. Espero poder encontrar desde este mismo instante el tiempo suficiente para escribir tres artículos de cierta dimensión cada dos meses, como mínimo (y creedme que haré todo lo posible por llevarlo a cabo).
&lt;br&gt;
&lt;br&gt;Por descontado, toda sugerencia sobre nuevos artículos será bienvenida, por lo que os animo a poneros en contacto conmigo al respecto como habéis hecho hasta ahora. Un saludo y hasta muy pronto.</description>
    </item>
    <item>
      <title>Lazy Fetch en JPA</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=246</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=246</guid>
      <pubDate>Thu, 23 Feb 2012 23:53:08 +0100</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Una de las características que ofrecen JPA (entre otros frameworks de mapeo relacional de objetos) que más puede beneficiarnos cuando la entendemos y aplicamos de forma correcta, y que más quebraderos de cabeza provoca a quienes están empezando, es &lt;i&gt;Lazy Fetch&lt;/i&gt;. Aunque ya hemos hablado con anterioridad de forma superficial sobre Lazy Fetch durante el &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=150&quot;&gt;tutorial de JPA&lt;a/&gt; publicado en esta misma web, debido a la cantidad de personas que se ponen en contacto conmigo al respecto y por la satisfacción inherente de entender un poco mejor una importante caracteristica del lenguaje, he considerado interesante escribir un pequeño artículo donde se analice con cierta profundidad qué es, cómo funciona, y cómo podemos beneficiarnos (además de cómo evitar errores típicos) de Lazy Fetch . Comencemos.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;LAZY FETCH, A.K.A. LECTURA DEMORADA
&lt;br&gt;El termino Lazy Fetch, que traducido literalmente significa &lt;i&gt;obtención perezosa&lt;/i&gt; (aunque yo prefiero entenderlo como &lt;i&gt;lectura demorada&lt;/i&gt;), viene a reflejar la característica de JPA que permite que, cuando existen relaciones entre distintas entidades, las que son dependientes de otras no sean inicializadas con sus valores almacenados en base de datos hasta que no sean explícitamente accedidas (&lt;i&gt;leidas&lt;/i&gt;). Toda esta verborrea se entiende mejor con un sencillo ejemplo:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Entity
&lt;br&gt;public class Factura {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;@Entity
&lt;br&gt;public class Proveedor {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@OneToMany
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private List&lt;Factura&gt; facturas;
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, tenemos una entidad contenedora (&lt;code&gt;Proveedor&lt;/code&gt;) que contiene una relación &lt;i&gt;uno-a-muchos&lt;/i&gt; (&lt;code&gt;@OneToMany&lt;/code&gt;) con otra entidad, &lt;code&gt;Facturas&lt;/code&gt; a través de un objeto &lt;code&gt;List&lt;/code&gt;. Hasta aquí todo es bastante simple, por lo que... ¡compliquémoslo!
&lt;br&gt;
&lt;br&gt;Imaginemos que cada proveedor concreto suele tener multitud de facturas asociadas (algo bastante habitual), aunque gran parte de las consultas a la entidad &lt;code&gt;Proveedor&lt;/code&gt; no están accediendo en ningún momento a dichas facturas; cada obtención de un proveedor desde base de datos supondría realizar diferentes subconsultas para inicializar todas sus facturas, de manera que estaríamos incurriendo en una sobrecarga innecesaria de los recursos del sistema (esto en un ejemplo &lt;i&gt;de juguete&lt;/i&gt; como el nuestro no es apreciable ni notorio, pero en un sistema real que esté recibiendo miles o decenas de miles de peticiones por minuto (por poner una cifra) puede sobrecargar y hasta agotar los recursos de la red, procesadores, ram, base de datos, etc...).
&lt;br&gt;
&lt;br&gt;Por este motivo, JPA permite marcar una relación entre entidades como Lazy, de manera que la inicialización desde base de datos de los objetos afectados es retrasada hasta que éstos son explicitamente requeridos por código cliente.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;¿QUIÉN ES LAZY?
&lt;br&gt;Por defecto, de los cuatro tipos de relación entre entidades permitidos en JPA (&lt;code&gt;@OneToOne&lt;/code&gt;, &lt;code&gt;@OneToMany&lt;/code&gt;, &lt;code&gt;@ManyToOne&lt;/code&gt; y &lt;code&gt;@ManyToMany&lt;/code&gt;) sólo dos son de tipo Lazy: &lt;code&gt;@OneToMany&lt;/code&gt; y &lt;code&gt;&lt;@ManyToMany&lt;/code&gt;. Esto tiene mucho sentido, pues son estos dos tipos los que a más objetos conectan en el otro lado de la relación. Al ser el comportamiento por defecto, no debemos hacer nada para declarar estas relaciones como Lazy (es su comportamiento implícito).
&lt;br&gt;
&lt;br&gt;El resto de relaciones &lt;i&gt;no-Lazy&lt;/i&gt; (&lt;code&gt;@ManyToOne&lt;/code&gt; y &lt;code&gt;@OneToOne&lt;/code&gt;) deben ser marcadas explícitamente como Lazy si queremos que se comporten de dicha manera:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Entity
&lt;br&gt;public class Empleado {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@OneToOne(fetch=FetchType.LAZY)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Direccion direccion;
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;EL GRAN PROBLEMA
&lt;br&gt;Una vez una entidad contenedora ha sido desconectada (&lt;i&gt;dettached&lt;/i&gt;) del gestor de persistencia (por ejemplo al enviarla de vuelta al código cliente que la solicitó), esta se enviará tal como esté en ese momento sin importar en que estado estén sus relaciones que hayan sido marcadas como Lazy. Si una relación ha sido inicializada antes de desconectar la entidad del gestor de persistencia, podremos acceder a sus valores de forma normal; en caso contrario, la relación no apuntará a ningún objeto, y por tanto obtendremos un error al intentar manejarla:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class ClaseDelLadoServidor {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Proveedor obtenerProveedor(Long proveedorId) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Conectamos con BBDD y obtenemos la entidad a devolver
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return proveedor;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Supongamos que en este momento la colección &lt;code&gt;facturas&lt;/code&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// no ha sido inicializada aún
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;
&lt;br&gt;public class ClaseDelLadoCliente {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void procesarFacturas(long proveedorId) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Proveedor proveedor = claseLadoServidor.obtenerProveedor(proveedorId);
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(Factura factura : proveedor.getFacturas()) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Procesar cada factura
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;En el ejemplo anterior, la simple llamada a &lt;code&gt;getFacturas()&lt;/code&gt; en la clase del lado del cliente provocaría una excepción que, dependiendo de tu proveedor de persistencia (en mi caso es EclipseLink) se parecerá más o menos a esto:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;Exception in thread &quot;main&quot; Local Exception Stack: 
&lt;br&gt;Exception [EclipseLink-7242] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.ValidationException
&lt;br&gt;Exception Description: An attempt was made to traverse a relationship using indirection that had a null Session.  This often occurs when an entity with an uninstantiated LAZY relationship is serialized and that lazy relationship is traversed after serialization.  To avoid this issue, instantiate the LAZY relationship prior to serialization.
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at org.eclipse.persistence.exceptions.ValidationException.instantiatingValueholderWithNullSession(ValidationException.java:979)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:219)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:83)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at org.eclipse.persistence.indirection.IndirectList.buildDelegate(IndirectList.java:237)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at org.eclipse.persistence.indirection.IndirectList.getDelegate(IndirectList.java:397)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at org.eclipse.persistence.indirection.IndirectList.size(IndirectList.java:726)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at es.davidmarco.ejb.lazyloading.standaloneclient.LazyLoadingClient.main(LazyLoadingClient.java:43)
&lt;br&gt;
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;El mensaje principal que se informa en el error es el siguiente:
&lt;br&gt;
&lt;br&gt;&lt;i&gt;
&lt;br&gt;Ha sido realizado un intento de recorrer una relación mediante indirección que tenía una sesión null. Esto ocurre a menudo cuando una entidad que contiene una relación Lazy sin inicializar es serializada y dicha relación es recorrida después de la serialización. Para evitar este problema, inicializa la relación Lazy de forma previa a la serialización.
&lt;br&gt;&lt;/i&gt;
&lt;br&gt;
&lt;br&gt;Los primeros de la clase se estarán preguntando: ¿cómo es posible que nuestro cliente, que posiblemente se esté ejecutando fuera de un contenedor de aplicaciones, tal vez incluso en otra máquina funcionando bajo una JVM distinta, esté lanzando una excepción JPA en lugar de algo como la archimalvada &lt;code&gt;NullPointerException&lt;/code&gt;? El proveedor de persistencia puede hacer esto de algunas maneras, como devolviendo objetos proxy que envuelven al objeto original, o manipulando el código de bytes, entre otras. No voy a profundizar en este asunto pues no nos afecta de forma directa, pero tenlo simple presente de manera que, cuando suceda, sepas lo que está ocurriendo.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;LA GRAN SOLUCIÓN
&lt;br&gt;Es un poco atrevido pensar en que existe una gran solución a nuestro gran problema, pues primero deberíamos preguntarnos si éste es realmente tal; hasta ahora lo hemos llamado así por el simple hecho de que a todos (al menos a todos los que hemos trabajado con JPA) nos ha ocurrido en alguna ocasión, sobre todo al principio, y los sentimientos que produce van desde &quot;chocante&quot; hasta &quot;desconcertante&quot; (sobre todo si no sabemos que está ocurriendo y, todavía peor, tampoco porqué). Lo cierto es que no es ningún problema, y tal como hemos dicho anteriormente, Lazy Fetch trata simple y llanamente de eso: enviar la información necesaria, y omitir el resto hasta que sea explicitamente accedida.
&lt;br&gt;
&lt;br&gt;Una solución par evitar enviar a un cliente relaciones no inicializadas es definirlas explícitamente como &lt;i&gt;no-lazy&lt;/i&gt; (o dicho de forma más correcta, &lt;i&gt;Eager&lt;/i&gt;):
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Entity
&lt;br&gt;public class Empleado {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ManyToMany(fetch=FetchType.EAGER)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private List&lt;Proyecto&gt; proyectos;
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;También podemos inicializar implícitamente las entidades asociadas a través de algún mecanismo del lenguaje:
&lt;br&gt;
&lt;br&gt;&lt;code&gt;
&lt;br&gt;@Stateless
&lt;br&gt;public class ClaseDelLadoServidor {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Proveedor obtenerProveedor(Long proveedorId) {
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Conectamos con BBDD y obtenemos la entidad a devolver
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;facturas.size();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Inicializa la relación al completo. No usar para inicializar de
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// forma explícita, en su lugar usar &lt;code&gt;fetch=FetchType.EAGER&lt;/code&gt;.
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return proveedor;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br&gt;}
&lt;br&gt;&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;Para no violar el cometido principal de Lazy, sólo debemos inicializar una relación (ya sea de forma explícita o implícita) en escenarios como los siguientes: 
&lt;br&gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Cuando conocemos de antemano que los clientes de nuestra entidad van a acceder a el/los miembros de la relación después de que esta sea desconectada del contexto de persistencia.
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Cuando, a pesar de mantenernos aún dentro de una transacción, sabemos que se van a producir multitud de llamadas a los elementos referenciados en la relación (cada una de ellas realizando sus peticiones a base de datos de forma exclusiva e independiente de las demas), de manera que el coste total va a terminar siendo mayor que si hubiéramos inicializado la relación en el momento de la inicializar la entidad contenedora.
&lt;br&gt;
&lt;br&gt;Evidentemente, estas situaciones no son faciles de preveer en la mayoría de los casos, más aún cuando no tenemos control sobre el código cliente. Éste último, si está bajo nuestro control, no debe hacer llamadas a relaciones no inicializadas (evidentemente). En caso de no conocer de antemano si una relación ha sido inicializada, debemos manejar un posible error mediante tratamiento de excepciones (esto es, capturándo la excepción e inicializando la relación dentro del bloque &lt;code&gt;catch&lt;/code&gt;). Al margen del tratamiento de excepciones, si deseamos acceder a una relación que sabemos que no está inicializada, deberemos gestionarlo a través de lógica de negocio adicional (podemos enviar la entidad contenedora de vuelta al servidor de aplicaciones para que sea &lt;i&gt;refrescada&lt;/i&gt; con la información ausente y devuelta de nuevo al cliente, solicitar sólo las entidades contenidas en la relación a traves de algún valor de la entidad contenedora que permita identificarlas, etc...). Esta lógica adicional estará integrada en el lado del servidor, pues es allí donde tenemos acceso al contexto de persistencia.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;MOJÁNDONOS LOS PIES
&lt;br&gt;Es importante entender que ocurre entre bambalinas cuando tratamos con relaciones de tipo Lazy, por lo que vamos a sumergirnos un poco (aunque muy poco) en la forma en que esto ocurre dentro de JPA. Todas (repito, todas) las operaciones de persistencia JPA se producen dentro de una transacción. Tarde o temprano, toda transacción finaliza, y en ese momento todas las entidades involucradas son &lt;i&gt;desconectadas&lt;/i&gt; del contexto de persistencia, dejando de estar gestionadas por &lt;code&gt;EntityManager&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;En el ejemplo de la sección anterior, la clase &lt;code&gt;ClaseDelLadoServidor&lt;/code&gt; ha sido marcada como &lt;code&gt;@Stateless&lt;/code&gt;, de manera que ya sea mediante persistencia manejada por el contenedor (JTA) o controlada manualmente (RESOURCE-LOCAL), en el momento de terminar la ejecución del método se debe dar por terminada la transacción. Es en este momento cuando la entidad puede ser devuelta al cliente que la solicitó.
&lt;br&gt;
&lt;br&gt;En el caso de estar trabajando con componentes de tipo &lt;code&gt;@Statefull&lt;/code&gt;, podemos mantener una transacción por un periodo de tiempo mayor al de una única invocación a cualquiera de los métodos del componente, por lo que la entidad y sus relaciones pueden permanecer gestionadas por un tiempo mayor al de una única invocación a cualquiera de los métodos del componente (esto implica que cualquier acceso a una relación no inicializada se trataría de forma transparente para nosotros).
&lt;br&gt;
&lt;br&gt;Al trabajar con relaciones Lazy, debemos usar siempre interfaces (como &lt;code&gt;List&lt;/code&gt; o &lt;code&gt;Map&lt;/code&gt;) en lugar de implementaciones concretas (como &lt;code&gt;ArrayList&lt;/code&gt; o &lt;code&gt;HashMap&lt;/code&gt;): esto, además de ser una las grandes-reglas/buenas-prácticas cuando utilizamos un lenguaje orientado a objetos como Java, va a permitir al proveedor de persistencia usar sus propias implementaciones lo que a su vez nos permitirá a nosotros beneficiarnos de la magia de Lazy Fetch.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;LA OTRA CARA DE LA MONEDA
&lt;br&gt;El comportamiento opuesto a Lazy Fetch, como vimos en un ejemplo anterior, es &lt;i&gt;Eager Fetch&lt;/i&gt; (el término puede traducirse literalmente como &lt;i&gt;obtención impaciente&lt;/i&gt;, pero yo, de nuevo, prefiero entenderlo como &lt;i&gt;inicialización temprana&lt;/i&gt;). Cuando una relación es de tipo Eager, o es marcada con este comportamiento de forma explícita, ésta es inicializada en el mismo instante en que lo es su entidad contenedora. Esto conlleva cero problemas para el código cliente, pues a efectos prácticos estamos en la misma situación que cuando trabajamos con POJOs en un entorno de &lt;i&gt;no-persistencia&lt;/i&gt; (se aplican las reglas de construcción típicas del class loader). Tan simple como eso.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;USO Y ABUSO
&lt;br&gt;Lazy Fetch tiene un cometido concreto, y esto por si sólo ya es motivo para su existencia. El coste de crear objetos puede ser inmenso si todas las relaciones dentro de una entidad (relaciones que a su vez pueden contener sus propias relaciones, y así indefinidamente) fueran iniciadas en cascada desde el momento de creación de la entidad contenedora original. Otra situación en la cual Lazy Fetch es sumamente útil es cuando definimos una relación con objetos de gran tamaño (como BLOBs y CLOBs). Esta clase de relaciones suelen definirse como Lazy y, en caso de ser necesario el/los objeto/s referenciados, accedidos mediante lógica adicional. Todo esto representa el buen uso de Lazy Fetch.
&lt;br&gt;
&lt;br&gt;Por supuesto podemos inicializar explícitamente todas las relaciones como Eager y olvidarnos de todo lo demás, y esto representa el mal uso de la arquitectura. Tarde o temprano terminaremos incurriendo en costes extra, ya que entre todos los objetos que estaremos inicializando, multitud de ellos serán accedidos en muy raras ocasiones (o incluso ninguna).
&lt;br&gt;
&lt;br&gt;En este punto, y a pesar del &lt;i&gt;gran problema&lt;/i&gt; que tuvimos unas secciones más atrás, podríamos pensar que &lt;i&gt;&quot;Lazy Fetch es un mecanismo mejor que Eager Fetch&quot;&lt;/i&gt;; nada más lejos de la realidad, pues podemos terminar cometiendo un pecado distinto pero igual de grave, el de marcar toda relación viviente como Lazy: puesto que ninguna relación estará inicializada dentro de la entidad contenedora, todos y cada una de los accesos que realicemos sobre ellas conllevará el coste extra de una nueva petición a base de datos, situándonos de nuevo frente a posibles futuros problemas de agotamiento de recursos.
&lt;br&gt;
&lt;br&gt;La solución, como casi siempre, se encuentra en encontrar el equilibrio (en nuestro caso determinar que componentes deben ser Lazy y cuales Eager). Si bien esto es algo que no puede ser definido con exactitud en el momento de iniciar el desarrollo de una aplicación, lo será en mayor o menor medida durante su periodo de vida (en parte gracias a herramientas externas y en parte gracias al propio comportamiento y/o respuesta de la aplicación ante situaciones de estress).
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;RESUMEN
&lt;br&gt;Esto es todo lo que necesitas saber para, si no ser el gran &lt;i&gt;Gurú&lt;/i&gt; de Lazy Fetch, si al menos saber en cierto detalle qué es y cómo funciona. Puedes encontrar información adicional en esta misma web sobre persistencia en general y JPA en particular &lt;a href=&quot;http://www.davidmarco.es/tutoriales/hibernate-reference/&quot;&gt;aquí&lt;/a&gt; y &lt;a href=&quot;http://www.davidmarco.es/blog/entrada.php?id=144&quot;&gt;aquí&lt;/a&gt;. Saludos.</description>
    </item>
    <item>
      <title>Cambio de alojamiento externo</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=247</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=247</guid>
      <pubDate>Sun, 04 Mar 2012 20:28:59 +0100</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Desde este momento, los tutoriales en &lt;i&gt;versión PDF&lt;/i&gt; de Spring MVC e Hibernate, así como el proyecto para eclipse del primero, se mueven desde el servicio de almacenamiento externo &lt;i&gt;4Shared&lt;/i&gt; a &lt;i&gt;Dropbox&lt;/i&gt;. Este último, además de ofrecer descargas simultaneas, mantener la misma url al subir nuevas versiones y carecer de tiempo de espera, requiere menos mantenimiento por mi parte. Las nuevas direcciones son las siguientes:
&lt;br&gt;
&lt;br&gt;Tutorial de Spring MVC: &lt;a href=&quot;http://dl.dropbox.com/u/42898825/davidmarco.es/SpringMVC.pdf&quot;&gt;http://dl.dropbox.com/u/42898825/davidmarco.es/SpringMVC.pdf&lt;/a&gt;
&lt;br&gt;Tutorial de Hibernate: &lt;a href=&quot;http://dl.dropbox.com/u/42898825/davidmarco.es/Hibernate.pdf&quot;&gt;http://dl.dropbox.com/u/42898825/davidmarco.es/Hibernate.pdf&lt;/a&gt;
&lt;br&gt;Proyecto para eclipse (Spring MVC): &lt;a href=&quot;http://dl.dropbox.com/u/42898825/davidmarco.es/springapp.rar&quot;&gt;http://dl.dropbox.com/u/42898825/davidmarco.es/springapp.rar&lt;/a&gt;
&lt;br&gt;
&lt;br&gt;Como consecuencia de este cambio, dentro de 60 días dejaré de dar soporte a mi cuenta de 4Shared, por lo que los citados archivos sólo estarán accesibles desde las nuevas direcciones.
&lt;br&gt;
&lt;br&gt;Estoy seguro que este cambio supondrá una mejora para todos, y como siempre os invito a que me enviéis vuestro feedback. Por último, recordaros que las versiones html siguen siendo accesibles desde la habitual &lt;a href=&quot;http://www.davidmarco.es/tutoriales&quot;&gt;página de tutoriales&lt;/a&gt;.</description>
    </item>
    <item>
      <title>Cambio de alojamiento externo</title>
      <link>http://www.davidmarco.es/blog/entrada.php?id=247</link>
      <guid>http://www.davidmarco.es/blog/entrada.php?id=247</guid>
      <pubDate>Sun, 04 Mar 2012 20:29:21 +0100</pubDate>
      <author>programacion@davidmarco.es (David Marco)</author>
      <description>Desde este momento, los tutoriales en &lt;i&gt;versión PDF&lt;/i&gt; de Spring MVC e Hibernate, así como el proyecto para eclipse del primero, se mueven desde el servicio de almacenamiento externo &lt;i&gt;4Shared&lt;/i&gt; a &lt;i&gt;Dropbox&lt;/i&gt;. Este último, además de ofrecer descargas simultaneas, mantener la misma url al subir nuevas versiones y carecer de tiempo de espera, requiere menos mantenimiento por mi parte. Las nuevas direcciones son las siguientes:&lt;br&gt;&lt;br&gt;Tutorial de Spring MVC: &lt;a href=&quot;http://dl.dropbox.com/u/42898825/davidmarco.es/SpringMVC.pdf&quot;&gt;http://dl.dropbox.com/u/42898825/davidmarco.es/SpringMVC.pdf&lt;/a&gt;&lt;br&gt;Tutorial de Hibernate: &lt;a href=&quot;http://dl.dropbox.com/u/42898825/davidmarco.es/Hibernate.pdf&quot;&gt;http://dl.dropbox.com/u/42898825/davidmarco.es/Hibernate.pdf&lt;/a&gt;&lt;br&gt;Proyecto para eclipse (Spring MVC): &lt;a href=&quot;http://dl.dropbox.com/u/42898825/davidmarco.es/springapp.rar&quot;&gt;http://dl.dropbox.com/u/42898825/davidmarco.es/springapp.rar&lt;/a&gt;&lt;br&gt;&lt;br&gt;Como consecuencia de este cambio, dentro de 60 días dejaré de dar soporte a mi cuenta de 4Shared, por lo que los citados archivos sólo estarán accesibles desde las nuevas direcciones.&lt;br&gt;&lt;br&gt;Estoy seguro que este cambio supondrá una mejora para todos, y como siempre os invito a que me enviéis vuestro feedback. Por último, recordaros que las versiones html siguen siendo accesibles desde la habitual &lt;a href=&quot;http://www.davidmarco.es/tutoriales&quot;&gt;página de tutoriales&lt;/a&gt;.</description>
    </item>
  </channel>
</rss>

