Java Enterprise

159

Click here to load reader

Transcript of Java Enterprise

Page 1: Java Enterprise

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

índi

ce g

ener

al_

Page 2: Java Enterprise
Page 3: Java Enterprise

1

Introducción a J2EE 1

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

índi

ce_

Page 4: Java Enterprise
Page 5: Java Enterprise

3

Introducción a J2EE 1

1.1. JAVA

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.

Page 6: Java Enterprise

4

Introducción a J2EE 1

1.2.1. El período de ejecución

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.

Page 7: Java Enterprise

5

Introducción a J2EE 1

Este API está formado por dos componentes:

• 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.

Page 8: Java Enterprise

6

Introducción a J2EE 1

− 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.

Page 9: Java Enterprise

7

Introducción a J2EE 1

− 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

Page 10: Java Enterprise

8

Introducción a J2EE 1

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.

Page 11: Java Enterprise

9

Introducción a J2EE 1

1.4. LA ARQUITECTURA MULTICAPA

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

Page 12: Java Enterprise

10

Introducción a J2EE 1

como ejemplo.

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

Page 13: Java Enterprise

11

Introducción a J2EE 1

programa cliente.

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.

Page 14: Java Enterprise

12

Introducción a J2EE 1

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.

Page 15: Java Enterprise

13

Introducción a J2EE 1

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.

Page 16: Java Enterprise

14

Introducción a J2EE 1

Page 17: Java Enterprise

15

Introducción a J2EE 1

− 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.

− 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.

recu

erde

_

Page 18: Java Enterprise
Page 19: Java Enterprise

17

Aplicaciones web 2

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

índi

ce_

Page 20: Java Enterprise
Page 21: Java Enterprise

19

Aplicaciones web 2

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

Page 22: Java Enterprise

20

Aplicaciones web 2

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.

Page 23: Java Enterprise

21

Aplicaciones web 2

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

Page 24: Java Enterprise

22

Aplicaciones web 2

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

Page 25: Java Enterprise

23

Aplicaciones web 2

“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.

Page 26: Java Enterprise

24

Aplicaciones web 2

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.

Page 27: Java Enterprise

25

Aplicaciones web 2

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

Page 28: Java Enterprise

26

Aplicaciones web 2

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á

Page 29: Java Enterprise

27

Aplicaciones web 2

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.

Page 30: Java Enterprise

28

Aplicaciones web 2

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.

Page 31: Java Enterprise

29

Aplicaciones web 2

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

Page 32: Java Enterprise

30

Aplicaciones web 2

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.

Page 33: Java Enterprise

31

Aplicaciones web 2

− 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.

recu

erde

_

Page 34: Java Enterprise
Page 35: Java Enterprise

33

Enterprises Beans y servicios de contenedor 33

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

índi

ce_

Page 36: Java Enterprise
Page 37: Java Enterprise

35

Enterprises Beans y servicios de contenedor 33

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.

Page 38: Java Enterprise

36

Enterprises Beans y servicios de contenedor 33

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.

Page 39: Java Enterprise

37

Enterprises Beans y servicios de contenedor 33

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.

Page 40: Java Enterprise

38

Enterprises Beans y servicios de contenedor 33

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.

Page 41: Java Enterprise

39

Enterprises Beans y servicios de contenedor 33

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.

Page 42: Java Enterprise

40

Enterprises Beans y servicios de contenedor 33

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”.

Page 43: Java Enterprise

41

Enterprises Beans y servicios de contenedor 33

− 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.

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.

<?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>

Page 44: Java Enterprise

42

Enterprises Beans y servicios de contenedor 33

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.

<?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>

Page 45: Java Enterprise

43

Enterprises Beans y servicios de contenedor 33

− 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();

}

Page 46: Java Enterprise

44

Enterprises Beans y servicios de contenedor 33

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.

Page 47: Java Enterprise

45

Enterprises Beans y servicios de contenedor 33

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.

Page 48: Java Enterprise

46

Enterprises Beans y servicios de contenedor 33

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.

Page 49: Java Enterprise

47

Enterprises Beans y servicios de contenedor 33

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:

Page 50: Java Enterprise

48

Enterprises Beans y servicios de contenedor 33

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.

Page 51: Java Enterprise

49

Enterprises Beans y servicios de contenedor 33

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

Page 52: Java Enterprise

50

Enterprises Beans y servicios de contenedor 33

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”.

Page 53: Java Enterprise

51

Enterprises Beans y servicios de contenedor 33

Suponiendo que estamos en Linux y lo hemos instalado en

“/home/alumno/SUNWappserver”, escribiremos:

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

