ANÁLISIS Y USO DE FRAMEWORKS DE PERSISTENCIA EN JAVA · Análisis y Uso de Frameworks de...

193
PROYECTO FIN DE CARRERA ANÁLISIS Y USO DE FRAMEWORKS DE PERSISTENCIA EN JAVA Autor: Alfredo Payá Martín Director: José Miguel Ordax Cassá UNIVERSIDAD PONTIFICIA COMILLAS ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI) INGENIERO TÉCNICO EN INFORMÁTICA DE GESTIÓN INGENIERO TÉCNICO EN INFORMÁTICA DE SISTEMAS

Transcript of ANÁLISIS Y USO DE FRAMEWORKS DE PERSISTENCIA EN JAVA · Análisis y Uso de Frameworks de...

PROYECTO FIN DE CARRERA

ANÁLISIS Y USO DE FRAMEWORKS DE PERSISTENCIA EN JAVA

Autor: Alfredo Payá Martín Director: José Miguel Ordax Cassá

UNIVERSIDAD PONTIFICIA COMILLAS

ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI) INGENIERO TÉCNICO EN INFORMÁTICA DE GESTIÓN

INGENIERO TÉCNICO EN INFORMÁTICA DE SISTEMAS

Análisis y Uso de Frameworks de Persistencia en Java

I

Agradecimientos

Gracias a todos.

A mi familia que me ha apoyado durante toda la carrera. Pero en

especial a mis padres, por esta gran oportunidad.

A Esther, que me ha ayudado a sentar la cabeza, y ha sufrido todas las

horas de trabajo dedicadas al proyecto sacrificando preciosos días de

vacaciones.

A todos mis amigos y compañeros de clase, por haberme animado y

apoyado durante todos los años de carrera.

Análisis y Uso de Frameworks de Persistencia en Java

II

Resumen

Análisis y Uso de Frameworks de Persistencia en Java

III

RESUMEN

Este proyecto pretende realizar un análisis completo de las diferentes

alternativas que hay para conseguir la persistencia de datos en Java. A continuación, se

construirá una aplicación Web para la explotación de datos empleando una de las

alternativas analizadas en un principio. Como consecuencia, el proyecto va a estar

formado por dos partes bien diferenciadas, una primera parte teórica y otra práctica.

La motivación que inspira este proyecto es fácil de explicar. Lo más importante

para una empresa son los datos que maneja. Todos los elementos que conforman una

empresa están reflejados en datos, desde los empleados hasta los clientes, desde los

recursos que posee hasta los productos que vende, etc. La información y características

asociadas de estos elementos siempre pueden ser útiles y, en otros casos, indispensables

para el funcionamiento de la empresa.

¿Qué sería de un banco si tiene problemas a la hora de manejar los datos de sus

clientes? ¿Y los datos de sus transacciones? Es evidente que los datos conforman el

corazón de las empresas y, por esta razón, es crucial la forma de manejarlos.

Toda la información que posee cualquier empresa, generalmente, está

almacenada en forma de tablas que comparten datos y conforman bases de datos

relacionales. Si los accesos a la información toman un papel importante en las

operaciones rutinarias empresariales, es normal que la forma de explotar esos datos

Análisis y Uso de Frameworks de Persistencia en Java

IV

tenga una repercusión directa en la eficiencia de la empresa. Dada la trascendencia que

toman los accesos a dicha información, se puede afirmar que la forma de realizar

consultas a las bases de datos es tan importante como el diseño de sus tablas.

Hoy en día Java sigue siendo un lenguaje en pleno desarrollo. Su falta de

sencillez a la hora de trabajar con bases de datos, ha provocado la aparición de

diferentes frameworks que facilitan estas tareas. Existen diversas alternativas que

aportan métodos diferentes: Hibernate, EJB’s, JDO, o, sencillamente, JDBC. La

eficiencia de dichas alternativas será definitiva a la hora de manejar bases de datos con

Java.

Ahora, si nos paramos a pensar en las aplicaciones prácticas de esta tecnología

veremos que una gran forma de aprovechar estas tecnologías es la explotación de tablas

en un entorno Web. Por ejemplo, en una empresa sería de gran utilidad que, a través de

un portal común, los empleados de los diferentes departamentos puedan hacer consultas

directamente sobre las bases de datos de una forma sencilla e intuitiva. Gracias a los

perfiles de usuario, un mismo portal serviría a todos los componentes de la empresa.

Todo el mundo tendría un acceso cómodo, rápido y sin intermediarios a la información

que necesite en cada momento, dentro de una selección de los datos más usados por los

departamentos. A su vez, el departamento de informática sería el encargado del

mantenimiento del portal. Esto se puede realizar con tecnología J2EE y una de las

alternativas de persistencia de datos.

Análisis y Uso de Frameworks de Persistencia en Java

V

ABSTRACT

This proyect tries to do a complete analysis of the most important alternatives

that can be found in order to persist data with Java. Next, a web application will be

designed and built using one of the alternatives studied in the first place. This way, the

proyect will be divided into two different parts, theoretical and practical.

The motivation that inspires this proyect is easy to explain. The most important

thing about any company is the data management. Every component of the system is

going to be represented by data: employees and clients, products and resources... The

information associated to these elements is always useful, and many times is essential.

What would happen to a bank if it finds difficulties when managing the data

about its clients? And what would happen with the transactions? It is obvious that the

data is the heart of the companies and, because of this, its management is critical.

All the information about a company is usually stored with the help of relational

data bases. If the access to the information is important when doing daily operations in a

company, it is normal that the way used to get the data is linked to the company’s

efficiency. This means that the way used to get the information is as important as the

data base design

Análisis y Uso de Frameworks de Persistencia en Java

VI

Today, Java is still a growing technology. The complicated process involved

while working with data bases has caused the release of frameworks in order to make

the task a little easier. There are different alternatives such as Hibernate, JDO, EJB or

just JDBC. The efficiency of this layer will be critical while working with data bases.

Now, one of the possible ways to take advantage with these technologies is to

manage data bases through a web application. For example, it would be useful for a

company that the employees of the different departments could consult some data bases

trough a web site. The same site would provide services to everyone using different user

profiles. Every employee would have a fast and easy access to the information required

related to his department. This could be build with J2EE (Java 2 Enterprise Edition) and

one of the alternatives to persist data.

Análisis y Uso de Frameworks de Persistencia en Java

VII

Índice

Análisis y Uso de Frameworks de Persistencia en Java

VIII

ÍNDICE

1. Introducción……………………………………………………………………...1

2. Definición del Problema…………………………………………………………3

3. Análisis de las Tecnologías……………………………………………………...6

3.1. Objetivos…………………………………………………………………7

3.2. Alternativas de Persistencia……………………………………………...9

3.2.1. Introducción…….…………………………………………………9

El Mapeo Objeto-Relacional (ORM)…………………………….9

JDBC: Componente indispensable para los ORM……………...12

3.2.2. Tecnologías basadas en el estándar………………………………15

Java Data Objects (JDO) – Definición………………………….15

Enterprise Java Beans (EJB) de Entidad – Definición………….18

3.2.3. Tecnologías Open Source: Hibernate – Definición……………...20

3.3. Funcionamiento de las Alternativas…………………………………….21

3.3.1. Tecnologías basadas en el estándar………………………………21

Java Data Objects (JDO) – Funcionamiento……………………21

Crear un Objeto…………………………………………21

Crear un Gestor de Persistencia…………………………23

Crear un Descriptor JDO para el JDOEnhancer………...30

Construir y Ejecutar la Aplicación……………………...31

El Lenguaje de Consulta JDOQL……………………….35

Enterprise Java Beans (EJB) de Entidad – Funcionamiento……37

Persistencia Manejada por el Contenedor (CMP)………37

Análisis y Uso de Frameworks de Persistencia en Java

IX

La Clase Bean…………………………………..38

Interface Home………………………………….43

Interface Remoto………………………………..46

Métodos de Retrollamada……………………….48

Persistencia Manejada por el Bean (BMP)……………..53

3.3.2. Tecnologías Open Source: Hibernate – Funcionamiento………..62

Creación del Objeto……………………………………..63

Persistencia……………………………………………...65

El Fichero de Mapeo……………………………………67

Configuración de la Base de Datos……………………..71

Construcción y Ejecución……………………………….73

3.4. Evaluación……………………………………………………………...76

JDO vs. EJB…………………………….....................................76

JDO vs. JDBC/SQL…………………………………………….77

Hibernate vs. JDO………………………………………………79

3.5. Conclusiones……………………………………………………………80

4. Diseño y Desarrollo de la Aplicación Web…………………………………….84

4.1. Objetivos………………………………………………………………..85

4.2. Descripción de la Aplicación…………………………………………...86

4.3. Requisitos funcionales………………………………………………….87

4.3.1. Actores Participantes……………………………………………87

4.3.2. Casos de uso…………………………………………………….88

Descripción detallada de los Casos de Uso……………..90

Diagramas de Casos de Uso…………………………...100

4.4. Diseño Externo………………………………………………………..103

Análisis y Uso de Frameworks de Persistencia en Java

X

4.4.1. Diseño del Interfaz del Usuario……………………………….103

Inicio…………………………………………………...103

Navegación Básica…………………………………….105

Gestión de Pacientes…………………………………...108

Gestión de Alergias……………………………………111

Gestión del Portal (Noticias y Cuentas de Usuario)…...114

Cierre de Sesión………………………………………..120

4.5. Diseño Interno…………………………………………………………121

4.5.1. JSP y Servlets………………………………………………….121

4.5.2. Diagrama de navegación………………………………………126

4.5.3. Diagramas de clases…………………………………………...127

Clases Objeto…………………………………………..128

Clases de Acceso a la Base de Datos………………….131

4.5.4. Modelo de datos……………………………………………….133

5. La alternativa a JDBC: Hibernate……………………………………………..135

5.1. Las clases a persistir…………………………………………………..136

5.2. Los ficheros de mapeo………………………………………………...147

5.3. Las clases gestoras de objetos…………………………………………152

5.4. Implantación…………………………………………………………..172

5.4.1. Instalación y Configuración…………………………………...172

5.4.2. Requisitos del Sistema………………………………………...174

6. Presupuesto……………………………………………………………………175

7. Conclusiones.………….………………………………………………………177

8. Bibliografía……………………………………………………………………180

Análisis y Uso de Frameworks de Persistencia en Java

1

1- Introducción

Análisis y Uso de Frameworks de Persistencia en Java

2

1- INTRODUCCIÓN

El fin de este proyecto es dar a conocer ciertas alternativas a JDBC a la hora de

persistir objetos Java en bases de datos relacionales, así como ver su funcionamiento en

una aplicación real. Una forma de abordar el problema es realizar un análisis de las

alternativas más importantes que están a nuestra disposición.

Conocer el funcionamiento de las diferentes alternativas da pie a enfrentarlas y a

poder comparar su servicio al problema de la persistencia. Sin embargo, cada una de las

tecnologías tiene su propio origen y filosofía para alcanzar el mismo fin y, por esta

razón, no será fácil analizar sus ventajas y desventajas frente a las demás alternativas.

Una vez terminado el análisis de las tecnologías, se procederá a diseñar una

aplicación Web que se caracterice por su necesidad de persistir objetos. Dicha

aplicación contará con diversas funciones relacionadas con los accesos a bases de datos,

especialmente la persistencia de objetos Java.

La fase final del proyecto consistirá en introducir en la aplicación una de las

tecnologías analizadas. Dicha tecnología será seleccionada por ser la más adecuada, y se

encargará de realizar la tarea de persistir objetos, sirviendo de enlace entre la lógica y la

interacción con una base de datos. La aplicación será construida en un principio con

JDBC y sentencias SQL de forma que, al introducir la tecnología, se podrá ver

claramente la gran función que es capaz de desempeñar un framework de persistencia.

Análisis y Uso de Frameworks de Persistencia en Java

3

2- Definición del Problema

Análisis y Uso de Frameworks de Persistencia en Java

4

2- DEFINICIÓN DEL PROBLEMA

La persistencia de datos en Java viene facilitada por mapeadores

Objeto/Relacionales (O/R). Estas tecnologías conforman técnicas de programación para

enlazar un lenguaje de programación orientado a objetos con una base de datos

relacional. Los mecanismos de mapeo O/R permiten al programador mantener una

perspectiva orientada a objetos y cuidar que se consiga aportar una solución a la lógica

de negocio, eliminando el obstáculo que supone compatibilizar objetos con modelos

relacionales. El framework para la persistencia de datos se ocupa de todos los detalles

que conllevaría desarrollar un mecanismo de mapeo personalizado.

Hoy en día, uno de los asuntos más debatidos y discutidos más apasionadamente

en la industria del software es: ¿cuál de las tecnologías de persistencia (o frameworks

para el mapeo Objeto/Relacional) merece ser la alternativa dominante? Esta discusión

ha creado una división en la comunidad Java. Mientras esto siga así, dicho debate

seguirá en pie y los desarrolladores de software deberán elegir la tecnología que mejor

se adapte a sus necesidades, y esto se debe extender a cualquier componente que

conforme la arquitectura del sistema completo, incluyendo el driver JDBC.

Análisis y Uso de Frameworks de Persistencia en Java

5

En la figura podemos observar la estructura básica de una aplicación Web

desarrollada con Java empleando Servlets y JSP. La lógica de la aplicación localizada

en el servidor contiene, entre otros, un módulo (representado por una estrella roja) que

será el encargado de interactuar con las bases de datos. Todas y cada una de las

consultas y modificaciones que deba realizar la aplicación sobre las bases de datos

dependerán de la implementación del módulo en cuestión. Es en esa parte de la lógica

del programa donde entran en escena los frameworks de persistencia.

Análisis y Uso de Frameworks de Persistencia en Java

6

3- Análisis de las Tecnologías

Análisis y Uso de Frameworks de Persistencia en Java

7

3- ANÁLISIS DE LAS TECNOLOGÍAS

3.1.- OBJETIVOS

• Definición de las alternativas

Es necesario conocer qué alternativas de persistencia son las más

importantes actualmente. Se pretende definir cuáles son las se van a barajar y

cuáles son sus orígenes. Se especificará cómo cada una de las alternativas está

asociada a una organización o comunidad de desarrollo, así como su filosofía.

• Descripción de su funcionamiento

Se pretende conocer el funcionamiento de cada una de las alternativas

analizadas de una forma sencilla. Para ello es necesario explicar paso a paso la

metodología a seguir para conseguir la persistencia de los objetos, mostrando

ejemplos y código fuente.

• Evaluación: Características más relevantes

Análisis y Uso de Frameworks de Persistencia en Java

8

Antes de finalizar el análisis, se pretende identificar las características

más relevantes de cada una de las alternativas estudiadas. De esta forma,

enfrentando unas con otras se dará pie a obtener conclusiones.

• Conclusiones

A continuación, se obtendrán diversas conclusiones acerca de la

información reunida en los puntos anteriores.

Por último, para dar sentido al estudio, se elegirá la alternativa de

persistencia más apropiada para suplir la codificación JDBC empleada en la

aplicación que se desarrolle a continuación, incorporándola al servidor.

Análisis y Uso de Frameworks de Persistencia en Java

9

3.2- ALTERNATIVAS DE PERSISTENCIA

3.2.1. Introducción

El Mapeo Objeto-Relacional (ORM)

Si se está trabajando con programación orientada a objetos y bases de

datos relacionales, es fácil observar que estos son dos paradigmas diferentes. El

modelo relacional trata con relaciones y conjuntos, y es muy matemático por

naturaleza. Sin embargo, el paradigma orientado a objetos trata con objetos, sus

atributos y asociaciones de unos con otros.

Tan pronto como se quieran persistir los objetos utilizando una base de

datos relacional se puede observar que hay un problema de compatibilidad entre

estos dos paradigmas, la también llamada diferencia objeto-relacional.

Un mapeador objeto-relacional (ORM) es de gran ayuda para evitar esta

diferencia. Esta diferencia se manifiesta cuando se tienen diversos objetos en

una aplicación y se alcanza el punto donde es oportuno que sean persistentes. En

este caso se debe abrir una conexión JDBC, crear una sentencia SQL y copiar

todos los valores de las propiedades de los objetos sobre la selección. Esto

Análisis y Uso de Frameworks de Persistencia en Java

10

podría ser fácil para un objeto pequeño, pero si se considera para un objeto con

muchas propiedades, la labor se convierte en un proceso incómodo.

Este no es el único problema. Las asociaciones entre objetos también hay

que tenerlas en cuenta, así como las restricciones de claves. Lo mismo se puede

aplicar para la carga. Si se asume que se carga un objeto desde la base de datos y

que tiene una colección asociada. A la hora de carga el objeto ¿se cargará

también la colección? Si se cargan también los elementos de la colección, se

considerará que cada objeto elemento tiene una asociación con todavía más

objetos. En este caso, sería mejor cargar todo el árbol de objetos.

Por tanto, la diferencia objeto-relacional se amplia muy rápidamente

cuando se está trabajando con grandes modelos de objetos. Y hay muchas más

cosas a considerar como la carga lenta, las referencias circulares, el caché, etc.

Como detalle, se han realizado estudios que demuestran que el 35% del código

de una aplicación se produce para mapear datos entre la aplicación y la base de

datos.

Para la mayoría de las aplicaciones, almacenar y recuperar información

implica alguna forma de interacción con una base de datos relacional. Esto ha

representado un problema fundamental para los desarrolladores porque algunas

veces el diseño de datos relacionales y los ejemplares orientados a objetos

Análisis y Uso de Frameworks de Persistencia en Java

11

comparten estructuras de relaciones muy diferentes dentro de sus respectivos

entornos.

Las bases de datos relacionales están estructuradas en una configuración

tabular y los ejemplares orientados a objetos normalmente están relacionados en

forma de árbol. Esta 'diferencia de impedancia' ha llevado a los desarrolladores

de varias tecnologías de persistencia de objetos a intentar construir un puente

entre el mundo relacional y el mundo orientado a objetos.

Persistir objetos Java en una base de datos relacional es un reto único que

implica serializar un árbol de objetos Java en una base de datos de estructura

tabular y viceversa. Este reto actualmente está siendo corregido por varias

herramientas diferentes. La mayoría de estas herramientas permite a los

desarrolladores instruir a los motores de persistencia de cómo convertir objetos

Java a columnas/registros de la base de datos y al revés. Esencial para este

esfuerzo es la necesidad de mapear objetos Java a columnas y registros de la

base de datos de una forma optimizada en velocidad y eficiencia.

Análisis y Uso de Frameworks de Persistencia en Java

12

JDBC: Componente indispensable para los ORM

La mayoría de las aplicaciones que son importantes en una empresa están

respaldadas por una arquitectura normalizada y optimizada de bases de datos

relacionales. Tradicionalmente, dichas aplicaciones están basadas en sentencias

SQL con las cuales se gestionan todos los datos que manejan.

Este modelo continúa teniendo una gran importancia estratégica y es la

base para el continuo crecimiento del mapeo Objeto-Relacional (O/R) y está

asociado a los mecanismos de persistencia.

El mapeo O/R es una herramienta muy útil para la programación en Java

puesto que el desarrollador se puede concentrar en la construcción de la

aplicación mientras que delega los detalles de la persistencia de datos al

framework de persistencia.

Hay múltiples alternativas para los programadores de Java cuando se

pretende trabajar con mapeadores O/R. Hay tres organizaciones o comunidades

que están implicadas en el mundo de la persistencia O/R de Java de forma

activa: organizaciones basadas en el estándar, comunidades open source y

grupos comerciales.

Las comunidades open source incluyen importantes tecnologías, entre ellas

Hibernate y el framework Spring. Las alternativas más importantes basadas en el

estándar, son EJB 3.0 y JDO. Entre las implementaciones comerciales se pueden

Análisis y Uso de Frameworks de Persistencia en Java

13

resaltar Oracle’s TopLink. Para este proyecto se analizarán las tecnologías open

souce y las basadas en el estándar.

Sin tener en cuenta el mecanismo de mapeo O/R que se vaya a utilizar

para comunicarse con la base de datos relacional, todos ellos dependen de

JDBC. Teniendo en cuenta que la mayor parte de las aplicaciones se comunican

con bases de datos relacionales, es fundamental considerar cada uno de los

niveles del software (desde el código del programa hasta la fuente de datos) para

asegurar que el diseño de persistencia O/R sea óptimo.

Tal y como se verá más adelante, cada uno de los mecanismos de mapeo

O/R tiene una dependencia particular en el driver JDBC para poder comunicarse

