Sunteți pe pagina 1din 159

índice general_

1. INTRODUCCIÓN A J2EE ..............................................................1


2. APLICACIONES WEB .................................................................17
3. ENTERPRISES BEANS Y SERVICIOS DE CONTENEDOR ...............33
4. BEANS DE SESIÓN ....................................................................83
5. BEANS DE ENTIDAD................................................................109
6. BEANS CONTROLADOS POR MENSAJE. EMPAQUETADO Y
ROLES ....................................................................................139

GLOSARIO ....................................................................................155
BIBLIOGRAFÍA..............................................................................157
índice_ 1 Introducción
a J2EE

1.1. JAVA ........................................................................................3


1.2. ¿QUÉ ES J2EE? .........................................................................3
1.2.1. El período de ejecución..................................................4
1.2.2. Los API J2EE .................................................................4
1.3. CONTENEDORES .......................................................................7
1.4. LA ARQUITECTURA MULTICAPA ................................................9
1.4.1. Las capas ......................................................................9
1.4.2. Las capas de J2EE........................................................11

1
1.1. JAVA
1 Introducción
a J2EE

Hace ya varios años que el lenguaje de programación Java vio la luz. Desde entonces ha ido
ganando en popularidad a pasos agigantados. Lo que en principio empezó siendo un lenguaje
para la programación de electrodomésticos, es actualmente una de las mejores opciones
para el desarrollo de software.

La que inicialmente se conoció como la plataforma Java, evolucionó con el paso del tiempo a
la plataforma Java 2 (la versión 1.2) y se crearon tres ediciones distintas, cada una de ellas
especializada en un conjunto de necesidades específicas y con un kit de desarrollo de
software propio:

− La plataforma Java 2 Edición Estándar (J2SE o Java 2 Standard Edition): Consiste en


un entorno de tiempo de ejecución y un conjunto de API para crear aplicaciones y
applets.

− La plataforma Java 2 Edición Móvil (J2ME o Java 2 Mobile Edition): Permite la creación
de aplicaciones para pequeños dispositivos y dispositivos inalámbricos, generalmente,
con recursos muy limitados.

− La plataforma Java 2 Edición Empresarial (J2EE o Java 2 Enterprise Edition): Contiene


los API necesarios para la creación de aplicaciones para arquitecturas multicapa.

1.2. ¿QUÉ ES J2EE?

J2EE es una tecnología que se centra fundamentalmente en el desarrollo de componentes


para entornos distribuidos. Es un conjunto de especificaciones e indica tanto la estructura
para gestionar las aplicaciones de empresa, como los servicios API para construir dichas
aplicaciones.

La plataforma J2EE es un entorno Java que ofrece:

− Una infraestructura de período de ejecución para contener y gestionar aplicaciones.

− Un conjunto de API para la construcción de aplicaciones.

3
1.2.1. El período de ejecución
1 Introducción
a J2EE

El período de ejecución de un servidor J2EE es el contexto en el que “viven” las


aplicaciones, es decir, el entorno en el que residen y se ejecutan.

La especificación J2EE no indica cómo debe o puede construirse un período de ejecución.


Esto conlleva la separación entre las aplicaciones y la infraestructura del período de
ejecución, la cual permite al periodo de ejecución abstraerse de los servicios de
infraestructura.

Desde el punto de vista del desarrollo, esto significa que los desarrolladores pueden
centrarse en la lógica de negocio y despreocuparse de las cuestiones del nivel de sistemas.

De este modo, la arquitectura J2EE nos proporciona un medio uniforme de acceder a los
servicios a escala de la plataforma a través de su entorno de período de ejecución. Entre
estos servicios podemos citar las transacciones distribuidas y la gestión de seguridad, entre
otros.

1.2.2. Los API J2EE

Ya sabemos que J2EE es un conjunto formado por varios API que nos permite realizar
aplicaciones distribuidas. En este apartado vamos a enumerar los distintos API de los que se
compone, junto con una breve descripción de cada uno de ellos.

− Enterprise JavaBeans (EJB). Especifica una estructura de componentes para


aplicaciones distribuidas. Además, suministra el medio para definir componentes del
lado servidor y especifica la infraestructura de período de ejecución para albergar a
dichos componentes.

Un componente Enterprise JavaBeans es un bloque de código que implementa


reglas de negocio. Puede ser autónomo o funcionar en conjunción con otros
componentes para ejecutar lógica de negocio en un servidor J2EE.

− Java Database Connectivity (JDBC). Permite el acceso a la información contenida


en bases de datos mediante la utilización de sentencias SQL. Es una interfaz
independiente del sistema de gestión de bases de datos, por lo que permite escribir
código independiente del servidor de bases de datos.

4
Este API está formado por dos componentes:
1 Introducción
a J2EE

• Una interfaz a nivel de aplicación que usan los componentes para poder acceder
a la base de datos.

• Una interfaz del proveedor de servicios (base de datos) que hace de puente
entre el controlador JDBC y la plataforma J2EE.

− Java Servlet. Proporciona abstracciones para la construcción de aplicaciones web


dinámicas y permite definir clases servlet específicas para el protocolo HTTP,
extendiendo la capacidad de los servidores en los que las aplicaciones acceden
mediante el modelo de programación solicitud-respuesta.

− JavaServer Pages. Extiende las posibilidades de las aplicaciones web facilitando su


desarrollo en el caso de aplicaciones dirigidas por un modelo.

− Java Message Service (JMS). Es un API para colas de mensaje. Publica y suscribe
tipos de servicios de software intermediarios controlados por mensajes.

Además, permite a las aplicaciones la creación, envío, recepción y lectura de


mensajes. Hace posible que las comunicaciones distribuidas con bajo nivel de
acoplamiento sean fiables.

− Java Naming and Directory Interface (JNDI). Este API pertenece realmente a la
edición estándar de Java (J2SE), no obstante, lo incluimos aquí por la gran relación
que tiene con el desarrollo de aplicaciones J2EE.

Su finalidad es proveer funcionalidad de nombres y directorios y es independiente de


cualquier implementación específica de servicio de designación de directorio.

Por otra parte, provee métodos para la realización de las operaciones comunes de
directorio, como la asociación de atributos con objetos y la búsqueda de objetos a
partir de sus atributos.

El API JNDI provee el acceso de las aplicaciones al entorno de nombres de JNDI. Este
entorno permite personalizar los componentes sin tener que cambiar su código fuente.

5
1 Introducción
a J2EE
− Java Transaction API (JTA). Permite delimitar las operaciones transaccionales
dentro las aplicaciones distribuidas. Es un medio para trabajar con transacciones y con
transacciones distribuidas independientes de la implementación del gestor de
transacciones.

En la plataforma J2EE, las transacciones distribuidas están controladas por el


contenedor, por lo que no debemos preocuparnos por las transacciones entre
componentes.

− JavaMail API. Proporciona una infraestructura independiente de la plataforma y del


protocolo para el uso de mensajes (correo electrónico) desde las aplicaciones Java.

Está formado por dos componentes:

• Una interfaz a nivel de aplicación que se usa para el envío de mensajes.


• Una interfaz de proveedor de servicios.

− JavaBeans Activation Framework (JAF). Este API se incluye porque es necesario


para el API JavaMail. Lo utiliza para determinar los contenidos de un mensaje y las
operaciones apropiadas que pueden realizarse sobre las diferentes partes de un
mensaje.

− Java API for XML Processing (JAXP). Este API soporta el procesamiento de
documentos XML usando DOM (Document Object Model), el API SAX (Simple API for
XML Parsing) y XSLT (XML Stylesheet Language Transformation).

Permite que las aplicaciones puedan analizar y transformar documentos XML con
independencia de cualquier implementación específica.

− Java API for XML Registries (JAXR). Permite el acceso sobre la web a los registros
de empresa y de propósito general.

• Soporta los estándares ebXML Registry/Repository y las nuevas especificaciones


UDDI.
• Con JAXR se puede aprender un único API para acceder a ambas tecnologías.

6
1 Introducción
a J2EE
− Java API for XML-Based RPC (JAX-RPC). Permite que las aplicaciones puedan
realizar llamadas a procedimientos remotos (RPC) sobre Internet mediante el uso de
SOAP y HTTP.

También soporta WSDL (Web Service Description Language), por lo que se pueden
importar y exportar documentos WSDL.

Por último decir que, mediante JAX-RPC y WSDL se puede interactuar con otros
clientes y servicios.

− SOAP with Attachments API for Java (SAAJ). Es un API de bajo nivel del que
depende JAX-RPC. Hace posible la producción y consumo de mensajes que cumplan la
especificación SOAP.

− J2EE Connector Arquitecture (JCA). Se ha implementado para permitir la


integración de componentes de aplicación J2EE de sistemas de información
propietarios.

Este API lo utilizan los desarrolladores de herramientas de J2EE y los integradores de


sistemas para crear adaptadores de recursos que soporten acceso a sistemas de
información corporativos que se puedan conectar con aplicaciones J2EE.

Un adaptador de recursos es un componente que permite a los componentes de


aplicaciones J2EE interactuar con el gestor de recursos subyacente (el sistema de
información propietario). Cada adaptador de recursos es específico, ya que depende de
dicho sistema de información.

− Java Authentication and Authorization Service (JAAS). Proporciona mecanismos


de autentificación y autorización para las aplicaciones.

1.3. CONTENEDORES

Como ha hemos mencionado anteriormente, la especificación J2EE no describe la naturaleza


y estructura del período de ejecución. En lugar de ello, introduce lo que se denomina
contenedor y mediante los API especifica un contrato entre los contenedores y las
aplicaciones, que no es más que un conjunto de normas que ambos deben cumplir.

Podemos definir un contenedor J2EE como un período de ejecución para gestionar los

7
1 Introducción
a J2EE
componentes de la aplicación desarrollados según las especificaciones del API y destinado a
proporcionar acceso a los API de J2EE.

Dentro de la arquitectura de J2EE, existen cuatro tipos de contenedores:

− Contenedor de aplicación cliente: Alberga las aplicaciones Java estándar.

− Contenedor de applets: Alberga applets de Java.

− Contenedor web: Alberga aplicaciones web (servlets y páginas JSP).

− Contenedor EJB: Alberga componentes Enterprise JavaBean.

Cada de estos contenedores proporciona un entorno de período de ejecución para los


componentes que aloja. Es el contenedor el que crea y gestiona dichos componentes, así
como sus ciclos de vida.

En esta arquitectura, los clientes empleados más frecuentemente son:

− Clientes web. Se suelen ejecutar en navegadores web. La interfaz de usuario es


generada dinámicamente por el servidor y mostrada por los navegadores. Se utiliza el
protocolo HTTP para la comunicación entre el cliente y el servidor.

− Clientes EJB. Son aplicaciones que acceden a componentes EJB. Existen tres tipos de
clientes:

• De aplicación. Son aplicaciones de escritorio que acceden a los EJB mediante el


protocolo RMI-IIOP.

• Componentes de contenedores web. Son servlets y páginas JSP que acceden


a los componentes EJB utilizando el protocolo RMI-IIOP o llamadas estándar de
métodos de Java mediante interfaces locales.

• Componentes EJB. Se trata de EJB que acceden a otros EJB y que pueden
utilizar RMI-IIOP o llamadas estándar de métodos estándar Java.

Ambos tipos de clientes acceden a los componentes de la aplicación mediante sus


respectivos contenedores.

8
1.4. LA ARQUITECTURA MULTICAPA
1 Introducción
a J2EE

Se entiende por capa a un grupo de tecnologías que suministran uno o más servicios a sus
clientes.

La primera tecnología basada en capas que existió fue el modelo cliente/servidor y está
basada en dos capas. En dicho modelo, las aplicaciones cliente son aplicaciones de escritorio
y realizan peticiones a los servidores que ejecutan programas y que responden a las
peticiones de los clientes.

Un gran inconveniente de este tipo de arquitectura es que el mantenimiento actualizado del


software de los clientes resulta difícil y costoso, sobre todo, a medida que va aumentando el
número de clientes.

Por el contrario, los sistemas multicapa basados en web no necesitan que se actualice el
software de los clientes cuando se modifica la presentación o la funcionalidad de las
aplicaciones.

1.4.1. Las capas

En el apartado anterior definimos una capa como un grupo de tecnologías que suministran
servicios a sus clientes. Para entender cómo se organiza una estructura de capas, podemos
ver su similitud con una empresa de tamaño grande:

En el nivel más bajo están los servicios de infraestructura que se componen de los recursos
necesarios para mantener las instalaciones. Entre estos recursos tenemos: la electricidad, los
ascensores, la telefonía y las redes informáticas.

La siguiente capa contiene los servicios de soporte para la actividad principal de la empresa.
Se compone de recursos como: la contabilidad, proveedores e informática.

Sobre esta última se encontraría la capa de producción, que permite producir los productos y
servicios que vende la empresa. Cuenta con recursos como: las compras, diseño de
productos y facturación.

Y por último, la capa más alta de la organización sería la de marketing, que permite
determinar qué productos y servicios vender a los clientes.

La siguiente figura muestra cómo se organiza en capas la estructura empresarial puesta

9
como ejemplo.
1 Introducción
a J2EE

Por otro lado, hemos de entender por cliente a cualquier recurso que envía una petición de
un servicio a un proveedor de servicios (o, como comúnmente se le hace referencia,
servicio).

Un servicio se define como cualquier recurso que recibe y atiende una petición de un
cliente, y puede ser, a su vez, cliente de otro servicio.

En una arquitectura multicapa, cada capa contiene servicios que incluyen objetos de
software, sistemas de gestión de base de datos o conexiones con sistemas heredados.

La arquitectura multicapa se utiliza porque es la forma más efectiva de construir


aplicaciones flexibles y escalables. Esto se debe a que la funcionalidad de la aplicación se
divide en componentes lógicos que se asocian con cada una de las capas, siendo cada
componente un servicio que se construye y mantiene de forma independiente de los demás
servicios.

Los servicios se enlazan mediante un protocolo de comunicaciones que les permiten recibir y
enviar información de y a otros servicios.

De este modo, el cliente envía una petición de servicio, recibe los resultados y no debe
preocuparse por la forma en que el servicio le debe proporcionar dichos resultados. Esto
significa que podemos desarrollar rápidamente mediante la creación de un programa cliente
que envía peticiones a los servicios que ya existen en la arquitectura multicapa. Estos
servicios ya contienen la funcionalidad necesaria para atender la petición de nuestro

10
programa cliente.
1 Introducción
a J2EE

Asimismo, los servicios pueden ir modificándose según va cambiando la funcionalidad y sin


que afecte al programa cliente. Por ejemplo, podríamos tener un cliente que solicitara los
impuestos asociados a un pedido determinado. Para ello, enviaríamos la petición al servicio
que contiene la funcionalidad necesaria para calcular los impuestos (la lógica de negocio
necesaria para calcular los impuestos estaría dentro del servicio) y en un futuro podría
modificarse la lógica de negocio del servicio conforme a los cambios de las leyes de
impuestos sin tener que modificar el programa cliente.

1.4.2. Las capas de J2EE

La arquitectura J2EE está basada en cuatro capas, que son las siguientes:

− Capa cliente. También es conocida como la capa de presentación o de aplicación, ya


que es en la que se ubican los clientes finales (los usuarios de las aplicaciones).

− Capa web.

− Capa EJB o la capa de negocio. En ella se ubican las reglas de negocio.

− Capa EIS. Llamada capa de los sistemas de información empresarial (Enterprise


Information Systems).

Cada capa está orientada para proporcionar a una aplicación un tipo específico de
funcionalidad.

Es preciso diferenciar entre ubicación física y funcionalidad. A pesar de que varias capas
puedan residir físicamente dentro de una misma máquina virtual (JVM), cada una
proporciona a las aplicaciones J2EE distinto tipo de funcionalidad. Las aplicaciones J2EE
tienen acceso únicamente a aquellas capas de las que requiere su funcionalidad.

11
1 Introducción
a J2EE
En la siguiente figura podemos ver la estructura de capas de la arquitectura J2EE.

La mayoría de los API de J2EE tampoco están asociados con ninguna capa en concreto, es
decir, se pueden utilizar en más de una capa. Por ejemplo, el API JDBC se puede utilizar en
las capas web y EJB, mientras que el API EJB sólo es aplicable a la capa EJB.

La capa cliente está compuesta por los programas que interactúan con el usuario de la
aplicación. Estos programas le piden datos al usuario y convierten su respuesta en peticiones
que se reenvían a un componente que procesa la petición y devuelve el resultado al
programa cliente. El componente puede funcionar en cualquier capa, aunque normalmente
las peticiones de clientes suelen ir dirigidas a componentes de la capa web. El programa
cliente también traduce la respuesta del servidor en texto y pantallas que se muestran al
usuario.

Por otro lado, la capa web proporciona funcionalidad web a la aplicación J2EE. Los
componentes de esta capa utilizan el protocolo HTTP para recibir peticiones de los clientes y
enviar respuestas a los mismos (que pueden estar en cualquier capa). Recordemos que un
cliente es cualquier componente que inicia una petición.

La capa EJB (Enterprise JavaBeans) es la que contiene la lógica de negocio de las


aplicaciones. Aquí se encuentran los componentes Enterprise JavaBeans a los que llaman los
clientes. En esta capa, los EJB van a permitir que múltiples componentes de la aplicación
tengan acceso a la lógica y datos de negocio de forma concurrente.

12
1 Introducción
a J2EE
Los Enterprise JavaBeans se encuentran dentro del contenedor de EJB, que es un servidor
de objetos distribuidos que trabaja en la capa EJB. El contenedor gestiona las transacciones
y la seguridad, y se asegura que los hilos y la persistencia se implementen de forma correcta
cada vez que se invoca a un Enterprise JavaBeans.

Aunque un EJB puede tener acceso a componentes de cualquier capa, generalmente llama a
componentes y recursos como el DBMS (Database Management System) en la capa de
sistemas de información empresarial (EIS).

Por último, la capa EIS es la que conecta a la aplicación con recursos y sistemas heredados
que están en la red corporativa. En esta capa, la aplicación J2EE se conecta con tecnologías
como DBMS y mainframes que forman parte de los sistemas críticos de la empresa. Los
componentes de esta capa se conectan a los recursos utilizando CORBA o conectores Java
(JCA, Java Connector Architecture).

En el apartado en el que tratamos los contenedores mencionamos un tipo de cliente


consistente en una aplicación de escritorio. Se trata de una aplicación cliente/servidor que
prescinde de la capa web y puede acceder directamente a la capa EJB para utilizar sus
servicios.

Normalmente, dichas aplicaciones acceden a los mismos componentes de la capa EJB que
acceden los componentes de la capa web. Ya sabemos que la capa EJB es la que implementa
la lógica de negocio y, por tanto, debe ser la capa que canalice las peticiones y les dé un
trato homogéneo, con independencia del tipo de cliente que esté accediendo.

En el siguiente gráfico se muestra cómo fluyen las peticiones y respuestas entre las distintas
capas. Podemos ver que la aplicación cliente salta la capa web y usa directamente los
servicios de la capa EJB. En dicha figura vemos también que la aplicación cliente y la capa
web acceden a EJB distintos, sin embargo, no tiene que ser necesariamente así. Por ejemplo,
si tenemos un componente EJB que determina las condiciones de venta de un determinado
producto, lo razonable sería que cualquier cliente que necesite conocer dichas condiciones
utilice el servicio que ofrece dicho componente EJB.

13
1 Introducción
a J2EE

14
1 Introducción
a J2EE
− J2EE es una tecnología que se centra fundamentalmente en el desarrollo de
recuerde_
componentes para entornos distribuidos. Es un conjunto de especificaciones,
e indica tanto la estructura para gestionar las aplicaciones de empresa, como
los servicios API para construir dichas aplicaciones.

− Un contenedor J2EE se define como un período de ejecución para gestionar


los componentes de la aplicación desarrollados según las especificaciones del
API y destinado a proporcionar acceso a los API de J2EE.

− J2EE permite definir una arquitectura multicapa en la que cada una de las
capas está orientada a proporcionar a una aplicación un tipo específico de
funcionalidad.

15
índice_ 2 Aplicaciones
web

2.1. CONCEPTOS BÁSICOS.............................................................19


2.2. EL PROTOCOLO HTTP..............................................................20
2.2.1. La solicitud HTTP .........................................................21
2.2.1.1. El método GET ................................................21
2.2.1.2. El método POST ..............................................21
2.2.1.3. El método HEAD ..............................................22
2.2.2. La respuesta HTTP.......................................................22
2.3. CONTENEDORES WEB .............................................................23
2.4. SERVLETS...............................................................................25
2.5. PÁGINAS JSP .........................................................................27
2.6. EL DESCRIPTOR DE DESPLIEGUE ............................................29

17
2 Aplicaciones
web

2.1. CONCEPTOS BÁSICOS

Una aplicación web es un conjunto de páginas JSP, servlets, clases ayudantes, librerías de
clases y recursos estáticos. Entre los recursos estáticos más comunes podemos citar los
documentos HTML y XML y los ficheros de imágenes.

En toda aplicación web podemos distinguir cuatro partes principales, que son:

− Directorio público. Los recursos alojados en él están accesibles directamente a los


clientes de la aplicación, exceptuando el directorio “WEB-INF” y su contenido.

− Fichero “web.xml”. Es el fichero de despliegue de la aplicación web y está ubicado


en el directorio “WEB-INF”.

− Directorio “WEB-INF/classes”. Es el directorio en el que están almacenados los


ficheros de clases que necesita la aplicación. Las clases deben estar organizadas en
una estructura de directorios acorde a los nombres de los paquetes a los que
pertenecen dichas clases.

− Directorio “WEB-INF/lib”. Es el directorio en el que se almacenan los ficheros de


clases empaquetadas (ficheros JAR o ZIP) que necesita la aplicación.

En el tema anterior vimos que existen principalmente dos tipos de clientes: los clientes web
y los clientes de aplicación. Los clientes de aplicación tienen su origen en la arquitectura
cliente-servidor. En ella, los clientes dirigen la interacción del usuario y la mayor parte de la
lógica de aplicación. A los clientes de aplicación se les conoce también como clientes
robustos y procesan la lógica de la aplicación de forma local.

En una arquitectura multicapa, los clientes de aplicación pueden delegar parte de la lógica de
aplicación y acceso a bases de datos en los componentes de la capa media (como los
Enterprise JavaBeans). A pesar de esta distribución de la lógica de la aplicación en los
componentes de la capa media, los clientes de aplicación requieren su instalación para cada
usuario.

Con la llegada de Internet, los clientes web sustituyeron a muchos clientes de aplicación
autónomos. El principal motivo de este cambio radica en la propia naturaleza de los clientes
web. En las arquitecturas basadas en ellos, la capa de interacción con el usuario está
separada de la capa de cliente tradicional. Los navegadores web gestionan la interacción de
usuario pero dejan el resto a las aplicaciones del lado servidor, incluidos la lógica para

19
2 Aplicaciones
web

controlar la interfaz de usuario, la interacción con los componentes de la capa media y el


acceso a las bases de datos.

Para un usuario final, el navegador es el cliente para todas las aplicaciones basadas en web.
Puesto que este tipo de clientes no impone ningún requisito especial en la instalación, los
clientes web también son conocidos como clientes ligeros.

Los clientes web se caracterizan por utilizar habitualmente:

− Un navegador web para la interacción con el usuario.

− El uso de HTML, DHTML y XML para crear la interfaz de usuario. Normalmente se suele
emplear también Javascript para el control dentro de dicha interfaz.

− Los protocolos HTTP y/o HTTPS para el intercambio de información entre el cliente y el
servidor.

La arquitectura J2EE nos ofrece un modelo de programación flexible y rico en funciones para
construir aplicaciones web dinámicas. Dicha arquitectura nos proporciona contenedores web,
el API Java Servlet y el API JavaServer Pages para la construcción y gestión de las
aplicaciones web de forma que el contenedor web ofrece el entorno de período de ejecución
y un marco para proporcionar apoyo a las aplicaciones web y los API Java Servlet y
JavaServer Pages componen la base para el desarrollo de las aplicaciones web.

2.2. EL PROTOCOLO HTTP

El protocolo de comunicación determina la naturaleza de los clientes y los servidores, y la


relación entre ellos en el desarrollo de aplicaciones distribuidas. Lo mismo ocurre en el caso
de las aplicaciones basadas en web. La complejidad de muchas de las características de
nuestro navegador web y del servidor web depende del protocolo subyacente, que en este
caso es HTTP (HiperText Transfer Protocol).

Hemos de tener presente que HTTP es un protocolo de aplicación que suele implementarse
sobre conexiones TCP/IP y que es un protocolo sin estado basado en solicitudes y
respuestas.

Los clientes envían solicitudes al servidor web para recibir información o para iniciar un
proceso específico en el servidor.

20
2 Aplicaciones
web

2.2.1. La solicitud HTTP

El protocolo HTTP define los tipos de solicitudes que los clientes pueden enviar a los
servidores y los tipos de respuestas que los servidores pueden enviar a los clientes. También
especifica cómo están estructuradas estas solicitudes y respuestas.

Los tipos de métodos de solicitud especificados por el protocolo HTTP han cambiado con la
aparición de nuevas versiones. La versión 1.0 especifica tres tipos de métodos de solicitud:
GET, POST y HEAD. La versión 1.1 añade cinco métodos nuevos: OPTIONS, PUT, TRACE,
DELETE y CONNECT. De todos ellos, los métodos GET y POST cumplen la mayoría de los
requisitos más comunes de desarrollo de aplicaciones.

2.2.1.1. El método GET

Es el método de solicitud más sencillo y usado con más frecuencia. Se utiliza normalmente
para acceder a recursos estáticos como documentos HTML.

Por otra parte, las solicitudes GET pueden utilizarse para recuperar información dinámica,
incluyendo parámetros de consulta en el URL de la solicitud. Por último, el servidor web
puede utilizar el valor de este parámetro para enviar contenido específico a un cliente.

2.2.1.2. El método POST

Se suele emplear para acceder a recursos dinámicos. Las solicitudes POST se utilizan
habitualmente por dos motivos: para transmitir información que depende de la solicitud o
cuando una gran cantidad de información compleja debe ser enviada al servidor.

La solicitud POST permite encapsular los mensajes multiparte en el cuerpo de la solicitud.


Como ejemplo podemos citar su uso para enviar archivos al servidor. Además, las solicitudes
POST ofrecen una opción más amplia que las solicitudes GET en cuanto a los contenidos de
dichas solicitudes.

