Aplicaciones enterprise con EJB
 

Introducción a los servidores de aplicaciones y a Glassfish

¿Qué es un servidor de aplicaciones?

Un servidor de aplicaciones Java EE es una plataforma que da soporte a los servicios definidos en la especificación, desde aplicaciones web con servlets y JSP, hasta aplicaciones distribuidas con soporte transaccional utilizando Enterprise JavaBeans (EJB) o servicios web.

Hasta ahora hemos estado trabajando con Apache Tomcat. ¿Es un servidor de aplicaciones? Sólo en parte, porque no implementa completamente el estándar Java EE. Hemos visto que sólo implementa un contenedor Web en el que se pueden instalar servlets y páginas JSP. Pero no implementa toda la parte de procesamiento transaccional distribuido definido por el contenedor de EJBs.

La siguiente figura muestra los distintos componentes del servidor de aplicaciones Glassfish.

Arquitectura J2EE.

La primera capa de la figura define los dos contenedores más importantes definidos en un servidor de aplicaciones. El contenedor web que gestiona el ciclo de vida de servlets y el contenedor EJB que gestiona el ciclo de vida de los beans de negocio. El primero se basa en el servidor web Apache Tomcat y el segundo en una tecnología ORB (Object Request Broker), una tecnología que permite realizar llamadas distribuidas entre objetos Java. Una diferencia fundamental en ambos casos es el protocolo utilizado por ambas tecnologías. El servidor web permite comunicación distribuida entre los clientes y el servidor utilizando un protocolo HTTP o HTTPs. El ORB que soporta la tecnología EJB utiliza los protocolos IIOP y IIOP/SSL (IIOP con comunicación segura SSL) que permiten serializar objetos Java y gestionar llamadas síncronas a objetos remotos.

Bajo esta capa aparece en la figura una tercera capa que muestra servicios proporcionados por el servidor de aplicaciones. Estos servicios son accesibles tanto desde el servidor web como desde el contenedor EJB. Iremos conociendo algunos de estos servicios conforme avancemos en los distintos módulos de esta segunda parte del especialista.

  • Servicio de nombres: un servicio de nombres liga (binds) objetos java a nombres lógicos. Estos nombres pueden ser utilizados por las aplicaciones para obtener acceso a los objetos. El servicio que permite realizar este proceso se denomina JNDI (Java Naming and Directory Interface).
  • Seguridad: La tecnología de seguridad definida por el estándar Java EE es la denominada JACC (Java Authorization Contract for Containers). Dependiendo de la identidad del cliente, se permite el acceso a los distintos recursos de los contenedores y de los servicios.
  • Gestión de transacciones: el servicio JTA (Java Transaction API) da soporte a la utilización de transacciones distribuidas que pueden englobar distintas bases de datos gestionadas por distintos servidores de aplicaciones.

Junto con estos servicios, el servidor de aplicaciones proporciona tecnologías que permiten el acceso a un conjunto de recursos externos:

  • JDBC: proporciona acceso a bases de datos relacionales SQL. El servidor de aplicaciones Glassfish incluye por defecto la base de datos Java DB (Derby).
  • Mensajes: la tecnología JMS permite la comunicación asíncrona entre aplicaciones y objetos Java.
  • Conectores: la tecnología de conectores permite la integración entre aplicaciones Java y aplicaciones EIS (Enterprise Information System) ya existentes. Una aplicación Java accede a un EIS mediante un componente portable llamado conector o adaptador de recurso (resource adapter).
  • JavaMail: con el API JavaMail las aplicaciones pueden conectarse con un servidor SMTP para enviar y recibir correo.
  • Administración del servidor: La parte inferior derecha de la figura muestra un conjunto de tareas realizadas por el administrador del servidor de aplicaciones. El servidor de aplicaciones proporciona herramientas que permiten la realización de estas tareas.