escribiríamos lo siguiente:

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:

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

c:\SUNWappserver> asadmin start-domain domain1

Page 54: Java Enterprise

52

Enterprises Beans y servicios de contenedor 33

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

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

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”).

asadmin stop-domain domain1

Page 55: Java Enterprise

53

Enterprises Beans y servicios de contenedor 33

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”.

Page 56: Java Enterprise

54

Enterprises Beans y servicios de contenedor 33

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.

Page 57: Java Enterprise

55

Enterprises Beans y servicios de contenedor 33

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”.

Page 58: Java Enterprise

56

Enterprises Beans y servicios de contenedor 33

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.

Page 59: Java Enterprise

57

Enterprises Beans y servicios de contenedor 33

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

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 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;

}

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() {

Page 60: Java Enterprise

58

Enterprises Beans y servicios de contenedor 33

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

}

// 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;

}

}

Page 61: Java Enterprise

59

Enterprises Beans y servicios de contenedor 33

“/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();

Page 62: Java Enterprise

60

Enterprises Beans y servicios de contenedor 33

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%>

<%

Page 63: Java Enterprise

61

Enterprises Beans y servicios de contenedor 33

} 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>

Page 64: Java Enterprise

62

Enterprises Beans y servicios de contenedor 33

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.

<%

}

%>

</body>

</html>

Page 65: Java Enterprise

63

Enterprises Beans y servicios de contenedor 33

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:

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

CREATE TABLE empresa (nombre VARCHAR(20));

INSERT INTO empresa VALUES ('Construcciones K');

Page 66: Java Enterprise

64

Enterprises Beans y servicios de contenedor 33

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.

Page 67: Java Enterprise

65

Enterprises Beans y servicios de contenedor 33

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.

Page 68: Java Enterprise

66

Enterprises Beans y servicios de contenedor 33

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

Page 69: Java Enterprise

67

Enterprises Beans y servicios de contenedor 33

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

Page 70: Java Enterprise

68

Enterprises Beans y servicios de contenedor 33

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”

Page 71: Java Enterprise

69

Enterprises Beans y servicios de contenedor 33

− 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:

Page 72: Java Enterprise

70

Enterprises Beans y servicios de contenedor 33

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 >”.

Page 73: Java Enterprise

71

Enterprises Beans y servicios de contenedor 33

Prestemos atención a la siguiente ventana.

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.

1 2

3

Page 74: Java Enterprise

72

Enterprises Beans y servicios de contenedor 33

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

1

2 3

4

5

Page 75: Java Enterprise

73

Enterprises Beans y servicios de contenedor 33

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.

Page 76: Java Enterprise

74

Enterprises Beans y servicios de contenedor 33

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.

12

3

Page 77: Java Enterprise

75

Enterprises Beans y servicios de contenedor 33

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”.

Page 78: Java Enterprise

76

Enterprises Beans y servicios de contenedor 33

− “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.

Page 79: Java Enterprise

77

Enterprises Beans y servicios de contenedor 33

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.

Page 80: Java Enterprise

78

Enterprises Beans y servicios de contenedor 33

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:

Page 81: Java Enterprise

79

Enterprises Beans y servicios de contenedor 33

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.

Page 82: Java Enterprise

80

Enterprises Beans y servicios de contenedor 33

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.

Page 83: Java Enterprise

81

Enterprises Beans y servicios de contenedor 33

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.

Page 84: Java Enterprise

82

Enterprises Beans y servicios de contenedor 33

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

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.

recu

erde

_

Page 85: Java Enterprise

83

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

índi

ce_

Page 86: Java Enterprise
Page 87: Java Enterprise

85

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.

Page 88: Java Enterprise

86

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.

Page 89: Java Enterprise

87

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

Page 90: Java Enterprise

88

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.

Page 91: Java Enterprise

89

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.

Page 92: Java Enterprise

90

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.

Page 93: Java Enterprise

91

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.

Page 94: Java Enterprise

92

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:

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

En Linux: /home/alumno/cursoEJB/ejemplo2

En Windows: c:\cursoEJB\ejemplo2

Page 95: Java Enterprise

93

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:

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.

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;

}

}

Page 96: Java Enterprise

94

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.

Page 97: Java Enterprise

95

4 Beans de sesión

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

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

package gestion;

import javax.ejb.*;

public interface MtoClientesHome extends javax.ejb.EJBHome {

public gestion.MtoClientes create ()

throws javax.ejb.CreateException, java.rmi.RemoteException;

}

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;

}

Page 98: Java Enterprise

96

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,

Page 99: Java Enterprise

97

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));

}

}

Page 100: Java Enterprise

98

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");