Por otra parte, existen ciertas diferencias entre las solicitudes GET y POST. Con las
solicitudes GET, los parámetros de solicitud son transmitidos como una cadena de consulta
adjunta en el URL de la solicitud. Por el contrario, en el caso de las solicitudes POST los
parámetros son transmitidos en el cuerpo de la solicitud. Esto tiene dos consecuencias
directas: en primer lugar, dado que la solicitud GET contiene la información completa de
solicitud adjunta en el mismo URL, permite a los navegadores guardar la dirección de la
página y volver a visitarla más tarde. Dependiendo del tipo y de la sensibilidad de los

21
2 Aplicaciones
web

parámetros de la solicitud, esto puede interesarnos o no. En segundo lugar, los servidores
suelen imponer restricciones en cuanto a la longitud del URL. Esto limita la cantidad de
información que podamos adjuntar al URL de solicitud.

2.2.1.3. El método HEAD

Un cliente enviará una solicitud de tipo HEAD cuando sólo desee ver las cabeceras de una
respuesta, como “Contenido-Tipo” o “Contenido-Longitud”.

Junto con el tipo de solicitud, la aplicación de cliente también especifica el recurso que
necesita como parte de la cabecera de la solicitud. Vamos a ver un ejemplo: cuando
introducimos “http://java.sun.com/index.jsp” en la barra de dirección de nuestro navegador,
éste envía la solicitud GET al servidor web identificado por “java.sun.com”, para el recurso
“index.jsp”. Para el protocolo HTTP, un identificador de recursos uniformes (URI, Uniform
Resource Identifier) especifica un recurso. El URI es el URL pero excluyendo el nombre del
dominio. En nuestro caso, el recurso es el archivo “index.jsp” localizado en el documento raíz
del servidor web que sirve al dominio “java.sun.com”.

2.2.2. La respuesta HTTP

Cuando un servidor recibe una solicitud HTTP responde con el estado de la respuesta y con
información adicional que describe la respuesta. Todos estos elementos son parte de la
cabecera de respuesta. Además, exceptuando el caso de las solicitudes HEAD, el servidor
también enviará el contenido correspondiente al recurso que se ha especificado en la
solicitud. Es decir, si en un navegador enviamos una solicitud a
“http://java.sun.com/index.html” recibiremos el contenido del archivo “index.html” como
parte del mensaje.

Los campos de cabecera del contenido de la respuesta contienen información útil que los
clientes pueden querer comprobar en determinadas circunstancias. Entre los campos
habituales incluidos en la cabecera están: la fecha, el tipo de contenido y la fecha de
expiración. Como ejemplo, podemos citar que el campo de fecha de expiración de una página
podemos fijarlo con la misma fecha que el campo de fecha para indicar a los navegadores
que no deben guardar la página en la caché. Las aplicaciones Web que suministren
información dependiente del tiempo pueden necesitar establecer estos campos.

Los servidores y clientes que se comunican utilizando el protocolo HTTP hacen uso de “Multi-
Purpose Internet Mail Extensions” (MIME) para indicar el tipo de contenido de los
cuerpos de solicitud y respuesta. Los tipos MIME más comunes son: “text/html” y

22
2 Aplicaciones
web

“image/gif”. La primera parte de la cabecera indica el tipo de datos y la segunda indica la


extensión estándar.

Los servidores HTTP utilizan cabeceras MIME al principio de cada transmisión y los
navegadores utilizan esta información para decidir cómo analizar y generar el contenido. Los
navegadores también utilizan cabeceras MIME al transmitir datos en el cuerpo de las
solicitudes para describir el tipo de datos que envían.

El tipo de codificación MIME por defecto para solicitudes POST es “application/x-www-form-


urlencoded”.

Las características principales del protocolo HTTP son:

− HTTP es un protocolo sin estado. Es muy simple y ligero.

− Es el cliente el que inicia siempre la solicitud. El servidor no puede realizar una


conexión de retrollamada al cliente.

− Requiere que el cliente establezca conexiones previas a cada solicitud y que el servidor
cierre la conexión después de enviar la respuesta. Esto garantiza que un cliente no
pueda mantener una conexión después de recibir la respuesta. Cualquiera de los dos
puede finalizar prematuramente una conexión.

2.3. CONTENEDORES WEB

Las aplicaciones web son aplicaciones de lado servidor. Los requisitos fundamentales para
el desarrollo de este tipo de aplicaciones son los siguientes:

− Un API y un modelo de programación que especifique cómo desarrollar aplicaciones.

− Soporte de período de ejecución en el servidor que incluya el apoyo para los servicios
de red necesarios y la ejecución de las tareas.

− Soporte de implementación, es decir, de proceso de instalación y configuración de


aplicaciones en el servidor.

23
2 Aplicaciones
web

Para que estos requisitos se cumplan, la especificación J2EE suministra los siguientes
elementos:

− Servlets y páginas JSP. Estos elementos son los bloques básicos de construcción
para el desarrollo de aplicaciones web. Suelen recibir el nombre de componentes
web.

− Aplicaciones web. Las tratamos al principio de este tema.

− Contenedor web para albergar aplicaciones web. Es un periodo de ejecución


Java que proporciona una implementación del API Java Servlet y facilidades para las
páginas JSP. El contenedor web es el responsable de inicializar, invocar y gestionar el
ciclo de vida de los componentes web.

− Estructura de empaquetado y descriptores de implementación. La especificación


J2EE define una estructura de empaquetado para las aplicaciones web y un descriptor
de implementación para cada aplicación. El descriptor de implementación es un archivo
XML que permite la adaptación de aplicaciones web en tiempo de despliegue.

Un contenedor web puede residir en tres ubicaciones distintas:

− Integrado en un servidor de aplicaciones J2EE. La mayoría de los servidores de


aplicaciones J2EE incluyen contenedores web. Como ejemplo podemos citar la
implementación de referencia de Sun Microsystems.

− Integrado en un servidor web. Es el caso de los servidores web basados en Java.


Como ejemplo podemos citar el servidor Jakarta Tomcat.

− Alojado en un período de ejecución independiente. Es el caso de servidores web


ajenos a la especificación J2EE. Estos servidores requieren de un período de ejecución
externo para la ejecución de los servlets y de un plugin en el propio servidor web para
integrar dicho período de ejecución. Como ejemplo podemos citar el servidor Apache.

24
2 Aplicaciones
web

2.4. SERVLETS

Los servlets permiten que la lógica de la aplicación esté integrada en el proceso de


solicitudes y respuestas con el protocolo HTTP.

Podemos definir un servlet de Java como un programa pequeño que se ejecuta en el lado del
servidor, que es independiente de la plataforma y que amplía la funcionalidad del servidor
web. El API Java Servlet proporciona un marco sencillo para construir aplicaciones en estos
servidores.

Para que comprendamos mejor la función de la lógica de aplicación en el proceso de


solicitud-respuesta, pensemos en un servidor de correo basado en web. Cuando nos
registramos en dicho servidor, éste debe poder enviar una página con vínculos a nuestro
correo, nuestras carpetas de correo, nuestro libro de direcciones, etc. Esta información es
dinámica, es decir, cada usuario verá su propio buzón. Para poder generar este contenido, el
servidor debe ejecutar una lógica de aplicación capaz de recuperar el correo y componer las
páginas.

Los clientes pueden enviar información de contexto o información específica propia al


servidor en las solicitudes, y este último debe decidir cómo generar el contenido.

El protocolo HTTP no define un medio estándar para integrar la lógica de aplicación durante
la fase de generación de respuestas. Por lo tanto, no existe un modelo de programación
específico para estas tareas. HTTP sólo define cómo pueden los clientes solicitar información
y cómo pueden responder los servidores. Pero no especifica nada en cuanto a cómo puede o
debe ser generada la respuesta.

Los servlets Java no son aplicaciones que puedan invocar los usuarios. Es el contenedor
web en el que está desplegada la aplicación que contiene los servlets, el que invoca a dichos
servlets basándose en solicitudes HTTP entrantes. Cuando un servlet es invocado, el
contenedor web le envía la información de la solicitud entrante de modo que éste pueda
procesarla y generar una respuesta dinámica. El contenedor web actúa sólo como interfaz
con el servidor web, aceptando solicitudes para los servlets y transmitiendo las respuestas
de vuelta al servidor web.

Si lo comparamos con CGI y extensiones de servidor de propiedad como NSAPI o ISAPI, el


marco de servlet proporciona mejor abstracción para el paradigma solicitud-respuesta del
protocolo HTTP, especificando un API de programación para encapsular solicitudes y
respuestas. Por otra parte, los servlets tienen todas las ventajas del lenguaje de

25
2 Aplicaciones
web

programación Java, como la independencia de la plataforma, ya que, las aplicaciones


basadas en servlets pueden ser desplegadas en cualquier servidor web, con independencia
del sistema operativo y de la plataforma de hardware.

Para que podamos entender cómo un servlet interactúa con un servidor web a través de un
contenedor web, vamos a tener en cuenta el proceso de invocación con el que el servidor
web recibe una solicitud HTTP. Antes mencionamos que el protocolo HTTP se basa en un
modelo de solicitudes y respuestas. Un cliente conecta con un servidor web y envía una
solicitud HTTP en la conexión. Basado en un URL de solicitud, la secuencia de eventos que
vemos a continuación tiene lugar en una secuencia típica. En la siguiente figura, las flechas
que apuntan hacia la derecha representan las solicitudes, mientras que las que apuntan
hacia la izquierda indican las respuestas.

Veamos algunas explicaciones sobre la figura anterior:

− El servidor web tiene que descifrar si la solicitud entrante corresponde a una aplicación
web del contenedor, lo que implica que debe haber un entendimiento entre el servidor
y el contenedor. Los contenedores web utilizan el concepto de contexto de servlet para
identificar las aplicaciones web. Este contexto debe ser especificado cuando la
aplicación se despliega en el contenedor.

− Si el contenedor puede manejar la solicitud, el servidor la delega en él.

− Cuando el contenedor ha recibido la solicitud decide qué aplicación es la que debe


manejarla. En una aplicación Web de J2EE, una solicitud puede estar representada en
un servlet, una página JSP o cualquier recurso estático. Esta representación está

26
2 Aplicaciones
web

basada en patrones URL. Todos los recursos indicados forman parte de la aplicación
web. Cuando empaquetamos y desplegamos una aplicación, especificamos esta
información de representación. El contenedor web la utiliza para representar cada
solicitud entrante en un servlet, página JSP o recurso estático. Si el recurso está
representado en un recurso estático, el contenedor se limita a pasar el recurso al
servidor. Esto conforma el cuerpo de la respuesta que el servidor web envía al
navegador.

− En base a la información de representación, el contenedor web determina si la solicitud


debe ser manejada por un Servlet. Y en caso de ser así, el contenedor crea o localiza
una instancia de dicho servlet y delega en ella la solicitud.

− Cuando el contenedor delega la solicitud en un servlet, le pasa objetos que encapsulan


la solicitud y respuesta HTTP a la instancia del servlet. Para dicho servlet, estos
objetos representan los flujos de solicitud y respuesta del navegador. El servlet puede
leer la información de la solicitud y escribir una respuesta.

Para construir y desplegar una aplicación basada en un servlet se requieren los siguientes
dos pasos:

− Escribir el servlet que contengan la lógica de negocio que se necesita.

− Proporcionar un contexto y la información opcional de representación de patrón URL


durante la fase de despliegue. Esta información es la que va a permitir identificar al
servlet que debe manejar las solicitudes.

2.5. PÁGINAS JSP

La generación de contenido dinámico puede conseguirse mediante generación de contenido


basado en código (como los servlets) o la generación de contenido basado en una plantilla
(como las páginas JSP).

La tecnología JSP es una extensión de la tecnología servlets. La diferencia entre los


servlets y las páginas JSP se basa en que los primeros son programas Java mientras que las
páginas JSP son documentos basados en texto.

27
2 Aplicaciones
web

Una página JSP se compone de dos tipos de elementos:

− HTML, DHTML o XML para los contenidos estáticos.

− Etiquetas y scriptlets escritos en Java que se utilizan para envolver la lógica que
genera el contenido dinámico.

Dado que una página JSP proporciona una representación general del contenido y puede
producir múltiples vistas en función del resultado de las etiquetas y scriptlets, las páginas
JSP actúan como una plantilla para generar un contenido.

Una plantilla es una página de anotación con marcas especiales (etiquetas y scriptlets)
incrustados. Estas marcas contienen información para el procesador de la plantilla (el que
genera el contenido). En una página JSP, la anotación nos permite definir su estructura
estática y su contenido, y las marcas especiales nos posibilitan incluir lógica de programación
para que se ejecute durante la generación de las páginas.

La gran ventaja de esta tecnología es que ayuda a mantener separados el diseño del
contenido y la lógica de la aplicación. Si utilizamos servlets únicamente ambos aspectos
estarán estrechamente unidos, lo que conlleva que las aplicaciones sean más difíciles de
mantener.

En algunas otras tecnologías controladas por plantillas, éstas son evaluadas en el periodo de
ejecución. Es decir, cada vez que se solicita una página el procesador de plantilla tiene que
interpretar la plantilla.

Por el contrario, la tecnología JSP está basada en la compilación de páginas. En lugar de


interpretar la página, el contenedor web la convierte en un servlet y lo compila. Este proceso
tiene lugar cuando el contenedor web invoca una página por primera vez.

Algunos contenedores permiten precompilar las páginas en servlets, evitando la demora que
se produce cuando se invoca por primera vez. La mayoría de los contenedores repiten el
proceso de compilación cada vez que se modifica la página.

En la siguiente figura podemos ver las diferentes fases de este proceso. La flecha punteada
representa la compilación de la página.

28
2 Aplicaciones
web

2.6. EL DESCRIPTOR DE DESPLIEGUE

Los descriptores de despliegue son parte integrante de las aplicaciones web de la


especificación J2EE y ayudan a gestionar la configuración de las aplicaciones una vez que se
han desplegado.

El descriptor de despliegue es un archivo XML llamado “web.xml” que se almacena en el


directorio “WEB-INF” de la aplicación. La especificación proporciona una definición de tipo de
documento (DTD) para el descriptor de despliegue.

El descriptor de despliegue tiene varios propósitos:

− La inicialización de los parámetros para los servlets y las aplicaciones. Esta


característica nos permite modificar los valores de inicialización en nuestras
aplicaciones. Un ejemplo muy común es que si nuestro servlet requiere acceso a una
base de datos, el mejor lugar para especificar los detalles, como el registro y la
contraseña, es el descriptor de despliegue, lo que nos va a permitir configurar nuestra
aplicación sin tener que recompilar el código del servlet.

− Definir los servlets y las páginas JSP. Cada servlet y página JSP precompilada que
utilicemos en nuestra aplicación debe estar definida en el descriptor de despliegue. La
definición incluye el nombre del elemento, su clase y una descripción.

− La representación de los servlets y las páginas JSP. Los contenedores web utilizan esta
información para representar solicitudes entrantes a los servlets y las páginas JSP.

− Los tipos MIME. Debido a que cada aplicación web puede contener varios tipos de
contenidos, podemos especificar los tipos MIME para cada tipo.

− La seguridad. Podemos gestionar el control de acceso de nuestra aplicación utilizando

29
2 Aplicaciones
web

el descriptor de despliegue. Por ejemplo, podemos especificar si nuestra aplicación


requiere un registro, cual es la página de registro y qué rol debe tener el usuario.

En el descriptor de despliegue también se indican otras características, como cuáles son las
páginas de bienvenida, las páginas de error y la configuración de la sesión.

30
recuerde_ 2 Aplicaciones
web

− Una aplicación web es un conjunto de páginas JSP, servlets, clases


ayudantes, librerías de clases y recursos estáticos. Entre los recursos
estáticos más comunes podemos citar los documentos HTML y XML, y los
ficheros de imágenes.

− El protocolo subyacente en el que se apoyan las aplicaciones web es HTTP


(HiperText Transfer Protocol). Es un protocolo de aplicación que suele
implementarse sobre conexiones TCP/IP, que es sin estado y está basado en
solicitudes y respuestas.

− El contenedor web alberga las aplicaciones web y es un periodo de ejecución


Java que proporciona una implementación del API Java Servlet y facilidades
para las páginas JSP. Es el responsable de inicializar, invocar y gestionar el
ciclo de vida de los componentes web.

31
índice_ 3 Enterprises Beans y
servicios de contenedor

3.1. ¿QUÉ ES UN ENTERPRISE JAVABEAN? ....................................35


3.2. TIPOS DE EJB .........................................................................37
3.3. EL CONTENEDOR EJB ..............................................................37
3.4. EL DESCRIPTOR DE DESPLIEGUE ............................................40
3.5. UTILIZACIÓN DE BEANS.........................................................42
3.6. DESARROLLO DE BEANS .........................................................44
3.7. EJEMPLO PRÁCTICO ...............................................................46
3.7.1. El software necesario ..................................................46
3.7.1.1. Instalación de Firebird y Firebird SQL .............47
3.7.1.2. Instalación de IBAccess ..................................47
3.7.1.3. Instalación de Sun Java System Application
Server ............................................................49
3.7.1.4. Instalación de NetBeans .................................52
3.7.2. El desarrollo ................................................................53
3.7.2.1. Desarrollo del componente EJB .......................53
3.7.2.2. Desarrollo del componente web ......................58
3.7.2.3. Configuración del servidor de aplicaciones ......63
3.7.2.4. Desplegando la aplicación ...............................68
3.7.3. El funcionamiento........................................................80

33
3 Enterprises Beans y
servicios de contenedor

3.1. ¿QUÉ ES UN ENTERPRISE JAVABEANS?

Antes de explicar qué es un EJB, un Enterprise JavaBean o un Enterprise Bean (se les conoce
por cualquiera de los tres nombres), vamos a aclarar un aspecto que ha sido fuente de
confusión para muchos desarrolladores. Se trata de su nombre.

A pesar de la similitud entre los términos JavaBean y Enterprise JavaBean, no tienen nada en
común. Sus objetivos, implementación y usos son muy distintos.

La arquitectura JavaBeans se diseñó para la especificación de componentes de propósito


general, mientras que la arquitectura Enterprise JavaBeans se ha diseñado para
componentes distribuidos residentes en entornos J2EE.

Los componentes EJB tienen la finalidad de contener la lógica de la empresa (las reglas de
negocio). Encapsulan la funcionalidad crítica y permiten que el desarrollador de aplicaciones
se despreocupe de los servicios del nivel de sistemas como la concurrencia, la persistencia y
las transacciones.

Un Enterprise JavaBean es un conjunto de ficheros de clases Java y un fichero XML que


conforman una única entidad. Las clases cumplen determinadas reglas y proporcionan
métodos de retrollamada, todo ello según está definido en las especificaciones J2EE.

Dado que es tecnología Java, son independientes del sistema operativo y la plataforma
(siempre que no se utilice código nativo). Por ello, se pueden desarrollar en cualquier
plataforma para ser usados posteriormente en cualquier otra plataforma. Actualmente sólo
existe otra tecnología similar, se trata de la tecnología DCOM de Microsoft, pero tiene el
inconveniente de que sólo se pueden utilizar en plataformas Windows.

Como hemos mencionado con anterioridad, J2EE es una especificación. Por lo tanto, la
tecnología EJB también es una especificación, y concretamente define cómo debe ser la
arquitectura de componentes del lado servidor. Dicha especificación es la que deben seguir
los proveedores de contenedores EJB para ser capaces de alojar componentes EJB. Pero
además, dichos proveedores tienen la libertad de darle algún valor añadido a sus
contenedores añadiéndole extensiones propias.

Siempre que un EJB no haga uso de dichas extensiones, puede ser trasladado de un
contenedor a otro en base a las necesidades. Por ejemplo, los EJB pueden desarrollarse
utilizando un contenedor de bajo coste o gratis y posteriormente ponerlos en explotación en
contenedores comerciales de alto rendimiento.

35
3 Enterprises Beans y
servicios de contenedor

Un EJB puede utilizarse con muchos tipos de clientes. Algunos ejemplos comunes de
llamadas de clientes son los siguientes:

− Desde servlets y páginas JSP para proporcionar acceso a clientes web.

− Desde otros EJB.

− Desde aplicaciones autónomas Java mediante la utilización del API RMI (Invocación de
métodos remotos).

− Mediante CORBA si el servidor en el que reside el EJB soporta RMI/IIOP.

La especificación EJB tiene la finalidad de proporcionar servicios de nivel de empresa. En


otras palabras, proporcionar la funcionalidad que requiere una organización. Por lo tanto,
resulta compleja desde los puntos de vista del desarrollo y la administración. La
contrapartida de esta complejidad es que permite a los desarrolladores olvidarse de la
complejidad del nivel de sistemas para centrarse en la lógica de negocio.

En la documentación de la plataforma Java 2 Enterprise Edition, Sun Microsystems incluye un


documento llamado “Designing Enterprise Applications with the Java 2 Platform Enterprise
Edition” que cataloga cuatro arquitecturas para las aplicaciones web. Son las siguientes:

− HTML básico: Sólo contenido estático, puesto que no existe la necesidad de contenido
dinámico.

− HTML con páginas JSP y servlets: Contenidos estáticos y dinámicos. Utilización de


componentes java para cubrir necesidades no muy exigentes.

− Páginas JSP, servlets y componentes JavaBeans: Similares a la anterior pero


añadiendo las ventajas del uso de los componentes JavaBeans.

− Páginas JSP, servlets, componentes JavaBeans y componentes Enterprise


JavaBeans: Grandes exigencias de ejecución de lógica de negocio y utilización de
componentes distribuidos.

36
3 Enterprises Beans y
servicios de contenedor

3.2. TIPOS DE EJB

La tecnología EJB se ha diseñado para proporcionar una arquitectura de componentes para la


creación y uso de sistemas de empresa distribuidos. Para cubrir todas las posibilidades, la
especificación EJB define tres modelos para métodos de retrollamada y ciclos de vida de
período de ejecución. Los tres modelos son: beans de sesión, beans de entidad y beans
controlados por mensaje.

− Un bean de sesión es utilizado por un único cliente a la vez y se utiliza para


proporcionar lógica de empresa. Puede ser de dos tipos: con estado o sin estado: El
primero puede mantener su información entre distintas llamadas a métodos. Por el
contrario, un bean sin estado no puede. Es un matiz distintivo fundamental, y de
hecho se utilizan para fines distintos.

− Un bean de entidad representa información de una base de datos. Por ese mismo
motivo, a un bean de entidad pueden acceder múltiples clientes simultáneamente.
Existen dos tipos: persistencia gestionada por el contenedor y persistencia
gestionada por el bean. La diferencia entre ellos radica en que sea el contenedor
EJB el que interactúe con la base de datos o sea el programador quien tenga que
escribir el código para interactuar con la base de datos.

− Un bean controlado por mensaje es llamado de forma asíncrona y puede recibir e


influir sobre mensajes JMS mediante el proveedor de servicio de mensajes Java. Los
clientes enviarán mensajes a una cola y todos los beans de este tipo que estén
suscritos a dicha cola recibirán el mensaje.

3.3. EL CONTENEDOR EJB

Un contenedor EJB es el entorno en el que se ejecuta un componente EJB. El contenedor se


encarga de proporcionarle los servicios necesarios durante su ciclo de vida.

Los contenedores EJB suelen estar contenidos en servidores de aplicaciones que les
suministran un entorno de ejecución, y que normalmente incluyen también otro tipo de
contenedores, como pueden ser los contenedores web.

El siguiente gráfico ilustra la estructura típica de un servidor de aplicaciones.

37
3 Enterprises Beans y
servicios de contenedor

Los componentes EJB aprovechan los servicios que proporciona el contenedor EJB, por lo que
es importante que conozcamos dichos servicios para así poder sacarles el máximo partido.

A continuación, vamos a describir algunos de los más importantes:

− Persistencia: Los enterprise beans proporcionan servicios de persistencia que


comprenden desde reservas de conexiones hasta la gestión automática de la
persistencia (evitándonos la escritura de código SQL).

− Transacciones declarativas: Existen distintas API Java capaces de soportar


transacciones: API JDBC, JTA (Java Transaction API) y JTS (Java Transaction Service),
no obstante, ninguna de ellas es apropiada para la gestión de transacciones en las que
intervienen múltiples componentes de acceso a datos o múltiples fuentes de datos,
dado que dicha gestión podría volverse excesivamente compleja. Además, las
transacciones complejas con EJB se pueden gestionar sin escribir ningún código, por lo
que, al delegar esta tarea en el contenedor, podemos centrarnos en el desarrollo del
código de la lógica de negocio.

− Seguridad declarativa: El acceso a los componentes EJB también puede ser regulado
sin la necesidad de escribir código.

− Reajustabilidad: La especificación J2EE permite a los servidores de aplicación


gestionar gran cantidad de clientes simultáneos. Los componentes están diseñados
para ejecutarse en múltiples equipos virtuales Java y el servidor de la aplicación está
capacitado para funcionar en un clúster (conjunto de varios equipos trabajando en
colaboración).

− Portabilidad: Dado que los EJB se escriben siguiendo un API estándar, pueden ser
ejecutados en distintos servidores J2EE sin necesidad de modificar el código.

38
3 Enterprises Beans y
servicios de contenedor

Se define como contrato a las responsabilidades definidas entre las partes de una aplicación
que utiliza componentes EJB: el cliente, el contenedor y el componente. Si cada parte
implicada respeta las reglas de su contrato, podrá interactuar con las demás sin necesidad
de conocerlas.

Por otro lado, el contenedor proporciona los servicios del nivel de sistemas mediante la
interposición. Para ello se interpone entre la interfaz de empresa de cliente y la lógica de
empresa EJB.

La llamada de un cliente a un método de un EJB funciona, a grandes rasgos, de la siguiente


forma:

− El cliente realiza la llamada mediante un stub RMI, que es la interfaz básica del bean.

− El stub RMI codifica (serializa) los parámetros y envía la información a través de la


red.

− Un skeleton situado en el servidor decodifica los parámetros y los envía al contenedor


EJB, quien los recibe mediante una clase de interposición que genera.

− El contenedor empezará o se unirá a las transacciones requeridas.

− El contenedor desencadenará varias retrollamadas para que el componente EJB


adquiera los recursos necesarios.

− Invocará al método de empresa correspondiente.

− Envía de vuelta los datos al cliente.