con la base de datos de una forma eficiente. Si el driver JDBC que va a

participar en la comunicación no es óptimo, la posible gran eficiencia de

cualquier framework quedará debilitada. Por tanto, elegir el driver JDBC que

mejor se adapte a la aplicación es esencial a la hora de construir un sistema

eficiente en el que participe un mecanismo de mapeo O/R.

Análisis y Uso de Frameworks de Persistencia en Java

14

La figura muestra una representación de los diferentes mecanismos de

mapeo O/R y cómo se relacionan con el código de la aplicación y con los

recursos de datos relacionados. Esto muestra claramente la función crítica que

desempeña el driver JDBC puesto que está situado en la base de cada uno de los

frameworks.

La eficiencia del driver JDBC tiene importantes consecuencias en el

comportamiento de las aplicaciones. Cada mecanismo de mapeo O/R es

completamente dependiente del driver, sin tener en cuenta el diseño de la API

del framework que esté expuesta al código fuente de la aplicación.

Como los mecanismos de mapeo O/R generan llamadas eficientes para

acceder a la base de datos, mucha gente defiende que la importancia del driver

JDBC se ha visto reducida. Sin embargo, como en cualquier arquitectura, la

Análisis y Uso de Frameworks de Persistencia en Java

15

totalidad de eficiencia en una aplicación siempre estará afectada por el nivel más

débil del sistema.

Independientemente del código JDBC generado, los mecanismos de

mapeo O/R son incapaces de controlar cómo los drivers interactúan con la base

de datos. Al fin y al cabo la eficiencia de la aplicación depende en gran parte de

la habilidad que tenga el driver del nivel JDBC para mover todos los datos

manejados entre la aplicación y la base de datos.

Aunque hay múltiples factores que considerar a la hora de elegir un

driver JDBC, seleccionar el mejor driver JDBC posible basándose en

comportamiento, escalabilidad y fiabilidad es la clave para obtener el máximo

beneficio de cualquier aplicación basada en un framework O/R.

3.2.2. Definición de las tecnologías basadas en el estándar

• Java Data Objects (JDO) – Definición

Java Data Objects (JDO) es una especificación desarrollada para

conseguir una persistencia de objetos Java de forma transparente. Es una API de

alto nivel que permite a las aplicaciones almacenar objetos Java en un almacén

Análisis y Uso de Frameworks de Persistencia en Java

16

de datos transaccional (ficheros y bases de datos) siguiendo unos estándares

predefinidos.

Esta API puede ser utilizada para acceder a datos en servidores o

sistemas embebidos. Además, las implementaciones de JDO pueden llegar a la

telefonía móvil, PDA y demás tecnologías wireless. Sin embargo, su función

más destacada es su capacidad para manejar como objetos cierta información

perteneciente a una base de datos relacional.

JDO ha sido creado bajo la dirección de la comunidad de Java y

documentado como una Especificación Java (JSAR 12). Craig Russell de Sun

Microsystems lideró a un grupo de expertos de varias compañías para desarrollar

la documentación.

Como con otras muchas tecnologías de Java, Sun Microsystems ha

lanzado una especificación y una referencia para la implementación. Además,

los vendedores están desarrollando productos compatibles con JDO.

La siguiente tabla muestra una lista de algunos vendedores:

Análisis y Uso de Frameworks de Persistencia en Java

17

Vendedores de JDO

Compañía Producto URL Asociada

SolarMetric Kodo JDO Enterprise Edition, Kodo

JDO Standard Edition

www.solarmetric.com

Poet Software

Corporation

FastObjects www.fastobjects.com

LiBeLIS LiDO www.libelis.com

Hemisphere

Technologies

JDO Genie www.hemtech.co.za/jdo

ObjectFrontier Inc. FrontierSuite for JDO www.objectfrontier.com

Versant Versant enJin www.versant.com

Sun Microsystems,

Inc.

Reference Implementation www.java.sun.com

Object Industries

GMBH

JRelay www.objectindustries.com

JDO ha sido diseñado para poderse incorporar fácilmente a servidores de

aplicación. Esto permite que la tecnología pueda asumir muchas funciones

ofrecidas también por las Enterprise Java Beans (EJB) de Entidad, CMP. Dicha

funcionalidad consiste en separar los objetos Java del código JDBC con sus

correspondientes sentencias SQL necesarios para acceder a las bases de datos.

Análisis y Uso de Frameworks de Persistencia en Java

18

JDO define un lenguaje de consulta conocido como JDOQL. Este

lenguaje está embebido dentro del interface javax.jdo.Query.

• Enterprise Java Beans (EJB) de Entidad – Definición

El bean de entidad es uno de los dos tipos de beans primarios: entidad y

sesión. El bean de entidad es usado para representar datos en una base de datos.

Proporciona un interface orientado a objetos a los datos que normalmente serían

accedidos mediante el JDBC u otro API. Más que eso, los beans de entidad

proporcionan un modelo de componentes que permite a los desarrolladores de

beans enfocar su atención en la lógica de negocio del bean, mientras el

contenedor tiene cuidado de manejar la persistencia, las transacciones, y el

control de accesos.

El objetivo de los EJB de entidad es encapsular los objetos de lado del

servidor que almacena los datos. Los EJBs de entidad presentan la característica

fundamental de la persistencia:

Análisis y Uso de Frameworks de Persistencia en Java

19

* Persistencia gestionada por el contenedor (CMP): el contenedor se

encarga de almacenar y recuperar los datos del objeto de entidad mediante un

mapeado en una tabla de una base de datos.

* Persistencia gestionada por el bean (BMP): el propio objeto entidad

se encarga, mediante una base de datos u otro mecanismo, de almacenar y

recuperar los datos a los que se refiere, por lo cual, la responsabilidad de

implementar los mecanismos de persistencia es del programador.

Con CMP, el contenedor maneja la persistencia del bean de entidad. Las

herramientas de los vendedores se usan para mapear los campos de entidad a la

base de datos y no se escribe ningún código de acceso a las bases de datos en la

clase del bean. Con BMP, el bean de entidad contiene código de acceso a la base

de datos (normalmente JDBC) y es responsable de leer y escribir en la base de

datos su propio estado. Las entidades CMP tienen mucha ayuda ya que el

contenedor alertará al bean siempre que sea necesario hacer una actualización o

leer su estado desde la base de datos. El contenedor también puede manejar

cualquier bloqueo o transacción, para que la base de datos se mantenga íntegra.

Análisis y Uso de Frameworks de Persistencia en Java

20

3.2.3. Tecnologías Open Source: Hibernate - Definición

Hibernate es un marco de trabajo de mapeo O/R Open Source que

evita la necesidad de utilizar el API JDBC. Hibernate soporta la mayoría de los

sistemas de bases de datos SQL. El Hibernate Query Language, diseñado como

una extensión mínima, orientada a objetos, de SQL, proporciona un puente

elegante entre los mundos objeto y relacional. Además, ofrece facilidades para

recuperación y actualización de datos, control de transacciones, repositorios de

conexiones a bases de datos, consultas programáticas y declarativas, y un control

de relaciones de entidades declarativas.

Hibernate es un servicio de alto rendimiento para la persistencia O/R.

Permite desarrollar clases que se pueden persistir y que son acordes con la

programación orientada a objetos, incluyendo asociación, herencia,

polimorfismo, composición y colecciones. Hibernate dispone de si propio

lenguaje llamado HQL, que ofrece portabilidad a SQL.

Hibernate es un proyecto profesional Open Source y un componente

crítico del catálogo de productos de JBoss Enterprise Middleware System

(JEMS). JBoss es una división de Red Hat, y ofrece servicios de mantenimiento,

consulta y entrenamiento para asistir a sus usuarios.

Análisis y Uso de Frameworks de Persistencia en Java

21

3.3- FUNCIONAMIENTO

3.3.1. Tecnologías basadas en el estándar

• Java Data Objects (JDO) - Funcionamiento

Para comprender el funcionamiento de JDO se pretende describir los

diversos pasos a seguir para construir una aplicación que permita realizar el

proceso de persistencia. Primero, se creará un objeto Persona (Person) para

persistirlo en la base de datos. A continuación, se creará el objeto

PersistePersona (PersistPerson) que será el encargado de gestionar el objeto

persona en la base de datos. Después se construirá un descriptor JDO para

decirle al JDOEnhancer qué es lo que deseamos persistir. Por último se verá qué

pasos se deben seguir para construir y ejecutar el sistema.

OBJETO:

Creación del objeto Persona (Person.java)

El objeto ‘Person’ incluye los métodos “getters” y “setters” para sus

atributos, tal y como es conveniente para cualquier clase de Java. Los únicos

requisitos para que una clase se pueda persistir son:

Análisis y Uso de Frameworks de Persistencia en Java

22

1. Sus atributos deben ser accesibles para las clases JDO (“public” o métodos

“setters”).

2. Los tipos de datos de los atributos deben estar permitidos por la JDO

specification.