Frente a la tradicional estructura en dos capas de un servidor web (ver siguiente figura) un servidor de aplicaciones proporciona una estructura en tres capas que permite estructurar nuestro sistema de forma más eficiente. Un concepto que debe quedar claro desde el principio es que no todas las aplicaciones de empresa necesitan un servidor de aplicaciones para funcionar. Una pequeña aplicación que acceda a una base de datos no muy compleja y que no sea distribuida probablemente no necesitará un servidor de aplicaciones, tan solo con un servidor web (usando servlets y jsp) sea suficiente.

Arquitectura en dos capas frente a tres capas utilizando el servidor de aplicaciones.

Como hemos comentado, un servidor de aplicaciones es una implementación de la especificación JavaEE. Existen diversas implementaciones, cada una con sus propias características que la pueden hacer más atractiva en el desarrollo de un determinado sistema. Algunas de las implementaciones más utilizadas son las siguientes:

  • BEA WebLogic (Oracle)
  • JBoss (RedHat)
  • Glassfish (Sun, ahora Oracle)
  • Websphere (IBM)

Se puede consultar en esta página de la wikipedia una lista completa de servidores de aplicaciones compatibles con Java EE.

Nosotros vamos a utilizar el servidor Glassfish de Sun. La principal ventaja de Glassfish es que proporciona la implementación de referencia de la especificación Java EE. Se trata también de un servidor de aplicaciones rápido, ligero y fácil de administrar. Es también multiplataforma, pudiéndose instalar en Linux, Windows o Mac Os X.

Otros conceptos que aparecerán a lo largo de este módulo:

  • Servidor proxy: Centraliza peticiones de los clientes y las reenvía hacia otras máquinas. Puede servir como nivel de indirección y seguridad. También puede ser usado para realizar balanceo de carga.
  • Cortafuegos (firewall): Proporciona servicios de filtrado, autorización y autentificación. Puede actuar como proxy y ayuda a manejar los ataques de los hackers.
  • Máquina: Representa una unidad física donde reside un servidor. Una máquina se define como tipo Unix o no Unix (Windows NT, etc.).
  • Servidor: Un servidor es una instancia de la clase Server ejecutándose dentro de una máquina virtual de Java. Un servidor está alojado en una máquina, pero una máquina puede contener varios servidores.
  • Dominio: Un dominio es una unidad administrativa. Sirve para declarar varios servidores, aplicaciones, etc. y que todos ellos estén asociados mediante el nombre del dominio.
  • Clustering (asociación): Los clusters permiten asociar maquinas y servidores para que actúen de forma conjunta como una única instancia. La creación de un cluster va a permitir el balanceo de carga y la recuperación frente a fallos.
  • Balanceo de carga: Es una técnica utilizada para distribuir las peticiones entre varios servidores de tal forma que todos los servidores respondan al mismo número de peticiones.
  • Recuperación ante fallos (failover): Permite evitar la caída de un sistema cuando una máquina deja de funcionar o funciona incorrectamente.
  • Puerto de escucha: Un servidor tiene varios puertos por los que puede "escuchar" las peticiones. Existen puertos ya asignados a aplicaciones concretas, como por ejemplo el puerto de http que suele ser el 80. Los puertos permiten que varias aplicaciones puedan atender distintas peticiones en la misma máquina. Un puerto en una dirección se especifica de la siguiente manera: http://localhost:7001/direc . Con :7001 indicamos el puerto que estamos atacando. Los puertos del 0 al 1023 son reservados por el sistema. Podemos disponer de los puertos del 1024 al 65536. Hay que tener en cuenta que dos servicios no pueden estar escuchando en el mismo puerto.

Características de Glassfish v3