Para hacernos una idea clara de la diferencia entre las interfaces básica y remota, la interfaz
básica es el punto de entrada a los EJB y es la única entidad accesible desde el exterior.

Una vez obtenida una instancia de la interfaz básica se le pide que cree o localice un EJB y, a
continuación, se puede acceder a dicho EJB a través de la interfaz remota.

39
3 Enterprises Beans y
servicios de contenedor

3.4. EL DESCRIPTOR DE DESPLIEGUE

Un módulo J2EE se compone de uno o más componentes J2EE (para el mismo tipo de
contenedor) y un descriptor de despliegue, siendo éste último un fichero XML que
describe la configuración de despliegue del componente J2EE.

La información de los descriptores de despliegue es declarativa, por lo que se puede cambiar


sin modificar el código fuente. El servidor J2EE lee los descriptores de despliegue durante la
ejecución y actúa acorde a sus contenidos.

Según la especificación existen cuatro tipos de descriptores:

− Descriptor de la aplicación J2EE. Debe haber sólo uno, su nombre es


“application.xml” y se almacena en el directorio “META-INF”. Lo trataremos en el tema
“Empaquetado y despliegue”.

− Descriptores de módulos EJB. Existe uno por cada módulo EJB y describe la
totalidad de EJB contenidos en él. Su nombre es “ejb-jar.xml” y se almacena dentro
del directorio “META-INF”.

40
3 Enterprises Beans y
servicios de contenedor

− Descriptores de módulos web. Existe uno por cada módulo web. Su nombre es
“web.xml” y se almacena dentro del directorio “WEB-INF”. Los vimos en el tema
“Aplicaciones web”.

− Descriptores de adaptadores de recursos. Quedan fuera del ámbito de este


manual y no vamos a tratarlos.

Los distintos servidores J2EE existentes suelen requerir descriptores de despliegue


adicionales a los indicados por la especificación. Por ejemplo, en nuestro caso concreto el
servidor de aplicaciones que vamos a utilizar para los ejemplos requiere que cada módulo
EJB incluya un descriptor de despliegue llamado “sun-ejb-jar.xml” y se almacene en el
directorio “META-INF”.

El siguiente es un ejemplo de descriptor de despliegue de una aplicación J2EE. En él


podemos ver que la aplicación se compone de un módulo EJB y un módulo web. Corresponde
al ejemplo que veremos al final de este tema.

<?xml version="1.0" encoding="UTF-8"?>


<application xmlns="http://java.sun.com/xml/ns/j2ee" version="1.4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/application_1_4.xsd">
<description xml:lang="es">Aplicación ejemplo1</description>
<display-name xml:lang="es">Ejemplo1</display-name>
<module>
<ejb>ejb-jar-ic.jar</ejb>
</module>
<module>
<web>
<web-uri>war-ic.war</web-uri>
<context-root>/ejemplo1</context-root>
</web>
</module>
</application>

A continuación, consideramos otro ejemplo de descriptor de despliegue. En este caso se trata


del módulo EJB que corresponde al ejemplo que también estudiaremos al final de este tema.

41
3 Enterprises Beans y
servicios de contenedor

<?xml version="1.0" encoding="UTF-8"?>


<ejb-jar xmlns="http://java.sun.com/xml/ns/j2ee" version="2.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">
<display-name xml:lang="es">moduloEJB</display-name>
<enterprise-beans>
<session>
<ejb-name>VentasBean</ejb-name>
<home>gestion.VentasHome</home>
<remote>gestion.Ventas</remote>
<ejb-class>gestion.VentasBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>

Este manual pretende ser una introducción al desarrollo de EJB. El servidor de aplicaciones
que hemos elegido para los ejemplos nos va a permitir abstraernos de ciertas complejidades
como, por ejemplo, los descriptores de despliegue. Por lo tanto, dado que la sintaxis y
explicación de los descriptores es sumamente extensa, no vamos a detallarla aquí. La mejor
información para estudiarla detalladamente podemos encontrarla en la documentación de la
especificación J2EE.

3.5. UTILIZACIÓN DE BEANS

Para utilizar un enterprise bean necesitamos saber cómo encontrarlo o crearlo, cómo utilizar
sus métodos y como liberar sus recursos. No tenemos que preocuparnos sobre su
implementación ni los servicios provistos por el contenedor.

Un EJB de sesión o entidad puede tener las siguientes interfaces:

− Una interfaz básica y/o una interfaz básica local. Se utilizan para operaciones de ciclo
de vida (crear, encontrar y eliminar EJB). No están asociadas a una instancia de bean
concreta, sólo a un tipo de bean.

42
3 Enterprises Beans y
servicios de contenedor

− Una interfaz remota y/o local. Permiten el acceso a los métodos de empresa. Están
asociadas a una instancia de bean concreta.

En lo que respecta a las interfaces de los EJB de sesión y de entidad, pueden tener las
interfaces básica y remota, pueden tener las interfaces básica local y local, o pueden tenerlas
todas. En el siguiente apartado veremos los usos y diferencias entre ellas.

Los pasos para hacer uso de un componente EJB son los siguientes:

− Adquirir la interfaz básica (o básica local) a través de JNDI.

− Crear o encontrar una instancia de un bean que se obtendrá como interfaz remota (o
local).

− Ejecutar los métodos de empresa necesarios.

− Eliminar el bean.

Veamos los pasos anteriores en un ejemplo concreto:

try {
// Obtenemos una referencia al contexto de ejecución
Context ctx = new InitialContext();
// Obtenemos una referencia al componente mediante JNDI
Object obj = ctx.lookup("java:comp/env/ejb/Ventas");
// Obtenemos una referencia a la interfaz básica
VentasHome home = (VentasHome) javax.rmi.PortableRemoteObject.narrow(obj,
VentasHome.class);
// Obtenemos una instancia al bean mediante la interfaz remota
Ventas ventas = home.create();
// Invocamos los métodos de negocio
ventas.calcularDescuentos();
ventas.actualizarDescuentos();
// Eliminamos el EJB
ventas.remove();
} catch (Exception e) {
errText = e.getMessage();
}

43
3 Enterprises Beans y
servicios de contenedor

3.6. DESARROLLO DE BEANS

Un enterprise bean se compone, generalmente, de un conjunto de ficheros de clases Java


y un descriptor de despliegue. El conjunto de clases java está formado obligatoriamente por
la clase que implementa la lógica de negocio y una o las dos parejas de interfaces que
permiten que los clientes puedan hacer uso del EJB. Adicionalmente, pueden incluirse clases
Java adicionales de apoyo al bean y, en el caso de los beans de entidad con clave primaria
compuesta, una clase que represente a dicha clave.

Una de dichas parejas está formada por las interfaces básica y remota y permiten que los
clientes remotos (aquellos que no están en la misma unidad de despliegue del bean) puedan
hacer uso del enterprise bean.

La otra pareja está formada por las interfaces básica local y local. Permiten que clientes que
están en la misma unidad de despliegue puedan hacer uso del EJB, sin necesidad de utilizar
las interfaces remotas.

El problema del acceso remoto a un EJB reside en que es más costoso (a nivel de recursos) y
lento debido a que hace uso de RMI (y todo lo que conlleva). La interfaz local no hace uso de
RMI, no obstante, tiene el inconveniente de que sólo pueden usarla los clientes que formen
parte de la misma unidad de despliegue en que esté el EJB.

En definitiva, un enterprise bean puede incluir las interfaces para acceso local, remoto o
ambas.

Para las siguientes explicaciones vamos a suponer un bean llamado “VentasBean”. En base a
dicho nombre indicaremos la nomenclatura que se suele emplear para nombrar las clases e
interfaces relacionadas con dicho bean.

La interfaz remota debe ampliar la clase “javax.ejb.EJBObject” y suele denominarse con el


nombre del bean. En nuestro caso la interfaz se llamaría “Ventas”.

La interfaz local debe ampliar la clase “javax.ejb.EJBLocalObject” y suele denominarse


anteponiendo el texto “Local” al nombre del bean. En nuestro caso, la interfaz la
denominaríamos “LocalVentas”.

Tanto la interfaz remota como la local deben declarar los métodos de negocio que
implementa el bean y pueden utilizar los clientes.

44
3 Enterprises Beans y
servicios de contenedor

La interfaz básica debe ampliar la clase “javax.ejb.EJBHome” y suele denominarse


posponiendo el texto “Home” al nombre del bean. En nuestro caso la llamaríamos
“VentasHome”.

La interfaz básica local debe ampliar la clase “javax.ejb.EJBLocalHome” y suele nombrarse


anteponiendo y posponiendo los textos “Local” y “Home” respectivamente, al nombre del
bean. En nuestro caso, la interfaz recibiría el nombre de “LocalVentasHome”.

Tanto la interfaz básica como la interfaz básica local declararán uno o más métodos que
dependerán del tipo de bean:

− Un bean de sesión con estado añadirá uno o más métodos “create()”.

− Un bean de entidad añadirá ninguno, uno o varios métodos “create()” y uno o más
métodos “finder()”.

− Un bean de sesión sin estado tendrá uno y sólo un método “create()”.

Por último, la clase de implementación del bean:

− Los beans de sesión derivarán de la clase “javax.ejb.SessionBean”.

− Los beans de entidad derivarán de la clase “javax.ejb.EntityBean”.

− Los beans controlados por mensaje derivarán de la clase


“javax.bean.ejb.MessageDriven”.

La clase del bean debe implementar los métodos de retrollamada definidos en su respectiva
interfaz, aunque a veces se dejen vacíos. También debe añadir los métodos de empresa
declarados en las interfaces remota y básica.

En los temas correspondientes a los distintos tipos de EJB entraremos en más detalles.

45
3 Enterprises Beans y
servicios de contenedor

3.7. EJEMPLO PRÁCTICO

Ahora dejemos la teoría y vamos con un ejemplo que nos ayude a asimilar los conocimientos
que hemos tratado.

3.7.1. El software necesario

Para los ejemplos que vamos a estudiar desde este tema en adelante, usaremos los
siguientes productos:

− Firebird versión 1.5. Es una base de datos gratuita (licencia GPL). Tiene su origen en la
liberación del código de la base de datos Interbase de Borland, de ahí que ofrezca un
rendimiento excelente. Podemos descargarla de http://www.firebirdsql.org

− Firebird SQL versión 1.5.0. Contiene los controladores JDBC que vamos a usar con la
base de datos Firebird. También podemos descargarlo desde la dirección anterior.

− IBAccess 1.18. Herramienta de administración de bases de datos Firebird. Podemos


descargarla de http://www.ibaccess.org y es gratuita.

− Sun Java System Application Server Platform Edition 8.1. Es un servidor de


aplicaciones J2EE de Sun Microsystems. Es gratuito. Podemos descargarlo de
http://java.sun.com

− NetBeans 4.1. Entorno de desarrollo integrado (IDE) para Java. Es gratuito y podemos
descargarlo de http://www.netbeans.org.

La elección del software anterior se ha realizado, en primer lugar, buscando el menor coste
posible. Es por eso que todos los productos mencionados son gratuitos y que la mayoría
permite su uso bajo licencia GPL. El segundo factor a evaluar ha sido la calidad y simplicidad.

Si estamos interesados en utilizar otro tipo de software, habremos de tener en cuenta sus
diferencias con respecto a los que aquí mencionamos para hacer los cambios pertinentes de
cara a que los ejemplos funcionen. Para los ejemplos crearemos un directorio llamado
“cursoEJB”. Para los usuarios de Linux se asumirá el trayecto “/home/alumno/cursoEJB”,
mientras que para los usuarios de Windows se asumirá el trayecto “c:\cursoEJB”. Dentro de
dicho directorio vamos a crear la base de datos Firebird que utilizaremos en los ejemplos que
lo necesiten.

46
3 Enterprises Beans y
servicios de contenedor

3.7.1.1. Instalación de Firebird y Firebird SQL

La instalación del servidor de bases de datos Firebird tendremos que realizarla como
administrador del sistema. El proceso de instalación es muy sencillo y no vamos a entrar en
los detalles.

Una vez finalizada la instalación, el servidor estará en funcionamiento y a la espera de


peticiones. En algunas plataformas Windows tal vez requiera reiniciar el ordenador y levantar
manualmente los servicios mediante el administrador de servicios. En cualquier caso, es
conveniente revisar la documentación de Firebird por si hubiera alguna consideración
especial para algunas situaciones concretas.

En lo que respecta a Firebird SQL, se trata de un fichero comprimido que contiene los
controladores JDBC para conectar con bases de datos Firebird. De él nos interesa el fichero
“firebirdsql-full.jar”.

En este manual asumiremos que hemos instalado Firebird en “/opt/firebird” o en


“c:\firebird”, según estemos en una plataforma Linux o Windows, respectivamente.
Crearemos un directorio llamado “jdbc” dentro del directorio de instalación de Firebird (para
tener organizados los ficheros) y copiaremos dentro el fichero “firebirdsql-full.jar”.

3.7.1.2. Instalación de IBAccess

Esta utilidad de administración de servidores de bases de datos Firebird tampoco reviste


ninguna complejidad en su instalación y tampoco entraremos en detalles. No obstante, dado
que puede resultar un proceso confuso para usuarios que no conozcan Firebird, vamos a
explicar cómo configurar una conexión a una base de datos. Cuando se ejecuta IBAccess, se
nos muestra la siguiente ventana:

47
3 Enterprises Beans y
servicios de contenedor

En el menú “File” seleccionaremos la opción “New database...” para crear una base de datos
nueva. A continuación, se nos muestra una nueva ventana con el título “Create a new
Interbase database” en la que debemos elegir la base de datos a crear. No obstante, lo
primero que hemos de hacer es crear una conexión y para ello, pulsaremos el botón
“Configure databases”.

Nos volverá a aparecer una nueva ventana con el título “Global Database Definition” y
pulsaremos el botón “New”. Nos preguntará por el alias que queremos asignarle a la base de
datos. En nuestro ejemplo usaremos el texto “cursoEJB” y pulsaremos el botón “OK”.

A continuación, podremos ver que en la ventana se nos solicitan varios datos, de entre ellos
debemos considerar los siguientes:

− “User name”. Nombre del usuario. No vamos a crear usuarios, si no que nos
limitaremos a utilizar el nombre del administrador de la base de datos. Tendremos que
indicar el texto “sysdba”.

− “Password”. Contraseña. La contraseña del administrador es “masterkey”.

− “Local connection”. La dejaremos seleccionada porque la conexión con el servidor de


datos será local.

− “Filename”. Nombre (y trayecto) del fichero que da soporte a la base de datos. Cada
base de datos Firebird se almacena en uno o más ficheros físicos. En nuestro caso
vamos a crear una base de datos de nombre “cursoEJB.gdb”. Los usuarios de Linux
escribirán “/home/alumno/cursoEJB/cursoEJB.gdb”, mientras que los usuarios de
Windows indicarán “c:\cursoEJB\cursoEJB.gdb”.

− “Dialect”: Dialecto que se va a utilizar en la base de datos. Seleccionaremos de la lista


el valor “Dialect 3 (IB 6.X)” para que la base de datos permita que los identificadores
puedan ir encerrados entre comillas dobles (los nombres de tablas y de columnas).

− El resto de datos son indiferentes para nuestros intereses.

48
3 Enterprises Beans y
servicios de contenedor

Tras lo que hemos visto, la ventana tendrá el siguiente aspecto (recordemos que los usuarios
de Windows verán un valor distinto en “Filename”):

Seguidamente pulsaremos los botones “Save” y “OK”, en ese orden. Se cerrará la ventana y
nos pedirá confirmación para guardar los cambios. Responderemos afirmativamente.

Ya de vuelta a la ventana “Create a new Interbase database” seleccionaremos del control


combo “Databases” el elemento “CURSOEJB” (se trata del alias que acabamos de crear) y
pulsaremos el botón “Create”. Es justo en ese momento cuando se procede a la creación de
la base de datos (creación del fichero físico) y se cierra la ventana.

En adelante, cada vez que entremos en la utilidad IBAccess seleccionaremos la opción “Open
database...” del menú “File” y en el combo “Databases” elegiremos el alias “CURSOEJB”. Una
vez hecho esto, aparecerá una ventana que será donde manipularemos la base de datos
(crear tablas, introducir datos, etc.) de cara a los ejemplos que se van a tratar más adelante.

3.7.1.3. Instalación de Sun Java System Application Server

La instalación la haremos siguiendo los pasos que nos va sugiriendo el asistente. Tendremos
que prestar especial atención cuando se nos pregunte por el directorio del kit de desarrollo
de Java 2 Edición Estándar (JDK).

Si seleccionamos una versión inferior a la recomendada nos mostrará una ventana

49
3 Enterprises Beans y
servicios de contenedor

indicándonoslo y pidiéndonos confirmación. La versión del servidor de aplicaciones que


estamos instalando aquí requiere al menos el JDK versión 1.4.2.

No obstante, la ventana más importante de todas las que nos va a mostrar el proceso de
instalación es la siguiente:

En ella definiremos los siguientes datos:

− Nombre de la cuenta de administración del servidor.

− Contraseña de la cuenta de administración.

− Definiremos si queremos que nos pregunte el nombre y contraseña cuando nos


conectemos o que los guarde para que no tengamos que indicarlo al entrar. En nuestro
caso da igual lo que elijamos porque sólo vamos a hacer pruebas, pero en un servidor
real sería conveniente que estos datos se preguntaran al entrar.

− Los puertos de administración y de los protocolos HTTP y HTTPS. Podemos dejarlos


con los valores sugeridos si no están en uso en nuestro sistema.

Una vez finalizada la instalación estaremos en disposición de iniciar el servidor y poder


administrarlo. Para iniciar el servidor de aplicaciones nos iremos al directorio “bin” dentro del
directorio de instalación y ejecutaremos el programa “asadmin”.

50
3 Enterprises Beans y
servicios de contenedor

Suponiendo que estamos en Linux y lo hemos instalado en


“/home/alumno/SUNWappserver”, escribiremos:

alumno@mhost:~/SUNWappserver/bin$ ./asadmin start-domain domain1

Si estuviéramos en Windows y lo hubiéramos instalado en “c:\SUNWappserver”,


escribiríamos lo siguiente:

c:\SUNWappserver> asadmin start-domain domain1

A continuación nos mostrará un mensaje que nos indicará que el servicio está iniciado.

Para administrar el servidor disponemos de dos mecanismos: la línea de comando y una


interfaz de gráfica de usuario basada en web. Nosotros nos vamos a decantar por la interfaz
gráfica (por motivos obvios).

Para entrar en la consola de administración tendremos que abrir un navegador web y


navegar a la dirección “http://localhost:4848”. Si durante la instalación le cambiamos el
puerto de administración que nos sugería por defecto, tendremos que indicar aquí dicho
puerto.

Lo siguiente que veremos será una página de registro en la que se nos solicita el nombre y
clave de la cuenta de administración. Indicaremos los mismos que pusimos durante la
instalación y pasaremos a la página principal de administración que tiene el siguiente
aspecto:

51
3 Enterprises Beans y
servicios de contenedor

Para detener el servidor de aplicaciones usaremos también el comando “asadmin” pero


indicándole el parámetro “stop-domain”. Sería como sigue:

asadmin stop-domain domain1

3.7.1.4. Instalación de NetBeans

NetBeans es un entorno de desarrollo integrado para aplicaciones Java. Es ampliamente


utilizado, de una gran calidad y de coste cero. Su instalación la haremos siguiendo los pasos
que nos va sugiriendo el asistente. Tendremos que prestar especial atención cuando se nos
pregunte por el directorio del kit de desarrollo de Java 2 Edición Estándar (JDK). La versión
del NetBeans que estamos instalando aquí requiere al menos el JDK versión 1.4.2.

Podríamos prescindir de cualquier entorno de desarrollo, utilizar nuestro editor de textos


favorito y compilar desde la línea de comandos pero el desarrollo dentro de un IDE tiene
numerosas ventajas que van a permitirnos una mayor productividad.

Empezaremos abriendo el entorno NetBeans. Dentro de él podemos ver que la zona de


trabajo se divide en dos paneles. El panel de la derecha es la zona de edición de código y
presenta una página de bienvenida.El de la izquierda muestra distintas ventanas. Entre las
ventanas más comunes están el proyecto actual (“Projects”), la ventana de ficheros del
proyecto (“Files”) y la ventana del punto de entrada de los recursos del proyecto
(“Runtime”).

52
3 Enterprises Beans y
servicios de contenedor

Para cerrar la página de bienvenida utilizaremos el botón izquierdo del ratón sobre el icono
cerrar (“x”) de la pestaña “Welcome”.

3.7.2. El desarrollo

Seguidamente, analizaremos un ejemplo básico de una aplicación J2EE. Se trata de una


aplicación para saber el importe de una venta a partir de la cantidad y el precio unitario
donde las reglas de la empresa determinan que el precio de una venta se calcula
multiplicando la cantidad por el importe y añadiendo un 5% de comisión.

Queremos construir una aplicación que reciba peticiones de clientes web, invoque a un
componente de empresa para obtener los resultados y muestre dicho resultado al cliente que
lo solicitó.

Nuestra aplicación se va a componer de los siguientes módulos:

− Un módulo EJB que se ejecutará en el contenedor de EJB del servidor de aplicaciones.


Dicho módulo estará compuesto por un único EJB que será el que contenga la lógica de
negocio que describimos anteriormente.

− Un módulo web que estará compuesto por una única página que solicitará los datos y
mostrará los resultados.

3.7.2.1. Desarrollo del componente EJB

Ejecutaremos NetBeans y elegiremos la opción “Files” y subopción “New Project”. Crearemos


entonces un nuevo proyecto “Java Application”.

53
3 Enterprises Beans y
servicios de contenedor

A continuación, pulsaremos “Next” y llamaremos “ejemplo1” al proyecto. Seleccionaremos la


dirección de nuestro directorio y no crearemos la clase principal.

Tras terminar pulsaremos el botón “Finish”.

Seguidamente, se creará la estructura de carpetas del proyecto. Dentro de la subcarpeta


“Source Packages” vamos a crear un nuevo paquete.

54
3 Enterprises Beans y
servicios de contenedor

Este paquete lo vamos a llamar “gestion”.

Para poder desarrollar aplicaciones J2EE (concretamente para poder compilar) desde dentro
de NetBeans, necesitaremos indicarle el fichero de clases “j2ee.jar”. Puesto que vamos a
utilizar el servidor de aplicaciones de Sun Microsystems, lo razonable es indicar el que viene
incluido en el servidor dentro del directorio “lib”. Para ello, pulsaremos el botón derecho
sobre el nodo “Libraries”, pincharemos sobre la opción “Add JAR/Fólder” y seleccionaremos el
fichero de clases “j2ee.jar”.

Lo próximo que haremos será crear las tres clases que necesitará nuestro EJB. Para ello,
sobre el nodo “gestion” pulsamos el botón derecho del ratón y seleccionamos la opción
“New” y subopción “Java Class”. Esta operación la realizaremos tres veces y los nombres de
clases que emplearemos serán los siguientes: “VentasHome”, “Ventas” y “VentasBean”.

55
3 Enterprises Beans y
servicios de contenedor

En estos momentos, el aspecto del entorno podría ser similar al siguiente:

Habremos podido comprobar que NetBeans crea cada clase incluyendo en ella el nombre del
paquete al que pertenece y añadiéndole un constructor vacío. En breve modificaremos el
contenido de cada clase para que se ajuste a lo que queremos de ella. Concretamente, dos
de esas clases deberían ser interfaces, por lo que las cambiaremos. Pero veamos primero
cual es la finalidad de cada una de ellas:

− “VentasHome”: Es la interfaz básica del EJB. A veces también recibe el nombre de


interfaz inicial.

− “Ventas”: Es la interfaz remota del EJB.

− “VentasBean”: Es la clase de implementación. Contiene el código de los métodos de


negocio.

56
3 Enterprises Beans y
servicios de contenedor

Seguidamente, editaremos la clase “VentasHome” y escribiremos el siguiente código:

package gestion;
import javax.ejb.*;
public interface VentasHome extends javax.ejb.EJBHome {
public gestion.Ventas create()
throws javax.ejb.CreateException, java.rmi.RemoteException;
}

Para la clase “Ventas”, su código será:

package gestion;
import javax.ejb.*;
public interface Ventas extends javax.ejb.EJBObject {
// Calcula el importe de la venta añadiendo el % de comisión
public float calculaImporte(int cantidad, float precio) throws
java.rmi.RemoteException;
}

Y por último a la clase “VentasBean”, que es la que contiene el código que soporta las reglas
de negocio, le escribimos el siguiente código:

package gestion;
import javax.ejb.*;
public class VentasBean implements javax.ejb.SessionBean {
private javax.ejb.SessionContext context;
private static final int comision = 5;
public void setSessionContext(javax.ejb.SessionContext aContext) {
context=aContext;
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void ejbRemove() {
}
public void ejbCreate() {

57
3 Enterprises Beans y
servicios de contenedor

}
// Calcula el importe de la venta añadiendo el % de comisión
public float calculaImporte(int cantidad, float precio) {
float importe = cantidad * precio;
return importe + importe * this.comision / 100;
}
}

Si hemos escrito correctamente todo el código anterior, no debería haber problemas con la
compilación, no obstante, lo comprobaremos compilando las clases.

Un método rápido que podemos utilizar para compilar la clase y las interfases es usar el
botón derecho sobre el nombre del paquete (“gestion”) y elegir del menú emergente la
opción “Compile Package”. En caso de que se muestren errores, revisaremos las líneas en
cuestión y los solventaremos.

En este momento tenemos compilados los ficheros Java que componen el EJB. Según la
especificación EJB nos faltaría el descriptor de despliegue, el fichero “ejb-jar.xml”. También
nos faltaría el fichero de despliegue específico de la plataforma en la que vamos a desplegar
el EJB. En nuestro caso no hemos de preocuparnos, ya que, el servidor de aplicaciones que
hemos elegido incorpora una herramienta para el despliegue que será la que se va a
encargar de crear ambos ficheros XML.

El siguiente paso es crear el módulo EJB que debe contener a nuestro Enterprise Bean pero
también nos despreocuparemos de esta labor debido a que también la realiza la herramienta
de despliegue que acabamos de mencionar.

3.7.2.2. Desarrollo del componente web

Hemos decidido que se va a componer de una única página JSP. Dicha página mostrará el
nombre de nuestra empresa y decidirá si los parámetros cantidad y precio que recibe son
correctos. Si es así mostrará el importe de la venta. En cualquier caso, mostrará un
formulario para poder realizar un nuevo cálculo.

Para añadir una página JSP en NetBeans necesitaremos en primer lugar añadir un módulo
web. Para evitar complejidad a este ejemplo, vamos a crear manualmente la página JSP en
el directorio del ejemplo (recordemos que se trata del directorio

58
3 Enterprises Beans y
servicios de contenedor

“/home/alumno/cursoEJB/ejemplo1” para los usuarios de Linux y de “c:\cursoEJB\ejemplo1”


para los usuarios de Windows). El fichero se llamará “index.jsp” y lo podemos crear en
nuestro editor de textos favorito.

El contenido de la página JSP será el siguiente:

<%@page contentType="text/html"%>
<%@page import="javax.naming.*"%>
<%@page import="javax.sql.*"%>
<%@page import="java.sql.*"%>
<%@page import="gestion.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
<title>cursoEJB/ejemplo1</title>
</head>
<body>
<%
String errText = "";
String nombreEmpresa = "";
int cantidad = 0;
float precio = 0;
float importe = 0;
try {
// Obtenemos una referencia al contexto de ejecución
Context ctx = new InitialContext();

// Obtenemos una referencia al pool de conexiones


DataSource ds = (DataSource)
ctx.lookup("java:comp/env/jdbc/CursoEJB");

// Obtenemos una conexión del pool


Connection con = ds.getConnection();
// Leemos el nombre de la empresa
Statement stmt = con.createStatement();

59
3 Enterprises Beans y
servicios de contenedor

ResultSet rs = stmt.executeQuery("SELECT nombre FROM empresa");


if (rs.next()) {
nombreEmpresa = rs.getString("nombre");
}

// Cerramos el conjunto de resultados y la conexión


// La conexión será devuelta al pool para ser reutilizada
rs.close();
con.close();

// Obtenemos los parámetros de la petición HTTP


cantidad = Integer.parseInt(request.getParameter("cantidad"));
precio = Float.parseFloat(request.getParameter("precio"));

// Obtenemos una referencia al componente EJB


Object obj = ctx.lookup("java:comp/env/ejb/Ventas");
// Obtenemos la referencia a la interfaz básica
VentasHome home = (VentasHome) javax.rmi.PortableRemoteObject.narrow(obj,
VentasHome.class);
// Obtenemos la referencia a la interfaz remota
Ventas ventas = home.create();
// Mediante la interfaz remota invocamos al método de negocio que realiza el
cálculo
importe = ventas.calculaImporte(cantidad, precio);
// Eliminamos el EJB
ventas.remove();
} catch (NamingException e) {
errText = e.getMessage();
}
%>

<%
// Si se ha producido algún error, lo mostramos
if (!errText.equals("")) {
%>
<%=errText%>
<%

60
3 Enterprises Beans y
servicios de contenedor

} else {
%>
<h2><%=nombreEmpresa%></h2>
<hr>
<table border="0" cellspacing="2" cellpadding="2">
<tbody>
<tr>
<td><span style="font-weight: bold;">Cantidad:</span><br> </td>
<td><span style="text-decoration:
underline;"><%=cantidad%></span><br> </td>
<td><span style="font-weight: bold;">Precio:</span><br> </td>
<td><span style="text-decoration:
underline;"><%=precio%></span><br> </td>
<td><span style="font-weight: bold;">Importe:</span><br> </td>
<td><span style="text-decoration:
underline;"><%=importe%></span><br> </td>
</tr>
</tbody>
</table>
<hr>
<br>
<form name="calculos" method="post" action="index.jsp">
<table border="0" cellspacing="2" cellpadding="2">
<tbody>
<tr>
<td>Cantidad:</td>
<td><input type="text" name="cantidad" value="0"></td>
<td rowspan="2"><input type="submit" value="Calcular"></td>
</tr>
<tr>
<td>Precio:</td>
<td><input type="text" name="precio" value="0"><br> </td>
</tr>
</tbody>
</table>
</form>

61
3 Enterprises Beans y
servicios de contenedor

<%
}
%>
</body>
</html>

En la página JSP hacemos uso de JNDI en dos ocasiones: la primera es para obtener una
conexión del pool de conexiones del servidor y la segunda es para obtener la referencia al
componente de negocio (el EJB) y poder hacer uso de él. Los nombres JNDI de ambos
recursos son “java:comp/env/jdbc/cursoEJB” y “java:comp/env/ejb/Ventas”,
respectivamente.

La creación del primer recurso la tendremos que hacer manualmente desde la consola de
administración del servidor de aplicaciones. La creación del segundo formará parte del
despliegue de nuestra aplicación web, pero para que sea así tendremos que indicarlo dentro
del fichero de despliegue, más concretamente, en el fichero descriptor de despliegue del
componente EJB.

Si observamos el código de la página JSP, veremos que mediante JDBC utilizamos una
sentencia SQL para obtener información de una tabla. Esto implica que tendremos que crear
dicha tabla para hacer funcionar nuestro ejemplo. La tabla en cuestión se llama “empresa” y
contendrá una única columna denominada “nombre”, de tipo VARCHAR y longitud 30. Tras
crear la tabla le añadiremos una fila con el nombre de nuestra empresa ficticia.

Para crear y rellenar la tabla utilizaremos el programa IBAccess y una vez dentro
emplearemos la opción de abrir una base de datos existente y seleccionaremos el alias
“CURSOEJB”, que creamos en el apartado en el que tratábamos de la instalación de
IBAccess. Una vez abierta la ventana de la base de datos, seleccionaremos el botón “Shows
the exec SQL window”, que aparece resaltado en la siguiente figura.

62
3 Enterprises Beans y
servicios de contenedor

A continuación, observaremos una ventana que nos va a permitir ejecutar sentencias SQL
interactivamente. Ejecutaremos las líneas siguientes teniendo en cuenta que se han de
ejecutar de una en una:

CREATE TABLE empresa (nombre VARCHAR(20));


INSERT INTO empresa VALUES ('Construcciones K');

Cuando cerremos esta ventana nos pedirá confirmación para guardar la transacción en curso
(la que hemos generado con la sentencia INSERT), responderemos afirmativamente y
podremos salir de IBAccess. No lo vamos a utilizar más por el momento.

Para cerrar este apartado, mencionaremos que nos faltaría el descriptor de despliegue del
módulo web (el fichero “web.xml”) y empaquetarlo todo en el correspondiente fichero WAR.
Pero al igual que vimos en el apartado del componente EJB, también serán tareas que
delegaremos en la herramienta de despliegue del servidor de aplicaciones.

3.7.2.3. Configuración del servidor de aplicaciones

El último uso que hicimos del servidor de aplicaciones fue entrar en la consola de
administración para hacernos una idea de su estructura. Sabemos que nuestro servidor
funciona, pero hasta el momento poco uso podemos darle puesto que no hemos hecho nada
con él.

En este apartado realizaremos dos labores de administración. Por una parte, el servidor de
aplicaciones debe saber donde están las clases que le van a permitir conectarse a la base de
datos, es decir, el controlador JDBC. La segunda tarea depende de la primera y consiste en

63
3 Enterprises Beans y
servicios de contenedor

definirle un recurso de tipo fuente de datos (Data Source) y asignarle un nombre JNDI. El
servidor de aplicaciones puede implementar un pool de conexiones (uno o más), de donde
puede suministrar conexiones a los clientes que las solicitan y con la ventaja de que reutiliza
dichas conexiones.

Lo primero que vamos a hacer es indicarle al servidor donde se encuentran las clases del
controlador JDBC para que pueda cargarlas cuando las necesite. Recordemos que las clases
estaban almacenadas en el fichero JAR siguiente: “firebirdsql-full.jar” que estaba almacenado
en “/opt/firebird/jdbc” o en “c:\firebird\jdbc”, según la plataforma fuera Linux o Windows,
respectivamente.

En primer lugar, nos iremos a la consola de administración utilizando un navegador web y


navegar a la dirección “http://localhost:4848”. Si el servidor estuviera detenido, lo
iniciaríamos mediante el comando “asadmin start-domain domain1” alojado en el directorio
“bin”.

Una vez identificados, seleccionaremos el nodo “Application Server” y se nos mostrará una
ventana con información general del servidor. Seguidamente, seleccionaremos la pestaña
“Configuración JVM” y la opción “Configuración de ruta”. Podemos verlo en la figura
siguiente.

64
3 Enterprises Beans y
servicios de contenedor

Dentro de esta ventana se configuran los directorios y ficheros de clases que utiliza el
servidor agrupados en distintas categorías. En nuestro caso tenemos que añadir el fichero
JAR del controlador JDBC, y un buen lugar para él es el apartado “Sufijo de ruta de clase”.
Veamos en la siguiente figura cómo debe quedar después de que lo hayamos añadido.

Las dos primeras líneas no las hemos puesto nosotros, si no que van incluidas cuando se
instala el servidor y sirven para una base de datos que lleva para usar con los ejemplos.

La figura anterior corresponde a un ordenador con Linux. Los usuarios de Windows tendrán
que ponerlo acorde a su plataforma. Sirva como ejemplo que la línea
“/opt/firebird/jdbc/firebirdsql-full.jar” mostrada en la figura, tendrían que indicarla como
“c:\firebird\jdbc\firebirdsql-full.jar”.

Tras este cambio utilizaremos el botón “Guardar” que aparece en la parte superior derecha
de esta misma página, reiniciaremos el servidor para que tenga en cuenta los cambios
realizados y volveremos a entrar en la consola de administración.

Seguidamente, expandimos el nodo “JDBC”, seleccionamos el nodo “Conjunto de conexiones”


y pulsamos el botón “Nuevo” de la página de la derecha. En la siguiente figura podemos ver
la relación de elementos mencionados.

65
3 Enterprises Beans y
servicios de contenedor

A continuación, nos irá solicitando una serie de datos de los cuales detallamos sólo los más
importantes junto con los valores que hemos de utilizar. Los campos que no estén en la
siguiente lista no es necesario (ni conveniente) que los cambiemos:

− “Nombre”. Nombre que queremos dar al pool de conexiones. Lo llamaremos


“CursoEJBPool”.

− “Tipo de recurso”. En nuestro caso es una fuente de datos y seleccionaremos el valor


“javax.sql.DataSource”.

− “Nombre de clase de la fuente de datos”. Es el nombre de una de las clases definidas


en el controlador JDBC que proveen la fuente de datos. Indicaremos el valor
“org.firebirdsql.pool.FBSimpleDataSource”.

− Propiedad “Password”. Contraseña para la conexión con la base de datos. Utilizaremos


la contraseña de la cuenta del administrador, es decir, el valor “masterkey”.

− Propiedad “DatabaseName”. Nombre de la base de datos. Indicaremos


“/home/alumno/cursoEJB/cursoEJB.gdb” o “c:\cursoEJB\cursoEJB.gdb” según estemos
en Linux o en Windows.

− Propiedad “User”. Cuenta para la conexión con la base de datos. Utilizaremos la del
administrador, que es “sysdba”.

− Propiedad “url”. Tendremos que añadirla utilizando el botón “Agregar propiedad”. Hace
referencia a la url necesaria para conectar con la base de datos. Utilizaremos los
valores “jdbc:firebirdsql:localhost/3050:/home/alumno/cursoEJB/cursoEJB.gdb” o
“jdbc:firebirdsql:localhost/3050:c:\cursoEJB\cursoEJB.gdb” dependiendo de que
estemos en Linux o Windows.

Según vayamos cumplimentando los datos, iremos avanzando con el botón “Siguiente”. Así
hasta terminar utilizando el botón “Finalizar”, tras el cual quedará registrado el pool de
conexiones que acabamos de definir. Para verificar que funciona correctamente es
importante que hagamos uso del botón “Sondeo” y que no devuelva un mensaje de error.

Una vez que tenemos el pool de conexiones definido, vamos a crear un recurso JDBC con un
nombre JNDI para que podamos utilizarlo desde la aplicación. En nuestro ejemplo concreto lo
utilizamos en la página “index.jsp” para obtener el nombre de la empresa desde la base de

66
3 Enterprises Beans y
servicios de contenedor

datos. Seleccionamos el nodo “Recursos JDBC” que cuelga del nodo “JDBC” y pulsamos el
botón “Nuevo”, como podemos ver en la siguiente figura.

Los datos que nos solicita son simples. Conozcamos para qué sirve cada uno y qué valor
hemos de ponerles:

− “Nombre JNDI”. Nombre que queremos asignar al recurso y que será utilizado en las
búsquedas JNDI. No podemos olvidar que los recursos JNDI se encuadran dentro de un
subcontexto y que en nuestro caso se trata del subcontexto “jdbc”. Por lo tanto, en
nuestro ejemplo vamos a llamarlo “jdbc/CursoEJB”.

− “Nombre de conjunto”. Nombre del pool de conexiones del que va a obtener las
conexiones. Seleccionaremos el valor correspondiente al pool que creamos
anteriormente, es decir, el elemento “CursoEJBPool”.

− “Descripción”. Es una descripción del recurso. No vamos a escribir nada.

− “Estado”. Indica si está disponible o no. Lo dejaremos seleccionado para poder hacer
uso de él.

Para finalizar terminaremos pulsando el botón “Aceptar” y habremos acabado. En este

67
3 Enterprises Beans y
servicios de contenedor

momento, nuestro servidor de aplicaciones J2EE ya es capaz de conectar con la base de


datos y devolver conexiones a los clientes que las soliciten. Pero hay un problema, ya que,
seguimos sin poder usarlo porque no es capaz de servir aplicaciones. No hemos desplegado
ninguna aplicación dentro de él, por lo tanto prosigamos con el último paso de nuestro
ejemplo.

3.7.2.4. Desplegando la aplicación

Antes de ponernos manos a la obra con el proceso de despliegue de nuestra aplicación,


vamos a resumir la situación actual resaltando algunos detalles que nos hará falta recordar
para que el despliegue tenga éxito.

− Hemos escrito las clases que componen el componente EJB y las hemos compilado.
Dichas clases son “VentasHome” (interfaz básica), “Ventas” (interfaz remota) y
“VentasBean” (clase de implementación de la lógica de negocio). No hemos creado el
descriptor de despliegue del componente y, en consecuencia, no hemos podido crear el
módulo EJB que contendrá el EJB.

− Hemos escrito una página JSP para que forme parte del módulo web pero no el
descriptor de despliegue del módulo web y, por lo tanto, tampoco hemos podido crear
dicho módulo. En el módulo web hay elementos (la página JSP) que hacen referencia a
un recurso JNDI llamado “java:comp/env/jdbc/cursoEJB” y a otro recurso JNDI
llamado “java:comp/env/ejb/Ventas”. El primero no nos preocupa porque lo hemos
definido a nivel del servidor, pero el segundo forma parte de la aplicación que vamos a
desplegar. Por lo tanto no podemos olvidar que el módulo web hace referencia al
módulo EJB. De no tenerlo en cuenta, no va a encontrar el recurso JNDI (el
componente EJB) y obtendremos un error.

En lo que a descriptores de despliegue se refiere, vamos a resumir cuáles son las


necesidades para nuestro ejemplo. La especificación J2EE nos requiere los siguientes
descriptores:

− Un descriptor de despliegue llamado “ejb-jar.xml” por cada módulo EJB. Debe ir


incluido en el fichero JAR correspondiente al módulo, dentro del directorio “META-INF”.

− Un descriptor de despliegue llamado “web.xml” por cada módulo web. Debe ir incluido
en el fichero WAR correspondiente al módulo, dentro del directorio “WEB-INF”

68
3 Enterprises Beans y
servicios de contenedor

− Un descriptor de despliegue llamado “application.xml” único para la aplicación. Debe ir


incluido en el fichero EAR correspondiente a la aplicación, dentro del directorio “META-
INF”.

Por su parte, el servidor de aplicaciones que hemos elegido requiere de los siguientes
descriptores:

− Un descriptor de despliegue llamado “sun-ejb-jar.xml” por cada módulo EJB. Debe ir


incluido en el fichero JAR correspondiente al módulo, dentro del directorio “META-INF”.

− Un descriptor de despliegue llamado “sun-web.xml” por cada módulo web. Debe ir


incluido en el fichero WAR correspondiente al módulo, dentro del directorio “WEB-INF”.

− Un descriptor de despliegue llamado “sun-application.xml” único para la aplicación.


Debe ir incluido en el fichero EAR correspondiente a la aplicación, dentro del directorio
“META-INF”.

Ya hemos visto qué tenemos y qué nos falta. Afortunadamente lo que nos falta nos lo va a
suministrar la herramienta de despliegue.

Ha llegado el momento de conocer la herramienta de despliegue. Está en el directorio “bin”


del servidor de aplicaciones y se llama “deploytool”.

Para utilizar esta herramienta es importante que el servidor de aplicaciones esté en


ejecución. Vamos, por tanto, a ejecutarla y veamos qué aspecto tiene:

69
3 Enterprises Beans y
servicios de contenedor

El área de trabajo está dividida en dos zonas principales (sin tener en cuenta el menú y
la barra de botones):

− A la izquierda tenemos un panel que nos muestra una estructura de tipo árbol. En ella
podremos desplazarnos por las aplicaciones que vayamos creando o abriendo con esta
herramienta y por la lista de servidores que hayamos definido (por defecto viene
incluido el servidor local).

− En la parte derecha tenemos un panel que irá mostrando información relevante del
elemento seleccionado en el árbol de la izquierda.

Lo primero que tenemos que hacer es crear una aplicación J2EE. Para ello seleccionaremos
en el menú la opción “Archivo”, después la opción “Nuevo” y, por último, la opción
“Application...”. Aparecerá una caja de diálogo solicitándonos el nombre del fichero y la
descripción de la aplicación.

Como fichero utilizaremos “/home/alumno/cursoEJB/ejemplo1/ejemplo1.ear” si estamos en


Linux y “c:\cursoEJB\ejemplo1\ejemplo1.ear” si estamos en Windows. Le dejaremos la
descripción que nos sugiere por defecto y pulsaremos “Aceptar” para finalizar.

Ya hemos creado una aplicación, pero está vacía, ya que, no tiene ningún componente. El
próximo paso será crearle un módulo EJB con las clases que hemos desarrollado para el EJB
de nuestro ejemplo.

A continuación, vamos a pulsar el botón izquierdo del ratón sobre el nodo “ejemplo1”, que es
la aplicación recién creada, para seleccionarlo. Después, elegimos en el menú la opción
“Archivo” y las subopciones “Nuevo” y “Enterprise Bean...”. Aparecerá un asistente que nos
guiará a través del proceso de adición del componente EJB.

Sólo vamos a detenernos en aquellas ventanas que puedan ofrecernos o solicitarnos


información trascendente, el resto las ignoraremos e iremos pulsando el botón “Siguiente >”.

70
3 Enterprises Beans y
servicios de contenedor

Prestemos atención a la siguiente ventana.

1
2

En la ventana anterior destacamos los siguientes elementos:

1. Tenemos que decidir dónde incluir el EJB y se nos ofrecen tres opciones. En nuestro
caso no disponemos de ningún módulo, por lo que elegiremos que se cree uno nuevo
para almacenar el EJB.

2. Nombre del fichero JAR que se creará para el módulo EJB. Puesto que sólo vamos a
tener uno, lo hemos llamado “móduloEJB” para que destaque. Una aplicación J2EE
real podría tener más de uno y sería conveniente que tuvieran nombres descriptivos.

3. El botón “Editar contenido...” lo usaremos para indicar qué ficheros componen el


módulo. Nosotros tendremos que añadir los tres ficheros compilados que componen
el enterprise bean.

71
3 Enterprises Beans y
servicios de contenedor

2
3
4
5

La siguiente ventana sirve para que indiquemos qué papel juega cada una de las clases que
componen el EJB.

En ella tendremos que indicar los siguientes campos:

1. Nombre de la clase que implementa la lógica de negocio.

2. Nombre del enterprise bean. Sólo sirve a título informativo.

3. Como tipo, tendremos que elegir entre bean con estado y bean sin estado. En
nuestro caso se trata de un bean sin estado (“Stateless Session”).

4. Interfaz básica del EJB.

5. Interfaz remota del bean.

En la figura anterior pudimos ver que existen dos grupos relativos a las interfaces:

− “Interfaces Locales”. Las interfaces locales son aquellas que permiten comunicar con
componentes EJB que estén en la misma unidad de despliegue. En nuestro ejemplo no

72
3 Enterprises Beans y
servicios de contenedor

podemos utilizarlas porque, aunque la página JSP y el componente EJB forman parte
de la misma aplicación, no las hemos definido.

− “Interfaces Remotas”. Las interfaces remotas permiten comunicar con componentes


EJB mediante RMI.

Una vez terminado el asistente, nos aparecerá un nuevo nodo llamado “moduloEJB” colgando
del nodo de la aplicación. A su vez, del módulo EJB colgarán tantos nodos como enterprise
beans tengamos. En nuestro caso sólo el que acabamos de crear y que hemos llamado
“VentasBean”.

Recordemos que es en el descriptor de despliegue del módulo EJB donde se define el nombre
JNDI que van a utilizar los enterprise beans que contiene dicho módulo. Con la creación del
módulo que acabamos de realizar ya se le ha asignado un nombre JNDI por defecto al bean
de nuestro ejemplo. Además, en la página JSP hacíamos uso de dicho nombre y habíamos
decidido que sería “java:comp/env/ejb/Ventas”. Por lo tanto, vamos a seleccionar el nodo
“VentasVean” y, a continuación, el botón “Preferencias específicas de Sun...” en la pestaña
“General”. En la ventana que aparece podremos ver que el nombre JNDI asignado es
“VentasBean”. Se lo cambiaremos por el de “ejb/Ventas” editando la celda correspondiente.
En la figura siguiente podemos ver cómo quedaría.

Proseguiremos, a continuación, con el componente web. El proceso es parecido al anterior.


En el menú “Archivo” seleccionaremos las opciones “Nuevo” y “Componente Web...”. Nos
aparecerá un asistente que nos guiará a través del proceso de creación.

De nuevo, nos detendremos sólo en aquellas ventanas que tengan datos trascendentes. En
las demás podremos simplemente pulsar el botón “Siguiente >”.

Empezamos por la siguiente ventana, muy parecida a la que ya viéramos cuando añadimos
el enterprise bean.

73
3 Enterprises Beans y
servicios de contenedor

1
2

Los datos a tener en cuenta son los siguientes:

1. De las tres opciones posibles, nos interesa crear un nuevo módulo web (hasta el
momento nuestra aplicación no tiene ninguno).

2. Nombre del fichero WAR que va a contener el módulo web. Al igual que con los
módulos EJB, debería tener un nombre más descriptivo, pero en nuestro caso no nos
importa porque es el único que va a contener la aplicación J2EE.

3. Este botón se utiliza para indicar qué elementos forman parte del módulo web.
Nosotros sólo vamos a añadirle la página “index.jsp” pero en una situación real
tendríamos que añadir todos aquellos ficheros que compongan el módulo web
(páginas JSP, ficheros HTML, hojas de estilo, imágenes, etc.).

En la ventana en que nos solicite el tipo de componente web, elegiremos que no es ningún
componente. La utilidad de esta ventana es que podamos definir características adicionales
dependiendo del tipo de componente.

74
3 Enterprises Beans y
servicios de contenedor

Tras la creación del módulo web nos quedan una serie de cambios por realizar. Para todos
ellos tendremos que tener seleccionado el nodo “moduloWEB” en el árbol.

En primer lugar, asignaremos a la aplicación web un nombre de contexto. Para ello


seleccionaremos la pestaña “General” y el valor de “Raíz de contexto” lo fijaremos a
“/ejemplo1”. Esto nos va a permitir ejecutar el módulo web utilizando la url
“http://localhost:8080/ejemplo1”.

También definiremos una página de bienvenida por defecto para que sea la que se muestre
cuando se omita la página durante la navegación. A nosotros nos conviene que sea la página
“index.jsp” porque además es la única que tiene nuestro módulo web.

A continuación, seleccionaremos la pestaña “Referencias del archivo” y pulsaremos el botón


“Agregar archivo” del apartado “Archivos de bienvenida”. Se añadirá automáticamente una
fila y le indicaremos el valor “index.jsp”.

Lo próximo va a ser añadir la referencia al enterprise javabean para que el módulo web
pueda hacer uso de él. Seleccionaremos la pestaña “Referencias de EJB” y utilizaremos el
botón “Añadir...”. La información que tenemos que completar es la siguiente:

− “Nombre codificado”. Es el nombre de referencia del enterprise javabean. Tenemos


que utilizar el nombre del subcontexto JNDI. Por lo tanto, el valor a poner sería
“ejb/Ventas”.

− “Tipo de EJB”. Tipo de bean. Podemos elegir entre los tipos “Session” y “Entity”. En
nuestro caso estamos hablando de un bean de sesión.

− “Interfaces”. Tendremos que decidir si utilizaremos la interfaz local o remota.


Recordemos que al EJB sólo le hemos definido la interfaz remota, por lo tanto,
seleccionaremos la opción “Remote”.

75
3 Enterprises Beans y
servicios de contenedor

− “Interfaz de inicio”. Interfaz básica del EJB. Tenemos que incluir el nombre del paquete
al que pertenece.

− “Interfez local/remota”. Interfaz remota del EJB. También habremos de incluir el


nombre de la clase.

− “Nombre JNDI”. En el apartado “EJB de destino” tenemos que indicar cuál es el


enterprise bean al que queremos hacer referencia. Nosotros vamos a optar por hacer
referencia a él utilizando su nombre JNDI. Por lo tanto, será su nombre JNDI el que
indicaremos aquí, es decir, el valor “ejb/Ventas”.

En la siguiente figura se muestra la información explicada anteriormente.

No obstante, nuestro módulo web no sólo hace uso del EJB. Recordemos que también
utilizamos el pool de conexiones del servidor para obtener una conexión con la base de datos
y realizar una consulta. No accedemos directamente al pool de conexiones, sino que
hacemos referencia a un recurso JNDI que suministra una fuente de datos.

76
3 Enterprises Beans y
servicios de contenedor

Vamos entonces a añadirle al módulo web la referencia al recurso JNDI. Lo haremos


seleccionando la pestaña “Referencias del recurso” y pulsando el botón “Agregar”.

Los datos a cumplimentar son los siguientes:

− “Nombre codificado”. Es el nombre de referencia del recurso. Tenemos que utilizar el


nombre del subcontexto JNDI. Por lo tanto, el valor a poner sería “jdbc/CursoEJB”.

− “Tipo”. Este recurso será del tipo “javax.sql.DataSource”.

− “Autenticación”. Indicaremos que la autentificación para utilizar el recurso la realiza el


contenedor. Elegiremos la opción “Container”.

− “Compartible”. Indica si el recurso es compartible. Lo dejaremos habilitado.

− “Nombre JNDI”. Éste será el nombre del recurso JNDI que queremos utilizar. Le
asignaremos el valor “jdbc/CursoEJB”, que es con el que lo definimos en la consola de
administración del servidor de aplicaciones.

− “Nombre de usuario”. Nombre del usuario para la conexión con la base de datos.
Utilizaremos la cuenta de administración por lo que el usuario es “sysdba”.

− “Contraseña”. Contraseña de la cuenta de administración. Indicaremos “masterkey”.

En la siguiente figura podemos ver cómo quedarían los cambios que tenemos que realizar.

77
3 Enterprises Beans y
servicios de contenedor

Con todo lo que hemos realizado, ya hemos finalizado. El proceso ha sido un poco largo y
delicado y si algo no está como debiera, la aplicación no va a funcionar. Afortunadamente
esta herramienta suministra un mecanismo de comprobación de errores. Concretamente se
basa en comprobar que la aplicación cumple con la especificación J2EE. Por ejemplo, puede
ayudarnos a resolver problemas derivados de errores al hacer referencia a recursos JNDI.

Antes de desplegar la aplicación, verificaremos que cumple la especificación. Para ello,


seleccionaremos el nodo de la aplicación (el llamado “ejemplo1”) en el árbol de estructura y,
a continuación, elegiremos la opción “Herramientas” del menú y la subopción “Verificar la
compatibilidad con J2EE...”.

Nos aparecerá una ventana en la que podemos discriminar los mensajes obtenidos en base a
su tipo. Elegiremos el modo “Sólo fallos y advertencias” para sólo ver los mensajes de aviso
y error, pulsaremos el botón “OK” y empezará la comprobación. Cuando el proceso termine
nos informará del éxito o de los errores encontrados. En la parte inferior de la ventana se
nos mostrará el detalle del mensaje de error seleccionado (si lo hubiera).

Acabamos de ejecutar el proceso de verificación y el resultado lo vemos en la siguiente


ventana:

78
3 Enterprises Beans y
servicios de contenedor

En caso de error tendremos que analizar su detalle y realizar la acción correctora que
corresponda.

Ha llegado el momento final. Hemos terminado de crear la aplicación y dentro de poco


veremos el fruto de nuestro trabajo. No obstante, aún no la hemos desplegado, por lo que lo
haremos ahora. Se trata de un proceso de lo más simple: teniendo seleccionado el nodo
“ejemplo1”, utilizaremos el menú “Herramientas” y la opción “Implementar...”.

Se nos mostrará una ventana en la que tendremos que elegir el servidor de aplicaciones e
indicar el nombre y contraseña del administrador de dicho servidor. Seguidamente,
pulsaremos el botón “Aceptar” y comenzará el proceso de despliegue. Iremos viendo una
consola en la que se mostrarán mensajes relativos al proceso.

En la figura siguiente podemos observar el resultado del despliegue de nuestra aplicación de


ejemplo.

En la figura anterior tenemos la confirmación de que el despliegue ha tenido éxito y de que


la aplicación está en ejecución.

79
3 Enterprises Beans y
servicios de contenedor

3.7.3. El funcionamiento

Ahora viene la parte más esperada por todo desarrollador: ver en ejecución el código
desarrollado. No esperaremos más y veamos cómo funciona. Posteriormente analizaremos el
trabajo realizado y sacaremos algunas conclusiones.

Para ver el fruto de nuestro esfuerzo tenemos que abrir un navegador y navegar a la
dirección “http://localhost:8080/ejemplo1”. Recordemos lo siguiente:

− Nuestro servidor de aplicaciones atiende peticiones HTTP en el puerto 8080.

− El contexto raíz que hemos definido para la aplicación es “/ejemplo1”.

− En la petición no especificamos ninguna página porque le definimos al módulo web que


utilizara la página “index.jsp” como página de bienvenida.

Al navegar a la dirección indicada se nos muestra el siguiente contenido:

Utilicemos los valores 3 y 17 para la cantidad y el precio, y pulsemos el botón “Calcular”.


Veremos que nos muestra el resultado y nos permite volver a introducir nuevos valores.

Las conclusiones que podemos extraer son variadas. Lo primero que nos puede resultar poco
razonable es el volumen de trabajo que hemos tenido que realizar para obtener un producto
tan simple. Utilizando otras tecnologías hubiéramos podido obtener los mismos resultados
con menos esfuerzo. Por lo tanto, alguna ventaja debe tener el esfuerzo realizado.

80
3 Enterprises Beans y
servicios de contenedor

Veamos algunas características de la aplicación que hemos desarrollado:

− La experiencia demuestra que el esfuerzo realizado en el desarrollo de aplicaciones


J2EE no es el que se percibe durante los primeros desarrollos. El problema reside en
que es una tecnología muy distinta a otras que podamos conocer, por lo que aparenta
gran esfuerzo y complejidad. Realmente, no hemos hecho gran cosa: escribir tres
clases, compilarlas, escribir una página JSP, construir la aplicación y desplegarla en el
servidor.

− Supongamos que encontráramos una empresa interesada en utilizar nuestra


aplicación, pero que dispone de tres redes independientes y sus respectivos servidores
son UNIX, AS/400 y Windows 2000 Server. ¿Se nos plantea algún problema? En
absoluto. Nuestra aplicación es multiplataforma.

− Ahora, supongamos que nuestra aplicación es utilizada en la empresa en la que


trabajamos y que el volumen de usuarios ha crecido hasta el punto de que el
rendimiento del servidor de aplicaciones que estamos utilizando se ha degradado
demasiado. La empresa reconoce la necesidad de invertir en el mejor servidor de
aplicaciones del mercado y nuestra aplicación va a ser capaz de funcionar en él.

− Si decidimos cambiar la base de datos porque queremos migrar a otra más potente,
bastará con cambiar el recurso JNDI del servidor para que apunte a la nueva base de
datos, si hemos sido cuidadosos.

− Por otro lado, si la aplicación vuelve a dar problemas porque las exigencias ha
aumentado excesivamente, podemos distribuir la carga añadiendo otros servidores y
equilibrando el reparto de componentes J2EE.

Esta relación es sólo una pequeña muestra de características. La documentación de la


plataforma J2EE es mucho más extensa y específica al respecto.

81
3 Enterprises Beans y
servicios de contenedor

− Un enterprise javabean tiene la finalidad de contener la lógica de la


recuerde_
empresa (las reglas de negocio). Encapsula la funcionalidad crítica y permite
que el desarrollador de aplicaciones se despreocupe de los servicios del nivel
de sistemas, como la concurrencia, la persistencia y las transacciones

− La especificación J2EE define tres tipos de enterprise javabeans, cada uno


orientado a unos fines concretos. Dichos tipos son: beans de sesión, beans
de entidad y beans controlados por mensaje.

− El contenedor EJB es el entorno en el que se ejecuta un componente EJB y se


encarga de proporcionarle los servicios necesarios durante su ciclo de vida.

82
índice_ 4 Beans de sesión

4.1. TIPOS DE BEANS DE SESIÓN ..................................................85


4.2. LA LÓGICA DE NEGOCIO .........................................................86
4.3. LAS FACHADAS.......................................................................86
4.4. EL ESTADO CONVERSACIONAL ...............................................89
4.5. LA PERSISTENCIA ..................................................................91
4.6. UN EJEMPLO...........................................................................92
4.6.1. Un JavaBean ayudante ................................................92
4.6.2. El bean de sesión.........................................................93
4.6.3. El componente web .....................................................98
4.6.4. Desplegando la primera aplicación ............................102

83
4 Beans de sesión

4.1. TIPOS DE BEANS DE SESIÓN

Podemos distinguir dos tipos de beans de sesión: con estado y sin estado. A pesar de tener
matices diferenciadores, ambos tipos tienen muchos aspectos comunes:

− Implementan la interfaz “javax.ejb.SessionBean”, por lo que tienen las mismas


retrollamadas de contenedor.

− Se utilizan para modelar un proceso.

− Representan un recurso privado para el cliente que los crea.

− Pueden interactuar con datos compartidos pero no los representan como lo hacen los
beans de entidad.

Tanto tienen en común, que la única forma de distinguirlos es mediante el fichero descriptor
de despliegue. Mediante dicho fichero es capaz el contenedor EJB de saber de qué tipo de
bean de sesión se trata.

La diferencia fundamental entre ambos tipos de beans radica en la forma en la que tratan el
estado. Por estado del bean se entiende el conjunto de variables miembros. De este modo,
un bean de sesión con estado puede mantener los valores de sus variables entre distintas
llamadas a sus métodos, mientras que un bean de sesión sin estado, no.

Esta diferencia entre ambos tipos implica una gran repercusión en el diseño de una
aplicación. Una regla básica a tener en cuenta es que los beans de sesión con estado sólo
debemos utilizarlos en la frontera del modelo de objeto, es decir, en el extremo colindante
con los clientes de la aplicación.

85
4 Beans de sesión

4.2. LA LÓGICA DE NEGOCIO

Aunque vamos a tratarlos en el siguiente tema, podemos adelantar que un bean de entidad
es una entidad completa de datos. Por el contrario, los beans de sesión se utilizan para
controlar la interacción entre las entidades de datos y el proceso en su conjunto.

Una arquitectura muy adecuada para muchos objetivos en las aplicaciones corporativas
consiste en organizar los beans en dos capas:

− La capa inferior proporciona servicios genéricos y se denomina capa de servicios.

− La capa superior proporciona acceso controlado a estos servicios desde los clientes y
se denomina capa de control de acceso.

Para que esta arquitectura sea efectiva, debemos mantener una cierta cantidad de datos,
llamada estado conversacional, que representa la información creada durante un
intercambio de solicitudes y respuestas. A medida que avanza el diálogo, el estado
conversacional va acumulando información sobre el intercambio, y permite que las
solicitudes que vayan a continuación puedan hacer uso de dicha información.

El estado conversacional no debemos mantenerlo en la capa de servicios, sino que habremos


de mantenerlo en la capa de control de acceso. Existe una formulación general de esta regla
que prohíbe el estado en la capa de servicio basándose en criterios específicos de los EJB: Si
se utilizan beans de sesión con estado, nunca deben encadenarse mediante llamadas mutuas
de métodos de empresa.

El contenedor EJB tiene libertad para descartar el estado conversacional después de pasado
un tiempo considerable de inactividad. Es decir, puede destruir el bean de sesión con estado.
A partir de ese momento, si se intentara utilizar se generaría una excepción.

4.3. LAS FACHADAS

De los patrones de diseño que existen para la tecnología J2EE, uno de los más interesantes
es el que utiliza un bean de sesión para proporcionar una fachada a un cliente.

Se define como patrón a una solución usada comúnmente para la resolución de un problema
común.

86
4 Beans de sesión

Por otro lado, una fachada es una interfaz de nivel superior que se utiliza para configurar un
grupo de interfaces en un subsistema.

En la siguiente figura podemos ver que utilizar un bean de sesión para proporcionar una
fachada implica que sólo exista un punto de entrada a nuestro sistema. Desde el punto de
vista del cliente sólo hay un bean de sesión con el que interactuar. Así pues, la interacción
del cliente queda limitada a la fachada, que a su vez pasa las solicitudes al resto del sistema.
Este patrón es conocido como el patrón de fachada porque proporciona un frontal a
nuestro sistema.

Existen varias razones para utilizar el patrón de fachada. Las más obvias son que se reduce
la complejidad y se minimizan las dependencias entre los subsistemas.

Supongamos que un cliente necesitara acceder a la lógica de la empresa de varios beans de


sesión y a la lógica de validación de varios beans de entidad. Veamos las siguientes
ventajas al utilizar una fachada en lugar de acceder a los beans directamente desde el
cliente:

− Disminuye el tráfico de red. Éste siempre ha sido una limitación en el rendimiento de


los sistemas de objetos distribuidos. La programación orientada a objetos suele
implicar numerosas llamadas a métodos que cuando se realizan de forma remota, los
parámetros y los valores de retorno deben ser enviados por la red. Supongamos que
un cliente quiere sumar los resultados de invocar un método en un conjunto de 10
beans de entidad. Si el cliente invoca los beans de entidad directamente, cada

87
4 Beans de sesión

invocación y cada respuesta viaja por la red. Si el cliente invoca la fachada del bean (y
en él se realiza la suma), sólo es necesario que una invocación y una respuesta viajen
por la red.

− Control transaccional declarativo. Habitualmente, los resultados de múltiples


operaciones de manipulación de datos deben aplicarse como una única unidad (una
transacción). Cuando una fachada realiza todas las operaciones, el contenedor EJB
puede gestionar el proceso automáticamente conforme a la información declarativa
proporcionada por el desarrollador. Si es el cliente quien realiza las operaciones, debe
responsabilizarse de garantizar el éxito del conjunto de dichas operaciones de forma
atómica.

− Se necesitan menos interposiciones. El contenedor EJB añade una capa de indirección


entre el cliente y el bean para proporcionar sus servicios a los EJB. Esta capa consume
recursos en el servidor (memoria y tiempo de proceso). Si un EJB llama a otro dentro
del mismo contenedor, parte de su trabajo puede ser optimizado y pueden ahorrarse
recursos.

− La lógica de empresa estará en el nivel correcto. Cuando son necesarios varios beans
para proporcionar una función de empresa, suele haber algún orden y relación en sus
llamadas. Además de vincular estrechamente la capa cliente a la implementación de la
capa de lógica de empresa, realizar las llamadas desde el cliente significa que cierta
cantidad de flujo de trabajo se ubica en la capa cliente. Utilizando un bean de sesión
como fachada, el cliente deja de estar estrechamente vinculado a la lógica de empresa
y se preserva más flujo de trabajo en el servidor. Normalmente se organizan limitando
los beans de entidad a representar filas en su base de datos mientras que un único
método de empresa en un bean de sesión agrupa varias llamadas en uno o varios
beans de entidad.

Como norma general, todos nuestros accesos a los enterprise Javabeans desde las
aplicaciones cliente deberían ser a través de un número reducido de fachadas de beans de
sesión. Lógicamente, esta regla no se aplica a los mismos EJB, que pueden tener beans de
sesión sin fachada o de entidad como clientes; si no fuera así, la fachada necesitaría otra
fachada y así sucesivamente.

88
4 Beans de sesión

4.4. EL ESTADO CONVERSACIONAL

Podemos dividir el estado en dos tipos:

− Transaccional. Hace referencia a los datos que almacenamos en el almacén


persistente (la base de datos). Varios clientes pueden leer y modificar dichos datos
simultáneamente. Si cae el servidor de aplicaciones, los datos siguen disponibles en el
almacén de datos.

− Conversacional. Hace referencia a los datos almacenados en las variables de la


aplicación, en el cliente, en el contenedor EJB o en el servidor de aplicaciones. Son
datos privados accesibles sólo para un cliente dado. Si el estado conversacional no se
pasa a estado transaccional, desaparecerá cuando desaparezca el componente de la
aplicación que lo mantiene.

En este apartado vamos a tratar sólo el estado conversacional. El estado transaccional es


una cuestión ampliamente cubierta por las tecnologías actuales de bases de datos, que ya
gozan de una dilatada experiencia en estas tareas.

La mayoría de las aplicaciones tendrán estado conversacional. En función del cliente, el


estado puede almacenarse de distintas formas. Los navegadores web pueden almacenar el
estado en el cliente (mediante cookies o campos ocultos, por ejemplo) o en el servidor
(sesiones HTTP).

Los beans de sesión permiten otro espacio en el que puede almacenarse el estado (lo que
puede facilitar la programación en determinadas circunstancias). El estado puede ser
almacenado de forma unificada con independencia del tipo de clientes.

Sin embargo, las ventajas potenciales que nos puede ofrecer en el desarrollo de la aplicación
debemos equilibrarlas frente al coste de reajustabilidad y rendimiento. Para entender esto,
veamos algunos detalles acerca del funcionamiento del contenedor EJB.

89
4 Beans de sesión

En la figura anterior podemos ver que todos los beans de sesión están asociados uno a uno
con un cliente dado. El contenedor crea el EJB cuando el cliente invoca el método “create ()”,
y lo destruye cuando invoca el método “remove ()”.

Por ejemplo, si hubiera mil clientes web utilizando nuestra aplicación, habría mil beans de
sesión en el servidor. Por el contrario, con un bean de sesión sin estado, damos al
contenedor la oportunidad de optimizar los recursos utilizando la reserva de beans. Al no
tener estado, no hay ningún efecto sobre el bean desde ninguna llamada de cliente, por lo
que puede ser reutilizado en múltiples clientes. En la siguiente figura podemos ver un
ejemplo.

Esto tiene un efecto muy importante sobre los recursos disponibles en el servidor. En lugar
de tener mil beans de sesión sin estado, el contenedor puede tener una reserva de sólo cien.
Claro está que la reserva debería ajustarse dinámicamente para cubrir un número
indeterminado de solicitudes.

Por lo que acabamos de ver, una reserva es una colección de instancias que se encuentran
disponibles para ser utilizadas. El servidor podría reservar componentes, hilos, conexiones a
bases de datos y otros recursos. Y una gran ventaja es que estas reservas son transparentes
de cara al desarrollo de las aplicaciones.

Quizás nos preguntemos que si los beans de sesión sin estado no tienen estado, por qué
habrían de tener variables. La respuesta es que pueden tener estado que no esté asociado a
un bean concreto (un socket, por ejemplo).

Tampoco deben ser multihilo por motivos de diseño, ya que, se facilita el modelo de
desarrollo para componentes EJB. A un EJB nunca accede más de un hilo a la vez, por lo que
no necesitamos preocuparnos de la sincronización del acceso al estado.

90
4 Beans de sesión

Un bean de sesión sin estado pueden tener estado asociado a un cliente en una llamada de
método dado, pero no puede mantener dicho estado entre distintas llamadas a métodos.

Para ayudar al contenedor EJB en la gestión de un gran número de beans de sesión con
estado, la especificación J2EE incluye las retrollamadas y reglas que otorgan al contenedor la
capacidad de trasladar un bean de sesión con estado a almacenamiento temporal, y de
restaurarlo posteriormente desde ese almacén. El algoritmo que utilice el contenedor para
decidir cuándo debe almacenarlo es específico del contenedor EJB. La operación de
almacenamiento de un bean se denomina pasivación y la reactivación se conoce como
activación.

La activación y pasivación son métodos muy efectivos para tratar los problemas de la
limitación de recursos en los servidores. No obstante, si la reajustabilidad es importante para
nuestra aplicación, lo mejor es mantener el estado en el cliente y pasarlo de vuelta al
servidor con cada invocación.

4.5. LA PERSISTENCIA

La lógica de empresa a menudo suele realizar operaciones de adición y modificación de datos


del almacén persistente de nuestra empresa, es decir, de nuestra base de datos. La
especificación Enterprise JavaBeans proporciona beans de entidad para representar estos
datos y proveer los servicios relacionados con la persistencia.

Sin embargo, podemos no hacer uso de los beans de entidad y acceder directamente a un
almacén de datos desde nuestros beans de sesión. Es decir, nuestros beans de sesión
pueden ser los encargados de soportar la funcionalidad de los beans de entidad. Pero como
es normal, dejaremos de usar determinados servicios de persistencia del contenedor, lo que
añadirá complejidad a nuestro desarrollo.

En algunas ocasiones nos puede merecer la pena utilizar el acceso directo a los datos
mediante JDBC desde nuestros beans de sesión en lugar de utilizar beans de entidad. En
otras ocasiones, utilizar un enfoque de bean de sesión puede tener un efecto perjudicial en el
rendimiento porque terminaríamos implementando muchos servicios complejos que los
servidores de aplicación tienen más que optimizados. Las situaciones más comunes
requerirán el uso de beans de entidad con persistencia gestionada por contenedor para
operaciones sobre entidades individuales y conjuntos reducidos de valores. Los beans de
sesión serán más apropiados para operaciones sobre un conjunto de datos.

91
4 Beans de sesión

4.6. UN EJEMPLO

A continuación vamos a ver un ejemplo de uso de los Enterprise JavaBeans. Se trata de un


ejemplo de utilización conjunta de beans de sesión y de entidad. Por el momento sólo nos va
a interesar el bean de sesión.

La funcionalidad del ejemplo se va a limitar a una página JSP que nos muestre la relación de
clientes de nuestra base de datos y nos permita las operaciones de creación, modificación y
borrado sobre dichos clientes.

El ejemplo va a componerse de dos aplicaciones J2EE. Una de ellas va a contener los


componentes EJB que van a implementar la lógica de negocio. Sus componentes serán:

− Componente EJB de sesión sin estado. Va a ser la fachada de cliente. El único punto
posible a través del cual los clientes de la aplicación podrán acceder a la capa EJB.

− Componente EJB de entidad con persistencia gestionada por el contenedor.

Para el desarrollo y despliegue del ejemplo vamos a usar las mismas herramientas utilizadas
en el tema anterior, por lo que no vamos a repetir los detalles ya descritos.

Lo primero será ejecutar el entorno de desarrollo NetBeans y crear el proyecto con el nombre
“ejemplo2”, creándose la siguiente estructura de directorios en los respectivos sistemas
operativos:

En Linux: /home/alumno/cursoEJB/ejemplo2
En Windows: c:\cursoEJB\ejemplo2

A continuación, vamos a crear un paquete Java, llamado “gestion”, en el que meteremos


todas las clases e interfaces de nuestro ejemplo. No debemos olvidar en adelante que
cualquier clase que creemos tendrá que pertenecer a este paquete.

4.6.1. Un JavaBean ayudante

Definiremos una clase JavaBean, a la que llamaremos “ClienteDetalle”, que va a servirnos


para representar a cada uno de los clientes. Esta clase va a contener métodos “getter ()” y
“setter ()” para cada uno de los atributos del cliente. Nos va a servir para utilizarla en las
llamadas a métodos en lugar de usar la lista completa de propiedades del cliente. Además, si

92
4 Beans de sesión

en un futuro decidimos añadir o quitar propiedades del cliente, el volumen de modificaciones


va a ser significativamente menor. Para crear la clase, utilizamos el botón derecho del ratón
sobre el nodo “gestion” y seleccionamos la opción “New” y subopción “Java Class”. A
continuación, editaremos la clase “ClienteDetalle” y escribiremos el siguiente código:

package gestion;
public class ClienteDetalle implements java.io.Serializable {
private Integer cliente = null;
private String nombre = null;

public ClienteDetalle (Integer cliente, String nombre) {


this.cliente = cliente;
this.nombre = nombre;
}
public Integer getCliente() {
return this.cliente;
}
public void setCliente(Integer cliente) {
this.cliente = cliente;
}
public String getNombre() {
return this.nombre;
}
public void setNombre (String nombre) {
this.nombre = nombre;
}
}

Seguidamente compilaremos la clase.

4.6.2. El bean de sesión

Anteriormente vimos que el bean de sesión que vamos a desarrollar va a formar parte de la
fachada de la capa EJB. Nuestro bean estará en la frontera del modelo de componentes EJB y
será el único punto de entrada para los clientes que necesiten los servicios de la capa. En
dicha capa reside la lógica de negocio, y la fachada de cliente será la responsable de
canalizar los accesos.

93
4 Beans de sesión

Nuestro ejemplo es muy sencillo porque tras la fachada sólo se esconde un bean de entidad,
y la relación entre los métodos del bean de sesión y del bean de entidad es de uno a uno. Es
decir, cuando se invoca cualquier método del bean de sesión, éste llama en cada caso a un
método concreto (y sólo a uno) del bean de entidad. Esta situación puede parecer absurda,
ya que, el bean de sesión es un mero intermediario que no aporta nada (aparentemente). La
página JSP podría prescindir del bean de sesión y llamar directamente al método específico
del bean de entidad.

No obstante, las situaciones reales no suelen ser tan simples. Nos podemos encontrar con
beans de sesión que invocan a uno o más métodos de uno o más beans (del tipo que sean) y
en un orden determinado. Forma parte de la lógica de negocio que dichas llamadas se
realicen, y que sea en el orden necesario. Confiar esto al cliente (la página JSP) no es lo más
acertado. Estaríamos pasando la lógica de negocio a una capa que no le corresponde.
Además, si en un futuro necesitamos desarrollar una página JSP adicional o un cliente de
aplicación, también tendríamos que implementar en ellos la lógica de negocio, con el
consiguiente riesgo de errores.

Cuando decimos que el bean de sesión es el único punto de entrada a la capa donde reside la
lógica de negocio, no estamos haciendo referencia a que sea aconsejable acceder a través de
él. En este caso concreto se trata de que sea imposible acceder al bean de entidad puesto
que sólo el bean de sesión define una interfaz remota. Aunque lo vamos a ver en el próximo
tema, comentaremos aquí que el bean de entidad sólo tiene interfaz local, lo que impide que
se tenga acceso a él desde fuera de la unidad de despliegue de la que forma parte.

Lo próximo que vamos a hacer es crear la clase y las dos interfaces que necesitará nuestro
EJB de sesión. Utilizaremos el botón derecho del ratón sobre el nodo “gestion” y
seleccionamos la opción New y subopción Java Class. Esta operación la realizaremos tres
veces y los nombres que emplearemos serán los siguientes: MtoClientesHome,
MtoClientes y MtoClientesBean.

A continuación, vamos a modificar el contenido de cada clase para que se ajuste a lo que
queremos de ella. Concretamente, dos de esas clases deberían ser interfaces, por lo que las
cambiaremos. Pero veamos primero cual es la finalidad de cada una de ellas:

− “MtoClientesHome”. Es la interfaz básica del EJB.

− “MtoClientes”. Es la interfaz remota del EJB.

− “MtoClientesBean”. Es la clase de implementación. Contiene el código de los métodos


de negocio.

94
4 Beans de sesión

Seguidamente, editaremos la clase MtoClientesHome y escribiremos el siguiente código:

package gestion;
import javax.ejb.*;
public interface MtoClientesHome extends javax.ejb.EJBHome {
public gestion.MtoClientes create ()
throws javax.ejb.CreateException, java.rmi.RemoteException;

Para la clase “Mtoclientes”, su código será:

package gestion;
import javax.ejb.*;
public interface MtoClientes extends javax.ejb.EJBObject {

public java.util.Vector findAll () throws javax.naming.NamingException,


java.rmi.RemoteException, javax.ejb.FinderException;

public void alta (java.lang.Integer cliente, java.lang.String nombre) throws


java.rmi.RemoteException, javax.naming.NamingException,
javax.ejb.CreateException, java.sql.SQLException;

public void baja (java.lang.Integer cliente) throws


javax.naming.NamingException, javax.ejb.FinderException,
java.rmi.RemoteException, javax.ejb.RemoveException;

public void modificacion (java.lang.Integer cliente, java.lang.String nombre)


throws java.rmi.RemoteException, javax.naming.NamingException,
javax.ejb.FinderException;
}

95
4 Beans de sesión

Por último, a la clase MtoClientesBean, que es la que contiene el código que soporta las
reglas de negocio, le escribimos el siguiente código:

package gestion;
import javax.naming.*;
import javax.ejb.*;
import java.util.*;
public class MtoClientesBean implements javax.ejb.SessionBean {
private javax.ejb.SessionContext context;
public void setSessionContext (javax.ejb.SessionContext aContext) {
context=aContext;
}
public void ejbActivate () { }
public void ejbPassivate () { }
public void ejbRemove () { }
public void ejbCreate () { }
public java.util.Vector findAll()
throws javax.naming.NamingException, javax.ejb.FinderException {
Vector clientesDetalle = new Vector();
Context ctx = new InitialContext();
Object obj = ctx.lookup ("java:comp/env/ejb/Clientes");
LocalClientesHome home = (LocalClientesHome)
javax.rmi.PortableRemoteObject.narrow(obj,
LocalClientesHome.class);
Collection clientes = home.findAll();
if (clientes!=null) {
Iterator iter = clientes.iterator();
while (iter.hasNext()) {
ClienteDetalle detalle =
((LocalClientes)iter.next()).getClienteDetalle();
clientesDetalle.addElement(detalle);
}
}
return clientesDetalle;
}
public void alta(java.lang.Integer cliente, java.lang.String nombre)
throws javax.naming.NamingException, javax.ejb.CreateException,

96
4 Beans de sesión

java.sql.SQLException {
Context ctx = new InitialContext();
Object obj = ctx.lookup ("java:comp/env/ejb/Clientes");
LocalClientesHome home = (LocalClientesHome)
javax.rmi.PortableRemoteObject.narrow(obj,
LocalClientesHome.class);
try {
LocalClientes existe = home.findByPrimaryKey (cliente);
throw new java.sql.SQLException ("Ya existe un cliente con el
código " + cliente.toString ());
} catch (FinderException e) {
home.create (cliente, nombre);
}
}
public void baja (java.lang.Integer cliente)
throws javax.naming.NamingException, javax.ejb.FinderException,
javax.ejb.RemoveException {
Context ctx = new InitialContext ();
Object obj = ctx.lookup ("java:comp/env/ejb/Clientes");
LocalClientesHome home = (LocalClientesHome)
javax.rmi.PortableRemoteObject.narrow(obj,
LocalClientesHome.class);
LocalClientes clientes = home.findByPrimaryKey (cliente);
clientes.remove ();
}
public void modificacion (java.lang.Integer cliente, java.lang.String nombre)
throws javax.naming.NamingException, javax.ejb.FinderException {
Context ctx = new InitialContext ();
Object obj = ctx.lookup ("java:comp/env/ejb/Clientes");
LocalClientesHome home = (LocalClientesHome)
javax.rmi.PortableRemoteObject.narrow(obj,
LocalClientesHome.class);
LocalClientes clientes = home.findByPrimaryKey (cliente);
clientes.modify (new ClienteDetalle (cliente, nombre));
}
}

97
4 Beans de sesión

Por el momento no podemos compilar la clase MtoClientesBean, ya que hace referencia a


las interfaces remotas del bean de sesión y no hemos escrito su código aún. No hemos de
preocuparnos por esto, ya que en el siguiente tema completaremos el ejemplo. Por el
momento nos será suficiente con compilar las dos interfaces.

4.6.3. El componente web

Vamos ahora con el componente web. Hemos determinado que se va a componer de una
única página JSP. Dicha página mostrará la relación de los clientes que existen y nos
permitirá realizar las operaciones de creación, modificación y borrado sobre ellos.

Al igual que hicimos en el capítulo anterior, vamos a crear manualmente la página en el


directorio del ejemplo (recordemos que se trata del directorio
“/home/alumno/cursoEJB/ejemplo2” para los usuarios de Linux, y de “c:\cursoEJB\ejemplo2”
para los usuarios de Windows). El fichero se llamará “index.jsp” y lo podemos crear con
nuestro editor de textos favorito.

El contenido de la página JSP será el siguiente:

<%@page contentType="text/html"%>
<%@page import="javax.naming.*"%>
<%@page import="java.rmi.*"%>
<%@page import="javax.ejb.*"%>
<%@page import="java.util.Iterator"%>
<%@page import="gestion.ClienteDetalle"%>
<%@page import="gestion.MtoClientesHome"%>
<%@page import="gestion.MtoClientes"%>
<%
String errorText = "";
Iterator clientes = null;

try {
// Obtenemos una referencia al contexto de ejecución
Context ctx = new InitialContext ();
// Obtenemos una referencia al componente EJB
Object obj = ctx.lookup ("java: comp/env/ejb/MtoClientes");

98
4 Beans de sesión

// Obtenemos la referencia a la interfaz básica


MtoClientesHome home = (MtoClientesHome)
javax.rmi.PortableRemoteObject.narrow (obj, MtoClientesHome.class);
MtoClientes mtoClientes = home.create ();
String operacion = request.getParameter ("operacion");
Integer cliente = null;
String nombre = null;
if (operacion!=null && !operacion.equals("")) {
cliente = new Integer (request.getParameter ("cliente"));
nombre = request.getParameter ("nombre");
if (operacion.equals ("alta")) {
mtoClientes.alta(cliente, nombre);
} else if (operacion.equals("modificacion")) {
mtoClientes.modificacion(cliente, nombre);
} else if (operacion.equals("baja")) {
mtoClientes.baja(cliente);
}
}
clientes = mtoClientes.findAll().iterator();
mtoClientes.remove();
} catch (NamingException e) {
errorText = "Error de nombre de recurso JNDI";
} catch (java.sql.SQLException e) {
errorText = e.getMessage();
} catch (CreateException e) {
errorText = "CreateException";
} catch (FinderException e) {
errorText = "FinderException";
} catch (RemoteException e) {
errorText = "RemoteException";
} catch (NumberFormatException e) {
errorText = "Error de conversión numérica (" + request.getParameter("cliente") +
")";
}
%>

99
4 Beans de sesión

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">


<html>
<head>
<title>cursoEJB/ejemplo1</title>
<SCRIPT language='javascript'>
function baja(cliente) {
document.datos.operacion.value = "baja";
document.datos.cliente.value = cliente;
document.datos.nombre.value = "";
document.datos.submit();
}
function modificacion(cliente) {
document.datos.operacion.value = "modificacion";
document.datos.cliente.value = cliente;
document.datos.nombre.value = document.datos["nombre"+cliente].value;
document.datos.submit();
}
</SCRIPT>
</head>
<body>
<%
if (!errorText.equals("")) {
%>
<%=errorText%>
<hr>
<a href="index.jsp">Volver</a>
<%
} else {
%>
<FORM name="datos" method="POST" action="index.jsp">
<INPUT type="hidden" name="operacion" value="alta">
<TABLE border="0">
<TR>
<TD align="right"><b>C&oacute;digo</b></TD>
<TD><b>Nombre</b></TD>

100
4 Beans de sesión

<TD>&nbsp;</TD>
</TR>
<%
while (clientes.hasNext()) {
ClienteDetalle item = (ClienteDetalle)clientes.next();
%>
<TR>
<TD align="right"><A href="javascript:;" title="Borrar el cliente"
onclick=
"javascript:baja(<%=item.getCliente()%>);">
<%=item.getCliente()%></A></TD>
<TD><INPUT type="TEXT" name="nombre<%=item.getCliente()%>"
value="<%=item.getNombre()%>"></TD>
<TD><INPUT type="BUTTON" value="Guardar modificaci&oacute;n"
onclick="javascript:modificacion(<%=item.getCliente()%>);"></TD>
</TR>
<%
}
%>
</TABLE>
<HR>
C&oacute;digo:&nbsp;
<INPUT type="text" name="cliente"><br>
Nombre:&nbsp;
<INPUT type="text" name="nombre"><br>
<INPUT type="submit" value="Crear">
</FORM>
<%
}
%>
</body>
</html>

En la página JSP hacemos uso de JNDI para obtener la referencia al componente de negocio
(el EJB de sesión) y poder hacer uso de él. El nombre JNDI del recurso es
“java:comp/env/ejb/MtoClientes” y su creación forma parte del despliegue de la aplicación
J2EE que contiene los componentes EJB. No obstante, para que sea así tendremos que
indicarlo dentro del fichero descriptor de despliegue del componente EJB. En nuestro caso lo

101
4 Beans de sesión

definiremos desde la herramienta deploytool.

4.6.4. Desplegando la primera aplicación

Nos falta crear el bean de entidad para tener todo el código fuente que necesitamos, pero
vamos a dejarlo para el siguiente tema, en el que estudiaremos este tipo de EJB.

En lo que respecta a la aplicación J2EE que se va a componer del módulo web, ya estamos
preparados para desplegarla, no necesitamos nada más.

Ha llegado el momento de que utilicemos la herramienta de despliegue. Recordemos que


está en el directorio bin del servidor de aplicaciones y que se llama deploytool. Para
utilizarla es importante que el servidor de aplicaciones esté en ejecución.

La ejecutaremos y, una vez dentro, lo primero que tenemos que hacer es crear una
aplicación J2EE. Para ello, seleccionaremos en el menú la opción Archivo, después la opción
Nuevo y, por último, la opción Aplicación.... Aparecerá una caja de diálogo solicitándonos
el nombre del fichero y la descripción de la aplicación.

Como fichero utilizaremos “/home/alumno/cursoEJB/ejemplo2/ejemplo2.ear” si estamos en


Linux, y “c:\cursoEJB\ejemplo2\ejemplo2.ear” si estamos en Windows. Le dejaremos la
descripción que nos sugiere por defecto y pulsaremos Aceptar para finalizar.

Ya hemos creado una aplicación, pero está vacía. No tiene ningún componente. El próximo
paso será crearle un módulo web con la página JSP que hemos desarrollado.

A continuación, pulsaremos el botón izquierdo del ratón sobre el nodo “ejemplo2”, que es la
aplicación recién creada, para seleccionarlo. En el menú Archivo seleccionaremos las
opciones Nuevo y Componente Web... Nos aparecerá un asistente que nos guiará a través
del proceso de creación.

Nos detendremos sólo en aquellas ventanas que tengan datos trascendentes. En las demás
podremos simplemente pulsar el botón Siguiente >.

102
4 Beans de sesión

Veamos las ventanas principales:

Como vemos en la figura anterior, no podemos olvidar añadir la clase ClienteDetalle y las
interfaces MtoClientes y MtoClientesHome, ya que se hace referencia a ellas en la página
JSP.

103
4 Beans de sesión

Tras la creación del módulo web nos quedan una serie de cambios por realizar. Para todos
ellos tendremos que tener seleccionado el nodo moduloWEB en el árbol.

En primer lugar, asignaremos a la aplicación web un nombre de contexto. Para ello,


seleccionaremos la pestaña General y el valor de Raíz de contexto lo fijaremos a
“/ejemplo2”. Esto nos va a permitir ejecutar el módulo web utilizando la url
“http://localhost:8080/ejemplo2”.

También definiremos una página de bienvenida por defecto para que sea la que se muestre
cuando se omita la página durante la navegación. A nosotros nos conviene que sea la página
“index.jsp”, porque además es la única que tiene nuestro módulo web.

Seleccionaremos la pestaña “Referencias de archivo” y pulsaremos el botón “Agregar


Archivo” del apartado “Archivos de bienvenida”. Se añadirá automáticamente una fila y le
indicaremos el valor “index.jsp”.

Lo próximo va a ser añadir la referencia al enterprise javabean para que el módulo web
pueda hacer uso de él. Seleccionaremos la pestaña “Referencias de EJB” y utilizaremos el
botón “Agregar...”. La información que tenemos que completar es la siguiente:

− “Nombre codificado”. Es el nombre de referencia del enterprise javabean. Tenemos


que utilizar el nombre del subcontexto JNDI. Por lo tanto, el valor a poner sería
“ejb/MtoClientes”.

− “Tipo EJB”. Tipo de bean. Podemos elegir entre los tipos “Session” y “Entity”. En
nuestro caso estamos hablando de un bean de sesión.

− “Interfaces”. Tendremos que decidir si utilizaremos la interfaz local o remota.


Recordemos que al EJB sólo le hemos definido la interfaz remota, por lo tanto
seleccionaremos la opción “Remote”.

− “Interfaz de inicio”. Interfaz básica del EJB. Tenemos que incluir el nombre del paquete
al que pertenece.

− “Interfaz local/remota”. Interfaz remota del EJB. También habremos de incluir el


nombre de la clase.

− “Nombre JNDI”. En el apartado “EJB de destino” tenemos que indicar cuál es el

104
4 Beans de sesión

enterprise bean al que queremos hacer referencia. Nosotros vamos a optar por hacer
referencia a él utilizando su nombre JNDI. Por lo tanto, será su nombre JNDI el que
indicaremos aquí, es decir, el valor “ejb/MtoClientes”.

En la siguiente figura se muestra la información explicada anteriormente.

Hemos terminado de crear la aplicación y dentro de unos momentos veremos el fruto de


nuestro trabajo. No obstante, aún no la hemos desplegado, por lo que nos tenemos que
hacerlo ahora. Se trata de un proceso de lo más simple. Teniendo seleccionado el nodo
“ejemplo2”, utilizaremos el menú Herramientas y la opción Implementar...

Se nos mostrará una ventana en la que tendremos que elegir el servidor de aplicaciones e
indicar el nombre y contraseña del administrador de dicho servidor, y seguidamente
pulsaremos el botón Aceptar para comenzar el proceso de despliegue. Iremos viendo una
consola en la que se mostrarán mensajes relativos al proceso.

Una vez finalizado el despliegue de la aplicación habremos terminado la primera parte del
ejemplo. Si queremos podemos probarla abriendo el navegador web y apuntando a la

105
4 Beans de sesión

dirección “http://localhost:8080/ejemplo2”. La aplicación estará disponible pero


obtendremos una excepción debida a que no se puede localizar el bean de sesión.

En el siguiente tema terminaremos de completar este ejemplo y podremos probar la


aplicación web.

106
4 Beans de sesión

− Los beans de sesión se utilizan para modelar un proceso y se clasifican en


recuerde_
dos tipos: beans de sesión con estado y beans de sesión sin estado.

− Un bean de sesión con estado puede mantener los valores de sus variables
entre distintas llamadas a sus métodos, mientras que un bean de sesión sin
estado, no.

− Uno de los patrones de diseño más interesantes que existe para la tecnología
J2EE es el que utiliza un bean de sesión para proporcionar una fachada a un
cliente.

− Una fachada es una interfaz de nivel superior que se utiliza para configurar
un grupo de interfaces en un subsistema. La utilización de fachadas aporta
numerosas ventajas en el desarrollo y mantenimiento de los sistemas de
software.

− El estado conversacional hace referencia a los datos almacenados en las


variables de la aplicación, en el cliente, en el contenedor EJB o en el servidor
de aplicaciones. Son datos privados accesibles sólo para un cliente dado.

107
índice_ 5 Beans de entidad

5.1. ¿QUÉ ES UN BEAN DE ENTIDAD?..........................................111


5.2. LA PERSISTENCIA ................................................................112
5.3. LOS ACCESORES ABSTRACTOS..............................................114
5.4. EJB-QL .................................................................................115
5.4.1. Claúsula “SELECT” .....................................................116
5.4.2. Claúsula “FROM” .......................................................116
5.4.3. Cláusula “WHERE” .....................................................116
5.5. LAS CLAVES PRIMARIAS.......................................................117
5.6. LAS RETROLLAMADAS DEL CONTENEDOR .............................120
5.6.1. Creación ....................................................................120
5.6.2. Lectura......................................................................121
5.6.3. Modificación ..............................................................121
5.6.4. Borrado .....................................................................122
5.7. LOS MÉTODOS BUSCADORES ................................................122
5.8. ACTIVACIÓN Y PASIVACIÓN.................................................124
5.9. SIGAMOS CON EL EJEMPLO ..................................................124
5.9.1. El bean de entidad .....................................................124
5.9.2. Desplegando la segunda aplicación............................127

109
5 Beans de entidad

5.1. ¿QUÉ ES UN BEAN DE ENTIDAD?

El concepto fundamental que debemos tener presente acerca de los Enterprises JavaBeans
de entidad es que no se trata de meras clases, sino que representan entidades del modelo
de análisis de una aplicación. Estas entidades pueden corresponderse con conceptos
concretos, como clientes y proveedores, o con conceptos abstractos, como un proceso
productivo.

Un bean de sesión puede acceder a datos, no obstante, no puede darnos una representación
de objeto de dichos datos. ¿Qué significa esto? ¿Qué diferencia supone frente a la utilización
de beans de sesión?

En el tema anterior dijimos que el estado que mantienen los beans de sesión con estado es
privado. Esto significa que sólo el cliente que lo utiliza puede manipular el estado del bean.
Si varios clientes acceden a un mismo bean de sesión, cada uno de ellos accede a una
instancia distinta que le suministra el contenedor EJB. En el caso de los beans de entidad, el
estado es almacenado en la base de datos, por lo que varios clientes pueden acceder
simultáneamente a un mismo bean. Cada bean de entidad es único y cualquier cliente que
acceda a los datos tendrá que pasar por él.

Además de permitirnos representar estado compartido y transaccional, los beans de entidad


tienen otras ventajas adicionales. El contenedor EJB nos proporcionará una serie de servicios
de nivel de sistema, motivo por el cual podremos centrarnos en la programación de lógica de
empresa.

Los cuatro servicios principales que suministra un contenedor EJB son:

− Retrollamadas del contenedor para informar al EJB sobre el progreso de la transacción


actual.

− Control de accesos concurrentes. El contenedor puede emplear distintas estrategias


para lograr la compatibilidad de accesos concurrentes. Una de ellas consiste en
posponer el control concurrente a la base de datos.

− Mantenimiento de una caché entre transacciones, que puede mejorar


significativamente el rendimiento del sistema.

− Proporcionan todo el código necesario para la gestión de la persistencia. La


persistencia gestionada por el contenedor no sólo nos liberará de escribir código de

111
5 Beans de entidad

acceso a datos, sino que también nos puede proporcionar optimizaciones propias del
contenedor.

5.2. LA PERSISTENCIA

El contenedor EJB puede gestionar el proceso de guardar y restaurar el estado de los beans
de entidad. Esta característica recibe el nombre de persistencia gestionada por contenedor
(CMP, Container Managed Persistence). No obstante, podemos desear que nuestros beans
puedan gestionar la persistencia por si mismos. En este último caso hablaremos de
persistencia gestionada por bean (BMP, Bean Managed Persistence).

Es una decisión muy importante en cualquier aplicación que utilice la tecnología Enterprise
JavaBeans, la relacionada con la forma de gestión de la persistencia que utilizarán los beans
de entidad. La experiencia nos demuestra que la persistencia es uno de los servicios de nivel
de sistema más tediosos cuando se desarrolla la lógica de empresa. Suele utilizarse código
SQL y es un proceso que consume mucho tiempo y es muy proclive a errores.

La especificación EJB ha sido desarrollada, entre otras cosas, para trasladar estos temas de
nivel de sistema al contenedor EJB. Para la mayoría de los casos, lo más adecuado será
aprovechar esa capacidad del contenedor para gestionar la persistencia. Sin embargo, la
persistencia gestionada por bean es una elección importante en determinadas circunstancias.
Tendremos que determinar si nuestro contenedor EJB tiene el nivel de compatibilidad que
necesitamos para aprovechar su gestión de la persistencia. De ser así, deberíamos utilizarlo
para evitarnos escribir el código necesario para la persistencia.

El modelo CMP también aporta otras interesantes ventajas. Por ejemplo, si utilizamos el
modelo BMP, una consulta que recupere varios beans la traduciremos normalmente en dos
llamadas distintas a la base de datos: una para consultar las claves primarias y otra para
recuperar los beans. Si utilizamos CMP, el contenedor puede realizar sólo una solicitud a la
base de datos, cosa que es imposible con BMP. CMP tiene muchas otras ventajas, por lo que
utilizar BMP lo haremos en situaciones muy concretas. En caso de dudas, será mejor que nos
decidamos por CMP.

Si nuestro almacén de datos fuese un sistema ERP o alguna otra aplicación existente,
probablemente necesitaríamos utilizar persistencia gestionada por bean. La diferencia estaría
en que, en lugar de escribir código SQL, probablemente necesitáramos utilizar protocolos
específicos del almacén que no serían compatibles con el contenedor EJB.

112
5 Beans de entidad

Por otra parte, si nuestro almacén de datos es una base de datos relacional y el contenedor
EJB no es compatible con CMP para nuestra aplicación, podríamos optar entre las siguientes
opciones:

− Utilizar otro contenedor EJB. Esta opción no es siempre posible, no obstante, existen
servidores de aplicación con sofisticadas funciones de asociación objeto/relacional en
el mercado. Debemos tener en cuenta las capacidades de los distintos servidores de
aplicación a la hora de decidirnos por alguno de ellos.

− Utilizar alguna herramienta de asociación objeto/relacional. Podemos optar por


herramientas objeto/relacional de terceros para los beans de entidad. Es una buena
opción, pero tiene dos principales inconvenientes: suelen ser caras y estaremos
dependiendo de un sistema de terceros.

− Cambiar el diseño de la aplicación. Podemos cambiar nuestro diseño teniendo en


cuenta las limitaciones de la herramienta que elijamos y utilizar persistencia
gestionada por contenedor. Esta opción no es siempre posible, y presenta dos
desventajas: el rendimiento puede no ser el más óptimo y el nuevo diseño podría ser
más difícil de implementar, mantener y comprender.

− Escribir nuestro propio código para el acceso a datos. Es un compromiso muy


importante decidir si vamos a escribir el código de persistencia que necesitamos para
nuestra aplicación. En caso de hacerlo, deberíamos encapsular el código de
persistencia en componentes de ayuda de acceso a datos de los beans de entidad. Si
observamos que estamos dedicando un tiempo considerable en su desarrollo,
deberíamos volver a considerar el hecho de utilizar los servicios de persistencia del
contenedor. Uno de los objetivos de la especificación EJB es la del aprovechar los
servicios del contenedor para aumentar la productividad.

113
5 Beans de entidad

5.3. LOS ACCESORES ABSTRACTOS

Un bean de entidad con persistencia gestionada por contenedor se define por sus campos
CMP, los cuales son los campos Java que están asociados a las tablas de la base de datos.
La especificación EJB impone que estos campos se definan mediante accesores abstractos.
Por ejemplo, un campo de tipo texto llamado “direccionCliente” lo declararemos como:

public abstract String getDireccionCliente();


public abstract void setDireccionCliente(String direccionCliente);

Podría darse el caso de que en nuestra base de datos no tuviéramos una columna llamada
“direccionCliente”, pero no importa puesto que en el descriptor de despliegue sólo
tendríamos que especificar cómo asociarlo.

El contenedor tiene control total sobre el acceso a los campos. Generará código para cada
accesor y puede optimizar los accesos a la base de datos. Gracias a esto, hay algunas
ventajas que suelen proporcionar los contenedores EJB:

− Posponer la carga de los beans. Dado que el contenedor sabe qué campos son
accesibles y cuándo puede acceder a ellos, no tiene que cargar el estado completo del
bean inicialmente. Puede posponer la carga para cuando realmente se necesite la
información.

− Actualizar sólo los cambios. El contenedor sabe en todo momento qué campos han
sido modificados, por lo tanto, es capaz de actualizar en la base de datos sólo las
columnas correspondientes a los campos que hayan cambiado.

− Carga por grupos. Algunos contenedores pueden permitirnos definir grupos de


campos. Si tenemos un bean de entidad que contenga un objeto binario, además de
otros de tipo básico (como números), y realizamos una consulta, el estado completo
va a viajar por la red (incluyendo el objeto binario). Sería un consumo de recursos
innecesario si el cliente no estuviera interesado en el objeto binario. Cuando se definen
grupos de campos, el contenedor sólo manejará los campos que pertenecen al mismo
grupo que el campo solicitado.

114
5 Beans de entidad

5.4. EJB-QL

Uno de los mayores beneficios de la persistencia gestionada por contenedor es que nos
abstrae del almacén de datos. No necesitamos saber cómo se almacenan los beans o qué
tipo de base de datos está utilizando. El inconveniente de esto, es que se necesita un
lenguaje de consulta que sea independiente de la base de datos.

La especificación EJB define un lenguaje denominado EJB QL (EJB Query Language). Se


trata de un lenguaje cuya sintaxis es muy similar a la de SQL. Las sentencias EJB QL se
escriben en los descriptores de despliegue, y el contenedor EJB será el encargado de generar
las correspondientes instrucciones para interactuar con el almacén de datos.

El objetivo del lenguaje EJB QL es permitirnos la portabilidad de nuestros beans de entidad


CMP, es decir, que sigan funcionando con independencia del almacén de datos y del lenguaje
específico que utilice.

Aunque la sintaxis de EJB QL es muy similar a la de SQL, el concepto subyacente es muy


diferente. Necesitamos comprender cómo interactúan los objetos Java y las instancias de los
EJB para que podamos aprovechar todas las ventajas que nos ofrece este lenguaje.

EJB QL se utiliza para la implementación de los métodos buscadores y de los métodos de


selección. Trataremos sobre ellos más adelante.

Una consulta del lenguaje EJB QL es una cadena que se compone de las siguientes tres
cláusulas:

− “SELECT”. Indica el tipo de objeto o los valores que se quieren recuperar.

− “FROM”. Determina el origen de los datos.

− “WHERE”. Se emplea para restringir el conjunto de resultados. Es la única cláusula


opcional, las otras dos son obligatorias.

La sintaxis del lenguaje EJB QL es muy extensa y aquí vamos a exponerla brevemente. En la
documentación de la especificación J2EE podremos consultarla al completo.

115
5 Beans de entidad

5.4.1. Cláusula “SELECT”

Puede devolver diferentes valores según el tipo de método en el que se utilice:

− Métodos buscadores. Sólo pueden devolver beans del mismo tipo que los creados por
su interfaz inicial. Por lo tanto, el tipo de la cláusula “SELECT” debe coincidir con el
nombre de esquema abstracto del EJB.

− Métodos de selección. Pueden devolver cualquiera de los esquemas abstractos


definidos en el descriptor de despliegue.

Podemos utilizar la palabra clave opcional “DISTINCT” para descartar valores duplicados de
la consulta.

5.4.2. Cláusula “FROM”

Esta cláusula se utiliza para determinar el origen de la información a obtener. Veamos un


ejemplo para entender los detalles:

SELECT OBJECT(u)
FROM Usuarios AS u
WHERE u.login = 'juan' AND u.password = '1424'

En nuestro ejemplo, declaramos una variable de tipo “Usuarios”. No se trata del nombre del
bean, en una consulta EJB QL tenemos que utilizar el nombre especificado en la etiqueta
“<abstract-schema-name>” del descriptor de despliegue. Claro que, para simplificar, se
suele utilizar el mismo nombre que el nombre del EJB.

5.4.3. Cláusula “WHERE”

Esta cláusula es opcional y sirve para indicar una expresión que limite los resultados de la
consulta.

La expresión puede ser una combinación de expresiones mediante las palabras “AND” y
“OR”. También podemos incluir los literales “TRUE” y “FALSE”, y operadores como
“BETWEEN”, “IN” o “LIKE”. La igualdad se expresa con el símbolo “=” y la no igualdad con
"<>".

116
5 Beans de entidad

Cuando la consulta necesite parámetros, éstos se incluyen con el signo de interrogación


seguido del número de orden en que aparece el parámetro en el método buscador o de
selección. Si tenemos un buscador como el siguiente:

public Usuarios findByLogin(String login, String password);

La consulta a utilizar sería la siguiente:

SELECT OBJECT(u)
FROM Usuarios AS u
WHERE u.login = ?1 AND u.password = ?2

5.5. LAS CLAVES PRIMARIAS

Todo bean de entidad debe tener una clave primaria que lo identifique de forma única que se
representa mediante una clase. Dicha clase contendrá la información necesaria para
encontrar su entidad en el almacén persistente y tanto el cliente como el contenedor la
utilizarán cuando necesiten encontrar una determinada instancia. Esta clase tiene que
cumplir determinados requisitos que veremos a continuación. En el caso de los beans de tipo
BMP, los requisitos son:

− La clave primaria puede ser cualquier tipo de objeto Java que se pueda codificar, es
decir, que implemente la interfaz “java.io.Serializable”.

− El bean debe proporcionar implementaciones de los métodos “hashCode()” y


“equals()”.

− La clave primaria debe ser un valor único dentro del conjunto de todos los beans.

Adicionalmente, hay algunos requisitos extra para los beans de tipo CMP. El contenedor es el
responsable de manipular los beans y necesita poder crear una clave primaria. Para ello, la
clase de la clave primaria debe suministrar un constructor público sin argumentos.

El contenedor también necesita asociar el estado del bean con el estado de la clase de clave
primaria y viceversa. Para que sea posible, la especificación proporciona dos métodos
diferentes que proporcionan clases clave para beans CMP. El primero es válido para cualquier

117
5 Beans de entidad

caso en general, con independencia del número de campos, mientras que el segundo es para
el caso concreto de un único campo.

El primer método realiza la asociación utilizando una convención de nombres: los campos
públicos de la clase de clave primaria se corresponden con los campos públicos equivalentes
de la clase del bean. Por ejemplo, dado un bean de entidad llamado “Usuarios” y cuya clave
primaria está compuesta por los campos “empresa” y “usuario”, definiremos una clase de
clave primaria llamada “UsuariosPK” que necesitará los dos correspondientes campos (del
mismo tipo y con el mismo nombre). La clase de la clave primaria sería como sigue:

package paquete;
public class UsuariosPK implements java.io.Serializable {

private String empresa;


private Integer usuario;

public UsuariosPK() { }
public UsuariosPK(String empresa, Integer Usuario) {
this.empresa = empresa;
this.usuario = usuario;
}
public String getEmpresa() { return this.empresa; }
public Integer getUsuario() { return this.usuario; }
public int hashCode() {
return (empresa+usuario).hashCode();
}
public boolean equals(Object obj) {
if (obj==null || !(obj instanceof UsuariosPK)) {
return false;
}
UsuariosPK pk = (UsuariosPK) obj;
return this.empresa.equals(pk.getEmpresa()) && this.usuario ==
pk.getUsuario();
}
}

118
5 Beans de entidad

Es muy importante tener en cuenta que una vez que hayamos asociado un bean de entidad a
una clave primaria, no debemos reutilizar el mismo objeto de clave primaria para otro bean.
Para evitarlo, no debemos definir métodos “set... ()” en las clases de clave primaria.

Para el segundo método no es necesario definir una nueva clase, ya que, al tratarse de una
clave primaria de un único campo, la clase para dicha clave puede ser cualquiera de las
suministradas por Java.

Para los beans de entidad de tipo BMP tendremos que especificar la clase de la clave primaria
en el descriptor de despliegue.

Siguiendo con la clase del ejemplo anterior, la especificación de la clave primaria del
descriptor sería la siguiente (tanto para beans BMP como CMP):

<prim-key-class>paquete.UsuariosPK</prim-key-class>

En el caso de que la clave estuviera formada por un único campo, supongamos que sea de
tipo texto, el descriptor sería como sigue:

<prim-key-class>java.lang.String</prim-key-class>

Por último, para un bean de entidad de tipo CMP que utiliza un único campo para la clave
primaria, especificaremos en el descriptor de despliegue el campo del bean que contiene la
clave primaria. El tipo del campo debe ser el mismo que el tipo de clave primaria. A
continuación podemos ver un ejemplo:

<primkey-field>usuario<primkey-field>

119
5 Beans de entidad

5.6. LAS RETROLLAMADAS DEL CONTENEDOR

El acceso al almacén de datos está compuesto por cuatro tipo de operaciones: creación,
lectura, modificación y borrado.

Para cada una de estas operaciones existe un tipo de retrollamada en los beans de entidad.
Los métodos correspondientes son:

− “ejbCreate()” y “ejbPostCreate”. Creación.

− “ejbLoad()”. Lectura.

− “ejbStore()”. Modificación.

− “ejbRemove()”. Borrado.

Los métodos de retrollamada se definen igualmente tanto para los beans CMP como BMP. Por
el contrario, la implementación es diferente:

− En los beans de tipo BMP es nuestra responsabilidad escribir el código correspondiente


a la operación que debe realizarse en cada método.

− En los beans de tipo CMP los métodos de retrollamada suelen dejarse vacíos (con
excepción del método “ejbCreate()”), dado que es responsabilidad del contenedor
implementar la funcionalidad necesaria de cada método en cuestión.

5.6.1. Creación

Cuando se invoca el método “create()”, el estado se inserta en la base de datos y pasa a


estar disponible para todos los clientes.

El método “create()” se define en la interfaz inicial del bean y puede estar sobrecargado.
Debe devolver la interfaz remota del bean para que cuando el cliente lo invoque, mediante la
interfaz inicial, obtenga una referencia a dicho bean para poder utilizar sus métodos de
empresa.

De igual forma, este método debe lanzar la excepción “java.rmi.RemoteException”, pero sólo
en el caso de los métodos remotos (recordemos que los métodos locales no usan RMI).
También deben lanzar la excepción “javax.ejb.CreateException”, que se utilizará en caso de
que haya algún problema en la creación.
Por cada método “create()” que se defina en la interfaz inicial, deben existir dos métodos

120
5 Beans de entidad

que coincidan, en número y tipo de argumentos, en la clase de implementación. Dichos


métodos deben llamarse “ejbCreate()” y “ejbPostCreate()”, y deben ser públicos para que el
contenedor pueda realizar la retrollamada.

El tipo de retorno del método “ejbCreate()” debe ser la clase de la clave primaria. El código a
escribir en el método irá en función del tipo de persistencia del bean:

− Para los beans CMP, los parámetros del método se utilizarán para inicializar los campos
de estado.

− Para los beans BMP, los parámetros se utilizarán para inicializar los campos de estado
y se escribirá el código correspondiente (normalmente utilizando JDBC) para
almacenar los datos en el almacén de datos.

Por otra parte, el tipo de retorno del método “ejbPostCreate()” debe ser “void”. Este método
es invocado después “ejbCreate()” y, en la mayoría de los casos, suele dejarse vacío.

5.6.2. Lectura

El método de retrollamada relacionado con la carga de datos desde el almacén se llama


“ejbLoad()”. En el caso de los beans de tipo CMP el método se dejará vacío normalmente, a
menos que queramos realizar algún tratamiento adicional, ya que, es responsabilidad del
contenedor. Por el contrario, para los beans BMP tendremos que escribir el correspondiente
código que realice la carga de los datos desde el almacén.

5.6.3. Modificación

La actualización de la información se realiza mediante el método de retrollamada


“ejbStore()”. La llamada a determinados métodos de negocio ocasionará que el contenedor
invoque el método de retrollamada cuando necesite que el bean sincronice su estado con el
almacén de datos.

En el caso de los beans de tipo CMP este método se suele dejar vacío, mientras que para los
beans BMP habrá que escribir el código correspondiente para que se guarde el estado del
bean en el almacén de datos.

121
5 Beans de entidad

5.6.4. Borrado

El método “remove()” es utilizado para eliminar un bean de entidad. Al contrario de los


beans de sesión, la eliminación de un bean de entidad implica que éste se elimine en el
almacén de datos. No debemos invocar el método “remove()” a menos que nuestra intención
sea la de eliminar el estado del almacén de datos.

El método de retrollamada correspondiente es “ejbRemove()” y en el caso de los beans de


tipo CMP se suele dejar vacío. Por el contrario, en los beans BMP es necesario escribir el
código necesario para interactuar con el almacén de datos.

5.7. LOS MÉTODOS BUSCADORES

Ya hemos visto que los beans de entidad representan datos compartidos entre todos los
clientes. Como es lógico, existe un mecanismo para que dichos clientes tengan acceso a un
determinado bean de entidad. Con los beans de sesión no ocurría esto, puesto que el cliente
obtiene acceso al bean cuando se crea y nadie más lo puede utilizar. Por el contrario, un
bean de entidad puede ser creado por un cliente y utilizado por todos los demás, y para ello,
cada uno de estos clientes debe ser capaz de encontrarlo.

La especificación EJB define un mecanismo denominado método buscador y pueden definirse


tantos como sean necesarios. Estos métodos se declaran en la interfaz inicial del bean de
entidad y sirven para localizar un bean o una colección de ellos. Los métodos buscadores,
por convención, se suelen nombrar empezando por “find, como por ejemplo “findByLogin()”
o “findAll()”. Pueden utilizar parámetros para especificar los detalles de la búsqueda.

Los métodos buscadores, al igual que el resto de métodos remotos, declararán que pueden
lanzar la excepción “java.rmi.RemoteException”. Adicionalmente, también deben declarar la
excepción “java.ejb.FinderException”.

Los métodos buscadores que devuelven como máximo un único resultado, tendrán como tipo
de retorno la interfaz remota del bean. El ejemplo más claro es el caso del buscador para la
clave primaria; si tenemos un bean cuya clase de implementación se llama “UsuariosBean” y
la clave primaria es un entero, el método “findByPrimaryKey(...)” lo definiremos en la
interfaz “paquete.UsuariosHome”, recibirá un parámetro del tipo de la clase de la clave
primaria y su tipo de retorno será “paquete.Usuarios”. En caso de que no se encuentre
ninguna entidad, este tipo de métodos lanzará la excepción
“javax.ejb.ObjectNotFoundException”, que es una subclase de la clase

122
5 Beans de entidad

“javax.ejb.FinderException”.

En el caso de métodos buscadores que pueden devolver cero o más resultados, el tipo de
retorno será “java.util.Enumeration” o “java.util.Collection”. Un ejemplo posible sería el de
un método buscador por nombre de usuario (puede haber más de uno). Si un buscador de
este tipo no encuentra ninguna entidad, no se lanzará ninguna excepción, simplemente
devolverá una enumeración (o colección) vacía.

La especificación EJB requiere que todos los beans de entidad declaren un buscador llamado
“findByPrimaryKey()” con un único parámetro y que sea del mismo tipo que la clase de clave
primaria. Este método debe devolver la instancia del bean de entidad con dicha clave
primaria o generar una excepción “javax.ejb.ObjectNotFoundException”. El resto de métodos
buscadores son opcionales y podrían no existir.

En el caso de los beans de tipo CMP, la implementación de los métodos buscadores es


responsabilidad del contenedor y no necesitaremos escribir ningún código. Nuestra labor
como desarrolladores del bean quedará limitada a escribir la consulta en el descriptor de
despliegue utilizando el lenguaje EJB QL.

Por el contrario, en los beans de tipo BMP tendremos que proporcionar la implementación de
los métodos buscadores en la clase de implementación del bean. Dicho método tendrá
parámetros idénticos y tendrá un nombre que coincida, según la siguiente convención: si el
método buscador se denomina “findXXX()”, la implementación del método se denominará
“ejbFindXXX()”.

El tipo de retorno para un método buscador que tiene como máximo un resultado será una
instancia de la clase de clave primaria para esa entidad y el tipo de retorno para una
implementación de método buscador que tiene cero o más resultados será una
implementación concreta de “Collection” o “Enumeration”, según el tipo de retorno del
correspondiente método buscador de la interfaz inicial. Los elementos de “Collection” o
“Enumeration” serán instancias de las clases de clave primaria de las entidades encontradas.

123
5 Beans de entidad

5.8. ACTIVACIÓN Y PASIVACIÓN

Para terminar con las retrollamadas, nos quedan por describir las dos siguientes:
“ejbActivate()” y “ejbPassivate()”.

El método “ejbActivate()” notifica que la instancia de bean de entidad ha sido asociada a


una identidad del almacén de datos. Por el contrario, el método “ejbPassivate()” se
invocará para notificar que el bean de entidad está siendo disociado de dicha entidad.

La implementación de estos métodos suele dejarse vacía, sin embargo, en algunas ocasiones
puede interesarnos añadirles código para realizar algún tipo de gestión.

5.9. SIGAMOS CON EL EJEMPLO

En el tema anterior iniciamos un ejemplo conjunto sobre los beans de entidad y los beans de
sesión. Pospusimos la parte correspondiente al bean de entidad hasta que supiéramos qué es
y de qué se compone. Ya estamos listos para ponernos a trabajar.

El bean de entidad que proponemos va a ser un bean con persistencia gestionada por el
contenedor. No vamos a escribir código Java, no utilizaremos JDBC ni sentencias SQL, pero
sí que utilizaremos el lenguaje EJB QL para uno de los métodos buscadores.

Lo primero que haremos será ejecutar el entorno de desarrollo NetBeans. Una vez dentro, el
proyecto “ejemplo2” debería estar creado y de no ser así procederemos a crearlo.
Recordemos que en el tema anterior mencionamos que todas las clases e interfaces las
crearíamos dentro del paquete “gestion”.

5.9.1. El bean de entidad

En primer lugar vamos a crear la clase y las dos interfaces que necesitará nuestro EJB de
entidad. Utilizaremos el botón derecho del ratón sobre el nodo “gestion” y seleccionamos la
opción “New” y subopción “Java Class”. Esta operación la realizaremos tres veces y los
nombres que emplearemos serán los siguientes: “LocalClientesHome”, “LocalClientes” y
“ClientesBean”.

124
5 Beans de entidad

Seguidamente, editaremos la clase “LocalClientesHome” y escribiremos el siguiente código:

package gestion;
import javax.ejb.*;
public interface LocalClientesHome extends javax.ejb.EJBLocalHome {
public gestion.LocalClientes findByPrimaryKey(java.lang.Integer aKey)
throws javax.ejb.FinderException;
public LocalClientes create(java.lang.Integer cliente, java.lang.String nombre)
throws javax.ejb.CreateException;
public java.util.Collection findAll() throws javax.ejb.FinderException;

Para la clase “LocalClientes”, su código será:

package gestion;
import javax.ejb.*;
public interface LocalClientes extends javax.ejb.EJBLocalObject {
public gestion.ClienteDetalle getClienteDetalle();
public void modify(gestion.ClienteDetalle clienteDetalle);
}

Por último, a la clase “ClientesBean”, que es la clase de implementación del bean, le


escribimos el siguiente código:

package gestion;
import javax.ejb.*;
public abstract class ClientesBean implements javax.ejb.EntityBean {
private javax.ejb.EntityContext context;
public void setEntityContext(javax.ejb.EntityContext aContext) {
context=aContext;
}
public void ejbActivate() { }
public void ejbPassivate() { }
public void ejbRemove() { }

125
5 Beans de entidad

public void unsetEntityContext() {


context=null;
}
public void ejbLoad() { }
public void ejbStore() { }
public abstract java.lang.Integer getCliente();
public abstract void setCliente(java.lang.Integer cliente);
public abstract java.lang.String getNombre();
public abstract void setNombre(java.lang.String nombre);
public java.lang.Integer ejbCreate(java.lang.Integer cliente, java.lang.String
nombre) throws
javax.ejb.CreateException {
this.setCliente(cliente);
this.setNombre(nombre);
return cliente;
}
public void ejbPostCreate(java.lang.Integer cliente, java.lang.String nombre)
throws
javax.ejb.CreateException { }
public gestion.ClienteDetalle getClienteDetalle() {
return new ClienteDetalle(this.getCliente(), this.getNombre());
}
public void modify(gestion.ClienteDetalle clienteDetalle) {
this.setNombre(clienteDetalle.getNombre());
}
}

Compilaremos la clase e interfaces anteriores y ya podemos compilar la clase de


implementación del bean de sesión del ejemplo del tema anterior. Recordemos que dejamos
sin compilar la clase “MtoClientesBean” debido a que hacía referencia a las interfaces del
bean de entidad que acabamos de crear.

126
5 Beans de entidad

5.9.2. Desplegando la segunda aplicación

Ya estamos listos para crear la aplicación web que se compone del módulo EJB con los dos
beans. Nos aseguraremos de que el servidor de aplicaciones se está ejecutando y, a
continuación, ejecutaremos la herramienta de despliegue “deploytool”.

Una vez dentro, lo primero que tenemos que hacer es crear la aplicación J2EE. Para ello,
seleccionaremos en el menú la opción Archivo, después la opción Nuevo y por último la
opción Aplicación... Aparecerá una caja de diálogo solicitándonos el nombre del fichero y la
descripción de la aplicación.

Como fichero utilizaremos “/home/alumno/cursoEJB/ejemplo2/ejemplo2b.ear” si estamos en


Linux, y “c:\cursoEJB\ejemplo2\ejemplo2b.ear” si estamos en Windows. Le dejaremos la
descripción que nos sugiere por defecto y pulsaremos Aceptar para finalizar.

Lo primero que haremos será añadir el bean de entidad. Para ello, pulsaremos el botón
izquierdo del ratón sobre el nodo “ejemplo2b”, que es la aplicación recién creada, para
seleccionarlo. En el menú Archivo seleccionaremos las opciones Nuevo y Enterprise
bean… Nos aparecerá un asistente que nos guiará a través del proceso de creación.

Nos detendremos sólo en aquellas ventanas que tengan datos trascendentes. En las demás
podremos simplemente pulsar el botón Siguiente >.

Veamos las ventanas principales:

127
5 Beans de entidad

En la figura podemos ver que no debemos olvidar añadir la clase “ClienteDetalle”, puesto que
es una clase auxiliar que forma parte del bean de entidad.

En la figura anterior podemos ver que hemos de marcar los campos que nos interesa que
sean persistentes, en nuestro caso son “cliente” y “nombre”. También hemos de prestar
atención a seleccionar el campo “cliente” como la clase de la clave primaria. El botón

128
5 Beans de entidad

Buscar/seleccionar consultas... nos va a permitir escribir el código de los métodos


buscadores. Podemos verlo en la siguiente figura:

En nuestro caso, sólo tenemos dos métodos buscadores, que son:

− “findByPrimaryKey(Integer cliente)”. La herramienta deploytool lo va a describir


en el descriptor de implementación porque en la figura anterior le indicamos, a esta
última, las características de la clave primaria. No necesitamos escribir código EJB QL
debido a que el contenedor es capaz de generarlo por sí mismo.

− “findAll()”. La herramienta “deploytool” también lo describirá en el descriptor, pero al


contrario que el anterior, el contenedor no tiene forma de saber qué queremos buscar,
por lo que hemos de escribir el código EJB QL adecuado a lo que nos interese que haga
la consulta.

Tras los pasos anteriores, el proceso de creación del módulo EJB y de adición del bean de
entidad, habrán terminado, exceptuando algunos detalles que vamos a ver seguidamente.

Seleccionaremos el nodo moduloEJB que acaba de aparecer, y nos moveremos a la pestaña


General. En ella veremos el botón Preferencias específicas de Sun..., lo pulsaremos y
aparecerá una ventana en la que tendremos que añadir alguna información adicional
relacionada con la persistencia, pero no pondremos nada de momento. En lugar de ello,
pulsemos el botón Crear asignaciones en base de datos... y completemos una nueva

129
5 Beans de entidad

ventana según vemos en la siguiente figura:

Cuando pulsemos el botón Aceptar de la ventana de la figura anterior, ésta se cerrará y la


información de las columnas se habrá rellenado automáticamente en la ventana que
teníamos abierta previamente y que podemos ver a continuación.

130
5 Beans de entidad

En la lista de campos que nos muestra, hemos modificado la longitud del campo “nombre” a
50 caracteres, ya que, el valor por defecto es excesivo. También haremos uso del botón
Preferencia para la generación de tablas para permitir que se cree la tabla
automáticamente cuando se despliegue la aplicación, y para evitar que se pierda cuando se
elimine la aplicación.

Es muy importante ser extremadamente cuidadoso si se están haciendo pruebas con una
base de datos en explotación y sobre tablas con información importante debido a que, por
defecto, la casilla Eliminar tablas al anular implementación estará seleccionada y eso
implica que se elimine la tabla cuando se elimine la aplicación del servidor. El aspecto de la
ventana de la que estamos hablando es el siguiente:

Lo próximo será añadir el bean de sesión al módulo EJB. Pulsaremos el botón izquierdo del
ratón sobre el nodo moduloEJB y en el menú Archivo seleccionaremos las opciones Nuevo
y Enterprise bean... Nos aparecerá un asistente que nos guiará a través del proceso de
creación.

Al igual que en casos anteriores, sólo iremos viendo las ventanas más importantes. La
primera de ellas es la que nos permite indicar el contenido y en ella podemos ver que ya
están la clase ayudante “ClienteDetalle” y la clase e interfaces del bean de entidad:
“ClientesBean”, “LocalClientes” y “LocalClientesHome”. Ahora tendremos que añadir la clase
e interfaces del bean de sesión, que son: “MtoClientes”, “MtoClientesBean” y
“MtoClientesHome”, como se muestra en la siguiente figura.

131
5 Beans de entidad

En la ventana que se muestra en la figura anterior, hemos de tener en cuenta que el bean de
sesión que estamos añadiendo es sin estado (“Stateless Session”) y que sólo dispone de
interfaces remotas, al contrario de lo que sucedía con el bean de entidad, que sólo ofrecía

132
5 Beans de entidad

interfaces locales.

Tras finalizar el asistente para la adición del bean a nuestro módulo EJB, tendremos que
realizar aún algunas labores previas a poder desplegar la aplicación J2EE.

Recordaremos que el bean de sesión que acabamos de añadir hace uso del bean de entidad,
lo que significa que tenemos que indicarle a la herramienta “deploytool” la información
necesaria para que ésta sea capaz de añadirla al fichero de despliegue.

Seleccionaremos el nodo “MtoClientes” y a continuación nos moveremos a la pestaña


“Referencias de EJB”. En ella podemos ver una lista (vacía en este momento) con las
referencias a otros beans. Pulsaremos el botón Agregar... y rellenaremos los datos según se
muestra en la siguiente figura:

133
5 Beans de entidad

Por último, seleccionaremos el nodo “moduloEJB”, nos iremos a la pestaña General y


pulsaremos el botón Preferencias específicas de Sun....

En esta ventana tendremos que modificar el nombre JNDI, que por defecto tendrá el valor
“MtoClientes”, y ponerle el valor “ejb/MtoClientes”.

Ya hemos terminado de crear la aplicación, ahora ha llegado el momento de desplegarla en


el servidor. Para ello, seleccionaremos el nodo “ejemplo2b” y utilizaremos el menú
Herramientas y la opción Implementar...

Se nos mostrará una ventana en la que tendremos que elegir el servidor de aplicaciones e
indicar el nombre y contraseña del administrador de dicho servidor. Seguidamente
pulsaremos el botón Aceptar y comenzará el proceso de despliegue. Iremos viendo una
consola en la que se mostrarán mensajes relativos al proceso.
Una vez finalizado el despliegue de la aplicación habremos terminado el ejemplo por
completo. Ahora podemos probarla abriendo el navegador web y apuntando a la dirección
“http://localhost:8080/ejemplo2”.

Recordemos que la aplicación web cuyo contexto es “ejemplo2” la desarrollamos en el tema


anterior, y que esta nueva aplicación sólo se compone de beans, no tiene ningún módulo
web por el que puedan acceder los usuarios.

134
5 Beans de entidad

Si abrimos el navegador y apuntamos a la dirección anterior, el aspecto que nos mostrará


será el siguiente:

Probemos a crear dos clientes; el primero con código “4” y nombre “Juan”, y el segundo con
código “33” y nombre “Luis”. Para ello, colocaremos los valores en los campos
correspondientes y pulsaremos el botón Crear. Tras la creación de los dos, la ventana
mostrará el siguiente aspecto:

Podemos probar a modificar sus nombres editando la caja de texto correspondiente y


pulsando su botón Guardar modificación. Otra funcionalidad que soporta es la de eliminar
clientes utilizando el enlace del código de cliente.

135
5 Beans de entidad

En este ejemplo podemos ver que los tiempos de respuesta de la aplicación son muy buenos,
máxime si tenemos en cuenta que se trata de una aplicación web. Si el servidor de
aplicaciones está instalado en nuestra máquina local y tenemos una red, sería interesante
probar la aplicación desde otro ordenador distinto al nuestro para que comprobemos si se
aprecia diferencia en los tiempos de respuesta.

136
5 Beans de entidad

− Los enterprises javabeans de entidad representan entidades del modelo


recuerde_
de análisis de una aplicación y nos permiten representar estado compartido y
transaccional. Como ventaja adicional tenemos que el contenedor EJB nos
proporcionará una serie de servicios de nivel de sistema, motivo por el cual
podremos centrarnos en la programación de lógica de empresa.

− El contenedor EJB puede gestionar el proceso de guardar y restaurar el


estado de los beans de entidad. Esta característica recibe el nombre de
persistencia gestionada por contenedor (CMP, Container Managed
Persistence). No obstante, podemos desear que nuestros beans puedan
gestionar la persistencia por si mismos. En este último caso hablaremos de
persistencia gestionada por bean (BMP, Bean Managed Persistence).

− La especificación EJB define un lenguaje denominado EJB QL (EJB Query


Language). Las sentencias EJB QL se escriben en los descriptores de
despliegue, y el contenedor EJB será el encargado de generar las
correspondientes instrucciones para interactuar con el almacén de datos.

− Las retrollamadas son invocaciones que realiza el contenedor sobre el bean.


El acceso al almacén de datos está compuesto por cuatro tipos de
operaciones: creación, lectura, modificación y borrado, existiendo para cada
una de las cuales un método de retrollamada, exceptuando el caso de la
operación de creación, que existen dos.

− La especificación EJB define un mecanismo denominado método buscador y


pueden definirse tantos como sean necesarios. Estos métodos se declaran en
la interfaz inicial del bean de entidad y sirven para localizar un bean o una
colección de ellos.

137
índice_ 6 Beans controlados por mensaje.
Empaquetado y roles

6.1. INTRODUCCIÓN A LOS MDB .................................................141


6.1.1. Transacciones ...........................................................142
6.1.2. Ejemplo .....................................................................142
6.2. EMPAQUETADO DE APLICACIONES J2EE ...............................145
6.2.1. Contenedores ............................................................145
6.2.2. Elementos a empaquetar ...........................................146
6.2.3. Paquetes ...................................................................147
6.2.3.1. Estructura de los paquetes............................147
6.2.3.2. El descriptor de despliegue ...........................148
6.3. ROLES ..................................................................................150
6.3.1. El proveedor de productos J2EE .................................150
6.3.2. El proveedor de herramientas....................................150
6.3.3. El proveedor de componentes....................................151
6.3.4. El ensamblador de aplicaciones .................................151
6.3.5. El implementador ......................................................151
6.3.6. El administrador del sistema .....................................151

139
6 Beans controlados por mensaje.
Empaquetado y roles

6.1. INTRODUCCIÓN A LOS MDB

Para el correcto entendimiento de los beans controlados por mensaje es imprescindible tener
unos conocimientos básicos del Servicio de Mensajería de Java, es decir, del API JMS (Java
Messaging Service), el cual no se tratará aquí por quedar fuera del ámbito de este manual.

Un bean controlado por mensaje (también llamado MDB, Message Driven Bean) es un
receptor de mensajes que puede consumir los mensajes de una cola o de una suscripción (o
apartado) mediante el contenedor J2EE. Cuando el contenedor recibe un mensaje, invoca al
bean que corresponda.

Bajo el punto de vista del cliente del bean, un bean controlado por mensaje es un
consumidor que se adapta al API JMS (Java Message Service) y que implementa la lógica de
negocio, pero al cual sólo se puede acceder enviándole un mensaje mediante JMS. Por su
parte, un bean controlado por mensaje puede comunicar con beans de sesión y de entidad.

La consecuencia lógica de esta filosofía es que un bean controlado por mensaje no tiene
estado conversacional con los clientes. Por el mismo motivo, y al contrario de lo que ocurría
con los beans de entidad y de sesión, no tienen interfaces iniciales ni remotas. Esto se debe
a que los clientes no pueden interactuar con ellos, recordemos que es el contenedor quien se
encarga de invocarlos.

Por otro lado, los beans controlados por mensaje tienen una limitación importante debida a
que la cola o el apartado (de la suscripción) es definido en el descriptor de despliegue, en el
período de implementación en lugar del período de ejecución. Además, los selectores de
mensaje también son definidos en dicho descriptor. Esta situación es una característica de
JMS y, aunque la mayoría de los servidores de aplicación existentes permiten saltarse esto,
corremos el riesgo de depender de algún servidor en concreto si hacemos uso de sus
opciones.

Un bean controlado por mensaje debe implementar las interfaces


“javax.jms.MessageListener” y “”javax.ejb.MessageListener”. La lógica debe recogerse en la
implementación del método “onMessage()” de “MessageListener”, y no debe generar
excepciones JMS o de aplicación, si no que debe capturarlas y tratarlas. Como mínimo,
debería generarlas como excepciones “EJBException”.

141
6 Beans controlados por mensaje.
Empaquetado y roles

La clase de implementación de un bean controlado por mensaje debe proveer los


siguientes métodos:

− “setMessageDrivenContext()”. Informa del contexto de ejecución para el bean.

− “ejbCreate()”. Método invocado por el contenedor cuando el bean se crea.

− “onMessage()”. Método invocado por el contenedor en el que se notifica la llegada de


un mensaje.

− “ejbRemove()”. Método invocado por el contenedor cuando el bean se va a eliminar.

6.1.1. Transacciones

Para los beans controlados por mensaje existen dos tipos de gestión de transacciones:

− Gestionadas por contenedor.

− Gestionadas por bean.

Estos tipos afectan a los atributos transaccionales del método “onMessage()” y al manejo de
la entrega garantizada de los mensajes.

En el caso de las transacciones gestionadas por contenedor, la entrega del mensaje está
garantizada. En cuanto a los atributos transaccionales, sólo se permiten dos:”NotSupported”
y “Required”. Con el primero de ellos, el bean es ejecutado fuera de ninguna transacción,
mientras que con el segundo se abrirá una nueva transacción.

Por último, en lo que respecta a las transacciones gestionadas por bean, los límites de la
transacción deben estar dentro del método “onMessage()”. La entrega del mensaje no está
garantizada a menos que se utilice “javax.transaction.UserTransaction”, y en tal caso la
aplicación cliente será la que demarcará los límites de la transacción.

6.1.2. Ejemplo

A continuación veremos la implementación de un bean controlado por mensaje que tiene la


función de crear los pedidos de los clientes.

import java.util.Date;
import javax.ejb.EJBException;
import javax.ejb.MessageDrivenBean;

142
6 Beans controlados por mensaje.
Empaquetado y roles

import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class PedidoBean implements MessageDrivenBean, MessageListener {


private MessageDrivenContext mdctx;
private Context ctx;

public void setMessageDrivenContext(MessageDrivenContext mdctx) {


this.mdctx = mdctx;
try {
// Necesitamos la referencia al contexto para poder
// localizar posteriormente el bean de gestión de pedidos
ctx = new InitialContext();
} catch (NamingException e) {
throw new EJBException(e);
}
}
public void ejbCreate() {}
public void onMessage(Message msg) {
try {
// El mensaje debe ser del tipo MapMessage, en caso
// contrario se generará una excepción
MapMessage pedidoMap = (MapMessage) msg;

// El mensaje contiene los valores necesarios para la


// creación de un pedido
Date fecha = (Date) pedidoMap.getObject("fecha");
Integer cliente = new Integer(pedidoMap.getInt("cliente"));
String articulo = pedidoMap.getString("articulo");
Integer cantidad = new Integer(pedidoMap.getInt("cantidad"));

// Localizamos el bean de sesión encargado de la


// gestión de pedidos

143
6 Beans controlados por mensaje.
Empaquetado y roles

LocalPedidosHome pedidosHome = (LocalPedidosHome)


ctx.lookup("java:comp/env/ejb/Pedidos");
LocalPedidos pedidos = pedidosHome.create();
// Invocamos el método de negocio que crea el pedido
pedidos.crearPedido(fecha, cliente, articulo, cantidad);
} catch (Exception e) {
throw new EJBException(e);
}
}
public void ejbRemove() throws EJBException {
}
}

Al igual que ocurre con los beans de sesión y de entidad, es necesario el descriptor de
despliegue para que la implementación sea posible.

Para la creación del fichero de despliegue, bien sea mediante alguna herramienta o bien
manualmente, es necesario indicar la siguiente información:

− La clase de implementación del bean.

− El tipo de bean, que en este caso se trata de un bean controlado por mensaje.

− Si las transacciones están gestionadas por el contenedor o por el bean.

− El tipo de destino, es decir, si el mensaje se va a consumir desde una cola o un


apartado, así como el nombre de dicho destino.

− El nombre de la factoría de conexiones a utilizar.

− El método de acuse de recibo.

De la relación anterior, tanto el destino (cola o apartado) como la factoría de conexiones


deben ser definidos en el servidor de aplicaciones para que el contenedor sea capaz de
invocar a nuestro EJB cuando dicho destino reciba mensajes.

144
6 Beans controlados por mensaje.
Empaquetado y roles

6.2. EMPAQUETADO DE APLICACIONES J2EE

A lo largo de este manual hemos visto en qué consiste la especificación J2EE, concretamente
la parte relacionada con los Enterprise JavaBeans, cómo desarrollar el código y ejecutarlo en
el servidor.

Hasta ahora no hemos profundizado en lo relacionado con el empaquetado y despliegue de


las aplicaciones y de sus componentes debido a que utilizamos la herramienta deploytool
que nos ha permitido abstraernos de estas tareas.

Sin embargo, incluso un conocimiento básico de la tecnología J2EE debe pasar por conocer
cuál es la estructura de empaquetado de una aplicación J2EE y de los distintos componentes
que la forman.

La especificación J2EE dicta unas normas para la estructuración y creación de las


aplicaciones, incluido el empaquetado. Sabemos que dicha especificación se compone de un
conjunto de especificaciones menores y que, a su vez, también proporciona directrices para
el empaquetado de los componentes individuales.

Cualquier aplicación J2EE se compone de los siguientes elementos:

− Uno o más componentes J2EE.

− Un descriptor de despliegue.

Uno o más módulos J2EE se empaquetan en un único módulo de implementación, que se


corresponde físicamente con un archivo EAR (fichero comprimido similar a los ficheros JAR y
para el que se usa la extensión EAR).

6.2.1. Contenedores

J2EE hace una clara distinción entre los recursos que se pueden empaquetar en un archivo
de aplicación (EAR, Enterprise Application Archive) y los recursos que se ejecutan en un
contenedor.

La diferencia entre ambos estriba en que el contenedor de período de ejecución intercepta


las solicitudes para proporcionar servicios del nivel del sistema, mientras que el módulo de
implementación es una estructura de empaquetado para componentes que se ejecutarán, en
último lugar, en un contenedor de período de ejecución.

145
6 Beans controlados por mensaje.
Empaquetado y roles

Recordemos que la estructura de los contenedores J2EE es la siguiente:

− Contenedor web. Intercepta las solicitudes recibidas de determinados protocolos (HTTP


y HTTPS generalmente) y permite a los servlets y páginas JSP acceder a los recursos
de los contenedores EJB.

− Contenedor EJB. Intercepta las solicitudes en el nivel de la lógica de negocio y permite


que los Enterprise JavaBeans tengan acceso a determinados API.

− Contenedor cliente de aplicación. Intercepta solicitudes para las aplicaciones Java


independientes, las cuales se ejecutan remotamente en una máquina virtual distinta
de donde se encuentran los contenedores web y EJB.

− Contenedor de applets. Intercepta solicitudes a nivel de los programas Java que se


ejecutan dentro de un navegador.

6.2.2. Elementos a empaquetar

Un fichero EAR se compone de uno o varios de los siguientes tipos de componentes:

− Archivo WAR de aplicación web. Cada archivo WAR sólo puede contener una única
aplicación web y en caso de que el archivo EAR contenga más de una, cada una de
ellas habrá de tener un nombre de contexto único.

− Archivo JAR de aplicación EJB. Estará compuesto por al menos un Enterprise


JavaBean.

− Archivo JAR de cliente de aplicación. Contendrá una única aplicación Java destinada a
ejecutarse en un contenedor cliente de aplicación.

− Archivo RAR de adaptador de recursos. Contendrá clases Java y las librerías nativas
necesarias para implementar un adaptador de recursos de Arquitectura de Conectores
Java a un sistema de información de empresa.

Cada uno de los componentes debe ser desarrollado y empaquetado por separado, junto con
su correspondiente descriptor de despliegue. El archivo EAR unifica uno o más de estos
componentes en un único paquete, incluyendo su propio descriptor de implementación. Sin
embargo, existen componentes que no se pueden declarar dentro de los archivos EAR, a

146
6 Beans controlados por mensaje.
Empaquetado y roles

pesar de ser utilizados frecuentemente. Entre ellos podemos citar las fuentes de datos JDBC.
Recordemos que en algunos ejemplos de los temas anteriores teníamos componentes que
necesitaban tener acceso a la fuente de datos utilizando el nombre JNDI “jdbc/CursoEJB”.

En el caso de este tipo de componentes se hace necesario configurarlos y desplegarlos


manualmente mediante la consola de administración del servidor. Siguiendo con nuestros
ejemplos, recordemos que la definición de la fuente de datos y la asignación del nombre
JNDI las realizamos mediante la consola del servidor utilizando el navegador web en la
dirección “http://localhost:4848”.

6.2.3. Paquetes

La construcción de una aplicación J2EE es un proceso compuesto por las siguientes fases:

− Construcción de los componentes individuales como los servlets, las páginas JSP y los
Enterprise JavaBeans.

− Algunos de estos componentes se empaquetan en archivos con formato JAR junto con
el correspondiente descriptor de despliegue de módulo J2EE. Este último se compone
de uno o más componentes J2EE del mismo tipo, por lo tanto, un módulo EJB puede
estar compuesto por uno o más EJB y un módulo web puede estar compuesto por
múltiples servlets y páginas JSP.

− Uno o más módulos J2EE se unen en un archivo EAR junto con un descriptor de
despliegue para obtener la aplicación J2EE.

− La aplicación J2EE se despliega en el servidor de aplicaciones.

6.2.3.1. Estructura de los paquetes

Un paquete de aplicación J2EE está compuesto por uno o varios módulos J2EE y un
descriptor de despliegue llamado “application.xml” que se ubica en el directorio “META-INF”.
Los archivos se empaquetan (o comprimen) utilizando el formato JAR y se almacenan en un
fichero con extensión “ear”.

147
6 Beans controlados por mensaje.
Empaquetado y roles

Por ejemplo, un archivo EAR que contenga dos módulos EJB y un módulo web podría tener el
siguiente contenido:

− moduloEJB1.jar

− moduloEJB2.jar

− moduloWEB.war

− META-INF\application.xml

El archivo EAR de la aplicación se puede crear manualmente o utilizando las herramientas


que provee el propio servidor de aplicaciones. En el primer caso se trata de utilizar la
herramienta “jar” del JDK y los pasos son los siguientes:

− Crear un directorio para alojar los contenidos del archivo EAR.

− Copiar los módulos J2EE en dicho directorio y crear el directorio “META-INF”.

− Crear dentro del directorio “META-INF” el descriptor de implementación


“application.xml”.

− Utilizar la herramienta “jar”.

Siguiendo con el ejemplo anterior, para crear un fichero de aplicación llamado “MiApl,
utilizaríamos la herramienta “jar” con la siguiente sintaxis:

jar cvf MiApl.ear moduloEJB1.jar moduloEJB2.jar moduloWEB.war META-INF

6.2.3.2. El descriptor de despliegue

El descriptor de despliegue es un fichero XML llamado “application.xml”, por lo tanto


podemos editarlo con nuestro editor favorito. A pesar de ello, la forma más cómoda de
manipularlo es mediante las herramientas gráficas que nos pueda suministrar nuestro
servidor de aplicaciones. No obstante, es interesante que lo conozcamos por si necesitamos
editarlo manualmente.

El descriptor de implementación “application.xml” es muy sencillo y sólo requiere de un


conjunto reducido de etiquetas. Su declaración “DOCTYPE” debe ser la siguiente:

<!DOCTYPE application PUBLIC “-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN”

148
6 Beans controlados por mensaje.
Empaquetado y roles

“http://java.sun.com/dtd/application_1_3.dtd”>

La etiqueta raíz de la estructura de nodos es “<application>” y las etiquetas más


importantes que puede anidar son las siguientes:

− “<icon>”.

− “<display-name>”.

− “<description>”.

− “<module>”.

Las tres primeras proporcionan información sobre la aplicación, mientras que la última
engloba los módulos J2EE que conforman la aplicación.

La etiqueta “<module>” agrupará, a su vez, etiquetas “<ejb>”, “<web>” y “<java>”, para


los módulos EJB, web y programas cliente de aplicación, respectivamente.

En caso de utilizar la etiqueta “<web>”, es necesario anidarle las etiquetas “<web-uri>” y


“<context-root>”, para indicar el fichero que contiene el módulo web y el nombre del
contexto de ejecución de la aplicación web.

A continuación, podemos ver un ejemplo de un descriptor de despliegue:


6.3. ROLES

<!DOCTYPE application PUBLIC “-//Sun Microsystems, Inc.//DTD J2EE Application


1.3//EN” “http://java.sun.com/dtd/application_1_3.dtd”>

<application>
<display-name>Aplicación de ejemplo</display-name>
<module>
<ejb>moduloEJB.jar</ejb>
</module>
</module>
<web>
<web-uri>moduloWEB.war</web-uri>
<context-root>/miaplicacion</context-root>
</web>
</module>
</application>
<?xml version=”1.0” encoding=”UTF-8”?>

149
6 Beans controlados por mensaje.
Empaquetado y roles

La naturaleza modular de la especificación J2EE permite dividir el desarrollo de la aplicación


y el proceso de despliegue en distintos roles para que más de una persona o empresa
puedan intervenir en las distintas partes del proceso.

El primer rol que aparece en escena está relacionado con la instalación de los productos y
herramientas J2EE. Una vez instalados, el proveedor de componentes de aplicación puede
desarrollar dichos componentes, los ensambladores de aplicaciones pueden ensamblarlos, y
los implementadores pueden desplegarlos.

En una organización pequeña la mayoría de estos roles suelen estar desempeñados por la
misma persona o equipo, sin embargo, en las organizaciones grandes suelen estar
distribuidos en distintos equipos. Cada rol utiliza como entrada la salida del rol precedente,
hasta llegar al final del flujo de trabajo. Por ejemplo, en la fase de desarrollo de
componentes el desarrollador de Enterprise JavaBeans entregará ficheros JAR que serán
utilizados en la fase de ensamblaje, en la cual otro desarrollador combinará los ficheros JAR
en una aplicación J2EE para crear un fichero EAR.

En los siguientes apartados vamos a ver los principales roles existentes.

6.3.1. El proveedor de productos J2EE

El proveedor de productos J2EE es la organización (empresa o persona) que facilita la


plataforma, los API u otras características definidas por la especificación. Habitualmente se
trata de proveedores de bases de datos, servidores de aplicaciones o servidores web que
implementan la plataforma J2EE conforme a la especificación.

6.3.2. El proveedor de herramientas

El proveedor de herramientas es la organización que desarrolla, ensambla y empaqueta


herramientas que pueden ser utilizadas por los proveedores de componentes, los
ensambladores y los implementadores.

Un proveedor de herramientas puede suministrar herramientas que automaticen la


generación de descriptores de implementación para un archivo EAR en un servidor de
aplicación. Estas utilidades pueden ser independientes de la plataforma (funcionan con todos
los ficheros EAR con independencia del entorno) o dependientes de la plataforma (funcionan
para un determinado entorno).

150
6 Beans controlados por mensaje.
Empaquetado y roles

6.3.3. El proveedor de componentes

El proveedor de componentes es la organización que crea los componentes web, los


Enterprise JavaBeans, etc., para que sean usados en las aplicaciones J2EE.

También existen roles, dentro de la especificación J2EE, que pueden tener características
similares a las de los proveedores de componentes. Entre estos roles se incluyen los
desarrolladores de documentos, autores de JSP, desarrolladores de beans de negocio y
desarrolladores de adaptadores de recursos.

6.3.4. El ensamblador de aplicaciones

El ensamblador de aplicaciones es la organización que recibe los ficheros JAR con los
componentes de la aplicación y los ensambla en un fichero EAR. También es responsable de
crear el descriptor de despliegue de la aplicación J2EE y de identificar cualquier recurso
externo del que pueda depender dicha aplicación. Entre estos recursos puede haber
bibliotecas de clases, roles de seguridad y entornos de nombrado. El ensamblador de
aplicaciones suele utilizar las herramientas suministradas por el proveedor de productos J2EE
y por el proveedor de herramientas.

6.3.5. El implementador

El implementador es el responsable de implementar las aplicaciones web y EJB en el


servidor (o servidores). Entre sus labores no están las de implementar un archivo de
adaptador de recursos o de cliente de aplicación, pero sí la de la configuración adicional de
dichos componentes que, aunque se empaqueten como parte del archivo EAR de la
aplicación, no son considerados cuando se implementa la aplicación de empresa.

6.3.6. El administrador del sistema

El administrador del sistema es el responsable de la configuración del entorno de red y


del entorno operativo en los que se ejecutan los servidores de aplicaciones y, por lo tanto,
las aplicaciones J2EE. Así mismo, es el responsable del control y mantenimiento de dichas
aplicaciones.

151
6 Beans controlados por mensaje.
Empaquetado y roles

En todos los ejemplos de este manual nosotros hemos asumido cuatro de los seis roles
expuestos. Exceptuando los roles de proveedor de productos J2EE y proveedor de
herramientas, hemos desempeñado los siguientes:

− Proveedor de componentes. Hemos desarrollado los componentes web y EJB


necesarios.

− Ensamblador de aplicaciones. Hemos combinado los componentes J2EE para crear


nuestra aplicación final.

− Implementador. Hemos desplegado las aplicaciones en el servidor verificando que los


recursos externos necesarios (las fuentes de datos) estuvieran accesibles.

− Administrador del sistema. Hemos instalado y configurado el servidor de aplicaciones,


así como revisado el entorno operativo para verificar que las aplicaciones están
accesibles por los clientes.

152
6 Beans controlados por mensaje.
Empaquetado y roles

− Un bean controlado por mensaje es un receptor de mensajes que puede


recuerde_
consumir los mensajes de una cola o de una suscripción mediante el
contenedor J2EE.

− Un bean controlado por mensaje debe implementar las interfaces


“javax.jms.MessageListener” y “”javax.ejb.MessageListener”. La lógica debe
recogerse en la implementación del método “onMessage()” de la interfaz
“MessageListener”.

− La especificación J2EE dicta unas normas para la estructuración y creación de


las aplicaciones, incluido el empaquetado. Dicha especificación se compone
de un conjunto de especificaciones menores y que, a su vez, también
proporcionan directrices para el empaquetado de los componentes
individuales.

− Uno o más módulos J2EE se empaquetan en un único módulo de


implementación, que se corresponde físicamente con un archivo EAR.

− La naturaleza modular de la especificación J2EE permite dividir el desarrollo


de la aplicación y el proceso de despliegue en distintos roles para que más de
una persona o empresa puedan intervenir en las distintas partes del proceso.

− Los principales roles existentes son: el proveedor de productos J2EE, el


proveedor de herramientas, el proveedor de componentes, el ensamblador de
aplicaciones, el implementador y el administrador del sistema.

153
A
glosario_
API. Siglas de Application Program Interface (Interfaz para programas de
aplicación). Conjunto de convenciones de programación que definen cómo se
invoca un servicio desde un programa.

GUI. Siglas de Graphical User Interface (Interfaz Gráfica de Usuario). Permite a


los usuarios navegar e interactuar con las informaciones en la pantalla de su
ordenador utilizando un ratón para señalar, pulsar y desplazar iconos y otros
datos de la pantalla, en lugar de escribir palabras y frases.

HTML. Siglas de HiperText Transfer Protocol (Protocolo de Transferencia de


HiperTexto). Es un lenguaje que especifica el aspecto y estructura de las páginas
web.

JDBC. Abreviatura de “Java Database Connectivity”, un API Java que permite


ejecutar sentencias SQL a las aplicaciones Java sobre cualquier base de datos
compatible con SQL. Debido a que la mayoría de los sistemas de gestión de
bases de datos soportan SQL, y a que Java se ejecuta en casi todas las
plataformas, JDBC hace posible escribir una única aplicación que se pueda
ejecutar en distintas plataformas e interactúe con diferentes bases de datos.

MULTITHREADING. Técnica que permite la utilización de varios threads (hilos)


que se ejecutan en paralelo. Los términos empleados en español para hacer
referencia a esta característica son Multihilo y Multihebra.

OPTIMIZACIÓN. Proceso mediante el cual se detectan y aplican posibles


mejoras, logrando que la ejecución resulte más eficiente.

155
P
glosario_
PROTOCOLO. Conjunto de normas comunes que deben ser observadas por dos
elementos que desean comunicarse para poder entender los mensajes que se
reciben. En general, este término se emplea para la definición de técnicas de
comunicación en una red. En el caso de Internet, un ejemplo es el protocolo IP,
que define el formato de los mensajes que se envían de un nodo a otro. Sobre
este protocolo básico se pueden construir otros que proporcionan mayor
funcionalidad, como es el caso de HTTP, que permite transmitir la información
contenida en páginas web.

SQL. Es la abreviatura de Lenguaje de Consulta Estructurado (Structured Query


Language). Es un lenguaje de consulta estandarizado para interactuar con bases
de datos. La versión original se llamó SEQUEL (Structured English Query
Language) y fue diseñada por IBM entre 1974 y 1975. La primera base de datos
comercial en la que SQL se introdujo por primera vez fue la de Oracle
Corporation en 1979.

URL. Siglas de Uniform Resource Locator (Localizador Uniforme de Recursos).


Permite localizar o acceder de forma sencilla cualquier recurso de la red desde el
navegador de la WWW.

156
Scott W. Ambler y Tyler Jewell. Mastering Enterprise JavaBeans Second Edition.
bibliografía_
Ed. The Middleware Company. 2002.
Paul J. Perrone. J2EE Developer's Handbook. Ed. Sams Publishing. 2003.

157

S-ar putea să vă placă și