3. Ciertos a tributos no son admitidos (por ejemplo, Thread, File o Socket, que

no son “serializable”.

Teniendo en cuenta los requisitos, la clase ‘Person.java’ podría tener este

aspecto:

public class Person { // -- ATRIBUTOS private String name; private String address; private String ssn; private String email; private String homePhone; private String workPhone; // -- CONSTRUCTOR public Person(String name, String address, String ssn, String email, String homePhone, String workPhone) { this.name = name; this.address = address; this.ssn = ssn; this.email = email; this.homePhone = homePhone; this.workPhone = workPhone; } // -- MÉTODOS public String getName() { return name; } public String getAddress() { return address; } public String getSsn() { return ssn; } public String getEmail() { return email; } public String getHomePhone() { return homePhone; } public String getWorkPhone() { return workPhone; }

Análisis y Uso de Frameworks de Persistencia en Java

23

// -- mutators public void setName(String name) { this.name = name; } public void setAddress(String address) { this.address = address; } public void setSsn(String ssn) { this.ssn = ssn; } public void setEmail(String email) { this.email = email; } public void setHomePhone(String homePhone) { this.homePhone = homePhone; } public void setWorkPhone(String workPhone) { this.workPhone = workPhone; } }

PERSISTENCIA:

Creación del objeto gestor de la persistencia (PersonPersist.java)

Una vez que se tiene un objeto ‘Person’ con el cuál podemos trabajar,

necesitamos crear un objeto que se encargue de gestionar su persistencia. Este

objeto será el ‘PersonPersist’. Seguidamente, por pasos, se realizarán diversas

operaciones con el objeto ‘Person’:

1. Inicializar el JDO Persistente Manager.

2. Persistir tres personas en la base de datos.

3. Mostrar el contenido de la base de datos.

4. Cambiar el nombre de una persona.

5. Borrar una de las personas.

6. Realizar las operaciones desde el método main ( ).

Análisis y Uso de Frameworks de Persistencia en Java

24

Paso 1º: Inicializar el JDO Persistence Manager

Aquí figura el principio de la codificación del objeto ‘PersistPerson’. Es

necesario importar las clases estándar de JDO y la ‘ManagedConnectionFactory’

desde la implementación de OpenFusion. El constructor asigna la “Connection

Factory”, empleando la propiedad ‘javax.jdo.PersistenceManagerFactoryClass’.

Esto es como asignar el driver de la base de datos si se trabaja con JDBC.

package addressbook; import java.util.*; import javax.jdo.*; import com.prismt.j2ee.connector.jdbc.ManagedConnectionFactoryImpl; public class PersonPersist { private final static int SIZE = 3; private PersistenceManagerFactory pmf = null; private PersistenceManager pm = null; private Transaction transaction = null; // Array de personas a persistir private Person[] people; // Vector de identificadores de objetos private Vector id = new Vector(SIZE); public PersonPersist() { try { Properties props = new Properties(); props.setProperty("javax.jdo.PersistenceManagerFactoryClass", "com.prismt.j2ee.jdo.PersistenceManagerFactoryImpl"); pmf = JDOHelper.getPersistenceManagerFactory(props); pmf.setConnectionFactory( createConnectionFactory() ); } catch(Exception ex) { ex.printStackTrace(); System.exit(1); } }

Análisis y Uso de Frameworks de Persistencia en Java

25

La “Connection Factory” se crea en un método estático llamado

‘createConnectionFactory()’. Esta factoría necesita la URL de JDBC, el driver

JDBC, un nombre de usuario y la contraseña. OpenFusion JDO también viene

con una ‘DBHelper’ que busca un fichero de propiedades que contiene las

propiedades a usar de la base de datos.

public static Object createConnectionFactory() { ManagedConnectionFactoryImpl mcfi = new ManagedConnectionFactoryImpl(); Object connectionFactory = null; try { mcfi.setUserName("scott"); mcfi.setPassword("tiger"); mcfi.setConnectionURL( "jdbc:oracle:thin:@localhost:1521:thedb"); mcfi.setDBDriver("oracle.jdbc.driver.OracleDriver"); connectionFactory = mcfi.createConnectionFactory(); } catch(Exception e) { e.printStackTrace(); System.exit(1); } return connectionFactory; }

Paso 2º: Persistir tres personas en la base de datos

El método ‘persistPeople()’ crea a tres personas, usando el constructor

que aparece en ‘Person.java’. Lo primero que ha de hacerse es conseguir un

gestor de persistencia a través del método ‘getPersistenceManager()’. Después

se ha de crear una transacción donde se hará la operación. Para persistir el array

de personas llamamos al método ‘makePersistentAll()’ sobre el “Persistence

Análisis y Uso de Frameworks de Persistencia en Java

26

Manager” (pm). El bucle for{}sirve para obtener un identificador por cada

persona persistida, guardándolos para usarlos en el futuro.

public void persistPeople() { // CREACION DEL ARRAY DE PERSONAS people = new Person[SIZE]; // CREACION DE TRES PERSONAS (FUTBOLISTAS INGLESES) people[0] = new Person("Gary Segal", "123 Foobar Lane", "123-123-1234", "[email protected]", "(608) 294-0192", "(608) 029-4059"); people[1] = new Person("Michael Owen", "222 Bazza Lane, Liverpool, MN", "111-222-3333", "[email protected]", "(720) 111-2222", "(303) 222-3333"); people[2] = new Person("Roy Keane", "222 Trafford Ave, Manchester, MN", "234-235-3830", "[email protected]", "(720) 940-9049", "(303) 309-7599)"); // PERSISTENCIA DEL ARRAY DE PERSONAS pm = pmf.getPersistenceManager(); transaction = pm.currentTransaction(); pm.makePersistentAll(people); transaction.commit(); // OBTENCION DE LOS IDENTIFICADORES for(int i = 0; i < people.length; i++) { id.add(pm.getObjectId(people[i])); } // CLAUSURA DEL GESTOR DE PERSISTENCIA // AHORA LOS OBJETOS SE LEERAN DE LA BASE DE DATOS pm.close(); }

He aquí algunos otros métodos que se pueden usar sobre el gestor de

persistencia. Hay tres categorías:

• Hace Instancias Persistentes. Persiste un objeto transitorio.

• Elimina Instancias Persistidas. Elimina información de la base de datos.

Análisis y Uso de Frameworks de Persistencia en Java

27

• Hace Instancias Transitorias. Rompe la asociación de las instancias con el

gestor de persistencia. Sin embargo, la base de datos mantiene la información.

Hace Instancia Persitente Elimina Instancia Persistida Hace Instancia Transitoria makePersistent(Object o)

deletePersistent(Object o)

makeTransient(Object o)

makePersistentAll(Object[] os)

deletePersistentAll(Object[] os)

makeTransientAll(Object[] os)

makePersistentAll(Collection os)

deletePersistentAll(Collection os)

makeTransientAll(Collection os)

Paso 3º: Mostrar el contenido de la base de datos

El código para mostrar el contenido de la base de datos comienza por

obtener el gestor de persistencia (‘getPersistenceManager()’). Para mostrar las

personas creadas anteriormente, es necesario obtener los identificadores

guardados a través del método ‘persistPeople()’. Una vez devueltos los objetos,

se puede ejecutar los métodos que tienen definidos, en este caso los Getters:

public void display(int end) { Person person; int max = end <= SIZE ? end : SIZE; // OBTENCION DEL GESTOR DE PERSISTENCIA pm = pmf.getPersistenceManager(); // OBTENCION DE LAS PERSONAS for(int i = 0; i < max; i++) { person = (Person) pm.getObjectById(id.elementAt(i), false); System.out.println("Name : " + person.getName()); System.out.println("Address : " + person.getAddress()); System.out.println("SSN : " + person.getSsn()); System.out.println("Email : " + person.getEmail());

Análisis y Uso de Frameworks de Persistencia en Java

28

System.out.println("Home Phone: " + person.getHomePhone()); System.out.println("Work Phone: " + person.getWorkPhone()); } pm.close(); }

Paso 4º: Cambiar el nombre de una persona

El código para cambiar información de una persona de la base de datos es

muy similar al necesario para mostrar la información de las personas, sencillamente,

se ha de ejecutar el método ‘setName()’ sobre la persona correspondiente. Sin

embargo, hay una diferencia muy importante: en este caso se está realizando una

transacción, ya que la fila en la base de datos se ha de modificar. Por tanto, hay que

utilizar el método ‘commit()’ para guardar los cambios, al igual que se ha hecho al

crear las personas. La única diferencia entre esta operación y trabajar con objetos

transitorios es que hay que verificar la transacción.

public void change() { Person person; // OBTENCION DEL OBJETO pm = pmf.getPersistenceManager(); transaction = pm.currentTransaction(); person = (Person) pm.getObjectById(id.elementAt(1), false); person.setName("Steve Gerrard"); // VERIFICACIÓN DEL CAMBIO transaction.commit(); pm.close(); }

Análisis y Uso de Frameworks de Persistencia en Java

29

Paso 5º: Eliminar una persona de la base de datos

Para eliminar un objeto persistido hay que obtenerlo y ejecutar el método

‘deletePersistent()’ sobre el mismo, tal y como se ha mencionado en el Paso 2º. En este

caso, también se está realizando una transacción. Además, el identificador del objeto

también es eliminado.

public void delete() { pm = pmf.getPersistenceManager(); transaction = pm.currentTransaction(); pm.deletePersistent(pm.getObjectById(id.remove(1), false)); transaction.commit(); pm.close(); }

Paso 6º: Realizar las operaciones desde el método ‘main ( )’

Por último, el programa que contiene todo el código anterior, tiene un

método ‘main ( )’ donde se crea la gente, se modifica y se borra.

public static void main(String[] args) { System.out.println("Create PersonPersist"); PersonPersist personPersist = new PersonPersist();

Análisis y Uso de Frameworks de Persistencia en Java

30

System.out.println("Setup and persist a group of people"); personPersist.persistPeople(); System.out.println("Display the persisted people"); personPersist.display(SIZE); System.out.println("Change a name "); personPersist.change(); personPersist.display(SIZE); System.out.println("Delete a person "); personPersist.delete(); personPersist.display(SIZE - 1); }

JDOEnhancer:

Crear un JDO Descriptor para el JDOEnhancer

Ahora se ha codificado toda la aplicación. El siguiente paso a seguir es crear un

“JDO Descriptor” que usará el JDOEnhancer.

¿Qué es el JDOEnhancer? La arquitectura JDO está construida con la idea de

que una implementación JDO puede “mejorar” el bytecode de las clases a persistir

manipulándolas, con el fin de añadir funcionalidades necesarias para los objetos. Por

ejemplo, el JDOEnhancer hará que el interface ‘PersistanceCapable’ esté implementado

en la clase (tarea que ahorra al codificador), así como algunos de los métodos del

interface. Por tanto, después de compilar el código, se deberá ejecutar el JDOEnhancer

para que realice las manipulaciones oportunas.

Es necesario crear un fichero “Descriptor” para darle al “Enhancer” la

información sobre las clases que se desean persistir. He aquí el descriptor:

Análisis y Uso de Frameworks de Persistencia en Java

31

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE jdo SYSTEM "file:/D:/Apps/OpenFusionJDO/xml/schema/jdo.dtd"> <jdo> <package name="addressbook"> <class name="Person" identity-type="datastore"> </class> </package> </jdo>

Este es un fichero de mapeo sencillo. Sin embargo, he aquí un extracto de

uno un poco más complejo que pretende mapear un objeto Departamento con su

correspondiente ‘collection’ de empleados:

<class name="Department" identity-type="datastore"> <field name="name"/> <field name="employees"> <collection element- type="com.prismt.j2ee.jdo.examples.appKeyDepartment.Employee"> </collection> </field> <field name="manager"/> </class>

CONSTRUCCIÓN:

Pasos para construir y ejecutar la aplicación

Estos son los pasos a seguir para construir el sistema que permitirá

ejecutar la aplicación:

1. Compilar el Código

Análisis y Uso de Frameworks de Persistencia en Java

32

2. Ejecutar en JDOEnhancer

3. Preparar la base de datos (utilizando la salida del Enhancer)

4. Ejecutar la aplicación

Paso 1º: Compilar el código

La compilación se realizará como en cualquier código Java, usando

‘javac’. Por otra parte, es necesario asignar el ‘CLASSPATH’ correctamente. He

aquí un ejemplo en Windows:

% set OPENFUSION_DIR=D:\Apps\OpenFusionJDO % set CLASSPATH=%OPENFUSION_DIR%\lib\connector.jar;%OPENFUSION_DIR%\ lib\jndi.jar;%OPENFUSION_DIR%\lib\log4j.jar;%OPENFUSION_DIR%\l ib\xerces.jar;%OPENFUSION_DIR%\lib\classes12.zip;%OPENFUSION_D IR%\lib\jdo.jar;%OPENFUSION_DIR%\lib\jta- spec1_0_1.jar;%OPENFUSION_DIR%\lib\ofjdo.jar;. % javac –d . Person*.java

Paso 2º: Ejecutar el JDOEnhancer

El JDOEnhancer toma por un lado el código compilado y por otro el

fichero descriptor. Esta es la sintaxis completa del OpenFusion JDOEnhancer:

java com.prismt.j2ee.jdo.enhancer.JDOEnhancer Mandatory Options: -cp base directory to begin searching for classes to be enhanced. This is not the CLASSPATH, just where our compiled persistent classes are

Análisis y Uso de Frameworks de Persistencia en Java

33

-oc directory to place the enhanced classes -pd JDO descriptor file(s) Optional: -db specific target database [oracle, sybase, etc] -od directory to generate SQL scripts to

Para la aplicación compilada en el ejemplo, he aquí cómo se ejecutaría el

JDOEnhancer:

% java com.prismt.j2ee.jdo.enhancer.JDOEnhancer -oc . -pd person.jdo -db oracle -od db -cp .

Paso 3º: Preparar la base de datos

El JDOEnhancer es capaz de crear scripts para preparar la base de datos,

siempre que se transmitan las opciones ‘–db baseDeDatos’ y ‘-od

directorioDestino’. El Enhancer creará muchos scripts diferentes, pero uno de

ellos se llama ‘load_all.sql’. El archivo se ha de abrir y cargar en la localización

del SQL pertinente (ej: ‘sqlplus’ en Oracle).

Este es un ejemplo de lo que contiene el fichero de sentencias SQL que

ha sido creado para Oracle:

CREATE SEQUENCE instid_seq INCREMENT BY 1 ; CREATE TABLE JDO_addressbook_Person_SCO

Análisis y Uso de Frameworks de Persistencia en Java

34

( inst_id INTEGER NOT NULL, class INTEGER NOT NULL, JDO_address VARCHAR2(255), JDO_email VARCHAR2(255), JDO_homePhone VARCHAR2(255), JDO_name VARCHAR2(255), JDO_ssn VARCHAR2(255), JDO_workPhone VARCHAR2(255) ) ; CREATE TABLE JDO_addressbook_Person ( inst_id INTEGER NOT NULL, class INTEGER NOT NULL, JDO_address VARCHAR2(255), JDO_email VARCHAR2(255), JDO_homePhone VARCHAR2(255), JDO_name VARCHAR2(255), JDO_ssn VARCHAR2(255), JDO_workPhone VARCHAR2(255) ) ; CREATE TABLE prismjdoProp ( name VARCHAR2(255) PRIMARY KEY, value VARCHAR2(255) ) ; CREATE TABLE prismjdoExtents ( class_id NUMBER(38,0) PRIMARY KEY, class_name VARCHAR2(255) UNIQUE, app_key VARCHAR2(255) ) ; ALTER TABLE JDO_addressbook_Person_SCO ADD PRIMARY KEY (inst_id, class) ; ALTER TABLE JDO_addressbook_Person ADD PRIMARY KEY (inst_id, class) ; INSERT INTO prismjdoExtents VALUES(0, 'addressbook.Person', 'com.prismt.j2ee.jdo.spi.DBKey') ; COMMIT WORK ; INSERT INTO prismjdoProp VALUES('USE.RDBMS.TRIGGERS', 'true') ; COMMIT WORK ;

Análisis y Uso de Frameworks de Persistencia en Java

35

Paso 4º: Ejecutar la Aplicación

% java addressbook.PersonPersist

EL LENGUAJE DE CONSULTA JDOQL

JDO define un lenguaje de consulta conocido como JDOQL. Este lenguaje está

embebido dentro del interface ‘javax.jdo.Query’. El ‘PersistenceManager’ de JDO

define los siguientes métodos para construir ejemplares de las clases de implementación

de la consulta:

• Query newQuery();

• Query newQuery(Class cls);

• Query newQuery(Class cls, Collection coll);

• Query newQuery(Class cls, String filter);

• Query newQuery(Class cls, Collection c, String filter);

• Query newQuery(Extent ext);

• Query newQuery(Extent ext, String filter);

El ‘filter’ se especifica como una expresión booleana que se parece algo a los

operadores booleanos de SQL. El resultado de una consulta depende de si la expresión

booleana se evalúa a ‘true’ por las clases candidatas especificadas. El interface ‘Query’

proporciona el siguiente método para especificar un filtro:

• void setFilter(String filter);

Análisis y Uso de Frameworks de Persistencia en Java

36

Las clases candidatas se pueden especificar utilizando uno de los siguientes métodos del

interface ‘Query’:

• void setClass(Class candidateClass);

• void setCandidates(Collection candidates);

• void setCandidates(Extent candidates);

El interface ‘Query’ proporciona métodos para ejecutar una consulta. Los parámetros de

la consulta se pueden pasar directamente a cualquiera de estos métodos:

• Object execute(Object param);

• Object execute(Object param1, Object param2);

• Object execute(Object param1, Object param2, Object param3);

• Object executeWithMap(Map paramMap);

• Object executeWithArray(Object[] paramArray);

El interface ‘Query’ también proporciona un método para declarar un grupo arbitrario

de parámetros separados por comas:

• void declareParameters(String paramStr);

Este grupo de parámetros debe formatearse como una definición ‘String’ de las parejas

tipo-nombre. Por ejemplo, el siguiente fragmento ilustra un grupo de parámetros para

un nombre y una cuenta de usuario:

query.declareParameters("String userName, int accountNumber");

Análisis y Uso de Frameworks de Persistencia en Java

37

El siguiente código muestra una consulta completa utilizando JDOQL:

String filter = "userInfo.fullName == fullName && " + "userInfo.zip.startsWith(userZip)"; Extent extent = persistenceMgr.getExtent(UserInfo.class, true); Query query = persistenceMgr.newQuery(extent, filter); query.declareParameters("String city, String state"); Collection result = (Collection)query.execute("Shire", "New York"); Iterator iter = result.iterator(); while(iter.hasNext()) { UserInfo user = (UserInfo)iter.next(); System.out.println("User: " + user.getID()); }

• Entity Java Beans (EJB) de Entidad – Funcionamiento

PERSISTENCIA MANEJADA POR CONTENEDOR (CMP)

Los beans con persistencia manejada por contenedor son los más simples

para el desarrollador y los más complicados para que los soporte el servidor

EJB. Esto es porque toda la lógica de sincronización del estado del bean con la

base de datos es manejada automáticamente por el contenedor. Esto significa

que el desarrollador del bean no necesita escribir ninguna lógica de acceso a

datos, mientras que se supone que el servidor EJB tiene cuidado de toda la

persistencia que necesita automáticamente. La mayoría de los vendedores EJB

soportan la persistencia automática a una base de datos relacional, pero el nivel

Análisis y Uso de Frameworks de Persistencia en Java

38

de soporte varía. Algunos proporcionan un mapeo O/R muy sofisticado,

mientras que otros están muy limitados.

La clase Bean

Un bean enterprise es un componente completo que está compuesto de al

menos dos interfaces y una clase de implementación del bean.

import javax.ejb.EntityBean; public class CustomerBean implements EntityBean { int customerID; Address myAddress; Name myName; CreditCard myCreditCard; // CREATION METHODS public Integer ejbCreate(Integer id) { customerID = id.intValue(); return null; } public void ejbPostCreate(Integer id) { } public Customer ejbCreate(Integer id, Name name) { myName = name; return ejbCreate(id); } public void ejbPostCreate(Integer id, Name name) { } // BUSINESS METHODS public Name getName() { return myName; } public void setName(Name name) { myName = name; } public Address getAddress() { return myAddress; }

Análisis y Uso de Frameworks de Persistencia en Java

39

public void setAddress(Address address) { myAddress = address; } public CreditCard getCreditCard() { return myCreditCard; } public void setCreditCard(CreditCard card) { myCreditCard = card; } // CALLBACK METHODS public void setEntityContext(EntityContext cntx) { } public void unsetEntityContext() { } public void ejbLoad() { } public void ejbStore() { } public void ejbActivate() { } public void ejbPassivate() { } public void ejbRemove() { } }

Este es un buen ejemplo de un bean de entidad CMP bastante simple. Se

puede observar que no hay lógica de acceso a base de datos en el bean. Esto es

porque el vendedor del EJB proporciona herramientas para mapear los campos

del CustomerBean a la base de datos. La clase CustomerBean, por ejemplo,

podría ser mapeada a cualquier base de datos proporcionando los datos que

contienen y que son muy similares a los campos del bean. En este caso lo

campos de ejemplar del bean están comprendidos por un int y unos sencillos

Análisis y Uso de Frameworks de Persistencia en Java

40

objetos dependientes (Name, Address, y CreditCard) con sus propios atributos.

He aquí las definiciones de estos objetos dependientes.

// The Name class public class Name implements Serializable { public String lastName, firstName, middleName; public Name(String lastName, String firstName, String middleName) { this.lastName = lastName; this.firstName = firstName; this.middleName = middleName; } public Name() {} } // The Address class public class Address implements Serializable { public String street, city, state, zip; public Address(String street, String city, String state, String zip) { this.street = street; this.city = city; this.state = state; this.zip = zip; } public Address() {} } // The CreditCard class public class CreditCard implements Serializable { public String number, type, name; public Date expDate; public CreditCard(String number, String type, String name, Date expDate) { this.number = number; this.type = type; this.name = name; this.expDate = expDate;

Análisis y Uso de Frameworks de Persistencia en Java

41

} public CreditCard() {} }

Estos campos se llaman campos manejados por contenedor porque el

contenedor es el responsable de sincronizar su estado con la base de datos; el

contenedor maneja los campos. Estos campos pueden ser cualquier tipo de dato

primitivo o tipo serializable. Este caso usa tanto un tipo primitivo int

(customerID) y objetos serializables (Address, Name, CreditCard). Para mapear

los objetos dependientes a la base de datos necesitaríamos usar una herramienta

de mapeado muy sofisticada. No todos los campos del bean son

automáticamente campos manejados por el contenedor; algunos de ellos son sólo

campos de ejemplar para el uso temporal del bean. Un desarrollador de beans

distingue un campo manejado por contenedor de un campo de ejemplar normal

indicando los campos manejados por el contenedor en el descriptor de

desarrollo.

Los campos manejados por contenedor deben tener sus tipos

correspondientes (columnas en RDBMS) en la base de datos bien directamente o

a través de mapeo O/R. El CustomerBean podría, por ejemplo, mapear una tabla

CUSTOMER en la base de datos que tenga la siguiente definición.

CREATE TABLE CUSTOMER

Análisis y Uso de Frameworks de Persistencia en Java

42

{ id INTEGER PRIMARY KEY, last_name CHAR(30), first_name CHAR(20), middle_name CHAR(20), street CHAR(50), city CHAR(20), state CHAR(2), zip CHAR(9), credit_number CHAR(20), credit_date DATE, credit_name CHAR(20), credit_type CHAR(10) }

Con la persistencia controlada por contenedor, el vendedor debe tener

alguna clase de herramienta propietaria que pueda mapear los datos manejados

por el contenedor del bean a sus correspondientes columnas en la tabla

específica, CUSTOMER en este caso.

Una vez que los campos del bean se han mapeado a la base de datos, y se

ha desarrollado el bean CustomerBean, el contenedor manejará la creacción de

registros, el borrado, la carga y la actualización de registros en la tabla

CUSTOMER en respuesta a los métodos invocados en los interfaces home y

remoto del bean Customer.

Un subconjunto (uno o más) de los campos manejados por el contenedor

será identificado como la clave primaria del bean. Esta clave primaria es el

índice o puntero a un único registro(s) en la base de datos que crea el estado del

bean. En el caso de CustomerBean, el campo id es el campo clave primario y

Análisis y Uso de Frameworks de Persistencia en Java

43

será usado para localizar los datos de los beans en la base de datos. Los campos

clave de un campo sencillo primitivo se representan como su correspondiente

objeto envoltura. La clave primaria del bean CustomerBean por ejemplo es un

int primitivo en la clase bean pero los clientes del bean la manifestarán como del

tipo java.lang.Integer. Las claves primarias que se componen de varios campos,

llamadas claves primarias compuestas, serán representadas por un clase especial

definida por el desarrollador del Bean.

Interface Home

Para crear un nuevo ejemplar de un bean de entidad CMP, y por lo tanto

insertar los datos en la base de datos, se debe llamar al método create() del

interface home del bean. He aquí la definición del interface ‘CustomerHome’.

public interface CustomerHome extends javax.ejb.EJBHome { public Customer create( Integer customerNumber) throws RemoteException,CreateException; public Customer create(Integer customerNumber, Name name) throws RemoteException,CreateException; public Customer findByPrimaryKey(Integer customerNumber) throws RemoteException, FinderException; public Enumeration findByZipCode(int zipCode) throws RemoteException, FinderException; }

Análisis y Uso de Frameworks de Persistencia en Java

44

A continuación está un ejemplo de cómo se usaría el interface ‘home’ en

una aplicación cliente para crear un nuevo cliente.

CustomerHome home = // Get a reference to the //CustomerHome object Name name = new Name("John", "W", "Smith"); Customer customer = home.create( new Integer(33), name);

Un interface ‘home’ de un bean podría declarar cero o más métodos

create(), cada uno de los cuales debe tener sus correspondientes métodos

ejbCreate() y ejbPostCreate() en la clase del bean. Estos métodos de creación

son enlazados en tiempo de ejecución, para que cuando se llame a un método

create() del interface ‘home’, el contenedor delegue la invocación a los

correspondientes métodos ejbCreate() y ejbPostCreate() de la clase Bean.

Cuando se invoca al método create() de un interface ‘home’, el

contenedor delega esta llamada al correspondiente método ejbCreate() en el

bean. Estos métodos se usan para inicializar el estado del ejemplar antes de que

el registro sea insertado en la base de datos. En este caso, inicializa los campos

customerID y Name. Cuando el método ejbCreate() ha finalizado (devuelven

null en CMP) el contenedor lee los campos manejados por el contenedor e

inserta un nuevo registro en la tabla CUSTOMER indexado por la clave

primaria, en este caso customerID que se mapea a la columna CUSOTMER.ID.

Análisis y Uso de Frameworks de Persistencia en Java

45

En EJB un bean de entidad no existe técnicamente hasta después de que

sus datos hayan sido insertados en la base de datos, lo que ocurre durante el

método ejbCreate(). Una vez que los datos han sido insertados, el bean de

entidad existe y puede acceder a su propia clave primaria y a referencias

remotas, lo que no es posible hasta que se complete el método ejbCreate() y que

los datos estén en la base de datos. Si el bean necesita acceder a su propia clave

primaria o a una referencia remota después de haber sido creado, pero antes de

servir a cualquier método de negocio, puede hacerlo en el método

ejbPostCreate(). Este método permite al bean realizar cualquier proceso post-

creacción antes de empezar a servir peticiones de clientes. Por cada ejbCreate()

debe haber un método ejbPostCreate() correspondiente (con los mismos

argumentos).

Los métodos del interface ‘home’ que empiezan con "find" son llamados

métodos de búsqueda. Se usan para consultar al servidor EJB sobre beans de

entidad específicos, basándose en el nombre del método y los argumentos

pasados. Desafortunadamente, no hay un lenguaje de consultas estándard

definido para los métodos de búsqueda, por eso cada vendedor implementará

estos métodos de forma diferente. En los beans de entidad CMP, los métodos de

búsqueda no están implementados con los métodos correspondientes en la clase

del bean; los contenedores los implementan cuando el bean se desarrolla de una

forma específica del vendedor. El desarrollador usará las herramientas

Análisis y Uso de Frameworks de Persistencia en Java

46

específicas del vendedor para decirle al contenedor cómo se debería comportar

un método de búsqueda particular. Algunos vendedores usaran herramientas de

mapeo Objeto-Relacional para definir el comportamiento de un método de

búsqueda mientras que otros sólo requerirán que el desarrollador introduzca el

comando SQL apropiado.

Interface Remoto

Cada bean de entidad debe definir una interface remoto en adición del

interface ‘home’. El interface remoto define los métodos de negocio del bean de

entidad. A continuación está la definición del interface remoto del bean

CustomerBean.

import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Customer extends EJBObject { public Name getName() throws RemoteException; public void setName(Name name) throws RemoteException; public Address getAddress() throws RemoteException; public void setAddress( Address address) throws RemoteException; public CreditCard getCreditCard() throws RemoteException; public void setCreditCard(CreditCard card) throws RemoteException; }

Análisis y Uso de Frameworks de Persistencia en Java

47

Este es un ejemplo de cómo una aplicación cliente podría usar el

interface remoto para interactuar con un bean.

Customer customer = // ... obtain a remote //reference to the bean // get the customer's address Address addr = customer.getAddress(); // change the zip code addr.zip = "56777"; // update the customer's address customer.setAddress(addr);

Los métodos de negocio en el interface remoto se delegan a los

correspondientes métodos de negocio en el ejemplar del bean. En el bean

Customer, los métodos de negocios son todos simples accesores y

modificadores, pero podrían ser más complicados. En otras palabras, los

métodos de negicio de una entidad no están limitados a leer y escribir datos,

también pueden realizar tareas de cálculo.

Si, por ejemplo, los clientes tuvieran un programa de fidelidad que

premiara el uso frecuente, podría haber un método para mejorar los premios en

el programa, basado en una acumulación de estancias superiores a una noche.

import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Customer extends EJBObject { public MembershipLevel addNights(int nights_stayed) throws RemoteException;

Análisis y Uso de Frameworks de Persistencia en Java

48

public MembershipLevel upgradeMembership() throws RemoteException; public MembershipLevel getMembershipLevel() throws RemoteException; ... Simple accessor business methods go here }

Los métodos addNights() y upgradeMembership() son más sofisticados

que los sencillos métodos accesores. Aplican reglas de negocio para cambiar el

nivel del premio y van más allá de leer y escribir datos.

Métodos de RetroLlamada (CallBack Methods)

La clase bean define métodos create que corresponden con métodos del

interface home y métodos de negocio que corresponden con métodos del

interface remoto. La clase bean también implementa un conjunto de métodos

callback que permiten al contenedor notificar al bean los eventos de su ciclo de

vida. Los métodos de retrollamada están definidos en el interface

javax.ejb.EntityBean que es implementado por todos los beans de entidad,

incluyendo la clase CustomerBean. El interface EntityBean tiene la siguiente

definición. Se puede observar que la clase del bean implementa estos métodos.

public interface javax.ejb.EntityBean { public void setEntityContext(); public void unsetEntityContext(); public void ejbLoad(); public void ejbStore();

Análisis y Uso de Frameworks de Persistencia en Java

49

public void ejbActivate(); public void ejbPassivate(); public void ejbRemove(); }

El método setEntityContext() proporciona al bean un interface con el

contenedor llamado el EntityContext. Este interface contiene métodos para

obtener información sobre el contexto bajo el que opera el bean en un momento

particular. El interface EntityContext se usa para acceder a información de

seguridad sobre su llamador; para determinar el estado de la transación actual o

para forzar a deshacer una transación; o para obtener una referencia al propio

bean, su interface home o su clave primaria. Este interface sólo se configura una

vez en la vida de un ejemplar de bean de entidad, por eso su referencia debería

ponerse en uno de los campos de ejemplar del bean si la vamos a necesitar más

tarde.

El bean Customer de arriba no usa EntityContext, pero podría hacerlo.

Por ejemplo, podría usarlo para validad al llamador en un rol de seguridad

particular. Abajo tenemos un ejemplo, donde se usa el EntityContext para

validad que el llamador es un Manager, el único rol (indentidad de seguridad)

que puede seleccionar el tipo de la tarjeta de crédito de un cliente para que sea

una tarjeta mundial, no una tarjeta limitada. (A los clientes con esta tarjeta se le

ofrecen servicios especiales).

Análisis y Uso de Frameworks de Persistencia en Java

50

import javax.ejb.EntityBean; public class CustomerBean implements EntityBean { int customerID; Address myAddress; Name myName; CreditCard myCreditCard; EntityContext ejbContext; // CALLBACK METHODS public void setEntityContext( EntityContext cntx) { ejbContext = cntx } public void unsetEntityContext() { ejbContext = null; } // BUSINESS METHODS public void setCreditCard(CreditCard card) { if (card.type.equals("WorldWide")) if (ejbContext.isCallerInRole( "Manager")) myCreditCard = card; else throw new SecurityException(); else myCreditCard = card; } public CreditCard getCreditCard() { return myCreditCard; } ... }

El método unsetEntityContext() se usa al final del ciclo de vida del bean -

- antes de que el ejemplar sea sacado de la memoria -- para quitar la refencia del

EntityContext y realizar cualquier pequeña tarea de limpieza.

Análisis y Uso de Frameworks de Persistencia en Java

51

Los métodos ejbLoad() y ejbStore() en entidades CMP se invocan

cuando el estado del bean de entidad está siendo sincronizado con la base de

datos. El ejbLoad() se invoca justo después de que el contenedor haya refrescado

los campos del bean manejados por contenedor con su estado desde la base de

datos. El método ejbStore() se invoca justo antes de que el contenedor escriba

los campos del bean manejados por contenedor en la base de datos. Estos

métodos se usan para modificar datos que están siendo sincronizados. Los

métodos podrían usarse, por ejemplo, para comprimir los datos antes de

almacenarlos y descomprimirlos cuando son recuperados de la base de datos.

En el bean Customer los métodos ejbLoad() y ejbStore() podrían usarse

para converitir objetos dependientes (Name, Address, CreditCard) a sencillos

objetos String y tipos primitivos, si el contenedor EJB no es lo suficientemente

sofisticado para mapear los objetos dependientes a la tabla CUSTOMER. Abajo

tenemos un ejemplo de como se podría modificar el Bean.

import javax.ejb.EntityBean; public class CustomerBean implements EntityBean { //container-managed fields int customerID; String lastName; String firstName; String middleName; ... // not-container-managed fields Name myName; Address myAddress; CreditCard myCreditCard; // BUSINESS METHODS

Análisis y Uso de Frameworks de Persistencia en Java

52

public Name getName() { return myName; } public void setName(Name name) { myName = name; } ... public void ejbLoad() { if (myName == null) myName = new Name(); myName.lastName = lastName; myName.firstName = firstName; myName.middleName = middleName; ... } public void ejbStore() { lastName = myName.lastName; firstName = myName.firstName; middleName = myName.middleName; ... } }

Los métodos ejbPassivate() y ejbActivate() se invocan sobre el bean justo

antes de que el bean sea "pasivizado" o justo después de que se activado,

respectivamente. "Pasivizado" en un bean de entidad significa que el ejemplar

del bean ha sido des-asociado con su referencia remota para que el contenedor

pueda eliminarlo de la memoria o reutilizarlo. Es una medida de conservación de

recursos que emplea el contenedor para reducir el número de ejemplares en

memoria. Un bean podría ser "pasivizado" si no ha sido utilizado durante un

tiempo o como una operación normal realizada por el contenedor para

maximizar la reutilización del los recursos. Algunos contenedores eliminarán los

beans de la memoria, mientras que otros reutilizarán ejemplares para otros

interfaces remotos más activos. Los métodos ejbPassivate() y ejbActivate()

Análisis y Uso de Frameworks de Persistencia en Java

53

proporcionan al bean una notificación cuando está apunto de ser "pasivizado"

(des-asociado con la referencia remota) o activado (asociado con un referencia

remota).

PERSISTENCIA CONTROLADA POR EL BEAN (BMP)

En un bean enterprise con la persistencia manejada por el Bean (BMP)

maneja la sincronización de su estado con la base de datos directamente. El Bean

usa el API de bases de datos (normalmente JDBC) para leer y escribir sus

campos en la base de datos, pero el contenedor le dice cuando hacer cada

operación de sincronización y maneja las transacciones por el bean

automáticamente. La persistencia manejada por el bean le da al desarrollador de

bean la flexibilidad de realizar operaciones de persistencia que son demasiado

complicadas para el contenedor o para usar una fuente de datos que no está

soportada por el contenedor -- por ejemplo bases de datos legales y

personalizadas.

En esta sección, modificaremos la clase CustomerBean para crear un

bean con persistencia manejada por el Bean (BMP). Esta modificación no

impactará en absoluto en los interfaces home o remoto. De hecho, no

modificaremos directamente el CustomerBean original. En su lugar, lo

Análisis y Uso de Frameworks de Persistencia en Java

54

cambiaremos a persistencia manejada por el bean extendiendo el bean y

sobreescribiendo la clase para crear una entidad BMP. En la mayoría de los

casos, no extenderemos el bean para hacerlo BMP, sólo implementaremos el

bean como BMP directamente. Esta estrategia (extender el bean CMP) se hace

por dos razones: permite al bean ser un bean CMP o BMP; y acorta

significativamente la cantidad de código a mostrar. Abajo tenemos la definición

de la clase BMP.

public class CustomerBean_BMP extends CustomerBean { public void ejbLoad() { // override implementation } public void ejbStore() { // override implementation } public void ejbCreate() { // override implementation } public void ejbRemove() { // override implementation } private Connection getConnection() { // new helper method } }

Con beans BMP, los métodos ejbLoad() y ejbStore() los usa el

contenedor de forma diferente a como lo hacía con un bean CMP. En BMP,

estos métodos contienen código para leer los datos de la base de datos y para

escribir los cambios en la base de datos, respectivamente. Estos métodos se

llaman sobre el bean cuando el servidor EJB decide que es un buen momento

para leer o escribir los datos.

Análisis y Uso de Frameworks de Persistencia en Java

55

El bean CustomerBean_BMP maneja su propia persistencia. En otras

palabras, los métodos ejbLoad() y ejbStore() deben incluir lógica de acceso a

base de datos para que el bean pueda cargar y almacenar sus datos cuando el

contenedor EJB se lo diga. El contenedor ejecutará automátiamente los métodos

ejbLoad() y ejbStore() cuando crea apropiado.

El método ejbLoad() se invoca normalmente al principio de una

transación, justo antes de que el contenedor delege un método de negocio del

bean. El código mostrado abajo muestra cómo implementar el método ejbLoad()

usando JDBC.

import java.sql.Connection; public class CustomerBean_BMP extends CustomerBean { public void ejbLoad() { Connection con; try { Integer primaryKey = (Integer)ejbContext.getPrimaryKey(); con = this.getConnection(); Statement sqlStmt = con.createStatement("SELECT * FROM Customer " + " WHERE customerID = " + primaryKey.intValue()); ResultSet results = sqlStmt.executeQuery(); if (results.next()) { // get the name information //from the customer table myName = new Name(); myName.first = results.getString(" FIRST_NAME"); myName.last = results.getString(" LAST_NAME"); myName.middle = results.getString(" MIDDLE_NAME"); // get the address information from //the customer table myAddress = new Address(); myAddress.street =

Análisis y Uso de Frameworks de Persistencia en Java

56

results.getString("STREET"); myAddress.city = results.getString("CITY"); myAddress.state = results.getString("STATE"); myAddress.zip = results.getInt("ZIP"); // get the credit card information //from the customer table myCreditCard = new CreditCard(); myCreditCard.number = results.getString("CREDIT_NUMBER"); myCreditCard.expDate = results.getString("CREDIT_DATE"); myCreditCard.type = results.getString("CREDIT_TYPE"); myAddress.name = results.getInt("CREDIT_NAME"); } } catch (SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } }

El método ejbLoad(), usa la referencia ejbContext() hacia el

EntityContext del bean para obtener la clave primaria del ejemplar. Esto asegura

que usamos el índice correcto en la base de datos. Obviamente, el

CustomerBean_BMP necesitará usar los métodos heredados setEntityContext() y

unsetEntityContext().

El método ejbStore() es invocado sobre el bean, al final de la transación,

justo antes de que el contenedor intente enviar todos los cambios a la base de

datos.

import java.sql.Connection; public class CustomerBean_BMP extends CustomerBean {

Análisis y Uso de Frameworks de Persistencia en Java

57

public void ejbLoad() { ... read data from database } public void ejbStore() { Connection con; try { Integer primaryKey = (Integer)ejbContext.getPrimaryKey(); con = this.getConnection(); PreparedStatement sqlPrep = con.prepareStatement( "UPDATE customer set " + "last_name = ?, first_name = ?, middle_name = ?, " + "street = ?, city = ?, state = ?, zip = ?, " + "card_number = ?, card_date = ?, " + "card_name = ?, card_name = ?, " + "WHERE id = ?" ); sqlPrep.setString(1,myName.last); sqlPrep.setString(2,myName.first); sqlPrep.setString(3,myName.middle); sqlPrep.setString(4,myAddress.street); sqlPrep.setString(5,myAddress.city); sqlPrep.setString(6,myAddress.state); sqlPrep.setString(7,myAddress.zip); sqlPrep.setInt(8, myCreditCard.number); sqlPrep.setString(9, myCreditCard.expDate); sqlPrep.setString(10, myCreditCard.type); sqlPrep.setString(11, myCreditCard.name); sqlPrep.setInt(12,primaryKey.intValue()); sqlPrep.executeUpdate(); } catch (SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } }

En ambos métodos ejbLoad() y ejbStore() el bean sincroniza su propio

estado con la base de datos usando JDBC. El código muestra que el bean obtiene

sus conexiones a la base de datos desde una invocación misteriosa al método

this.getConnection(). Un método todavía no implementado. El método

getConnection() no es un método estándard EJB, sólo una ayuda privada

Análisis y Uso de Frameworks de Persistencia en Java

58

implementada para ocultar los mecanismos de obtención de conexiones a bases

de datos. Este es del método getConnection().

import java.sql.Connection; public class CustomerBean_BMP extends CustomerBean { public void ejbLoad() { ... read data from database } public void ejbStore() { ... write data to database } private Connection getConnection() throws SQLException { InitialContext jndiContext = new InitialContext(); DataSource source = (DataSource) jndiContext.lookup(" java:comp/env/jdbc/myDatabase"); return source.getConnection(); } }

Las conexiones a bases de datos se obtienen desde el contenedor usando

un contexto JNDI por defecto llamado "JNDI Environment Naming Context"

(ENC). El ENC proporciona acceso a almacenes de conexiones JDBC

transaccionales a través de la factoría de conexiones estándar, del tipo

javax.sql.DataSource.

En BMP, los métodos ejbLoad() y ejbStore() los invoca el contenedor

para sincronizar el ejemplar del bean con los datos en la base de datos. Para

insertar y eliminar entidades en la base de datos, se implementan los métodos

ejbCreate() y ejbRemove() con una lógica de acceso a bases de datos muy

similar. Los métodos ejbCreate() se implementan para insertar un nuevo registro

Análisis y Uso de Frameworks de Persistencia en Java

59

en la base de datos y los métodos ejbRemove() para eliminar los datos de una

entidad de la base de datos. Estos métodos de una entidad son invocados por el

contenedor en respuesta a invocaciones a sus correspondientes métodos en los

interface home y remoto. Estas son las implementaciones de estos métodos.

public void ejbCreate(Integer id) { this.customerID = id.intValue(); Connection con; try { con = this.getConnection(); Statement sqlStmt = con.createStatement("INSERT INTO customer id VALUES (" + customerID + ")"); sqlStmt.executeUpdate(); return id; } catch(SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } public void ejbRemove() { Integer primaryKey = (Integer)ejbContext.getPrimaryKey(); Connection con; try { con = this.getConnection(); Statement sqlStmt = con.createStatement("DELETE FROM customer WHERE id = " primaryKey.intValue()); sqlStmt.executeUpdate(); } catch(SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } }

Análisis y Uso de Frameworks de Persistencia en Java

60

En BMP, la clase bean es responsable de implementar los métodos de

búsqueda definidos en el interface home. Por cada método de búsqueda definido

en el interface home debe haber el correspondiente método ejbFind() en la clase

bean. Estos métodos localizan los registros del bean apropiado en la base de

datos y devuelve sus claves primarias al contenedor. El contenedor convierte la

clave primara en referencias a beans y los devuelve al cliente. Abajo tenemos un

ejemplo de implementación del método ejbFindByPrimaryKey() en la clase

CustomerBean_BMP, que corresponde al findByPrimaryKey() definido en el

interface CustomerHome.

public Integer ejbFindByPrimaryKey( Integer primaryKey) throws ObjectNotFoundException { Connection con; try { con = this.getConnection(); Statement sqlStmt = con.createStatement("SELECT * FROM Customer " + " WHERE customerID = " + primaryKey.intValue()); ResultSet results = sqlStmt.executeQuery(); if (results.next()) return primaryKey; else throw ObjectNotFoundException(); } catch (SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } }

Los métodos de búsqueda de entidades simples como el de arriba

devuelven una sola clave primara y lanza una ObjectNotFoundException si no se

Análisis y Uso de Frameworks de Persistencia en Java

61

localiza un registro correspondiente. Los métodos de búsqueda multi-entidad

devuelven una colección (java.util.Enumeration o java.util.Collection) de claves

primarias. El contenedor convierte la colección de claves primarias en una

colección de referencias remotas, que son devueltas al cliente. Abajo tenemos un

ejemplo de cómo el método ejbFindByZipCode() multi-entidad, que corresponde

al método findByZipCode() definido en el interface CustomerHome, sería

implementado en la clase CustomerBean_BMP.

public Enumeration ejbFindByZipCode( int zipCode) { Connection con; try { con = this.getConnection(); Statement sqlStmt = con.createStatement("SELECT id FROM Customer " + " WHERE zip = " +zipCode); ResultSet results = sqlStmt.executeQuery(); Vector keys = new Vector(); while(results.next()){ int id = results.getInt("id"); keys.addElement(new Integer(id)); } return keys.elements(); } catch (SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } }

Si no se encuentran registros correspondientes, se devuelve una colección

vacía al contenedor, que devuelve una colección vacía al cliente.

Análisis y Uso de Frameworks de Persistencia en Java

62

Con la implementación de todos estos métodos y unos pocos cambios

menores en el descriptor de desarrollo del bean, el CustomerBean_BMP esta

listo para ser desplegado como una entidad BMP.

3.3.2. Tecnología Open Source: HIBERNATE – Funcionamiento

Para comprender el funcionamiento de Hibernate se pretende describir

los diversos pasos a seguir para construir una aplicación que permita realizar el

proceso de persistencia. Primero, se creará un objeto Evento (Event) para

persistirlo en la base de datos. A continuación, se verá cómo persistir el objeto

Evento en la base de datos y realizar una transacción para obtenerlo de nuevo.

Después se procederá a construir un archivo XML de mapeo para decirle a

Hibernate qué es lo que deseamos persistir. A través de otro archivo XML se

configurarán las propiedades de Hibernate y la base de datos. Por último se verá

qué pasos se deben seguir para construir y ejecutar el sistema

Lo primero que tenemos que hacer es configurar nuestro directorio de

trabajo y poner en él todos los ficheros jar que necesitamos. Tenemos que

descargar la distribución de Hibernate de su página de descarga. Extraer los jars

necesarios desde el archivo de Hibernate. Los situaremos en un directorio lib

Análisis y Uso de Frameworks de Persistencia en Java

63

bajo el directorio de trabajo, tu despliegue de directorios debería parecerese a

esto:

+lib cglib2.jar commons-logging.jar hibernate2.jar jta.jar odmg.jar commons-collections.jar dom4j.jar jdbc2_0-stdext.jar log4j.jar

OBJETO:

Definición del objeto Evento

Lo primero será crear una clase que represente los eventos que se desean

persistir. Esta será un simple Java Bean, que contenga algunas propiedades.

package de.gloegl.road2hibernate; public class Event { private String title; private Date date; private Long id; public Long getId() { return id; } private void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; }

Análisis y Uso de Frameworks de Persistencia en Java

64

public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }

La propiedad id es una identificador único para el Event. Todos los

objetos persistentes necesitarán dicha id. Cuando se construyen aplicaciones

Hibernate es recomendable mantener dichas ids únicas separadas de la lógica de

la aplicación. Esto impide manipular la id en nuestro código, dejando que

Hibernate se ocupe de ella. De ahí viene porqué el método set de la id es

privado, permitiendo que Hibernate lo utilice (Hibernate podría acceder a los

métodos set y get de propiedades para todas las visibilidades), pero se aísla del

programador.

Este fichero se debe situar en un directorio llamado src en nuestro

directorio de trabajo. El directorio debería aparecer de esta forma:

+lib <hibernate jars> +src +de +gloegl +road2hibernate Event.java

Análisis y Uso de Frameworks de Persistencia en Java

65

PERSISTENCIA:

1º Creación del Objeto

El siguiente código muestra cómo se crea un objeto Evento desde el

método main:

public static void main(String[] args) throws java.text.ParseException { EventManager instance = new EventManager(); if (args[0].equals("store")) { String title = args[1]; Date theDate = new Date(); instance.store(title, theDate); } System.exit(0); }

Para este ejemplo se están pasando parámetros desde la línea de

comandos y se podrán leer en ‘args[]’. Si el primer argumento de recibido por la

aplicación es store, se toma el segundo argumento como un título, se crea un

nuevo Date y se pasan los dos al método store, donde se realiza la transacción

con la base de datos:

private void store(String title, Date theDate) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); session.save(theEvent); tx.commit(); session.close(); } catch (HibernateException e) {

Análisis y Uso de Frameworks de Persistencia en Java

66

e.printStackTrace(); } }

2º Mostrar los objetos almacenados

Modificando el método main, cuando el parámetro de entrada sea ‘list’,

se mostrarán los eventos persistidos:

public static void main(String[] args) throws java.text.ParseException { EventManager instance = new EventManager(); if (args[0].equals("store")) { String title = args[1]; Date theDate = new Date(); instance.store(title, theDate); } else if (args[0].equals("list")) { List events = instance.listEvents(); for (int i = 0; i<events.size(); i++) { Event theEvent = (Event) events.get(i); System.out.println("Event " + theEvent.getTitle() + " Time: " + theEvent.getDate()); } } System.exit(0); }

Se está llamando a listEvents() para imprimir todos los objetos Event

contenidos en la lista devuelta. Al llamar a listEvents() es donde se realizan

las transacciones:

Análisis y Uso de Frameworks de Persistencia en Java

67

private List listEvents() { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); List result = session.find("from Event"); tx.commit(); session.close(); return result; } catch (HibernateException e) { throw new RuntimeException(e.getMessage()); } }

EL FICHERO DE MAPEO

Una vez definida la clase para persistir en la base de datos, hay que

especificar a Hibernate cómo persistirla. Para ello es necesario construir un

fichero de mapeo. El fichero de mapeo le dice a Hibernate qué debería

almacenar en la base de datos y cómo.

La estructura exterior de un fichero de mapeo se parece a esto:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> </hibernate-mapping>

Análisis y Uso de Frameworks de Persistencia en Java

68

Entre las dos etiquetas <hibernate-mapping>, hay que incluir un

elemento class, donde se declara a que clase se refiere este mapeo y a qué tabla

de la base de datos SQL se debería mapear. La estructura interior del documento

de mapeo se debería parecer a esto:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="de.gloegl.road2hibernate.Event" table="EVENTS"> </class> </hibernate-mapping>

Se le ha indicado a Hibernate que persista la clase Event en la tabla

EVENTS. Ahora hay que dar a Hibernate la propiedad a utilizar como

identificador único: la propiedad id. Además hay que especificar cómo generar

los ids. Incluyendo esto, así queda el fichero de mapeo:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="de.gloegl.road2hibernate.Event" table="EVENTS"> <id name="id" column="uid" type="long"> <generator class="increment"/> </id> </class> </hibernate-mapping>

Análisis y Uso de Frameworks de Persistencia en Java

69

El elemento <id> es la declaración de la propiedad id. name="id" es el

nombre de la propiedad. Hibernate usará los métodos getId y setId para

acceder a ella. El atributo column le dice a Hibernate que cólumna de la tabla

EVENTS contendrá el id. El atributo type le dice a Hibernate el tipo de la

propiedad - en este caso un long.

El elemento <generator> especifica la técnica que se usará para la

generación de id. En este caso se usa un incremento. Finalmente se deben

incluir las declaraciones para las propiedades persistentes en el fichero de

mapeo:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="de.gloegl.road2hibernate.Event" table="EVENTS"> <id name="id" column="uid" type="long"> <generator class="increment"/> </id> <property name="date" type="timestamp"/> <property name="title" column="eventtitle"/> </class> </hibernate-mapping>

Análisis y Uso de Frameworks de Persistencia en Java

70

Al principio, igual que en el elemento <id>, el atributo name del

elemento <property> le dice a Hibernate que métodos get y set utilizar. Sin

embargo, la propiedad title contiene un atributo column, y el atributo date no

lo tiene. Esto es posible porque cuando no se utiliza el atributo column,

Hibernate usará por defecto el nombre de la propiedad como el nombre de

columna.

Por otra parte, la propiedad title carece de un atributo type. Otra vez,

Hibernate intentará determinar el tipo correcto por sí mismo. Sin embargo,

algunas veces Hibernate simplemente no puede hacer esto y hay que especificar

el tipo, como es el caso de la propiedad date. Hibernate no puede saber si la

propiedad se mapeará a una columna date, timestamp o time, por eso se debe

que especificar.

El mapeo se sitúa en un fichero llamado Event.hbm.xml en el mismo

directorio donde está la clase Event. Así quedaría la estructura del directorio de

trabajo:

+lib <hibernate jars> +src +de +gloegl +road2hibernate Event.java Event.hbm.xml

Análisis y Uso de Frameworks de Persistencia en Java

71

CONFIGURACIÓN DE LA BASE DE DATOS

Para configurar Hibernate se necesitan la información de la base de

datos, en este caso HSQLDB, una base de datos SQL en-memoria basada en

Java. Se debe copiar el fichero hsqldb.jar del directorio lib de la descarga al

directorio lib dentro del directorio de trabajo, que quedará de esta forma:

. +lib <hibernate jars> hsqldb.jar +src <Aquí va el fichero fuente y el de mapeo>

Además se creará un directorio data justo debajo del directorio de

trabajo, donde hsqldb almacenará sus ficheros.

Ahora se puede configurar Hibernate utilizando un fichero XML, que se

llamará hibernate.cfg.xml y que se situará directamente en el directorio src

del directorio de trabajo. Así queda el fichero:

<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//hibernate/hibernate Configuration DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

Análisis y Uso de Frameworks de Persistencia en Java

72

<hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="hibernate.connection.url">jdbc:hsqldb:data/test</property> <property name="hibernate.connection.username">sa</property> <property name="hibernate.connection.password"></property> <property name="dialect">net.sf.hibernate.dialect.HSQLDialect</property> <property name="show_sql">true</property> <property name="transaction.factory_class"> net.sf.hibernate.transaction.JDBCTransactionFactory </property> <property name="hibernate.cache.provider_class"> net.sf.hibernate.cache.HashtableCacheProvider </property> <property name="hibernate.hbm2ddl.auto">update</property> <mapping resource="de/gloegl/road2hibernate/data/Event.hbm.xml"/> </session-factory> </hibernate-configuration>

Los primeros cuatro elementos <property> contienen la configuración

necesaria para la Conexión JDBC que utilizará Hibernate. La propiedad dialect

especifica el SQLdialect que Hibernate deberá generar. Luego se especifica que

Hibernate delegará las transacciones a la conexión JDBC subyacente y se asigna

un proveedor de caché. La siguiente propiedad le dice a Hibernate que ajuste

automáticamente las tablas en la base de datos de acuerdo al mapeos. Finalmente

se le da el path al fichero de mapeo.

Análisis y Uso de Frameworks de Persistencia en Java

73

CONSTRUCCIÓN Y EJECUCIÓN DEL SISTEMA

1º Construcción

Por conveniencia, se crea un fichero batch en el directorio de trabajo que

contenga todos los comandos necesarios para la complicación. Bajo Windows,

este sería su contenido:

javac -classpath .\lib\hibernate2.jar -d bin src\de\gloegl\road2hibernate\*.java copy /Y src\hibernate.cfg.xml bin copy /Y src\de\gloegl\road2hibernate\*.xml bin\de\gloegl\road2hibernate

Este fichero se situará con el nombre de build.bat en nuestro directorio de

trabajo. Finalmente se crea el subdirectorio bin en nuestro directorio de trabajo

para situar ahí las clases compiladas.

2º Ejecución

El código que viene a continuación es una clase que arrancará Hibernate.

package de.gloegl.road2hibernate; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.HibernateException; import net.sf.hibernate.cfg.Configuration; public class EventManager { private SessionFactory sessionFactory;

Análisis y Uso de Frameworks de Persistencia en Java

74

public EventManager() { try { System.out.println("Initializing Hibernate"); sessionFactory = new Configuration().configure().buildSessionFactory(); System.out.println("Finished Initializing Hibernate"); } catch (HibernateException e) { e.printStackTrace(); } } public static void main(String[] args) { EventManager instance = new EventManager(); System.exit(0); } }

Esta clase simplemente crea un ejemplar de sí mismo, y crea un ejemplar

de SessionFactory en su constructor. El fichero EventManager.java debe

situarse en el directorio adecuado. La estructura de directorios sería la que figura

a continuación:

. +lib cglib2.jar commons-logging.jar hibernate2.jar jta.jar odmg.jar commons-collections.jar dom4j.jar jdbc2_0-stdext.jar log4j.jar hsqldb.jar +src +de +gloegl +road2hibernate Event.java Event.hbm.xml EventManager.java hibernate.cfg.xml +data

Análisis y Uso de Frameworks de Persistencia en Java

75

build.bat

Para ejecutar nuestra aplicación se crea otro fichero batch en el directorio

de trabajo bajo el nombre de run.bat, con el siguiente contenido (todo en una

línea):

java -classpath .\lib\hibernate2.jar;.\lib\jta.jar;.\lib\commons-logging.jar;.\lib\hsqldb.jar; .\lib\cglib2.jar;.\lib\commons-collections.jar;.\lib\dom4j.jar;.\lib\odmg.jar; .\lib\jdbc2_0-stdext.jar;.\bin de.gloegl.road2hibernate.EventManager %1 %2 %3 %4 %5

Ahora se deben compilar todos los ficheros fuentes ejecutando el fichero

build.bat desde el directorio de trabajo y lo ejecutamos utilizando el fichero

run.bat. Esta sería la salida:

Initializing Hibernate log4j:WARN No appenders could be found for logger (net.sf.hibernate.cfg.Environment). log4j:WARN Please initialize the log4j system properly. Finished Initializing Hibernate

Análisis y Uso de Frameworks de Persistencia en Java

76

3.4.- EVALUACIÓN

JDO vs. EJB

Desde la aparición de JDO se ha especulado que esta tecnología podría

sustituir a las EJB de entidad. Para entender esta afirmación se debe examinar

que es exactamente un EJB de entidad. Como ya se ha explicado, los beans de

entidad se dividen en dos categorías: persistencia manejada por contenedor

(CMP) y persistencia manejada por bean (BMP). Los beans BMP contienen un

código que puede almacenar el contenido del bean en un almacén de datos

permanente. Los BMP tienden a ser independientes y no forman relaciones

directas con otros beans BMP. No sería correcto decir que los beans BMP

pueden ser sustituidos por JDO, puesto que un bean BMP hace uso directo de

código JDBC. Esto viola uno de los principios de diseño de JDO ya que esta

tecnología pretende abstraer al usuario de codificar con JDBC.

Los beans CMP permiten manejar la persistencia al contenedor. El

contenedor es cualquier servidor que esté ejecutando el bean, y se encarga de

manejar todo el almacenamiento actual. Los beans CMP también pueden formar

las típicas relaciones [1 – n] ó [n a m] con otros beans CMP.

La función de un bean CMP es muy similar a la de JDO. Ambas

tecnologías permiten persistir datos con una perspectiva orientada a objetos ya

Análisis y Uso de Frameworks de Persistencia en Java

77

que siempre se persisten objetos y evitan tener que conocer los detalles de cómo

los objetos están almacenados. JDO y CMP también son capaces de manejar

relaciones entre objetos. Por tanto sí se puede hablar de que JDO puede sustituir

a CMP.

Se debe tener en cuenta el crecimiento de las tecnologías. Los beans

CMP todavía necesitan aumentar su aceptación en la comunidad de

programadores. La mayor parte de las mejoras y crecimiento en general de las

EJBs ha sido en el área de sesión. CMP y JDO padecen los mismos problemas a

la hora de ser acogidos ya que ambas tecnologías abstraen demasiado al

programador de lo que realmente sucede a nivel SQL. A la hora de realizar

consultas complicadas el programador debe dedicar mucho tiempo intentando

descubrir cómo generar dicha consulta equivalente a la sentencia SQL. En estos

casos los programadores preferirían haber programado en SQL desde un primer

momento.

JDO vs. JDBC/SQL

Sustituir a JDBC no es exactamente lo que busca JDO de la misma forma

que podría hacerlo con CMP. JDO puede ser realmente una buena capa en el

nivel superior a JDBC. En la mayoría de las instancias de JDO, se debe

especificar una fuente de datos JDBC que establezca una referencia a la base de

datos que JDO va a estar manejando. Por tanto, comparar a JDO con JDBC es

Análisis y Uso de Frameworks de Persistencia en Java

78

algo que se debe hacer si se duda entre usar directamente JDBC o permitir que

JDO lo use en lugar del programador.

Por una parte JDO libera al programador de la tarea de construir

consultas SQL y de distribuir entre los atributos de un objeto Java los resultados

obtenidos en un result set. Si se considera que la mayor parte de consultas JDBC

se realizan con el fin de dar valores a los atributos de objetos Java, JDO debería

ser una alternativa a tener en cuenta, puesto que en lugar de ejecutar una

consulta y copiar los campos desde el result set de JDBC a objetos Java, JDO se

puede hacer cargo de todo ello.

Las críticas a JDO vienen precisamente por las grandes cantidades de

accesos innecesarios que realiza para llevar a cabo su tarea. JDO debe coger su

consulta JDOQL y convertirla en su consulta SQL correspondiente. Entonces,

esta consulta SQL es enviada a la base de datos, los resultados son recibidos y

almacenados en sus respectivos objetos. Si hubiera un gran número de relaciones

entre los objetos, es muy fácil que, como consecuencia, JDO haya accedido a

muchos más datos de los necesarios. Es evidente que JDBC siempre va a ser más

rápido que JDO ya que es más directo. Será elección del programador si la

comodidad en la forma de trabajar que le ofrece JDO compensa su peor

rendimiento.

Otro de los aspectos discutidos de JDO es la posibilidad de sustituir SQL

por JDOQL. Cuando se usa JDBC se debe acudir a SQL para componer las

consultas mientras que con JDO se usa JDOQL. JDOQL es un lenguaje de

Análisis y Uso de Frameworks de Persistencia en Java

79

consultas basado en Java. Por una parte, JDOQL es mucho más sencillo de

componer que SQL, especialmente cuando nos referimos a consultas sencillas.

Sin embargo, no existen muchos programadores que dominen JDOQL.

De momento, este problema va a seguir existiendo ya que, como se ha

comentado anteriormente, JDO no ha sido muy acogido en la industria del

desarrollo de software. La mayoría de los programadores dominan SQL, y

además son capaces de construir consultas SQL muy optimizadas a pesar de

tener una gran complejidad.

Para muchos programadores, una herramienta que crea consultas

automáticamente no es de gran utilidad, sobre todo si nos referimos a JDOQL,

que solamente actúa en aplicaciones Java. Antes o después SQL será sustituido,

pero para ello tendrá que llevarlo a cabo una tecnología más universal.

Hibernate vs. JDO

Hibernate se caracteriza por su completa transparencia para el

programador. Al contrario que JDO, Hibernate se encarga de todo el proceso de

persistencia. No hay que pasar por la tarea de ejecutar nada parecido al

JDOEnhancer. Hibernate se encarga de hacer todo el proceso transparente, ya

que basta con añadir sus librerías a la aplicación y rellenar su archivo de

Análisis y Uso de Frameworks de Persistencia en Java

80

configuración para asignar la base de datos con la que se va a trabajar. Una vez

dispuestos los ficheros de mapeo, se puede trabajar con la misma facilidad con la

que se codifica con cualquier librería Java.

Otro punto muy a su favor es que Hibernate mantiene la posibilidad de

realizar sus consultas en SQL. El HQL es el lenguaje para consulta específico de

Hibernate, al igual que el JDOQL es el lenguaje a través del cual se realizan las

consultas cuando se trabaja con JDO. Para usar JDO, el JDOQL es

indispensable, ofreciendo una gran comodidad al programador a la hora de

componer consultas sencillas. Sin embargo, cuando se trata de realizar

sentencias más complejas, un programador que domine SQL con un nivel alto

seguramente eche de menos la alternativa estándar. Hibernate ofrece ambas

posibilidades.

3.5.- CONCLUSIONES

Se han encontrado muchos puntos de interés a través de la búsqueda de

información para el análisis de las diferentes tecnologías. Entre tantos, cabe

destacar la cantidad de usuarios que defienden una tecnología advirtiendo que es

la que mejor se adapta a su sistema.

Análisis y Uso de Frameworks de Persistencia en Java

81

El uso de los frameworks de persistencia se lleva a cabo, generalmente,

cuando un equipo de programadores busca una alternativa para intentar mejorar

el rendimiento de sus aplicaciones o para incrementar la sencillez de su

codificación y portabilidad. Las tecnologías que se han propuesto brindan esa

oportunidad a los usuarios, pero la clave a la hora de decidir sobre su

implantación está en su forma de adaptarse al sistema, y esto depende de algunos

factores que solamente se pueden identificar por medio de la experiencia

obtenida al probar varias alternativas.

Para mostrar la viabilidad de estas tecnologías se ha de escoger una de las

alternativas estudiadas. Siendo coherentes con la reflexión precedente y con el

apartado de evaluación, Hibernate es la alternativa más apropiada para ocuparse

de la persistencia en la aplicación que se va a desarrollar en el siguiente capítulo.

Estas son las razones fundamentales de por qué Hibernate se adapta a las

necesidades que se presentan:

o Es 100% orientado a objetos:

Hibernate es capaz de persistir clases que siguen una

orientación orientada a objetos, incluyendo herencia,

polimorfismo, relaciones de asociación y composición, y

colecciones.

Análisis y Uso de Frameworks de Persistencia en Java

82

o Máxima transparencia:

Hibernate es capaz de que el programador se olvide de la

tarea extraordinaria que se realiza al trabajar con una base de

datos. Todo el código para utilizar Hibernate será Java puro, ya

que existen cómodos asistentes para crear los archivos de

configuración y mapeo, que son XML. Además, en ninguna fase

de su utilización (instalación, configuración, desarrollo y

ejecución) será necesario escribir una sola instrucción en línea de

comandos, como sucede con JDO a la hora de ejecutar el

modificador de byte codes, el JDOEnhancer.

o Ofrece HQL pero también permite SQL:

Hibernate proporciona HQL, su propio lenguaje de

consulta cuya sintaxis busca mayor sencillez en cada sentencia.

Este lenguaje es similar a SQL, lo que aporta mucha facilidad a la

hora de aprender sus cláusulas. Sin embargo, para los

programadores que lo prefieran, Hibernate permite el uso de

sentencias SQL, con el fin de proporcionar libertad de elección,

sobre todo cuando hay que componer sentencias complejas.

o Herramientas oficiales de ayuda al mapeo:

Dentro de las diferentes herramientas oficiales que ofrece

Hibernate para facilitar su implantación, se encuentra el Mapping

Editor. Esta herramienta para la creación de los ficheros XML de

mapeo proporciona auto-relleno de campos como el nombre de la

Análisis y Uso de Frameworks de Persistencia en Java

83

clase, de los atributos, de la tabla correspondiente y de sus

columnas.

o Respaldo de una comunidad Open Source activa:

Hibernate es un proyecto profesional Open Source y un

componente crítico del catálogo de productos de JBoss Enterprise

Middleware System (JEMS). JBoss es una división de Red Hat, y

ofrece servicios de mantenimiento, consulta y entrenamiento para

asistir a sus usuarios.

Análisis y Uso de Frameworks de Persistencia en Java

84

4- Diseño y Desarrollo de la Aplicación

Análisis y Uso de Frameworks de Persistencia en Java

85

4- DISEÑO Y DESARROLLO DE LA APLICACIÓN

4.1- OBJETIVOS

Se pretende diseñar una aplicación que verifique la viabilidad de una de las

alternativas de persistencia O/R. La aplicación consistirá en un portal Web que

proporcione un interfaz mediante el cual se realicen múltiples accesos a una base de

datos relacional. Dicho portal presentará los resultados solicitados de forma vistosa y

ordenada. Con esto se pretende aplicar la tecnología a las actividades cotidianas

empresariales.

Puesto que el fin elemental del portal es la explotación de tablas y la distribución

de su información por todos los departamentos interesados en una empresa, se pretende

situar la aplicación en un entorno de intranet, de forma que solamente tengan acceso a

ella los empleados. Para hacer del portal una herramienta adecuada para todo tipo de

departamentos se deberán gestionar los perfiles de los usuarios con el fin de ofrecer los

servicios correspondientes a cada uno de ellos. Finalmente, para ser coherentes con la

motivación del proyecto, se deberá conseguir que la aplicación sea una herramienta

intuitiva y de uso cotidiano por parte de empleados de cualquier departamento de la

empresa, independientemente de su nivel de conocimientos.

La aplicación deberá adaptarse a MySQL Server, siendo este el gestor de bases

de datos que se va a utilizar. Se trabajará con MySQL por ser un sistema que admite

Análisis y Uso de Frameworks de Persistencia en Java

86

varias conexiones simultáneas, además de ser Open Source. Además, MySQL está

acompañado de herramientas como MySQL Administrator y MySQL Query Browser,

que, gracias a sus cuidados interfaces, son de gran ayuda a la hora de gestionar las bases

de datos.

4.2- DESCRIPCIÓN DE LA APLICACIÓN

La aplicación a desarrollar consiste en un portal Web para uso cotidiano, que

será accesible a través de la intranet en una pequeña empresa. Dado el carácter del

proyecto, la aplicación se basa en una empresa ficticia, pero gracias a un diseño sencillo

y sólido, añadiendo nuevas funcionalidades se podría adaptar a múltiples usos reales.

La empresa en cuestión consiste en una clínica privada de alergología. El portal

pretende servir de punto de encuentro entre todos los empleados, desde los médicos

hasta el personal informático. Además de ser una fuente de información para todos los

usuarios (noticias, enlaces de interés, etc…) el portal proporciona servicios a los

empleados, convirtiéndose en una útil herramienta para su trabajo cotidiano.

Al existir diferentes tipos de empleados, el portal adoptará un aspecto

determinado para cada perfil de usuario, ofreciendo a cada uno los servicios

correspondientes. En este caso, el personal informático tomará un papel de

Análisis y Uso de Frameworks de Persistencia en Java

87

administrador del portal, al servicio de las funcionalidades que están a disposición del

personal médico y administrativo de la clínica.

Para realizar un sencillo diseño de la aplicación Web se van a seguir las

siguientes etapas:

• Identificación de los requisitos funcionales mediante la definición de los Casos

de Uso y su representación mediante diagramas.

• Diseño externo mediante la asociación entre los Casos de Uso y los diseños de

páginas Web correspondientes realizados con HTML.

• Diseño interno a partir de los Casos de Uso, definiendo las herramientas, las

clases Java y el modelo de datos.

4.3– REQUISITOS FUNCIONALES

4.3.1. Actores Participantes

El portal está dirigido a todos los empleados de la clínica, entre los que se

distinguen tres grupos con perfiles diferentes:

a) Personal Informático (INF):

Análisis y Uso de Frameworks de Persistencia en Java

88

Este grupo desempeña el papel de administrador del portal, ocupándose

principalmente de la gestión de las cuentas. Por otra parte, debe tener acceso a

otras funcionalidades con el fin de supervisar la integridad de los datos.

b) Personal Médico (MED):

En este grupo se encuentran los médicos de la clínica. Éstos tendrán

acceso privilegiado a los datos de los pacientes que tengan asignados, así como a

su historia médica.

c) Personal Administrativo (AMD)

Los administrativos son los empleados encargados de recibir a los

clientes. De este modo gestionan los datos de todos los pacientes y los asocian

con un médico determinado.

4.3.2. Casos de Uso

Los requisitos funcionales de la aplicación vienen definidos por los siguientes

casos de uso:

1. Inicio

1.1. Solicitud de cuenta

1.2. Identificación

2. Navegación básica

2.1. Consulta de noticias

2.2. Cambio de contraseña

2.3. Consulta de enlaces

3. Acceso a Tablas

Análisis y Uso de Frameworks de Persistencia en Java

89

3.1. Gestión de pacientes

3.1.1. Creación de paciente

3.1.2. Edición de paciente

3.1.3. Eliminación de paciente

4. Acceso a Pacientes

4.1. Gestión de alergias

4.1.1. Asignación de alergia

4.1.2. Edición de alergia

4.1.3. Eliminación de alergia

5. Acceso a Portal

5.1. Gestión de noticias

5.1.1. Creación de noticia

5.1.2. Edición de noticia

5.1.3. Eliminación de noticia

5.2. Gestión de cuentas

5.2.1. Activación/Desactivación de cuenta

5.2.2. Edición de cuenta

5.2.3. Eliminación de cuenta

6. Cierre de sesión

6.1. Cierre de Sesión

Análisis y Uso de Frameworks de Persistencia en Java

90

DESCRIPCIÓN DETALLADA DE LOS CASOS DE USO

1. Inicio

ESCENARIO: 1.1. Solicitud de cuenta

ACTORES: INF, MED, ADM

Precondición: Seleccionar la opción “Registrarse” en la pantalla de inicio.

Flujo Primario:

1. El sistema pide los datos del usuario y su perfil.

2. El usuario introduce sus datos y envía el formulario.

3. El sistema valida los datos y advierte que la cuenta ha sido solicitada.

Flujo Secundario:

- El campo “Usuario” tiene un valor que ya existe:

El sistema advierte del error en la pantalla y vuelve a pedir los datos.

- La confirmación de contraseñas es incorrecta:

El sistema advierte del error en la pantalla y vuelve a pedir los datos.

- El campo “Dni” está vacío o no se ha seleccionado ningún perfil:

El sistema vuelve a pedir los datos.

ESCENARIO: 1.2. Identificación

ACTORES: INF, MED, ADM

Precondición: -

Flujo Primario:

1. El sistema pide los datos de identificación: Usuario y Contraseña.

2. El usuario introduce sus datos y envía el formulario.

Análisis y Uso de Frameworks de Persistencia en Java

91

3. El sistema valida los datos y da acceso al portal habilitando las opciones

correspondientes según su perfil.

Flujo Secundario:

- Los datos introducidos son válidos pero la cuenta no ha sido activada:

El sistema advierte del error y vuelve a pedir los datos.

- Los datos introducidos no son válidos:

El sistema advierte del error y vuelve a pedir los datos.

2. Navegación Básica

ESCENARIO: 2.1. Consulta de noticias

ACTORES: INF, MED, ADM

Precondiciones:

- El usuario acaba de acceder al portal.

- El usuario ha seleccionado la opción “Noticias” en la barra de navegación.

Flujo Primario:

1. El sistema muestra todas las noticias que se encuentran en la base de

datos, ordenadas por Fecha descendientemente.

Flujo Secundario: -

ESCENARIO: 2.2. Cambio de contraseña

ACTORES: INF, MED, ADM

Precondición: El usuario ha seleccionado la opción “Usuario” en la barra de

navegación.

Análisis y Uso de Frameworks de Persistencia en Java

92

Flujo Primario:

1. El sistema pide la contraseña actual del usuario y la nueva contraseña.

2. El usuario introduce los datos y envía el formulario.

3. El sistema valida los datos y advierte que la contraseña ha cambiado.

Flujo Secundario:

- La contraseña actual o la confirmación de nueva contraseña es incorrecta:

El sistema advierte del error y vuelve a pedir los datos.

ESCENARIO: 2.3. Consulta de enlaces

ACTORES: INF, MED, ADM

Precondición: El usuario ha seleccionado la opción “Enlaces” en la barra de

navegación.

Flujo Primario:

1. El sistema muestra diversos enlaces de interés.

2. El usuario pulsa sobre un enlace, que se abrirá en otra ventana o pestaña

de su navegador.

Flujo Secundario: -

3. Acceso a Tablas

3.1. Gestión de Pacientes

ESCENARIO: 3.1.1. Creación de paciente

ACTORES: INF, ADM

Análisis y Uso de Frameworks de Persistencia en Java

93

Precondición: El usuario ha seleccionado la opción “Nuevo Paciente” dentro de la

sección “Tablas” de la barra de navegación.

Flujo Primario:

1. El sistema pide los datos del nuevo paciente y muestra los médicos

disponibles en la base de datos.

2. El usuario introduce los datos del nuevo paciente, asignándole un médico

y envía el formulario.

3. El sistema valida los datos y advierte que el paciente ha sido dado de

alta.

Flujo Secundario:

- El dni del paciente ya ha sido registrado anteriormente:

El sistema advierte del error y vuelve a pedir los datos.

- No se ha asignado ningún médico:

El sistema advierte del error y vuelve a pedir los datos.

ESCENARIO: 3.1.2. Edición de paciente

ACTORES: INF, ADM

Precondición: El usuario ha seleccionado un paciente y pulsa sobre la opción “Editar”

dentro de la sección “Tablas” de la barra de navegación.

Flujo Primario:

1. El sistema muestra los datos del paciente y da opción a cambiarlos.

2. El usuario hace las modificaciones pertinentes y envía el formulario.

3. El sistema advierte que los datos del paciente se han actualizado.

Flujo Secundario: -

Análisis y Uso de Frameworks de Persistencia en Java

94

ESCENARIO: 3.1.3. Eliminación de paciente

ACTORES: INF, ADM

Precondición: El usuario ha seleccionado un paciente y pulsa sobre la opción “Borrar”

dentro de la sección “Tablas” de la barra de navegación.

Flujo Primario:

1. El sistema elimina el paciente seleccionado de la base de datos.

Flujo Secundario: -

4. Acceso a Pacientes

4.1. Gestión de Alergias

ESCENARIO: 4.1.1. Asignación de Alergia

ACTORES: MED

Precondición: El usuario ha seleccionado la opción “Pacientes” en la barra de

navegación.

Flujo Primario:

1. El sistema muestra los pacientes que tiene asignados el usuario.

2. El usuario selecciona un paciente y elige la opción “Ver Alergias”.

3. El sistema muestra las alergias que tiene asignadas el paciente.

4. El usuario elige la opción “Asignar Alergia”.

5. El sistema pide los datos de la alergia.

6. El usuario introduce los datos de la alergia y envía el formulario.

7. El sistema valida los datos y advierte que se ha asignado una alergia.

Flujo Secundario:

Análisis y Uso de Frameworks de Persistencia en Java

95

- No se ha especificado el tipo de alergia:

El sistema advierte del error y vuelve a pedir los datos.

- El tipo de alergia especificado ya ha sido asignado a ese paciente:

El sistema advierte del error y vuelve a pedir los datos.

ESCENARIO: 4.1.2. Edición de Alergia

ACTORES: MED

Precondición: El usuario ha seleccionado la opción “Pacientes” en la barra de

navegación.

Flujo Primario:

1. El sistema muestra los pacientes que tiene asignados el usuario.

2. El usuario selecciona un paciente y elige la opción “Ver Alergias”.

3. El sistema muestra las alergias que tiene asignadas el paciente.

4. El usuario selecciona un tipo de alergia y elige la opción “Ver Detalles”.

5. El sistema muestra los datos de la alergia.

6. El usuario modifica los datos de la alergia y envía el formulario.

7. El sistema valida los datos y advierte que se han modificado los detalles.

Flujo Secundario: -

ESCENARIO: 4.1.3. Eliminación de Alergia

ACTORES: MED

Desencadenante: El usuario ha seleccionado la opción “Pacientes” en la barra de

navegación.

Flujo Primario:

1. El sistema muestra los pacientes que tiene asignados el usuario.

Análisis y Uso de Frameworks de Persistencia en Java

96

2. El usuario selecciona un paciente y elige la opción “Ver Alergias”.

3. El sistema muestra las alergias que tiene asignadas el paciente.

4. El usuario selecciona un tipo de alergia y elige la opción “Borrar”.

5. El sistema elimina la alergia asignada y vuelve a mostrar la lista.

Flujo Secundario: -

5. Acceso a Portal

5.1. Gestión de Noticias

ESCENARIO: 5.1.1. Creación de noticia

ACTORES: INF

Precondición: El usuario ha seleccionado la opción “Portal” en la barra de navegación.

Flujo Primario:

1. El sistema muestra las opciones de gestión del portal.

2. El usuario selecciona la opción “Gestión de Noticias”.

3. El sistema muestra las noticias existentes.

4. El usuario selecciona la opción “Nueva Noticia”.

5. El sistema pide los datos de la nueva noticia.

6. El usuario introduce los datos y envía el formulario.

7. El sistema crea la noticia.

Flujo Secundario: -

ESCENARIO: 5.1.2. Edición de noticia

ACTORES: INF

Análisis y Uso de Frameworks de Persistencia en Java

97

Precondición: El usuario ha seleccionado la opción “Portal” en la barra de navegación.

Flujo Primario:

1. El sistema muestra las opciones de gestión del portal.

2. El usuario elige la opción “Gestión de Noticias”.

3. El sistema muestra las noticias existentes.

4. El usuario selecciona una noticia y elige la opción “Editar”.

5. El muestra los datos de la noticia seleccionada y permite su modificación.

6. El usuario modifica los datos de la noticia y envía el formulario.

7. El sistema actualiza los datos y advierte que la noticia ha sido modificada.

Flujo Secundario: -

ESCENARIO: 5.1.3. Eliminación de noticia

ACTORES: INF

Precondición: El usuario ha seleccionado la opción “Portal” en la barra de navegación.

Flujo Primario:

1. El sistema muestra las opciones de gestión del portal.

2. El usuario elige la opción “Gestión de Noticias”.

3. El sistema muestra las noticias existentes.

4. El usuario selecciona una noticia y elige la opción “Borrar”.

5. El sistema elimina la noticia y vuelve a mostrar la lista.

Flujo Secundario: -

5.2. Gestión de Cuentas de Usuario

Análisis y Uso de Frameworks de Persistencia en Java

98

ESCENARIO: 5.2.1. Activación / Desactivación de cuenta

ACTORES: INF

Precondición: El usuario ha seleccionado la opción “Portal” en la barra de navegación.

Flujo Primario:

1. El sistema muestra las opciones de gestión del portal.

2. El usuario elige la opción “Gestión de Cuentas”.

3. El sistema muestra las cuentas existentes, incluyendo las que están

desactivadas.

4. El usuario selecciona una cuenta y elige la opción “Activar / Desactivar”.

5. El sistema cambia el estado de actividad de la cuenta y vuelve a mostrar la

lista.

Flujo Secundario: -

ESCENARIO: 5.2.2. Edición de cuenta

ACTORES: INF

Precondición: El usuario ha seleccionado la opción “Portal” en la barra de navegación.

Flujo Primario:

1. El sistema muestra las opciones de gestión del portal.

2. El usuario elige la opción “Gestión de Cuentas”.

3. El sistema muestra las cuentas existentes, incluyendo las que están

desactivadas.

4. El usuario selecciona una cuenta y elige la opción “Editar”.

5. El sistema muestra los datos de la cuenta y permite su modificación,

exceptuando el perfil.

6. El usuario modifica los datos pertinentes y envía el formulario.

Análisis y Uso de Frameworks de Persistencia en Java

99

7. El sistema valida los datos y advierte que la cuenta ha sido actualizada.

Flujo Secundario: -

ESCENARIO: 5.2.3. Eliminación de cuenta

ACTORES: INF

Precondición: El usuario ha seleccionado la opción “Portal” en la barra de navegación.

Flujo Primario:

1. El sistema muestra las opciones de gestión del portal.

2. El usuario elige la opción “Gestión de Cuentas”.

3. El sistema muestra las cuentas existentes, incluyendo las que están

desactivadas.

4. El usuario selecciona una cuenta y elige la opción “Borrar”.

5. El sistema elimina la cuenta y vuelve a mostrar la lista.

Flujo Secundario: -

6. Cierre de Sesión

ESCENARIO: 6.1. Cierre de Sesión

ACTORES: INF, MED, ADM

Precondición: El usuario ha seleccionado la opción “Cerrar Sesión” en la barra de

navegación.

Flujo Primario:

1. El sistema muestra la pantalla inicial pidiendo los datos de identificación.

Flujo Secundario: -

Análisis y Uso de Frameworks de Persistencia en Java

100

DIAGRAMAS DE LOS CASOS DE USO

• Casos de uso del Personal Informático (INF):

Análisis y Uso de Frameworks de Persistencia en Java

101

• Casos de uso del Personal Administrativo (ADM):

Análisis y Uso de Frameworks de Persistencia en Java

102

• Casos de uso del Personal Médico (MED):

Análisis y Uso de Frameworks de Persistencia en Java

103

4.4- DISEÑO EXTERNO

4.4.1. Diseño del Interfaz del Usuario

• Inicio

- Identificación

Caso de uso: 1.2. Login de Acceso

Esta es la pantalla de inicio de la aplicación. A través del botón “Registrarse” en

la parte inferior derecha, el sistema pedirá los datos a un nuevo usuario para que realice

su solicitud de una nueva cuenta.

Análisis y Uso de Frameworks de Persistencia en Java

104

- Solicitud de Cuenta

Caso de uso: 1.1. Solicitud de Cuenta

Después de realizar la solicitud el sistema conducirá de nuevo al inicio de la

aplicación, donde se pedirán otra vez los datos de identificación.

Análisis y Uso de Frameworks de Persistencia en Java

105

• Navegación básica

- Consulta de noticias

Caso de uso: 2.1. Consulta de Noticias

Este es el aspecto que tendrá el portal. Desde aquí se accede a todas las

funcionalidades disponibles para el usuario a través de la barra de navegación situada en

el lateral izquierdo. En la parte superior derecha, el sistema muestra el perfil y el

nombre del usuario que ha iniciado la sesión.

La aplicación da la bienvenida con las últimas noticias ordenadas por fecha

descendentemente. Esta información será accesible en cualquier momento desde la

opción “Noticias” que aparece en la barra de navegación.

Análisis y Uso de Frameworks de Persistencia en Java

106

- Cambio de contraseña

Caso de uso: 2.2. Cambio de Contraseña

Esta funcionalidad se ubicará en el apartado “Usuario” de la barra de

navegación. Como se aprecia en la imagen, el sistema pedirá que el usuario introduzca

de nuevo su contraseña actual por cuestiones de seguridad.

Análisis y Uso de Frameworks de Persistencia en Java

107

- Consulta de enlaces

Caso de uso: 2.3. Consulta de Enlaces

En el apartado “Enlaces” los usuarios tendrán acceso a diversos enlaces de

utilidad para su uso cotidiano. Al pulsar sobre uno de ellos, la página Web

correspondiente se abrirá en una nueva ventana o pestaña del navegador.

Análisis y Uso de Frameworks de Persistencia en Java

108

• Gestión de pacientes

- Creación de paciente

Caso de uso: 3.1.1. Creación de Paciente

Este es el formulario que presentará el sistema al usuario para recibir los datos

de un nuevo paciente. Los médicos que figuren en la base de datos aparecerán en la

casilla “Médico” para realizar la asignación del paciente.

Análisis y Uso de Frameworks de Persistencia en Java

109

- Edición de paciente

Caso de uso: 3.1.2. Edición de Paciente

Este formulario muestra los datos del paciente correspondiente, así como el

médico que tiene asignado. Se permitirá el cambio de médico entre otras cosas.

Análisis y Uso de Frameworks de Persistencia en Java

110

- Eliminación de paciente

Caso de uso: 3.1.3. Eliminación de paciente

Esta será la pantalla que presenta el sistema para gestionar los pacientes. El

sistema muestra una lista con todos los pacientes registrados en la base de datos. Desde

aquí se accederá a los formularios para la creación y edición de los pacientes.

Para eliminar un paciente, se debe seleccionar uno de ellos y pulsar el botón

“Borrar” situado en la parte superior de la lista.

Análisis y Uso de Frameworks de Persistencia en Java

111

• Gestión de alergias

- Asignación de alergia

Caso de uso: 4.1.1. Asignación de Alergia

Mediante este formulario el médico asignará un tipo de alergia a uno de sus

pacientes. El sistema no permitirá registrar dos veces un tipo de alergia determinado a

un mismo paciente.

Análisis y Uso de Frameworks de Persistencia en Java

112

- Edición de alergia

Caso de uso: 4.1.2. Edición de Alergia

A través de este formulario el médico podrá ver los detalles de la alergia

correspondiente, así como cambiar el tratamiento.

Análisis y Uso de Frameworks de Persistencia en Java

113

- Eliminación de alergia

Caso de uso: 4.1.3. Eliminación de Alergia

Esta será la pantalla que presenta el sistema para gestionar las alergias. El

sistema muestra una lista con las alergias asignadas a un paciente determinado. Desde

aquí se accederá a los formularios para la asignación y edición de las alergias.

Para eliminar una alergia, se debe seleccionar una de ellas y pulsar el botón

“Borrar” situado en la parte superior de la lista.

Análisis y Uso de Frameworks de Persistencia en Java

114

• Gestión del Portal (Noticias y Cuentas de Usuario)

Esta es la pantalla que presenta el sistema al informático para gestionar el portal.

Desde aquí se accederá a la “Gestión de Noticias” y a la “Gestión de Cuentas”.

Análisis y Uso de Frameworks de Persistencia en Java

115

- Creación de noticia

Caso de uso: 5.1.1. Creación de Noticia

Este es el formulario que presentará el sistema al informático para recibir los

datos de una nueva noticia.

Análisis y Uso de Frameworks de Persistencia en Java

116

- Edición de noticia

Caso de uso: 5.1.2. Edición de Noticia

A través de este formulario el informático podrá ver los detalles de la noticia

correspondiente y modificar cualquiera de sus datos.

Análisis y Uso de Frameworks de Persistencia en Java

117

- Eliminación de noticia

Caso de uso: 5.1.3. Eliminación de Noticia

Esta será la pantalla que presenta el sistema para gestionar las noticias. El

sistema muestra una lista con las noticias existentes en la base de datos. Desde aquí se

accederá a los formularios para la creación y edición de las noticias.

Para eliminar una noticia, se debe seleccionar una de ellas y pulsar el botón

“Borrar” situado en la parte superior de la lista.

Análisis y Uso de Frameworks de Persistencia en Java

118

- Activación/Desactivación de cuenta y Eliminación de cuenta

Casos de uso:

5.2.1. Activación / Desactivación de Cuenta

5.2.3. Eliminación de cuenta

Esta será la pantalla que presenta el sistema para gestionar las cuentas. El

sistema muestra una lista con las cuentas de usuario, incluyendo las que no están

activas. Desde aquí se accederá al formulario para la edición de las cuentas.

Para eliminar una noticia o cambiar su estado de actividad, se debe seleccionar

una de ellas y pulsar el botón “Borrar” o “Activar / Desactivar” respectivamente.

Análisis y Uso de Frameworks de Persistencia en Java

119

- Edición de cuenta

Caso de uso: 5.2.2. Edición de Cuenta

A través de este formulario el informático podrá ver los detalles de la cuenta de

usuario correspondiente y modificar cualquiera de sus. Además, el sistema mostrará su

perfil, su dni y su estado de actividad en la parte superior. Para cambiar el perfil o el

dni, el usuario correspondiente a la cuenta deberá realizar una nueva solicitud.

Análisis y Uso de Frameworks de Persistencia en Java

120

• Cierre de Sesión

Caso de uso: 6.1. Cierre de Sesión

Con el fin de abandonar el portal el usuario deberá elegir la opción “Cerrar

Sesión” situada en la parte inferior de la barra de navegación. El sistema volverá a pedir

los datos de identificación en la página de inicio de la aplicación.

Análisis y Uso de Frameworks de Persistencia en Java

121

4.5- DISEÑO INTERNO

4.5.1- JSP y Servlets

Para hacer posible el desarrollo de la aplicación Web se va a diseñar una

estructura unida de páginas dinámicas JSP. Las páginas JSP permiten ejecutar

código Java con el fin de generar HTML dinámicamente. Esto será esencial,

entre otras cosas, para mostrar resultados de consultas a las bases de datos y para

mostrar mensajes de error cuando sea necesario.

Para la recepción de los formularios y la validación de sus datos se

utilizarán Servlets. Mediante algoritmos de validación y accesos a las bases de

datos, los diversos Servlets se encargarán de ejecutar un código u otro

dependiendo de los datos introducidos en los formularios. Posteriormente

devuelven el control a las páginas JSP.

Para realizar el diseño se analizarán los diferentes subsistemas de casos

de uso y se definirán las páginas JSP y Servlets necesarios para su viabilidad.

Los subsistemas son: Inicio, Navegación Básica, Gestión de Pacientes, Gestión

de Tablas, Gestión de Alergias, Gestión de Noticias y Gestión de Cuentas.

Análisis y Uso de Frameworks de Persistencia en Java

122

Subsistema: INICIO

Caso de Uso: 1.1. Solicitud de cuenta

- JSP: registro.jsp

- Servlet asociado: ValidaRegistro.java

Caso de Uso: 1.2. Identificación

- JSP: index.jsp

- Servlet asociado: ValidaUsuario.java

Subsistema: NAVEGACIÓN BÁSICA

Caso de Uso: 2.1. Consulta de Noticias

- JSP: home.jsp

- Servlet asociado: -

Caso de Uso: 2.2. Cambio de Contraseña

- JSP: usuario.jsp

- Servlet asociado: CambiaPass.java

Caso de Uso: 2.3. Consulta de Enlaces

- JSP: enlaces.jsp

- Servlet asociado: -

Análisis y Uso de Frameworks de Persistencia en Java

123

Subsistema: GESTIÓN DE PACIENTES

Caso de Uso: 3.1.1. Creación de Paciente

- JSP: creacionPaciente.jsp

- Servlet asociado: CreaPaciente.java

Caso de Uso: 3.1.2. Edición de Paciente

- JSP: edicionPaciente.jsp

- Servlet asociado: EditaPaciente.java

Caso de Uso: 3.1.3. Eliminación de Paciente

- JSP: tablas.jsp

- Servlet asociado: GestionaPaciente.java

Subsistema: GESTIÓN DE ALERGIAS

Caso de Uso: 4.1.1. Asignación de Alergia

- JSP: creacionAlergia.jsp

- Servlet asociado: CreaAlergia.java

Caso de Uso: 4.1.2. Edición de Alergia

- JSP: edicionAlergia.jsp

- Servlet asociado: EditaAlergia.java

Análisis y Uso de Frameworks de Persistencia en Java

124

Caso de Uso: 4.1.3. Eliminación de Alergia

- JSP: pacientesAlergias.jsp

- Servlet asociado: GestionaEnfermedad.java

Subsistema: GESTIÓN DE NOTICIAS

Caso de Uso: 5.1.1. Creación de Noticia

- JSP: creacionNoticia.jsp

- Servlet asociado: CreaNoticia.java

Caso de Uso: 5.1.2. Edición de Noticia

- JSP: edicionNoticia.jsp

- Servlet asociado: EditaNoticia.java

Caso de Uso: 5.1.3. Eliminación de Noticia

- JSP: portalNoticias.jsp

- Servlet asociado: GestionaNoticia.java

Subsistema: GESTIÓN DE CUENTAS

Caso de Uso: 5.2.1. Activación / Desactivación de Cuenta

- JSP: portalCuentas.jsp

Análisis y Uso de Frameworks de Persistencia en Java

125

- Servlet asociado: GestionaCuenta.java

Caso de Uso: 5.2.2. Edición de Cuenta

- JSP: edicionCuenta.jsp

- Servlet asociado: EditaCuenta.java

Caso de Uso: 5.2.3. Eliminación de Cuenta

- JSP: portalCuentas.jsp

- Servlet asociado: GestionaCuenta.java

Análisis y Uso de Frameworks de Persistencia en Java

126

4.5.2- Diagrama de Navegación

En el siguiente diagrama viene reflejada la intaracción entre todas las

páginas JSP que forman el sistema. Todas las líneas de conexión implican

navegación bidireccional, exceptuando aquellas que terminan con punta de

flecha. Las páginas JSP situadas dentro del recuadro gris sólo son accesibles

después de realizar la identificación.

Análisis y Uso de Frameworks de Persistencia en Java

127

4.5.3- Diagramas de clases

La aplicación va a trabajar con dos tipos de clases:

a) Clases objeto

b) Clases de acceso a la base de datos

Las clases objeto, que van a situarse en un paquete llamado “obj”, vienen

definidas por los subsistemas de gestión, debiendo crear una clase por cada uno

de ellos:

GESTIÓN DE PACIENTES Paciente.java

GESTIÓN DE ALERGIAS Alergia.java

GESTIÓN DE NOTICIAS Noticia.java

GESTIÓN DE CUENTAS DE USUARIO Usuario.java

Sin embargo, las clases de acceso a base de datos, que van a situar se en

un paquete llamado “util”, vienen definidas por la necesidad de persistencia de

cada uno de los objetos. En un principio, para desarrollar una primera versión

del portal, utilizaremos clases DAO para trabajar con JDBC. En el capítulo 5 se

verá cómo se va a sustituir JDBC por un framework de persistencia. Hasta

entonces se construirá la aplicación con JDBC, y éstas serán sus clases DAO:

Análisis y Uso de Frameworks de Persistencia en Java

128

Paciente.java DAO_paciente.java

Alergia.java DAO_alergia.java

Noticia.java DAO_noticia.java

Usuario.java DAO_usuario.java

Las clases no tienen relaciones entre sí, por tanto se representan por separado:

DIAGRAMAS UML DE CLASES OBJETO

Paciente.java

Análisis y Uso de Frameworks de Persistencia en Java

129

Alergia.java

Noticia.java

Análisis y Uso de Frameworks de Persistencia en Java

130

Usuario.java

Análisis y Uso de Frameworks de Persistencia en Java

131

DIAGRAMAS UML DE CLASES DE ACCESO A LA BASE DE DATOS

DAO_paciente.java

DAO_alergia.java

Análisis y Uso de Frameworks de Persistencia en Java

132

DAO_noticia.java

DAO_usuario.java

Análisis y Uso de Frameworks de Persistencia en Java

133

4.5.4- El modelo de datos

En esta aplicación el modelo de datos se debe ajustar perfectamente a la

estructura de las clases objeto. De esta forma se consigue simplificar la persistencia y

poder incorporar cómodamente la tecnología que va a sustituir a JDBC.

Las clases están definidas, y cada una de ellas será correspondida con una tabla

en la base de datos. Todos sus atributos van a ser reflejados por columnas en las tablas,

y las claves se definirán por la lógica de la aplicación.

Tabla PACIENTES

Tabla ALERGIAS

En el caso de las Alergias, la clave debe ser compuesta, ya que la aplicación no

permite tener más de un registro de un tipo de alergia para un mismo paciente.

Análisis y Uso de Frameworks de Persistencia en Java

134

Tabla NOTICIAS

Tabla USUARIOS

Análisis y Uso de Frameworks de Persistencia en Java

135

5- La alternativa a JDBC: Hibernate

Análisis y Uso de Frameworks de Persistencia en Java

136

5- LA ALTERNATIVA A JDBC: HIBERNATE

Después de haber diseñado la aplicación, se pueden identificar varias entidades

que, a la hora de persistirlas en su base de datos, se van a corresponder con tablas. En

este capítulo se pretende describir cómo Hibernate abstrae al programador de la

persistencia, creando las tablas a partir de las clases con las que se trabaja en la

aplicación.

La correspondencia entre clases y tablas es fundamental para mantener esa

perspectiva orientada a objetos. Además, se van a enfrentar las clases gestoras de

objetos de Hibernate con las DAO equivalentes de JDBC, con el fin de observar cómo

Hibernate evita el proceso de encapsulamiento y desencapsulamiento. Por último se

verá cómo es el proceso de implantación, echando un vistazo a los requisitos del sistema

y a la configuración de la tecnología.

5.1- LAS CLASES A PERSISTIR

- Usuario.java

La clase Usuario es la más extensa de todas las que se van a

persistir. La aplicación se encarga de que los valores correspondientes a

Análisis y Uso de Frameworks de Persistencia en Java

137

sus atributos “dni” y “user” sean únicos para cada usuario real que

representa la clase.

Este es el código final de la clase “Usuario.java”:

package obj; public class Usuario { private int dni; private String user; private String pass; private String nombre; private String ap1; private String ap2; private String email; private String cod_perfil; private int activo; //Cuenta 0:inactiva, 1:activa public static String PERFIL_MEDICO = "med"; public static String PERFIL_ADMINISTRATIVO = "adm"; public static String PERFIL_INFORMATICO = "inf"; // CONSTRUCTORES public Usuario( int dni, String user, String pass, String nombre, String ap1, String ap2, String email, String cod_perfil, int activo) { this.dni = dni; this.user = user; this.pass = pass; this.nombre = nombre; this.ap1 = ap1; this.ap2 = ap2; this.email = email; this.cod_perfil = cod_perfil; this.activo = activo; } //Constructor para la validación de usuarios public Usuario (String user, String pass){ this.user = user; this.pass = pass; } // Constructor por defecto: necesario para Hibernate

Análisis y Uso de Frameworks de Persistencia en Java

138

public Usuario(){ } // ----- Getters y Setters public String getPass() { return pass; } public void setPass(String pass) { this.pass = pass; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public int getActivo() { return activo; } public void setActivo(int activo) { this.activo = activo; } public String getAp1() { return ap1; } public void setAp1(String ap1) { this.ap1 = ap1; } public String getAp2() { return ap2; } public void setAp2(String ap2) { this.ap2 = ap2; } public String getCod_perfil() { return cod_perfil; } public void setCod_perfil(String cod_perfil) { this.cod_perfil = cod_perfil; } public int getDni() { return dni; } public void setDni(int dni) {

Análisis y Uso de Frameworks de Persistencia en Java

139

this.dni = dni; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } // ----- Otros métodos // Devuelve un String con el nombre completo del usuario public String getNombreCompleto() { String res = this.getAp1() +" "+ this.getAp2()+", "+ this.getNombre(); return res; } // Devuelve el código HTML para mostrar una imagen del Perfil public String perfilToHTML() { String res; if ((this.cod_perfil).equals(Usuario.PERFIL_MEDICO)) { res = "<img src=\"Iconos/perfilMed.jpg\">"; } else { if ((this.cod_perfil).equals(Usuario.PERFIL_ADMINISTRATIVO)) { res = "<img src=\"Iconos/perfilAdm.jpg\">"; } else { res = "<img src=\"Iconos/perfilInf.jpg\">"; } } return res; } // Devuelve el código HTML para mostrar una fila de tabla // con la información de la cuenta. public String toListaHTML(){ String iconoPerfil; String iconoActividad; // Asignación de perfil if ((this.cod_perfil).equals(Usuario.PERFIL_MEDICO)) { iconoPerfil = "<img src=\"Iconos/perfilMedMini.jpg\"width=\"40\" height=\"15\">"; }

Análisis y Uso de Frameworks de Persistencia en Java

140

else { if ((this.cod_perfil).equals(Usuario.PERFIL_ADMINISTRATIVO)) { iconoPerfil = "<img src=\"Iconos/perfilAdmMini.jpg\" width=\"40\" height=\"15\">"; } else { iconoPerfil = "<img src=\"Iconos/perfilInfMini.jpg\" width=\"40\" height=\"15\">"; } } // Asignación de actividad if (this.activo == 1) { iconoActividad = "<img src=\"Iconos/cuentaActiva.jpg\" width=\"100\" height=\"15\">"; } else { iconoActividad = "<img src=\"Iconos/cuentaInactiva.jpg\" width=\"100\" height=\"15\">"; } return "<tr>" + "<td width=\"9%\" align=\"center\" valign=\"middle\">"+ iconoPerfil +"</td>" + "<td width=\"70%\" align=\"left\" valign=\"middle\">" + "<div align=\"left\"><font face=\"Verdana, Arial, Helvetica, sans-serif\" size=\"2\">"+ this.getNombreCompleto() +"</font></div>" + "</td>" + "<td width=\"9%\" align=\"center\" valign=\"middle\">" + "<div align=\"center\"><input type=\"radio\" name=\"rbCuenta\" value=\""+ this.dni +"\"></div>" + "</td>" + "<td width=\"12%\" align=\"center\" valign=\"middle\">" + "<div align=\"center\">"+ iconoActividad +"</div>" + "</td>" + "</tr>"; } }

Cabe destacar que, entre los constructores se encuentra el constructor por

defecto, necesario para que Hibernate trabaje con los objetos “Usuario”. Como se

describe en el siguiente apartado (5.2- Los ficheros de mapeo), “dni” será la clave de la

tabla correspondiente a la hora de persistir esta clase.

Análisis y Uso de Frameworks de Persistencia en Java

141

- Paciente.java

En la clase Paciente nos encontramos con el atributo “dni”, que

será la clave de la tabla correspondiente.

Este es el código final de la clase “Paciente.java”:

package obj; public class Paciente { // Atributos private int dni; private int dni_med; private String nombre; private String ap1; private String ap2; private String telefono; // Constructores public Paciente (){ } public Paciente (int dni){ this.dni = dni; } public Paciente (int dni, int dni_med, String nombre, String ap1, String ap2, String telefono){ this.dni = dni; this.dni_med = dni_med; this.nombre = nombre; this.ap1 = ap1; this.ap2 = ap2; this.telefono = telefono; } // Getters y Setters public String getAp1() { return ap1; } public void setAp1(String ap1) { this.ap1 = ap1; }

Análisis y Uso de Frameworks de Persistencia en Java

142

public String getAp2() { return ap2; } public void setAp2(String ap2) { this.ap2 = ap2; } public int getDni() { return dni; } public void setDni(int dni) { this.dni = dni; } public int getDni_med() { return dni_med; } public void setDni_med(int dni_med) { this.dni_med = dni_med; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public String getTelefono() { return telefono; } public void setTelefono(String telefono) { this.telefono = telefono; } //------- Otros Métodos public String getNombreCompleto() { String res = this.getAp1() +" "+ this.getAp2()+", "+ this.getNombre(); return res; } }

Análisis y Uso de Frameworks de Persistencia en Java

143

- Alergia.java

Esta clase es, aparentemente igual que las demás, pero en el

código se pueden observar algunos detalles interesantes:

package obj; import java.io.Serializable; public class Alergia implements Serializable{ // Atributos private int dni; private String tipo; private String tratamiento; private String notas; // Constructores public Alergia (int dni, String tipo, String tratamiento, String notas){ this.dni = dni; this.tipo = tipo; this.tratamiento = tratamiento; this.notas = notas; } public Alergia (){ } // Getters y Setters public String getTipo() { return tipo; } public void setTipo(String tipo) { this.tipo = tipo; } public int getDni() { return dni; } public void setDni(int dni) { this.dni = dni; } public String getNotas() {

Análisis y Uso de Frameworks de Persistencia en Java

144

return notas; } public void setNotas(String notas) { this.notas = notas; } public String getTratamiento() { return tratamiento; } public void setTratamiento(String tratamiento) { this.tratamiento = tratamiento; } // OTROS MÉTODOS public boolean equals(Object obj){ boolean res = false; if (obj instanceof Alergia){ Alergia a = (Alergia)obj; if (dni==a.getDni() && tipo.equals(a.getTipo())){ res = true; } } System.out.println("Ejecuta EQUALS"); return res; } public int hashCode(){ System.out.println("Ejecuta HASHCODE"); return dni + tipo.hashCode(); } }

La clase “Alergia.java” difiere del resto porque:

implementa el Interface “Serializable”

redefine los métodos “equals()” y “hashCode()”

Esto se debe a que la aplicación se encarga de que un paciente

determinado tenga un registro de “Alergia” por cada tipo de alergia que

padezca. Lógicamente esto quiere decir que los valores de “dni” y “tipo”

formarán una clave compuesta en la tabla correspondiente. Para manejar

Análisis y Uso de Frameworks de Persistencia en Java

145

clases con este tipo de clave, Hibernate necesita que se codifiquen dichas

requerimientos en la clase correspondiente.

- Noticia.java

Esta es la clase más sencilla e independiente de la aplicación. Este

el código final de la clase:

package obj; public class Noticia { // Atributos private String fecha; private String titulo; private String cuerpo; private int codigo; // Constructores public Noticia (){ } public Noticia (int codigo){ this.codigo = codigo; } public Noticia (String fecha, String titulo, String cuerpo, int codigo){ this.fecha = fecha; this.titulo = titulo; this.cuerpo = cuerpo; this.codigo = codigo; } // MÉTODOS // Getters y Setters public String getCuerpo() { return cuerpo; } public void setCuerpo(String cuerpo) { this.cuerpo = cuerpo; }

Análisis y Uso de Frameworks de Persistencia en Java

146

public String getFecha() { return fecha; } public void setFecha(String fecha) { this.fecha = fecha; } public String getTitulo() { return titulo; } public void setTitulo(String titulo) { this.titulo = titulo; } public int getCodigo() { return codigo; } public void setCodigo(int codigo) { this.codigo = codigo; } // Otros Métodos public String toHTML(){ return "<table width=\"75%\" border=\"0\" height=\"108\">" + "<tr>" + "<td height=\"11\" bgcolor=\"#000000\"><font face=\"Verdana, Arial, Helvetica, sans-serif\" color=\"#FFFFFF\">" + "<font size=\"2\"><img src=\"Iconos/dot.gif\" width=\"12\" height=\"12\"> - " + this.fecha +" - <b>"+ this.titulo +"</b></font></font></td>" + "</tr>" + "<tr>" + "<td valign=\"top\" align=\"left\" height=\"70\"><font face=\"Verdana, Arial, Helvetica, sans-serif\" size=\"1\">" + this.cuerpo +"</font></td>" + "</tr>" + "<tr>" + "<img src=\"Iconos/separador.jpg\" width=\"600\" height=\"6\">" + "</tr>" + "</table>"; } public String getInfo() { return " " + this.fecha + " - " + this.titulo; } }

Análisis y Uso de Frameworks de Persistencia en Java

147

5.2- LOS FICHEROS DE MAPEO

Hibernate necesita saber de qué forma ha de hacer corresponder una clase

con una tabla de la base de datos. Aquí entran en juego los ficheros de mapeo

XML. El ellos se especifica, entre otras cosas, el nombre de la tabla que se

quiere crear, el nombre de las columnas y los atributos que forman la clave. Con

esta información Hibernate es capaz de relacionar los atributos con las columnas

de la tabla, definiendo los tipos de datos basándose en el código de la clase

correspondiente.

A continuación figuran los ficheros de mapeo de las diferentes clases a

persistir.

Análisis y Uso de Frameworks de Persistencia en Java

148

- Usuario.hbm.xml

Este es el código para mapear la clase “Usuario.java”:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="obj.Usuario" table="USUARIOS"> <id name="dni" column="dni"> <generator class="assigned"/> </id> <property name="user" column="user"/> <property name="pass" column="pass"/> <property name="nombre" column="nombre"/> <property name="ap1" column="apellido1"/> <property name="ap2" column="apellido2"/> <property name="email" column="email"/> <property name="cod_perfil" column="cod_perfil"/> <property name="activo" column="activado"/> </class> </hibernate-mapping>

Entre otras cosas, el fichero le dice a Hibernate que persista la

clase “obj.Usuario” en la tabla “USUARIOS”. Además en la sección

<id> se define el atributo “dni” como clave de la tabla. Al elegir

“assigned” en el apartado <generator> se está indicando que no se use

ningún generador, que el valor que lleve el atributo “dni” se persista en la

base de datos.

Análisis y Uso de Frameworks de Persistencia en Java

149

- Paciente.hbm.xml

Este es el código para mapear la clase “Paciente.java”:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="obj.Paciente" table="PACIENTES"> <id name="dni" column="dni"> <generator class="assigned"/> </id> <property name="dni_med" column="dni_med"/> <property name="nombre" column="nombre"/> <property name="ap1" column="ap1"/> <property name="ap2" column="ap2"/> <property name="telefono" column="telefono"/> </class> </hibernate-mapping>

Análisis y Uso de Frameworks de Persistencia en Java

150

- Alergia.hbm.xml

Este es el código para mapear la clase “Alergia.java”:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="obj.Alergia" table="ALERGIAS"> <!-- ID COMPUESTO: Requiere que obj.Alergia implemente Serializable--> <composite-id > <key-property name="dni" column="dni" /> <key-property name="tipo" column="tipo" /> </composite-id> <property name="tratamiento" column="tratamiento"/> <property name="notas" column="notas"/> </class> </hibernate-mapping>

Aquí se puede observar cómo se mapea una clave compuesta. Se

ha de utilizar la cláusula <composite-id> indicando qué atributos van a

formar la clave. En este caso “dni” y “tipo” serán la clave compuesta de

la tabla “ALERGIAS”.

Análisis y Uso de Frameworks de Persistencia en Java

151

- Noticia.hbm.xml

Este es el código para mapear la clase “Noticia.java”:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//hibernate/hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="obj.Noticia" table="NOTICIAS"> <id name="codigo" column="codigo"> <generator class="assigned"/> </id> <property name="fecha" column="fecha"/> <property name="titulo" column="titulo"/> <property name="cuerpo" column="cuerpo"/> </class> </hibernate-mapping>

Análisis y Uso de Frameworks de Persistencia en Java

152

5.3- LAS CLASES GESTORAS DE OBJETOS

Al igual que en JDBC se trabaja con clases DAO para definir los

métodos necesarios para que la aplicación interaccione con la base de datos,

Hibernate utiliza unas clases similares, que denominamos Clases Gestoras.

En las clases gestoras figuran todos los métodos que usa el programador

para realizar transacciones con las tablas. Se debe crear una clase gestora por

cada clase que se desee persistir. De este modo se deberá crear una instancia de

la clase gestora siempre que se quiera realizar una transacción de cualquiera de

los objetos.

A continuación se muestran las clases gestoras que se han implementado

para utilizar Hibernate en la aplicación diseñada. Se pretende comparar estas

clases con las DAO equivalentes que se usan al trabajar con JDBC.

Análisis y Uso de Frameworks de Persistencia en Java

153

- GestorUsuario.java

Tal y como se puede observar en el código, el constructor de

todas estas clases crea una instancia de “SessionFactory”, sobre la cual se

van a realizar todas y cada una de las transacciones.

package util; import java.util.Iterator; import obj.Usuario; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class GestorUsuario { private SessionFactory sessionFactory; public GestorUsuario() { try { System.out.println("Initializing Hibernate"); sessionFactory = new Configuration().configure().buildSessionFactory(); System.out.println("Finished Initializing Hibernate"); } catch (HibernateException e) { e.printStackTrace(); } } public Usuario getUsuario(int dni) { Usuario res = null; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); /* Con .get() */ res = (Usuario)session.get(Usuario.class, new Integer(dni)); /* Con QUERY: */

Análisis y Uso de Frameworks de Persistencia en Java

154

// String dniString = String.valueOf(dni); // res = (Usuario)session.createQuery("from Usuario as usuario where usuario.dni = ?") // .setString(0,dniString) // .uniqueResult(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; } public void insertarUsuario (Usuario u) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.save(u); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } // Comprueba si existe el "User" para el login. La comprobación // se realiza durante la solicitud de cuentas. public boolean existeUsuario(String s) { boolean res = false; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Usuario u_aux = (Usuario)session.createQuery("from Usuario as usuario where usuario.user = ?") .setString(0,s) .uniqueResult(); if (u_aux != null){ res = true; } tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }

Análisis y Uso de Frameworks de Persistencia en Java

155

return res; } // Comprueba si existe el "dni". La comprobación // se realiza durante la solicitud de cuentas. public boolean existeDni(String dni) { boolean res = false; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Usuario u_aux = (Usuario)session.createQuery("from Usuario as usuario where usuario.dni = ?") .setString(0,dni) .uniqueResult(); if (u_aux != null){ res = true; } tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return res; } public void borrarCuenta(int dni) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Usuario u = this.getUsuario(dni); session.delete(u); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public Iterator obtenerUsuarios(){ Iterator res = null; try {

Análisis y Uso de Frameworks de Persistencia en Java

156

Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); res = session.createQuery("from Usuario") .list() .iterator(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; } public Iterator obtenerMedicos(){ Iterator res = null; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); res = session.createQuery("from Usuario as usuario where usuario.cod_perfil=?") .setString(0,"med") .list() .iterator(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; } public void cambiarActivado(int dni) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Usuario u_aux = this.getUsuario(dni); int actividad = u_aux.getActivo(); if (actividad==0){ u_aux.setActivo(1); } else{ u_aux.setActivo(0); } session.update(u_aux); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace();

Análisis y Uso de Frameworks de Persistencia en Java

157

} } public void editarCuenta(Usuario u) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.update(u); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public void cambiarPass(int dni, String nuevaPass) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Usuario u = this.getUsuario(dni); u.setPass(nuevaPass); session.update(u); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } // Validación del LOGIN // Si los datos son válidos, devuelve el usuario con todos sus datos. public Usuario validarUsuario(String user, String pass) { Usuario res = null; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); res = (Usuario)session.createQuery("from Usuario as usuario where usuario.user = ? and usuario.pass= ?") .setString(0,user) .setString(1,pass) .uniqueResult(); tx.commit();