Page 101: Java Enterprise

99

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") +

")";

}

%>

Page 102: Java Enterprise

100

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>

Page 103: Java Enterprise

101

4 Beans de sesión

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

<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>

Page 104: Java Enterprise

102

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 >.

Page 105: Java Enterprise

103

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.

Page 106: Java Enterprise

104

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

Page 107: Java Enterprise

105

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

Page 108: Java Enterprise

106

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.

Page 109: Java Enterprise

107

4 Beans de sesión

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

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.

recu

erde

_

Page 110: Java Enterprise
Page 111: Java Enterprise

109

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

índi

ce_

Page 112: Java Enterprise
Page 113: Java Enterprise

111

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

Page 114: Java Enterprise

112

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.

Page 115: Java Enterprise

113

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.

Page 116: Java Enterprise

114

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:

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.

public abstract String getDireccionCliente();

public abstract void setDireccionCliente(String direccionCliente);

Page 117: Java Enterprise

115

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.

Page 118: Java Enterprise

116

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:

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

"<>".

SELECT OBJECT(u)

FROM Usuarios AS u

WHERE u.login = 'juan' AND u.password = '1424'

Page 119: Java Enterprise

117

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:

La consulta a utilizar sería la siguiente:

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

public Usuarios findByLogin(String login, String password);

SELECT OBJECT(u)

FROM Usuarios AS u

WHERE u.login = ?1 AND u.password = ?2

Page 120: Java Enterprise

118

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();

}

}

Page 121: Java Enterprise

119

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):

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:

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:

<prim-key-class>paquete.UsuariosPK</prim-key-class>

<prim-key-class>java.lang.String</prim-key-class>

<primkey-field>usuario<primkey-field>

Page 122: Java Enterprise

120

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

Page 123: Java Enterprise

121

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.

Page 124: Java Enterprise

122

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

Page 125: Java Enterprise

123

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.

Page 126: Java Enterprise

124

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”.

Page 127: Java Enterprise

125

5 Beans de entidad

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

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

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 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;

}

package gestion;

import javax.ejb.*;

public interface LocalClientes extends javax.ejb.EJBLocalObject {

public gestion.ClienteDetalle getClienteDetalle();

public void modify(gestion.ClienteDetalle clienteDetalle);

}

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() { }

Page 128: Java Enterprise

126

5 Beans de entidad

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.

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());

}

}

Page 129: Java Enterprise

127

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:

Page 130: Java Enterprise

128

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

Page 131: Java Enterprise

129

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

Page 132: Java Enterprise

130

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.

Page 133: Java Enterprise

131

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.

Page 134: Java Enterprise

132

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

Page 135: Java Enterprise

133

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:

Page 136: Java Enterprise

134

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.

Page 137: Java Enterprise

135

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.

Page 138: Java Enterprise

136

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.

Page 139: Java Enterprise

137

5 Beans de entidad

− Los enterprises javabeans de entidad representan entidades del modelo

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.

recu

erde

_

Page 140: Java Enterprise
Page 141: Java Enterprise

139

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

índi

ce_

Page 142: Java Enterprise
Page 143: Java Enterprise

141

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”.

Page 144: Java Enterprise

142

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;

Page 145: Java Enterprise

143

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

Page 146: Java Enterprise

144

6 Beans controlados por mensaje. Empaquetado y roles

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.

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 {

}

}

Page 147: Java Enterprise

145

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.

Page 148: Java Enterprise

146

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

Page 149: Java Enterprise

147

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”.

Page 150: Java Enterprise

148

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”

Page 151: Java Enterprise

149

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”?>

Page 152: Java Enterprise

150

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).

Page 153: Java Enterprise

151

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.

Page 154: Java Enterprise

152

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.

Page 155: Java Enterprise

153

6 Beans controlados por mensaje. Empaquetado y roles

− Un bean controlado por mensaje es un receptor de mensajes que puede

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.

recu

erde

_

Page 156: Java Enterprise
Page 157: Java Enterprise

155

A

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.

G

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.

H

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.

J

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.

M

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.

O

OPTIMIZACIÓN. Proceso mediante el cual se detectan y aplican posibles

mejoras, logrando que la ejecución resulte más eficiente.

glos

ario

_

Page 158: Java Enterprise

156

P

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.

S

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.

U

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.

glos

ario

_

Page 159: Java Enterprise

157

Scott W. Ambler y Tyler Jewell. Mastering Enterprise JavaBeans Second Edition.

Ed. The Middleware Company. 2002.

Paul J. Perrone. J2EE Developer's Handbook. Ed. Sams Publishing. 2003.

bibl

iogr

afía

_