Glassfish es el servidor de aplicaciones de Oracle/Sun y en su versión 3 (la actual) está preparado para trabajar con Java EE 6. El servidor es open source, aunque existe una versión comercial llamada Glassfish Enterprise Server. La diferencia entre ambas es el soporte que ofrece Oracle, junto con los parches y algunas herramientas adicionales de monitorización. Glassfish 3.1 incluye características avanzadas como el soporte de replicación en memoria, balanceo de carga, soporte para cluster, etc. La versión 3.0, al ser una versión inicial de la 'nueva generación' de Glassfish, todavía no tiene estas características. Todas las versiones incorporan una BD propia llamada Derby.

La versión 3 del servidor es totalmente modular, basada en OSGI, lo que nos permite usar solo los módulos que necesitemos y reducir así la carga del servidor en memoria. Esta es una importante ventaja con respecto a la versión 2, que es monolítica y requiere mayor memoria y un tiempo mayor para arrancar.

GlassFish proporciona una completa consola de administración (aplicación web) desde la que controlar y configurar el servidor de aplicaciones. Además incluye herramientas en línea de comandos y un servicio web de tipo REST.

A lo largo de este módulo iremos estudiando distintas funcionalidades de la consola gráfica y del resto de herramientas de administración.

Dominios

Un dominio define un conjunto de propiedades, recursos e instancias de servidores de aplicaciones. La definición de dominios permite flexibilizar y organizar la instalación de servidores de aplicaciones, ya que es posible asignar distintos dominios dentro de un mismo host a distintas organizaciones y administradores. Las aplicaciones y recursos instaladas en un dominio son independientes de los otros dominios. Para permitir que distintos dominios puedan estar en marcha al mismo tiempo, cada dominio utiliza distintos puertos de servicio y administración.

El instalador de Glassfish crea un dominio por defecto llamado domain1 y en él crea un servidor llamado server. Veremos en la siguiente sesión que un dominio puede definir más de un servidor. El puerto en el que escucha el servidor de administración del dominio por defecto es el 4848.

Cuando se crea un dominio y se pone en marcha, se inicializa el Domain Administration Server (DAS) del dominio, una aplicación que está a la escucha y que permite configura las características del dominio. La consola de administración se comunica con el DAS para enviarle peticiones. El DAS se comunica con los servidores del dominio para que realicen las peticiones. En la documentación de Sun, a veces se refieren al DAS como el servidor de administración o el servidor por defecto. El DAS es simplemente una instancia de servidor con capacidades adicionales de administración. Cada sesión de la consola de administración nos permite configurar y gestionar un único dominio.

Toda la configuración del dominio se guarda en el fichero domain.xml situado en el directorio domains/_dominio_/config. En el fichero se encuentran todos los detalles sobre los distintos elementos definidos en el dominio (como servidores, agentes de nodo, aplicaciones desplegadas, recursos, servicios, etc.) así como características de la configuración básica (puertos y hosts en los que se ejecutan los distintos servicios, ficheros de contraseñas, etc.)

Por último, la definición de dominios nos da la posibilidad de realizar copias de seguridad y de mover instalaciones de un host a otro. Para que funcionen correctamente las copias de seguridad el servidor de aplicaciones debe estar instalado exactamente en la misma ruta en ambas máquinas.

Comandos

El comando para crear un dominio es asadmin create-domain. Por ejemplo:

  • $ asadmin create-domain --adminport 5000 dominio2: crea un dominio con perfil de desarrollador con el nombre dominio2 administrado en el puerto 5000.
  • $ asadmin crate-domain --adminport 5000 --profile cluster cluster-domain: crea un dominio llamado cluster-domain con perfil de cluster y administrado en el puerto 5000.

En ambos comando el script solicitará el login de administrador y la contraseña para acceder posteriormente a la consola de administración del dominio.

El comando para borrar un dominio es asadmin delete-domain nombre-dominio. El dominio no debe tener ningún servidor en marcha. Por ejemplo:

$ asadmin delete-domain domain1

En las versiones 2.1 y 3.1 de glassfish se pueden hacer copias de seguridad del dominio para restaurarlas con posterioridad ante cualquier problema o llevar el dominio a otra máquina. Por desgracia en la versión 3.0 esto no está implementado. Para la copia se utiliza el comando asadmin backup-domain dominio. Por ejemplo:

$ asadmin backup-domain domain1

El comando crea un fichero ZIP que contiene toda la información del dominio en el directorio domain1/backups.

Podemos restaurar el dominio con el comando asadmin restore-domain dominio. El fichero de backup debe encontrarse en el directorio backups del dominio. Por ejemplo:

$ asadmin retore-domain domain1

También es posible restaurar un dominio que se ha borrado completamente del directorio de dominios (o copiar un dominio en otra instalación del servidor de aplicaciones). Para ello hay que indicar el fichero ZIP con el domino comprimido y el nombre del dominio. Supongamos que hemos copiado en el escritorio el fichero de backup del dominio y que hemos borrado completamente el dominio del directorio de dominios. Se restauraría con la instrucción:

$ asadmin restore-domain --filename ~/Escritorio/sjsas_backup_v00001.zip domain1
Más información
Para más detalles sobre parámetros adicionales de los comandos, consultar el manual de referencia de "Glassfish Enterprise Server".

Despliegue de aplicaciones web

Existen básicamente dos formas de desplegar una aplicación web en un dominio, desplegando directamente en un directorio o bien mediante la consola de administración. En ambos casos es necesario tener la aplicación empaquetada en un fichero WAR.

Despliegue en un directorio

Basta copiar el fichero WAR de la aplicación a desplegar en el directorio autodeploy del dominio. El servidor detecta la aplicación (hay que esperar un poco) y la pone en marcha. Cuando haga esto veremos que se ha creado en el directorio el fichero application.war_deployed.

Consola de administración

Para instalar una aplicación desde la consola de administración del dominio hay que seleccionar la opción Web Applications y escoger la opción Implementar... (la traducción a castellano de Deploy). Tenemos dos formas de indicar la aplicación, o indicando una ruta accesible desde el servidor en la que se encuentra la aplicación o proporcionándole un fichero WAR que se copia en el servidor.

En el primer caso el servidor trabaja directamente con el fichero (lo que es interesante si estamos en modo de desarrollo, probando y cambiando funcionalidades) y en el segundo copia el fichero al directorio del dominio donde se encuentran las aplicaciones instaladas. En la misma pantalla de despliegue de aplicaciones web aparece la información de la ruta final en la que queda instalada la aplicación.

Archivos EAR: empaquetamiento de aplicaciones enterprise

Hasta ahora hemos utilizado dos tipos de ficheros para empaquetar aplicaciones Java: ficheros JAR y ficheros WAR. Vamos a repasar algunos conceptos fundamentales, antes de explicar el nuevo tipo de fichero que introduciremos en esta sesión, el fichero EAR.

Los ficheros JAR empaquetan clases Java. Un fichero JAR contiene clases Java compiladas (ficheros .class) junto con un descriptor de la aplicación.

Cuando un fichero JAR se añade al claspath de una JVM (Máquina Virtual Java) las clases incluidas en él se ponen a disposición de cualquier aplicación Java que ejecute la JVM. De la misma forma, cuando un fichero JAR se define en el classpath del compilador Java, las clases incluidas en él pueden utilizarse en las clases que estamos compilando.

Una idea fundamental relacionada con el empaquetamiento de clases es que el compilador Java y la máquina virtual Java tienen distintos classpath, esto es, buscan las clases auxiliares en distintos directorios. Cuando estamos desarrollando una aplicación con un IDE, debemos decirle al IDE (que a su vez se lo dice a su compilador Java) dónde se encuentran los ficheros JAR con las clases auxiliares que estamos utilizando. Por ejemplo, si nuestra aplicación utiliza log4j debemos indicarle al IDE que las clases del API se encuentran, por ejemplo, en el fichero log4j-1.2.13.jar (e indicar su path). A su vez, cuando ejecutamos la aplicación, la JVM debe contener en su classpath un fichero que contenga esas clases. Podría ser incluso un fichero distinto, por ejemplo log4j-1.2.15.jar. Lo único necesario es que contenga las mismas clases (mismos nombres e interfaces) que las usadas en la compilación.