Análisis y Uso de Frameworks de Persistencia en Java

158

session.close(); } catch (HibernateException e){ e.printStackTrace(); } return res; } }

Para hacerse una idea de cómo Hibernate evita las tareas de

encapsulamiento y desencapsulamiento, se puede observar el método

“editarCuenta(Usuario u)“ y compararlo con otro equivalente

de una clase DAO:

// Con HIBERNATE: public void editarCuenta(Usuario u) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.update(u); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } }

// Con JDBC: public void editarCuenta(Usuario u) { if (this.conexion != null) { // DESENCAPSULAMIENTO: int dni = u.getDni(); String user = u.getUser(); String pass = u.getPass(); String nom = u.getNombre(); String ap1 = u.getAp1(); String ap2 = u.getAp2(); String email = u.getEmail();

Análisis y Uso de Frameworks de Persistencia en Java

159

try { Statement st = (this.conexion).createStatement(); st.executeUpdate("UPDATE personal.usuarios SET usuario='"+user+"' WHERE dni='"+dni+"'"); st.executeUpdate("UPDATE personal.usuarios SET pass='"+pass+"' WHERE dni='"+dni+"'"); st.executeUpdate("UPDATE personal.usuarios SET nombre='"+nom+"' WHERE dni='"+dni+"'"); st.executeUpdate("UPDATE personal.usuarios SET apellido1='"+ap1+"' WHERE dni='"+dni+"'"); st.executeUpdate("UPDATE personal.usuarios SET apellido2='"+ap2+"' WHERE dni='"+dni+"'"); st.executeUpdate("UPDATE personal.usuarios SET email='"+email+"' WHERE dni='"+dni+"'"); } catch (SQLException e) { System.out.println("ERROR query update"); } } }

Es fácil comprobar que la diferencia en cuanto a cantidad de

líneas de código es muy notable. Hibernate se sirve con

“session.update(u)”, comprobando el campo clave para

identificar el registro que se va a actualizar y sustituyendo todos los

valores que haya en la tabla por los que se encuentran poblando los

atributos del objeto “u”. Lo mismo sucede con instrucciones como

“session.save(u)” o “session.delete(u)” que aparecen en

de inserción y borrado, respectivamente.

Otro punto interesante es que la clase Query de Hibernate

redefine el método List(), de forma que facilita el uso del resultado y

no hay que recorrer el ResultSet como ocurre cuando se trabaja con

JDBC.

Análisis y Uso de Frameworks de Persistencia en Java

160

- GestorPaciente.java

Para trabajar con la clase Paciente se usará esta clase gestora:

package util; import java.util.Iterator; import obj.Paciente; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class GestorPaciente { private SessionFactory sessionFactory; public GestorPaciente() { try { System.out.println("Initializing Hibernate"); sessionFactory = new Configuration().configure().buildSessionFactory(); System.out.println("Finished Initializing Hibernate"); } catch (HibernateException e) { e.printStackTrace(); } } public void insertarPaciente(Paciente p) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.save(p); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public Paciente getPaciente(int dni) {

Análisis y Uso de Frameworks de Persistencia en Java

161

Paciente res = null; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); /* Con .get() */ res = (Paciente)session.get(Paciente.class, new Integer(dni)); /* Con QUERY: */ // String dniString = String.valueOf(dni); // res = (Paciente)session.createQuery("from Paciente as paciente where paciente.dni = ?") // .setString(0,dniString) // .uniqueResult(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; } public void borrarPaciente(Paciente p) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.delete(p); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public boolean existePaciente(int dni) { boolean res = false; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Paciente p = (Paciente)session.get(Paciente.class, new Integer(dni)); if (p != null){ res = true; } tx.commit(); session.close(); } catch (HibernateException e) {

Análisis y Uso de Frameworks de Persistencia en Java

162

e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return res; } public void editarPaciente(Paciente p) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.update(p); // Otro método: // Paciente p_old = (Paciente)session.get(Paciente.class, new Integer(p.getDni())); // // p_old.setDni_med(p.getDni_med()); // p_old.setNombre(p.getNombre()); // p_old.setAp1(p.getAp1()); // p_old.setAp2(p.getAp2()); // p_old.setTelefono(p.getTelefono()); // // session.flush(); //Hibernate guarda los cambios en "p_old" tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public Iterator obtenerPacientes(){ Iterator res = null; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); res = session.createQuery("from Paciente") .list() .iterator(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; }