Las aplicaciones web empaquetadas en ficheros WAR son aun más complicadas. Una aplicación web debe desplegarse en un contenedor que está siendo ejecutado por una JVM. Parece el juego de las muñecas chinas. ¿Qué sucede aquí con los classpath?. ¿Cómo indicar dónde se encuentran el API log4j, por ejemplo? Ya lo sabemos. Lo más habitual es incluir el fichero JAR en el directorio WEB-INF/lib del fichero WAR. El estándar de Java que define el comportamiento de los ficheros WAR indica que ese directorio se incluirá en el classpath del contenedor para las clases de la aplicación web desplegada. Esto es, basta con incluir en ese directorio todas las librerías que usa nuestra aplicación web para que estén disponibles en tiempo de ejecución (y también en tiempo de compilación, ya que el IDE también lo reconoce). ¿Existen otras opciones? ¿Qué sucede si queremos desplegar más de una aplicación web en el contenedor y todas utilizan las mismas librerías? ¿Debemos incluir estas librerías de forma repetida en todos los WAR? La respuesta es que no. Hay dos formas de evitarlo.

Una posible opción para que distintas aplicaciones web (cada una desplegada en un WAR) puedan usar las mismas clases auxiliares es instalar el fichero JAR con las clases en el propio servidor web (en un path definido por el servidor). Los contenedores web suelen tener un directorio estándar en el que colocar ficheros JAR, y suelen revisar de forma dinámica ese directorio y poner todos sus JAR en el classpath de las aplicaciones web que tienen desplegadas. De esta forma, por ejemplo, colocando en ese directorio el fichero log4j-1.2.15.jar cualquier aplicación web puede usar el API sin estar incluido en su fichero WAR.

La otra opción nos lleva directamente a los fichero EAR. Los ficheros EAR (Enterprise Archive) son la forma estándar de empaquetar en un único fichero distintas aplicaciones web (ficheros WAR) y distintos ficheros JAR con clases Java. Los ficheros JAR que se incluyan en el EAR se ponen a disposición de cualquier aplicación WAR incluida en el EAR. Esto es, cuando un fichero EAR con un conjunto de ficheros JAR y ficheros WAR se despliega en el servidor web (o servidor de aplicaciones) todos sus JAR se incluyen de forma automática en el classpath de cada WAR. De esta forma, siguiendo con el ejemplo anterior, incluyendo en el EAR el fichero log4j-1.2.15.jar, cualquier aplicación WAR incluida en el EAR puede usar el API log4j sin tener que contener el fichero físicamente en su directorio WEB-INF/lib. Un fichero EAR representa una aplicación enterprise formada por distintos módulos (aplicaciones web y ficheros JAR). Los ficheros JAR pueden ser Enterprise JavaBeans (EJB) usados por las aplicaciones web. También pueden ser aplicaciones cliente que usan los EJB desplegados en el EAR y que se ejecutan en un contenedor de aplicaciones clientes en máquinas cliente. Veremos más adelante estos módulos.

contenido de un fichero EAR

Físicamente, un fichero EAR es un fichero comprimido con el mismo formato que los ficheros JAR. Todos los comandos que se pueden utilizar con los ficheros JAR (jar -tvf mi-fichero.jar, etc.) sirven para los ficheros EAR. Los ficheros EAR llevan la extensión .ear. La estructura de un fichero EAR es muy sencilla, contiene un conjunto de ficheros WAR, un conjunto de ficheros JAR y el directorio META-INF, en el que se encuentra los distintos ficheros de configuración necesarios. Como mínimo debe contener el descriptor de despliegue application.xml en el que se identifican los módulos que se incluyen en él.

Referencias