Análisis y Uso de Frameworks de Persistencia en Java

163

public Iterator obtenerPacientesAsignados(int dni_med){ Iterator res = null; String dniString = String.valueOf(dni_med); try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); res = session.createQuery("from Paciente as paciente where paciente.dni_med= ?") .setString(0,dniString) .list() .iterator(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; } }

Análisis y Uso de Frameworks de Persistencia en Java

164

- GestorAlergia.java

Para trabajar con la clase Alergia se usará esta clase gestora:

package util; import java.util.Iterator; import obj.Alergia; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class GestorAlergia { private SessionFactory sessionFactory; public GestorAlergia() { try { System.out.println("Initializing Hibernate"); sessionFactory = new Configuration().configure().buildSessionFactory(); System.out.println("Finished Initializing Hibernate"); } catch (HibernateException e) { e.printStackTrace(); } } public void insertarAlergia(Alergia a) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.save(a); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public Alergia getAlergia(int dni, String tipo) {

Análisis y Uso de Frameworks de Persistencia en Java

165

/* Al tener una clave compuesta, para ejecutar el método load(), el identificador del objeto es una instancia del propio objeto con los atributos que forman la clave compuesta poblados con los datos correspondientes. */ Alergia res = null; Alergia a = new Alergia (dni,tipo,"",""); try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); /* Con .load() */ res = (Alergia)session.load(Alergia.class, a); System.out.println(res.getNotas()); /* Con QUERY: */ // String dniString = String.valueOf(dni); // res = (Alergia)session.createQuery("from Alergia as alergia where alergia.dni = ? and alergia.tipo = ?") // .setString(0,dniString) // .setString(1,tipo) // .uniqueResult(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; } public void borrarAlergia(Alergia a) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.delete(a); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public void editarAlergia(Alergia a) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction();

Análisis y Uso de Frameworks de Persistencia en Java

166

String tratamiento = a.getTratamiento(); String notas = a.getNotas(); Alergia a_old = (Alergia)session.load(Alergia.class, a); a_old.setTratamiento(tratamiento); a_old.setNotas(notas); session.flush(); //Hibernate guarda los cambios en "a_old" tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public boolean existeRegistro(int dni, String tipo) { boolean res = false; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Alergia a = (Alergia)session.get(Alergia.class, new Alergia(dni,tipo,"","")); if (a != null){ res = true; } tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return res; } public Iterator obtenerAlergiasAsignadas(int dni){ Iterator it = null; String dniString = String.valueOf(dni); try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); it = session.createQuery("from Alergia as alergia where alergia.dni = ?") .setString(0,dniString) .list() .iterator(); tx.commit();

Análisis y Uso de Frameworks de Persistencia en Java

167

session.close(); } catch (HibernateException e) { e.printStackTrace(); } return it; } }

Análisis y Uso de Frameworks de Persistencia en Java

168

- GestorNoticia.java

Para trabajar con la clase Paciente se usará esta clase gestora:

package util; import java.util.Iterator; import java.util.ListIterator; import obj.Alergia; import obj.Noticia; import obj.Paciente; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class GestorNoticia { private SessionFactory sessionFactory; public GestorNoticia() { try { System.out.println("Initializing Hibernate"); sessionFactory = new Configuration().configure().buildSessionFactory(); System.out.println("Finished Initializing Hibernate"); } catch (HibernateException e) { e.printStackTrace(); } } public Noticia getNoticia(int codigo) { Noticia res = null; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); /* Con .get() */ res = (Noticia)session.get(Noticia.class, new Integer(codigo)); /* Con QUERY: */ // String codigoString = String.valueOf(codigo); // res = (Noticia)session.createQuery("from Noticia as noticia where noticia.codigo = ?") // .setString(0,codigoString)

Análisis y Uso de Frameworks de Persistencia en Java

169

// .uniqueResult(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; } public void nuevaNoticia(Noticia n) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.save(n); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public void borrarNoticia(Noticia n) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.delete(n); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } } public void editarNoticia(Noticia n) { try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.update(n); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } }

Análisis y Uso de Frameworks de Persistencia en Java

170

public ListIterator obtenerNoticias(){ ListIterator res = null; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); res = session.createQuery("from Noticia") .list() .listIterator(); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } return res; } // Vuelve a enumerar los códigos de las noticias: // ... se utilizará despues de una operación de baja. // Devuelve el número de noticias que hay. public Integer recodificarNoticias() { int cont = 1; try { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); ListIterator noticias = this.obtenerNoticias(); if (noticias!=null) { while (noticias.hasNext()) { Noticia n = (Noticia)noticias.next(); int codigo_aux = n.getCodigo(); Noticia n_aux = this.getNoticia(codigo_aux); n_aux.setCodigo(cont); this.borrarNoticia(n); this.nuevaNoticia(n_aux); cont++; } } tx.commit(); session.close(); } catch (HibernateException e) { System.out.println("ERROR: hib exception en recodificarNoticias()");

Análisis y Uso de Frameworks de Persistencia en Java

171

e.printStackTrace(); } Integer res = new Integer(cont - 1); return res; } }

Análisis y Uso de Frameworks de Persistencia en Java

172

5.4- IMPLANTACIÓN

5.4.1. Instalación y Configuración

Primero hay que bajarse Hibernate 3.0 de su página de descarga. Después

hay que extraerlo y colocar los .jar la carpeta lib del proyecto Web, así como el

conector de la base de datos MySQL.

La configuración de Hibernate se realiza a través de un archivo XML

llamado “hibernate.cfg.xml” que se situará en la carpeta “JavaSource”. En la

página siguiente se puede ver el código del archivo, con los datos necesarios

para adaptarlo a esta aplicación.

Como se puede apreciar, en las secciones <property> se especifica todo

lo necesario para realizar la conexión a la base de datos MySQL “clinica_paya”,

incluyendo el usuario y la contraseña. Posteriormente, con las etiquetas

<mapping> se está indicando a Hibernate que tiene cuatro objetos para persistir,

uno por cada uno de los ficheros de mapeo creados en el apartado anterior.

Hibernate tomará esta información y será capaz de crear las tablas especificadas

por los ficheros de mapeo.

Análisis y Uso de Frameworks de Persistencia en Java

173

Hibernate.cfg.xml

<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <!-- Generated by MyEclipse Hibernate Tools. --> <hibernate-configuration> <session-factory> <property name="connection.username">anonimo</property> <property name="connection.url">jdbc:mysql://localhost:3306/clinica_paya</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="myeclipse.connection.profile">MySQL_personal</property> <property name="connection.password">anonimo</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.hbm2ddl.auto">update</property> <mapping resource="obj/Alergia.hbm.xml"></mapping> <mapping resource="obj/Noticia.hbm.xml"></mapping> <mapping resource="obj/Usuario.hbm.xml"></mapping> <mapping resource="obj/Paciente.hbm.xml"></mapping> </session-factory> </hibernate-configuration>

Cabe destacar que esta forma de configurar Hibernate permite una

sencillísima portabilidad entre diferentes entornos de bases de datos. Si se quiere

trasladar a otra base de datos con otro gestor, basta con editar algunas de las

propiedades de este fichero referentes a la base de datos.

Para no tener que trabajar con los XML existen asistentes para la edición

de este archivo y para la creación de ficheros de mapeo.

Análisis y Uso de Frameworks de Persistencia en Java

174

5.4.2. Requisitos del Sistema (Hibernate 3.0):

o JDK 1.3 o superior

o 128 Mb de RAM

o 50 Mb de espacio en disco

o 400 Mhz CPU

Análisis y Uso de Frameworks de Persistencia en Java

175

6- Presupuesto

Análisis y Uso de Frameworks de Persistencia en Java

176

6- PRESUPUESTO

Los costes establecidos se basan en que la empresa contratante dispone

del hardware requerido y que el autor del proyecto no tiene la condición de

ingeniero técnico titulado.

COSTES DE DESARROLLO

• Estudio...................................................................... 80 horas x 26 €/h = 2.080 €

• Análisis..................................................................... 80 horas x 26 €/h = 2.080 €

• Programación..........................................................100 horas x 24 €/h = 2.400 €

COSTES DE IMPLANTACIÓN

• Configuración y pruebas............................................. 40 horas x 20 €/h = 800 €

TOTAL..................................7.360 €

Análisis y Uso de Frameworks de Persistencia en Java

177

7- Conclusiones

Análisis y Uso de Frameworks de Persistencia en Java

178

7- CONCLUSIONES

Este trabajo ha hecho posible confirmar que el manejo de las bases de

datos es crítico para el comportamiento de una aplicación.

La aplicación Web se ha desarrollado utilizando Hibernate, pero

paralelamente se ha codificado el módulo equivalente en JDBC. Esto ha

permitido que percepción del contraste sea completa, haciendo posible reafirmar

las conclusiones obtenidas tras realizar el estudio teórico.

Tras la conclusión del desarrollo se ha comprobado que la programación

con Hibernate es mucho más sencilla y llevadera, ya que nos libera de tareas tan

ásperas como el encapsulamiento y desencapsulamiento de los objetos, y pone a

nuestra disposición una API completísima y fácil de usar. Sin embargo, después

de concluir con la implantación del portal, ha quedado patente que los accesos

con JDBC son siempre más rápidos que los gestionados por un framewok como

Hibernate, tal y como se había predecido en el estudio.

Estas conclusiones se corresponden perfectamente con las pretensiones

del proyecto. La intención del trabajo era confrontar y mostrar el funcionamiento

de las alternativas, creando finalmente una herramienta de trabajo sencilla y

versátil.

Análisis y Uso de Frameworks de Persistencia en Java

179

La realización de este proyecto me ha aportado una grandísima

experiencia personal y académica.

Este es un proyecto muy completo en muchos aspectos. Tiene gran

variedad de fases, las cuales se han abordado de formas distintas, lo que requiere

una planificación diferente para cada una de ellas. Por otra parte, el desarrollo de

la aplicación ha sido posible gracias al aprendizaje de múltiples herramientas

software, ampliando así mis conocimientos en un gran rango de materias.

El director del proyecto me ha sabido transmitir qué tipo de proyecto

tenía en mente. La filosofía seguida a lo largo del mismo ha conseguido que la

documentación tome continuidad entre sus capítulos y sea entretenida su lectura.

Análisis y Uso de Frameworks de Persistencia en Java

180

8- Bibliografía

Análisis y Uso de Frameworks de Persistencia en Java

181

8- BIBLIOGRAFÍA

Libros consultados:

[MONS04] Monson-Haefel R. “Enterprise JavaBeans”, O’Reilly, 4ª

Edición, 2004.

[BERG03] Bergsten H. “JavaServer Pages”, O’Reilly, 3ª Edición, 2003.

[SING02] Singh I. “Designing Enterprise Applications with the J2EE

Platform”, Addison Wesley, 2ª Edición, 2002.

[HUNT01] Hunter J. “Java Servlet Programming”, O’Reilly, 2ª Edición,

2001.

[BARR01] Barranco J. “Metodología del análisis estructurado de

sistemas”, Publicaciones Universidad Pontificia de Comillas, 2ª

Edición, Madrid, 2001.

[FOWL99] Fowler, M. “UML gota a gota”, Addison Wesley, México 1999.

[GOSL96] Gosling, J. “The Java Programming Language”, Addison

Wesley, Massachusetts 1996.

Análisis y Uso de Frameworks de Persistencia en Java

182

Otras fuentes:

Página oficial de Hibernate: www.hibernate.org

Web sobre JDO: www.JDOcentral.com

Programación en castellano: www.programación.com