ELIPS es el acrýnimo de ELectronic Issue Processing Software, una herramienta que permite el control de errores, tareas, peticiones de funcionalidades o peticiones de realizacrión de trabajos. El control de todos estos aspectos es una tarea compleja que normalmente conviene externalizar y para el cual es muy util una herramienta como ELIPS.
ELIPS es un proyecto con licencia libre, escrito en Java y que integra Tomcat y MySQL. Está basado en JSP y por ahora sýlo funciona en Microsoft Windows aunque pronto se portarý a Linux.
En la pýgina web de ELIPS podéis encontrar amplia documentacrión. En especial, dentro de la guía de usuario podéis encontrar numerosas capturas de pantalla.
Una de las nuevas características de JBoss 4.0 es que su nýcleo pasa a integrar un framework AOP basado en el nuevo proyecto de JBoss.org: Javassist. JBoss-AOP permitirý añadir fýcilmente servicios empresariales ( transacciones, seguridad, persistencia ) a clases Java simples.
La noticia está en que el grupo JBoss.org acaba de actualizar hace unos dýas toda la documentacrión sobre su framework AOP. Podéis echarle un vistazo desde
Mark Eagle ha creado un pequeño tutorial donde realiza una introduccrión a Hiberante, haciendo especial hincaprió en el control de las relaciones entre entidades.
Además, en el artículo se explica como integrar Hibernate con XDoclet. Seguro que a todos los que utilizýis/pensýis utilizar estas herramientas os puede resultar de utilidad este artículo.
Copyright (c) 2003, Miguel Ángel Abián. Este documento puede ser distribuido solo bajo los términos y condiciones de la licencia de Documentación de javaHispano v1.0 o posterior (la última versión se encuentra en /licencias/).
Introducción
"Todo es un plug-in." Eslógan no oficial de la plataforma Eclipse
"La música lo es todo. La gente debería morir por ella. La gente está muriendo por todo lo demás, así que por qué no morir por la música. Salva más vidas." Lou Reed, Desde el proscenio
9. Eclipse como IDE
La plataforma Eclipse, combinada con el JDT ( Java Development Tooling), permite disponer de un IDE ( Integrated Development Environment o Entorno de desarrollo integrado) para Java de excelente calidad. Aquí cobra más sentido la frase "Eclipse es un IDE abierto y extensible para todo y, sin embargo, para nada en particular". Por sí misma, la plataforma Eclipse proporciona funcionalidades demasiado genéricas. Solamente cuando se amplia con otras herramientas (el JDT en este caso, que figura en la distribución estándar de Eclipse y que es un plug-in formado, a su vez, por otros plug-ins), permite desarrollar actividades útiles para los usuarios que la vayan a utilizar como IDE.
Como IDE de Java, Eclipse posee un editor muy visual con sintaxis coloreada, ofrece compilación incremental de código, un potente depurador (que permite establecer puntos de interrupción, modificar e inspeccionar valores de variables, etc. e incluso depurar código que resida en una máquina remota), un navegador de clases, un gestor de archivos y proyectos... pero no se limita sólo a esto. La versión estándar de Eclipse proporciona también una biblioteca de refactorización de código y una lista de tareas, soporta la integración con JUnit, y suministra un front-end gráfico para Ant, la conocida herramienta de código abierto que forma parte del proyecto Jakarta de Apache.
También incluye una herramienta para completar código: el asistente de contenido, encargado de mostrar los métodos y atributos de las clases con las que se está trabajando, ya formen parte de las APIs de Java o de cualquier otra clase en el build path, aunque estén en ficheros JAR. Este asistente también proporciona información de cada uno de los métodos mediante una ventana secundaria contextual (Figura 8), y avisa -cuando se graba la clase o la interfaz- de los errores cometidos al escribir el código (Figura 9). Eclipse incluye también asistentes para la creación de clases e interfaces, y proporciona una integración perfecta con el sistema open source CVS ( Concurrent Version System), muy útil para llevar el control de la versiones con las que se trabaja y conocer en todo momento sus respectivas diferencias. CVS ( http://www.cvshome.org) es uno de los sistemas de control de código fuente más usados; muchos de los sistemas UNIX lo llevan preinstalado por defecto.
A continuación me voy a extender respecto a dos características de Eclipse como IDE para Java: el HotSwap y la compilación incremental automática del código. He elegido éstas, y no otras, por dos razones: a) por motivos de espacio resulta imposible abordar todas las funcionalidades de Eclipse (además, algunas de ellas todavía se hallan en desarrollo o cambio); y b) las mencionadas características reducen el tiempo -y por tanto el coste- de construcción, depuración y distribución del software. Cualquier desarrollador, ya sea profesional, ya sea principiante, puede usarlas para no desperdiciar muchas horas repitiendo tareas mecánicas.
Una característica de Eclipse como IDE, poco mencionada pero que encuentro muy útil, es el soporte que ofrece Eclipse a HotSwap ( cambio en caliente ), una de las novedades del JDK 1.4. Esta propiedad, incluida en la Java Platform Debugger Architecture (Arquitectura del Depurador de la Plataforma Java) de la versión 1.4, permite sustituir código o modificarlo mientras se está ejecutando un programa, sin necesidad de pararlo, realizar las modificaciones, grabarlas, volver a compilar y -finalmente- ejecutar de nuevo. Si utilizamos Eclipse con la versión 1.4 de Java, podemos establecer puntos de interrupción en el código, ejecutarlo, comprobar el estado de las variables en los puntos de interrupción cuando éstos se alcancen, modificar el código o introducir código nuevo, grabar los cambios y continuar la ejecución del programa. Los fallos pueden localizarse y analizarse al vuelo, sin vernos obligados a salir de la aplicación, cambiar el código, recompilar y comenzar una nueva sesión de depuración.
Para sacar partido de esta característica -ya existente en Visual Age for Java- no precisamos investigar la documentación de Eclipse con una lupa de 50 aumentos y luz ultravioleta, ni invocar a Cthulhu a la luz de la luna (actividad no del todo infrecuente, por desgracia, entre los que hemos tenido que lidiar con productos de IBM): basta con iniciar una sesión de depuración, sustituir o cambiar el código generador de errores, grabar el archivo y apretar el botón Resume de la barra de herramientas Debug. Automáticamente, el programa sometido a depuración proseguirá su ejecución, teniendo en cuenta los cambios efectuados. Utilizando HotSwap con Eclipse, se reducen los tiempos destinados a depuración, en particular cuando se trabaja con aplicaciones que tardan mucho tiempo en arrancar -como aplicaciones web de cierta complejidad o aplicaciones que accedan a bases de datos remotas- o en las que se tarda mucho en alcanzar los puntos calientes o problemáticos.
Otra característica de Eclipse, muy eficiente para reducir los tiempos de depuración y pruebas, es la compilación incremental automática del código. Eclipse -al igual que Visual Age for Java- no cuenta con un menú de compilación pues no es necesario: cada vez que se hacen cambios en uno o más ficheros, el compilador interno de Eclipse recompila todos los ficheros fuente afectados por los cambios. El usuario no tiene que preocuparse de compilar, y puede estar seguro de contar con archivos siempre compilados. En consecuencia, tampoco resulta preciso esperar a la compilación para detectar ciertos errores: Eclipse muestra indicaciones de los errores aparecidos según se van realizando o guardando los cambios.
Las ventajas que aportan estas dos propiedades se apreciarán mejor con un ejemplo: consideremos que trabajamos con servlets y JSPs ( Java Server Pages), y que hemos decidido usar Eclipse junto con algún servidor web. Debido al ciclo de vida de los servlets, se necesita parar y volver a arrancar el servidor web cada vez que se desea actualizar la clase servlet o recargar el código Java llamado por algún fichero JSP. Durante el desarrollo se cambia a menudo el código de los servlets y de las JSPs. En la mayoría de los IDEs resulta bastante tedioso y largo depurar el código, sobre todo si los problemas se producen sólo cuando el servlet (o la JSP) lleva un cierto tiempo en ejecución, o dentro de algún bucle largo, porque hay que parar y reiniciar el servidor web y sus plug-ins. Cuando se cambia en Eclipse un método de un servlet o de un fichero JSP, Eclipse compila incrementalmente solamente el método modificado en la clase, no la clase completa, y la liga en caliente al programa en ejecución. El ahorro de tiempo es considerable, pues no hay que volver a recrear el estado de ejecución (del programa) que ocasiona los problemas; puede modificarse repetidamente el servlet o la JSP en ejecución sin parar y reiniciar el servidor, y se pueden usar todas las características de Eclipse mientras el servidor está ejecutándose.
Sólo hay un tipo de IDEs libres de defectos o ausencias: el que no existe más que en las mentes de sus creadores (a condición de que no sean demasiado pragmáticos); lógicamente, Eclipse no constituye una excepción, y tiene algunas carencias y deficiencias reprochables. Las tres más relevantes, desde mi punto de vista, se detallan aquí:
Eclipse no incluye un diseñador visual de interfaces gráficas ( GUI builder).
Eclipse no incorpora plug-ins para comunicarse con servidores de aplicaciones J2EE.
La falta de soporte a los Enterprise JavaBeans, a las Java Server Pages y a los servlets es total. No se incluyen asistentes o plug-ins para la edición o depuración de estos.
Carencias de Eclpise
Tanto las versiones comerciales de Eclipse distribuidas por IBM como los productos profesionales de la compañía que tienen como núcleo la plataforma Eclipse sí cuentan con algunas de las características (o con todas) que faltan en el SDK ( Standard Development Kit o Kit de desarrollo estándar) de Eclipse. Existen plug-ins gratuitos que permiten integrar eficazmente Eclipse con servidores open source o free software de aplicaciones, como JBoss, o con servidores propietarios como los de IBM, BEA u Oracle; estos plug-ins permiten arrancar y parar el servidor dentro de Eclipse, así como depurar el código fuente dentro del servidor de aplicaciones. Igualmente, existen plug-ins -algunos comerciales- para el resto de características que Eclipse no incorpora, basta con ensamblarlos.
Figura 8: El asistente de contenido de Eclipse
Figura 9: Al guardar una clase, Eclipse muestra los errores cometidos
Al ser neutral con respecto a la plataforma y al lenguaje, Eclipse puede utilizarse con otros lenguajes además de Java; basta con usar los plug-ins adecuados. Hasta la fecha [Abril 2003], el consorcio Eclipse.org proporciona plug-ins sólo para C/C++ y COBOL, pero existen proyectos independientes más o menos avanzados (aunque todavía no estables o definitivos) para que pueda usarse con C#, PHP, Eiffel, JavaScript, Ruby, Pascal, Phyton y con algunos lenguajes experimentales.
El IDE de C y C++ se encuentra asignado al subproyecto CDT ( C/C++ Development Tools) del proyecto Herramientas Eclipse; y proporciona ya un editor que ofrece sintaxis coloreada y que completa automáticamente el código, además de adjuntar un depurador. Los plug-ins del IDE están escritos en Java, sin código nativo.
La prueba evidente de que COBOL no está muerto y de que sigue gozando de una relativa buena salud en el siglo XXI (para desespero de muchos ingenieros de software y programadores: la informática no miente, nunca nos prometió un jardín de rosas) la aporta el hecho de que se ha desarrollado un IDE para él antes que para lenguajes mucho más modernos. El IDE de COBOL está también escrito en Java, sin código nativo, pero sólo puede trabajar en sistemas en los que exista un compilador de COBOL, un depurador y una interfaz puente ( bridge interface) que permita a los plug-ins (seis por ahora) invocar al depurador y al compilador COBOL nativo. Inicialmente el IDE de COBOL de Eclipse se basa en un compilador y depurador comercial de COBOL (Fujitsu NetCOBOL 7.0), para el cual existe un puente entre los plug-ins, el compilador y el depurador; este IDE sólo funciona, por ahora, sobre Red Hat Linux 7.2.
Para C# existe un plug-in llamado Improve CSharp, gratuito y bajo licencia CPL, que permite la edición y compilación de código C# e incluye un asistente de contenido para las palabras clave del lenguaje. Está disponible para Windows y Linux. Aunque este plug-in funciona correctamente, queda aún mucho por hacer; por ahora no se ha implementado ni siquiera la noción de proyecto C#, y cuando se genera un nuevo fichero C#, Improve CSharp no crea automáticamente su estructura, salvo que sea la básica.
Para Python disponemos del plug-in Python Editor for Eclipse (Pe4eclcipse), capaz de editar y depurar aplicaciones Phyton. Se encuentra disponible para Windows 95/98/2000, AIX, Linux y SunOs/Solaris. Es una versión pre-alfa y se licencia bajo GNU GPL.
Para PHP existe -en estado de desarrollo beta- el PHP plug-in for Eclipse, disponible para Windows y Linux bajo la licencia CPL de IBM. Ruby cuenta con el plug-in Ruby Development Tool, independiente del sistema operativo, en estado beta.
El plug-in JSEditor es un editor de ficheros JavaScript. Muestra las funciones JavaScript en la vista Outline de manera que resulta muy sencillo navegar a través de los ficheros JavaScript para alcanzar las funciones implementadas; ofrece también sintaxis coloreada para funciones, cadenas y comentarios.
Un lenguaje tan veterano como Pascal también encuentra albergue en Eclipse: Pasclipse es un plug-in bajo licencia CPL, disponible para Mac Os, Windows y Linux, que proporciona la posibilidad de integrar cualquier compilador de Pascal basado en línea de comandos; Pasclipse incluye también un formateador de código fuente. Por ahora se halla en fase pre-alfa.
Para el desarrollo de aplicaciones J2EE hay disponibles muchas soluciones distintas: Lomboz, BEJY, DeployGUI, EASIE JBoss Plugin, EASIE Orion/Oracle 9iAS Plugin, EASIE Weblogic Plugin, EASIE Wepsphere Plugin, Easy Struts, EclipseAxis, EJBBuilder, JBoss-IDE... Una comparación crítica entre ellos queda fuera del objetivo de este artículo, pero me permito llamar la atención sobre dos de ellos: Lomboz y JBoss-IDE. Lomboz es un plug-in J2EE que permite construir aplicaciones web con páginas HTML, JSPs y servlets. Incorpora un editor para JSPs con sintaxis coloreada, asistente para código y comprobación de la sintaxis. Varios asistentes y generadores de código facilitan el trabajo con EJBs, y cuenta con la interesante característica de permitir la depuración de código JSP y EJB desde el depurador de Eclipse. Lomboz es gratuito para fines no comerciales. Por otro lado,
JBoss-IDE ofrece un IDE para controlar el conocido servidor JBoss desde el Workspace de Eclipse; se distribuye bajo licencia CPL.
Para XML existen numerosos plug-ins comerciales y open source: eclipsetydy, Improve XSLT, JMXLEditor, MetaCoder ...
Para el análisis y diseño de software mediante UML ya hay disponibles varios plug-ins open source para la plataforma Eclipse:
EMF, magicdraw, OMONDO y Slime UML. Ofrecen, en general, las utilidades habituales: generación de diagramas UML, ingeniería inversa, generación de código a partir de los diagramas de clases, etcétera.
10. Eclipse y Visual Age for Java: una sensación déjà vú, pero sólo una sensación. El reemplazo generacional llega a IBM. ¿Cómo encaja Eclipse en la nueva generación de herramientas de IBM?
Los desarrolladores que hayan trabajado con Visual Age for Java notarán algunas similitudes al trabajar con Eclipse. Muchos de los asistentes son iguales y también algunos botones (como el del hombre que corre o el que muestra un insecto; tienen asociadas las acciones de iniciar la ejecución del programa y arrancar el depurador, respectivamente).
Internamente, sin embargo, hay muchas diferencias. La lista sería muy larga, pero las más relevantes son éstas:
Eclipse se basa en ficheros individuales, muchos de los cuales tienen formato ASCII y, por tanto, son accesibles a otras herramientas. En Eclipse, IBM ha abandonado el repository propietario (EMSRV - ENVY) que usó para Visual Age for Java (tal y como se ha visto en el apartado anterior, Eclipse usa CVS de forma estándar). Para ejecutar o distribuir el código fuente en VAJ, debe exportarse el código al sistema de ficheros de la máquina donde vaya a ser utilizado. Nadie que manejara el repository propietario lo echará en falta; su insidiosa tendencia a corromperse era uno de los mayores problemas de los usuarios de VAJ, pero no el único: su excesivo consumo de espacio en el disco duro, y su complejo sistema de mantenimiento y administración tampoco contribuyeron a hacerle popular entre los desarrolladores. Una confesión personal: el único momento en que el
repository de VAJ me dio una alegría fue cuando me dijeron que ya no iba a necesitar usarlo.
Eclipse es mucho más configurable para diferentes máquinas virtuales Java que VAJ. Visual Age for Java emplea una máquina virtual llamada UVM ( Universal Virtual Machine, Máquina Virtual Universal) que permite ejecutar código Java y código SmallTalk. La UVM es propiedad de IBM y el usuario de VAJ no puede utilizar ninguna otra máquina virtual. Eclipse, en contraste, permite elegir para la ejecución la máquina virtual Java que se desee, desde la versión 1.1.7 del JRE a la versión 1.4, sin excluir máquinas virtuales hechas a medida, como la J9 VM de IBM para dispositivos embebidos. Esta posibilidad, ausente en VAJ, resulta muy ventajosa para los programadores: pueden elegir el JRE que vaya a emplear el usuario final, sin depender de las actualizaciones, por parte de IBM, de la UVM. Existe un pequeño matiz de carácter técnico: Eclipse usa un compilador interno, al igual que VAJ, pero el conjunto de clases contra el cual se compila el código fuente es el establecido por el usuario en Preferences/Installed JREs.
VAJ permite la generación y distribución de Enterprise JavaBeans, Java Server Pages y servlets, incluye asistentes tanto para la generación como para la distribución de EJBs, y soporta de serie la plataforma J2EE. Por citar ejemplos concretos, la última versión de VAJ incluye un Entorno de pruebas WebSphere ( WebSphere Test Environment), un servidor EJB, un depurador integrado para servlets, EJBs y JavaBeans, y un monitor de ejecución para JSPs. Todo lo necesario, en definitiva, para desarrollar aplicaciones J2EE dentro de un único entorno de desarrollo integrado.
[ Nota técnica: Un repository (almacén de datos) en programación es, en esencia, una base de datos que almacena código y material complementario (documentación, imágenes, etc.). Cuando se usa un repository, el código fuente con el que se trabaja se almacena en la base de datos y se extrae de él cuando se necesita.El código se almacena en el repository, no en ficheros. Este sistema de almacenamiento ofrece ventajas para los lenguajes orientados a objetos, pues resulta más fácil seguir la pista a las clases, con sus relaciones de herencia, en una base de datos. Además, la estructura de una base de datos se muestra idónea para llevar un control de las versiones y para la programación en equipo. Al ser el repository una base de datos se necesita configurarlo y mantenerlo a lo largo del tiempo.]
Diferencias más relevantes entre Eclipse y VAJ
La actual generación de herramientas de desarrollo de IBM (WebSphere Studio Application Developer, Websphere Studio Site Developer, WebSphere Studio Enterprise Developer, Websphere Studio Workbench, etc.) se basa en Java, al igual que los productos de la familia Visual Age se basaban en Smalltalk. IBM está reemplazando, tanto interna como externamente, sus productos de la familia Visual Age y WebSphere Studio por los nuevos productos basados en Eclipse. IBM ha abandonado ya Visual Age for Java en favor de sus nuevos productos basados en Eclipse; no habrá nuevas versiones de VAJ, aunque continuará dándole soporte durante un tiempo.
Los motivos de esta nueva estrategia basada en Eclipse obedecen a una suerte de relevo generacional tecnológico: Visual Age for Java y Websphere Studio se crearon en una época en la que las páginas web eran páginas HTML servidas por CGIs ( Common Gateways Interfaces). Hablo de época aunque sé que no han pasado muchos años, pero si comparásemos las tecnologías actuales con las de hace diez o veinte años, parecería que éstas últimas han salido de otra época, casi de una Edad Media incrustada en el siglo XX. En aquel entonces, gracias a los applets, Java alcanzó una gran popularidad en el lado del cliente. El panorama actual apenas guarda parecido con el de hace diez años: las páginas web actuales incluyen vídeo de alta resolución, animaciones, sonidos, HTML dinámico... Las redes de fibra óptica, extendidas ahora por todo el mundo, permiten olvidarse de las limitaciones de una Internet que daba sus primeros balbuceos, y posibilitan la inclusión de recursos multimedia, no sólo de texto e imágenes. También para Java ha pasado el tiempo: los applets han caído en desuso, y el lenguaje, ya maduro, se ha hecho fuerte en el lado del servidor. La plataforma J2EE, que comenzó a existir cuando ya se habían lanzado las primeras versiones de Visual Age y WebSphere Studio, ha crecido mucho y en direcciones muy distintas: servlets, JSPs, EJBs, XML, etc.
A toda herramienta, como a toda tecnología, le llega un momento en que intentar seguir expandiéndola resulta similar a pretender aumentar el volumen cerebral de un dinosaurio condenado a la extinción. IBM, consciente de que no hay tecnología que cien años dure, decidió -tal como se vio en la primera parte de este artículo- abandonar Visual Age for Java y WebSphere Studio, y construyó la plataforma Eclipse, escrita en Java, como base para su nueva generación de herramientas.
WebSphere Studio Site Developer y WebSphere Studio Application Developer han sido los primeros productos de la nueva familia WebSphere Studio que han visto la luz; forman parte de la nueva generación de herramientas de desarrollo de aplicaciones web construida sobre Eclipse. IBM distribuye su propia versión comercial de Eclipse (WebSphere Studio Workbench), que actúa como base de la nueva familia WebSphere Studio y de las futuras herramientas middleware de IBM. WebSphere Studio Site Developer permite el desarrollo de sitios web dinámicos (con servlets, XML, JSPs, servicios Web, etc.)
WebSphere Studio Application Developer va varios pasos por delante del Site Developer: permite el desarrollo de aplicaciones J2EE y de bases de datos en un entorno de programación en equipo. Incluye todas las funciones del Site Developer y permite la creación y distribución de EJBs, incorpora asistentes para conexiones a bases de datos y permite usar el servidor de aplicaciones de IBM (WebSphere Application Server) para efectuar pruebas. Dar una descripción exacta de todas sus capacidades escapa a los propósitos de este artículo, pero el repertorio de asistentes para XML, para la creación de bases de datos, para la implementación de consultas a bases de datos y para J2EE deslumbra por su extensión. WS Application Developer es un producto hecho por y para profesionales, además de ser una de las herramientas más completas que existen en el mercado.
Eclipse (en su versión comercial WS Workbench) constituye el núcleo de estas herramientas. Aunque WS Application Developer es una herramienta excelente, todas sus virtudes y funcionalidades derivan de una misma base: Eclipse. Cualquier programador o programadora puede añadir al SDK estándar de Eclipse los plug-ins -propietarios, open source o free software- que desee, y obtener un producto final comparable a WS Application Developer (o incluso más adaptado a sus necesidades). Los productos comerciales de IBM son derivaciones concretas de Eclipse, pero no tienen virtudes intrínsecas que no puedan obtenerse ensamblando plug-ins. IBM cuenta con la baza de proporcionar asesoramiento, asistencia técnica y soluciones personalizadas; no se limita a proporcionar el producto, pero sus herramientas basadas en Eclipse no tienen ninguna bendición papal: forman parte de la miríada de productos que cualquiera puede formar alrededor del archipiélago Eclipse.
Figura 10: Eclipse dentro de la familia WebSphere de IBM
La obsesión de IBM por el software open source es demasiado racional para figurar dentro del índice de Introducción a la Psiquiatría Moderna, en algún lugar entre Obsesiones-compulsiones y Paranoia. El fracaso de Eclipse implicaría el fracaso de toda la nueva gama de productos de IBM basados en él, y el adiós definitivo a su permanencia como líder en el mercado de herramientas de desarrollo. La competencia es demasiado fuerte y competitiva como para que IBM pueda conseguir una segunda oportunidad; Eclipse no forma parte de una de sus estrategias: es la Estrategia . Honradamente, no lanzar Eclipse bajo la licencia open source sí hubiera merecido estar en el índice de Introducción a la Psiquiatría Moderna, por algún lugar entre Lo-tuyo-no-son-los-negocios (Síndrome de) y Narcisismo. Esta opción hubiera entrañado el riesgo -tremendamente real- de quedarse descolgado del proceso de creación de herramientas, proceso cada vez más comunitario, y de llegar solamente a la porción de desarrolladores que ya utilizaban productos de IBM.
Los cuarenta millones de dólares invertidos en Eclipse acabarán dando buenos dividendos a IBM; probablemente no obtendrá de ellos la rentabilidad que algunos y algunas consiguieron con las punto com antes del hundimiento del mercado -al más puro estilo Titanic-, un hundimiento tan previsible e inevitable como la implosión del boom inmobiliario en Japón durante la década de los noventa, pero conseguirá mayor rentabilidad que la que proporcionan los bonos cupón cero del Tesoro de los Estados Unidos. Si IBM no pensara así, hubiera invertido el dinero en estos bonos y se hubiera limitado a esperar mejores tiempos antes de sacar al mercado su nueva generación de herramientas de desarrollo. Explicar a los gestores de fondos de pensiones estadounidenses, con miles de millones de dólares invertidos en acciones de blue chips, que IBM dona dinero por puro y sincero amor al desarrollo y progreso del software hubiera sido incómodo, cuanto menos. Los gestores hubieran sentido en sus oídos las mismas punzadas de dolor, aparejadas a la sensación común de que alguien les estaba hurgando en los bolsillos, que sufrieron los ejecutivos de RCA cuando Lou Reed les dio a escuchar Metal Machine Music (intentaron sacarlo en la serie clásica, pero el bueno de Lou se opuso, arguyendo que hubiera sido pretencioso). Cuando las empresas punto com estaban en la cúspide -dislumbrada, alcanzada y pronto olvidada, como un mal sueño-, hasta las sillas subían en bolsa, pero no las donaciones en las que no se veía recompensa, presente o futura, alguna. Habrá que esperar... y ver.
11. Eclipse y su énfasis en la calidad del software
Tal y como se comentó en el apartado 2, una herramienta de desarrollo integrado debería ayudar a los desarrolladores en todas las etapas del ciclo de vida del software. Rational Software (miembro de la junta directiva de Eclipse.org y cuya adquisición por parte de IBM finalizó en enero de este año) tiene su metodología RUP ( Rational Unified Process), un proceso unificado de desarrollo de software que utiliza UML y se sostiene sobre tres ideas básicas: casos de uso, arquitectura y desarrollo iterativo e incremental. De acuerdo con la metodología RUP, el proceso unificado se repite a lo largo de una serie de ciclos que constituyen la vida de un sistema software. Cada ciclo debe tener los siguientes modelos:
Un modelo de casos de uso
Un modelo de análisis
Un modelo de diseño
Un modelo de implementación
Un modelo de despliegue o distribución
Un modelo de prueba
Modelos dentro de un ciclo de RUP
En consecuencia, los flujos de trabajo de cada ciclo, según esta metodología, son cinco: requisitos, análisis, diseño, implementación y prueba.
Independientemente de la metodología seguida, los cinco flujos de trabajo expuestos suelen formar parte del desarrollo de software. Desde luego, Rational Software tiene su propia herramienta de desarrollo de acuerdo con RUP, pero resulta difícil encontrar IDEs que ayuden a los desarrolladores en todos los flujos de trabajo. Por ello, resulta fundamental la extensibilidad de los productos. En ese aspecto, Eclipse -debido a su arquitectura abierta- permite acoplar mediante plug-ins tantas herramientas de apoyo (open source o comerciales) como el desarrollador necesite, de manera que éste, independientemente de la metodología concreta usada, pueda conseguir con Eclipse su propio IDE, personalizado a sus necesidades. Por ejemplo, los desarrolladores pueden incorporar a Eclipse herramientas de distintos vendedores (un IDE no estándar, una herramienta de modelado UML, un framework de pruebas como JUnit, un editor de XML o de HTML, una herramienta como Ant, etc.) y beneficiarse así de una apariencia común y un control integrado para todas las herramientas.
De hecho, la versión estándar de Eclipse incluye una biblioteca de refactorización de código Java, utilizable a través de un sencillo interfaz para el usuario. Erich Gamma, uno de los grandes especialistas del momento en patrones y refactorización, forma parte del proyecto Eclipse.
Eclipse rompe, posiblemente debido a la participación de Rational Software y de TogetherSoft, con una larga -y justificada- tradición de que las herramientas de desarrollo de software aceleran el desarrollo de software al precio de conseguir diseños pobres, poco escalables y que suelen requerir un mantenimiento excesivo cuando los sistemas van creciendo, al permitir preocuparse tanto de la calidad del software como de su diseño, y no únicamente de la productividad inmediata.
Otras herramientas Java (JBuilder 7 y 8, IDEA de Intellij, por ejemplo) también proporcionan soporte a la refactorización del software, pero -por ahora- sólo Eclipse muestra tan claramente la importancia que los patrones y la refactorización han tenido en su propia construcción y sólo Eclipse, por su arquitectura abierta, permite integrar tantas herramientas para mejorar la calidad del software, facilitar los procesos de análisis y diseño, y documentar estas etapas.
12. La estructura de la plataforma Eclipse: una vista subterránea
Un concepto fundamental de Eclipse, necesario para comprender lo que sigue, es el de recurso . En Eclipse, un recurso básico es simplemente un fichero ASCII que contiene código fuente para un lenguaje de programación.
La plataforma Eclipse se compone de 6 grandes componentes:
El Platform runtime, que se encarga de gestionar los recursos y los plug-ins, además de permitir el arranque de la plataforma. Cuando se arranca Eclipse, este componente se encarga de buscar los ficheros de manifiestos de los plug-ins (que son archivos XML que describen los plug-ins), y carga esta información en un registro. Solamente cuando se requiere por primera vez un plug-in, el Platform runtime lo ejecuta; este componente descubre de forma dinámica plug-ins durante el tiempo de ejecución. Grosso modo, el Platform runtime define los puntos de extensión y el modelo de plug-ins.
El Workspace (Espacio de trabajo) permite gestionar el acceso a ficheros tanto a alto como a bajo nivel. Actúa como un componente que encapsulara la gestión de archivos, permitiendo que los plug-ins utilicen sus métodos sin tener que trabajar directamente con distintos sistemas de archivos, según la plataforma que se utilice.
El Workbench (Banco de trabajo) se encarga de la presentación de la información al usuario y de la gestión del diálogo con el mismo. Proporciona la interfaz gráfica de Eclipse y constituye uno de sus puntos más cuidados y atractivos. Resulta difícil no dejarse seducir por su apariencia, aunque uno se haya curtido en un entorno de línea de comandos y haya jurado no mirar de reojo, bajo pena de extirpación ocular, a cualquier cosa similar a una ventana en un monitor. Desde el punto de vista del usuario una ventana del Workbench consiste en vistas y editores. Tanto la API como la implementación del Workbench se han realizado mediante SWT y JFace.
El SWT se explicará más adelante, pero puede adelantarse que es -fundamentalmente- una biblioteca encargada de proporcionar los componentes gráficos (botones, listas, cuadros de texto, etc.), y que permite obtener una interfaz gráfica muy integrada con la plataforma nativa bajo la cual se use Eclipse. ¿Por qué utilizar una nueva biblioteca gráfica? La pregunta se contestará en la próxima entrega del artículo, pero aquí va un adelanto: porque esta biblioteca permite crear interfaces de usuario nativas, utilizando las capacidades gráficas del sistema operativo y del sistema gráfico de ventanas que se esté usando, a cambio de ciertos inconvenientes que ya veremos. JFace proporciona una interfaz de más alto nivel que la del SWT, basada en los componentes SWT, y lleva incorporadas muchas facilidades para usar con los plug-ins (preferencias, asistentes, etc.), además de definir frameworks muy útiles, como el modelo MVC ( Model View Controller).
El componente de ayuda ( Help) permite a los plug-ins proporcionar documentación HTML que pueda ser presentada contextualmente por el Workbench.
El componente de equipo ( Team o Team support) define un modelo de programación en equipo para crear y mantener un registro de las versiones de las aplicaciones que se desarrollen. Este componente permite que diferentes plug-ins de repositorys (véase la nota técnica del Apdo. 10) convivan dentro de la plataforma. Asimismo, añade las vistas que el usuario necesite para interaccionar con cualquier sistema de control de versiones (si hay alguno) que se esté usando. Tal y como se ha mencionado ya, Eclipse incluye de forma estándar un plug-in CVS, pero pueden añadirse repositorys como ChangeMan (Serena), ClearCase (Rational), CM Synergy (Telelogic), PVCS (Merant) y StarTeam (Starbase). Independientemente del VCM ( Version Control System) que se use, la interfaz de usuario no cambia.
El componente de depuración ( Debug) proporciona un modelo genérico de depuración, en el que se permiten expresiones, puntos de interrupción, acciones habituales de depuración, etc., junto a una interfaz gráfica genérica de depuración. Cualquier plug-in puede aprovechar los mecanismos de depuración que proporciona este componente.
Componentes de la plataforma Eclipse
Figura 11: Arquitectura de la plataforma Eclipse
El Workspace o espacio de trabajo refleja el estado actual de los proyectos locales, con su código fuente y sus ficheros compilados, que estén en la memoria activa. Al cerrar Eclipse se guarda el estado actual del Workspace local, de modo que cuando se reinicia Eclipse vuelve al estado en que se cerró.
El Workbench o banco de trabajo proporciona lo siguiente:
Editores: Un editor es un componente que permite interaccionar con los contenidos de un fichero (no sólo con el código fuente, sino también con su fichero XML asociado, sus propiedades, etc.) y modificarlos.
Vistas: Una vista proporciona metadatos sobre el recurso que se haya seleccionado: organización de un recurso dentro de un paquete o proyecto, estado de la compilación, etc.
Perspectivas: Una perspectiva representa una configuración de editores y vistas relacionadas, al igual que opciones de menú y de compilación. Hay tres perspectivas estándar en Eclipse ( CVS, Install/Update y Resource), pero usando plug-ins pueden añadirse otras nuevas. Al cambiar una perspectiva por otra se muestran diferentes editores, vistas y opciones de menú.
Funciones del Workbench
Figura 12: Ventana del Workbench y sus elementos
El único de los seis componentes de Eclipse que no es un plug-in es el Platform runtime. Los otros cinco componentes son plug-ins: adondequiera que dirijamos la mirada divisaremos plug-ins flotando en las apacibles aguas del archipiélago Eclipse. Cualquier plug-in susceptible de incorporarse a Eclipse se integra con éste de la misma manera que cualesquiera de los plug-ins que incluye de forma estándar. El Workbench y el Workspace son dos plug-ins indispensables porque proporcionan puntos de extensión usados por casi todos los plug-ins, pero su funcionamiento no difiere del de otros plug-ins.
13. AWT y Swing: Repaso de los hechos
Para entender por qué IBM optó por utilizar el SWT ( Standard Widget Toolkit) en Eclipse conviene repasar, muy rápidamente, las limitaciones del AWT y Swing.
El AWT ( Advanced Widget Toolkit) de Java utiliza widgets (componentes gráficos de la interfaz de usuario) nativos para los widgets que existen en todas las plataformas (botones, etiquetas, etc.), pero olvida necesariamente aquellos componentes que existen en una plataforma pero no en otras. Por ejemplo, los widgets tipo árbol ( tree), tabla ( table) y ToolBar, que son widgets nativos de Windows, no están incluidos en el AWT, pues no hay widgets árbol y tabla en plataformas como Motif.
Es importante comprender, al menos someramente, la estructura del AWT para comprender el distinto enfoque que aporta el SWT de Eclipse. El AWT usa una arquitectura peer : Cada componente AWT crea un objeto paralelo llamado su peer (igual). Los objetos peer implementan interfaces en el paquete Java
java.awt.peer. Por ejemplo, cada java.awt.Label usa un objeto peer que implementa java.awt.peer.LabelPeer. A cada componente AWT le corresponde una clase peer escrita en el código nativo del sistema (C habitualmente), por lo que los componentes AWT son, por construcción, dependientes de la plataforma. Cada widget del AWT no se dibuja a sí mismo, sino que es su objeto peer asociado (y nativo) el que interacciona con los widgets nativos de la API gráfica del sistema operativo subyacente, que se encargan de dibujar y controlar los eventos del widget AWT.
En la implementación de Motif -un buen ejemplo para entender la arquitectura peer del AWT-, a cada clase AWT le corresponde un fichero C y cada método nativo AWT cuenta con una implementación en C, con el código común almacenado en ficheros separados.
La encapsulación que hace el AWT de los widgets nativos de la API gráfica del sistema operativo es totalmente opaca: el código que interacciona con los widgets nativos de la plataforma está escrito en C y no es accesible directamente.
Figura 13: El AWT
El AWT cuenta con muchos inconvenientes: la lentitud (muy notable cuando se usan simultáneamente muchos componentes), la imposibilidad de cambiar estática o dinámicamente la apariencia de los componentes, su dependencia de la plataforma y su limitación, por decisiones de diseño, a permitir trabajar sólo con un pequeño conjunto de componentes comunes a todas las plataformas. Además, no resulta adecuado para construir aplicaciones profesionales, pues da un aire un tanto naïf a las aplicaciones. Sin embargo, los componentes AWT fueron los responsables de la rápida expansión inicial de Java, al ser muy sencillos de usar. A veces, menos resulta más.
Swing, que fue introducido con Java 1.2, y en cuyo desarrollo participaron Netscape e IBM, utiliza la interfaz entre el sistema gráfico de ventanas del sistema operativo subyacente y los componentes GUI de Java que proporciona el AWT, pero únicamente la interfaz. Es decir, no usa los componentes AWT para -mediante los objetos peer- manipular los widgets nativos, sino que utiliza sus propios componentes, escritos en Java. Los desarrolladores de Sun reescribieron en Java, desde cero, todos los widgets para Swing. Al estar escritos en Java, los componentes Swing son independientes del sistema de ventanas nativo y pueden ejecutarse en cualquier plataforma cuyo sistema de ventanas admita AWT.
Swing, a diferencia del AWT, permite cambiar rápida y fácilmente el aspecto y la sensación ( Look&Feel) de un componente o grupo de componentes. El aspecto y sensación de una aplicación consiste en el modo en que se presenta al usuario (su aspecto) y en la forma en que permite que el usuario interaccione con ella (su sensación). Swing incorpora los aspectos y sensaciones Basic, Mac, Motif, Windows, Organic y Metal. A diferencia también del AWT, Swing tiene sus propias implementaciones Java de los widgets y no depende de los widgets nativos, por lo que permite una mayor flexibilidad.
Las principales desventajas de Swing son:
Alto consumo de recursos del sistema.
Lentitud con respecto a las aplicaciones nativas.
Tamaño muy grande de la biblioteca.
Diferencias perceptibles en aspecto y sensación con respecto a las aplicaciones nativas y ausencia de soporte de características nativas.
Desventajas de Swing
Con respecto al último punto, la posibilidad de usar el L&F más adecuado para la plataforma que se esté usando permite realizar aplicaciones Java que se parezcan bastante a las nativas, pero suelen haber diferencias importantes en cuanto a la sensación (el modo en que se gestiona la interacción del usuario). A veces da la sensación de que Sun se olvidó de los eventos nativos y definió los
suyos propios, al margen de la realidad de cada plataforma, lo que
ocasiona comportamientos inesperados tanto para usuarios como para
desarrolladores. Existe también una dificultad adicional: al usar
en una aplicación un L&F similar al de una plataforma dada,
Swing debe
simular el L&F, con el consumo adicional de recursos, la
lentitud y, en ocasiones, el comportamiento anómalo con respecto a
las interfaces nativas que conlleva esta simulación.
En la versión 1.4 de Java se han reescrito los algoritmos
gráficos, con lo que Swing corre más rápido que en versiones
anteriores, pero dista mucho, salvo en condiciones muy específicas,
de igualar en velocidad a las aplicaciones nativas. El consumo de
recursos (en particular de memoria) que hace Swing en esta versión
sigue siendo alto, como se puede notar si se ejecutan
simultáneamente varias aplicaciones con muchos componentes
Swing.
Están previstas nuevos L&F para Java 1.4.2 (tipo Windows XP
y GTK) y Java 1.5 (un nuevo L&F, actual y moderno, para todas
las plataformas, similar al L&F Metal de Swing), pero el futuro
-a la vista de los resultados anteriores- no se presagia
Héctor Suárez González hsg arroba telecable punto es
Copyright (c) 2003, Héctor Suárez González. Este documento puede ser distribuido solo bajo los términos y condiciones de la licencia de Documentación de javaHispano v1.0 o posterior (la última versión se encuentra en /licencias/).
Introducción
Presentación del tutorial.
Logo de Hibernate
La intención de este tutorial es introducir al lector en el uso del framework Hibernate. A través del mismo se irán desarrollando diversos ejemplos y se propondrán ejercicios para su resolución. El objetivo último es que el lector pueda desarrollar un pequeña aplicación donde la capa de persistencia se utilizará para el acceso a la base de datos. Este objetivo se encuentra dividido en pequeños pasos :
Capas de persistencia y posibilidades que estas ofrecen.
Que es hibernate. Estructura de una arquitectura base.
Mapas de objetos relacionales en ficheros XML. Hasta aqui trataremos en este primer documento, posteriormente afrontaremos los demas puntos.
Generación de Código y Bases de Datos.
Utilización del API Hibernate.
HSQL. El lenguaje sql de Hibernate
Posibles arquitecturas y ejemplos implementados
Conclusiones
Posibles ejercicios
Lista 1: Capítulos.
Se esperá que el lector de este documento tenga conocimientos básicos de Hiberante. Dichos conocimientos se pueden obtener a través de la Guía hacia Hibernate[2] disponible en javaHispano.
1. Capas de persistencia y posibilidades que estas ofrecen.
(1)En el diseño de una aplicación ( me referiré a una aplicación a desarrollar utilizando Java ) una parte muy importante es la manera en la cual accedemos a nuestros datos en la base de datos ( en adelante BBDD ) determinar esta parte se convierte en un punto crítico para el futuro desarrollo.
La manera tradicional de acceder seria a través de JDBC directamente conectado a la BBDD mediante ejecuciones de sentencias SQL:
Figura 1: Sentencias SQL directas
Esta primera aproximación puede ser útil para proyectos o arquitecturas sin casi clases de negocio, ya que el mantenimiento del código esta altamente ligado a los cambios en el modelo de datos relacional de la BBDD, un mínimo cambio implica la revisión de casi todo el código así como su compilación y nueva instalación en el cliente.
Aunque no podemos desechar su utilidad. El acceso a través de SQL directas puede ser utilizado de manera puntual para realizar operaciones a través del lenguaje SQL lo cual seria mucho mas efectivo que la carga de gran cantidad de objetos en memoria. Si bien un buen motor de persistencia debería implementar mecanismos para ejecutar estas operaciones masivas sin necesidad de acceder a este nivel.
Una aproximación mas avanzada seria la creación de unas clases de acceso a datos ( DAO Data Acces Object). De esta manera nuestra capa de negocio interactuaría con la capa DAO y esta sería la encargada de realizar las operaciones sobre la BBDD.
Figura 2: Ejemplo de DAO (Data Access Object
Los problemas de esta implementación siguen siendo el mantenimiento de la misma así como su portabilidad. Lo único que podemos decir es que tenemos el código de transacciones encapsulado en las clases DAO. Un ejemplo de esta arquitectura podría ser Microsoft ActiveX Data Object (ADO).
Y como encaja Hibernate en todo esto?. Lo que parece claro es que debemos separar el código de nuestras clases de negocio de la realización de nuestras sentencias SQL contra la BBDD. Por lo tanto Hibernate es el puente entre nuestra aplicación y la BBDD, sus funciones van desde la ejecución de sentencias SQL a través de JDBC hasta la creación, modificación y eliminación de objetos persistentes.
Figura 3: Persistencia con Hibernate
Con la creación de la capa de persistencia se consigue que los desarrolladores no necesiten conocer nada acerca del esquema utilizado en la BBDD. Tan solo conocerán el interface proporcionado por nuestro motor de persistencia. De esta manera conseguimos separar de manera clara y definida, la lógica de negocios de la aplicación con el diseño de la BBDD.
Esta arquitectura conllevará un proceso de desarrollo más costoso pero una vez se encuentre implementada las ventajas que conlleva merecerán la pena. Es en este punto donde entra en juego Hibernate. Como capa de persistencia desarrollada tan solo tenemos que adaptarla a nuestra arquitectura.
2. Qué es hibernate
Hibernate[1] es una capa de persistencia objeto/relacional y un generador de sentencias sql. Te permite diseñar objetos persistentes que podrán incluir polimorfismo, relaciones, colecciones, y un gran número de tipos de datos. De una manera muy rápida y optimizada podremos generar BBDD en cualquiera de los entornos soportados : Oracle, DB2, MySql, etc.. Y lo más importante de todo, es open source, lo que supone, entre otras cosas, que no tenemos que pagar nada por adquirirlo.
Uno de los posibles procesos de desarrollo consiste en, una vez tengamos el diseño de datos realizado, mapear este a ficheros XML siguiendo la DTD de mapeo de Hibernate. Desde estos podremos generar el código de nuestros objetos persistentes en clases Java y también crear BBDD independientemente del entorno escogido.
Hibernate se integra en cualquier tipo de aplicación justo por encima del contenedor de datos. Una posible configuración básica de hibernate es la siguiente:
Figura 4: Arquitectura Base
Podemos observar como Hibernate utiliza la BBDD y la configuración de los datos para proporcionar servicios y objetos persistentes a la aplicación que se encuentre justo por arriba de él.
3. Mapas de objetos relacionales en ficheros XML
Antes de comenzar de verdad este tutorial es recomendable que miréis por lo menos el tutorial de Java Hispano una Guía hacia Hibernate[2]. En el se configura las propiedades de Hibernate para poder acceder a una BBDD determinada y se ejecuta un pequeño ejemplo. Si ya lo habéis hecho o queréis saltarlo, pues nada, adelante.
(2) Objetivos : Conseguir desde el diseño de un objeto relacional un fichero XML bien formado de acuerdo a la especificación Hibernate. Nuestro trabajo consistirá en traducir las propiedades, relaciones y componentes a el formato XML de Hibernate.
A partir de ahora asumiremos que objeto persistente, registro de tabla en BBDD y objeto relacional son la misma entidad.
3.1. Estructura del fichero XML
Esquema general de un fichero XML de mapeo es algo como esto:
<Encabezado XML> <Declaración de la DTD> <class - Definición de la clase persistente> <id - Identificador> <generator - Clase de apoyo a la generación automática de OID's> <component - Componentes, son las columnas de la tabla> . . <one-to-many / many-to-many - Posibles relaciones con otras entidades persistentes> . .
A continuación detallaremos las características, parámetros y definición de las etiquetas arriba utilizadas asi como de algunas otras que nos serán de utilidad a la hora de pasar nuestro esquema relacional a ficheros de mapeo XML.
3.1.1.Declaración de la DTD. El documento DTD que usaremos en nuestros ficheros XML se encuentra en cada distribución de Hibernate en el propio .jar o en el directorio src.
Elemento Raíz <hibernate-mapping>. Dentro de él se declaran las clases de nuestros objetos persistentes. Aunque es posible declarar más de un elemento <class> en un mismo fichero XML, no debería hacerse ya que aporta una mayor claridad a nuestra aplicación realizar un documento XML por clase de objeto persistente.
3.1.2.<class> Este es el tag donde declaramos nuestra clase persistente. Una clase persistente equivale a una tabla en la base de datos, y un registro o línea de esta tabla es una objeto persistente de esta clase. Entre sus posibles atributos destacaremos :
name : Nombre completo de la clase o interface persistente. Deberemos incluir el package dentro del nombre.
table : Nombre de la tabla en la BBDD referenciada. En esta tabla se realizaraá las operaciones de transacciones de datos. Se guardarán, modificarán o borrarán registros según la lógica de negocio de la aplicación.
discriminator-value : Permite diferenciar dos sub-clases. Utilizado para el polimorfismo.
proxy : Nombre de la clase Proxy cuando esta sea requerida.
Lista 2: Atributos del elemento class
3.1.3.<id> Permite definir el identificador del objeto. Se corresponderá con la clave principal de la tabla en la BBDD. Es interesante definir en este momento lo que será para nuestra aplicación un OID( Identificador de Objeto ). Tenemos que asignar identificadores únicos a nuestros objetos persistentes, en un primer diseño podríamos estar tentados a asumir un dato con significado dentro de la capa de negocios del propio objeto fuese el identificador, pero esta no seria una buena elección.
Imaginemos una tabla de personas con su clave primaria N.I.F.. Si el tamaño, estructura o composición del campo cambiase deberíamos realizar este cambio en cada una de las tablas relacionadas con la nuestra y eventualmente en todo el código de la aplicación.
Utilizando OID's (Identificadores de Objetos ) tanto a nivel de código como en BBDD simplificamos mucho la complejidad de nuestra aplicación y podemos programar partes de la misma como código genérico.
El único problema en la utilización de OID es determinar el nivel al cual los identificadores han de ser únicos. Puede ser a nivel de clase, jerarquía de clases o para todas la aplicación, la elección de uno u otro dependerá del tamaño del esquema relacional.
name : Nombre lógico del identificador.
column : Columna de la tabla asociada en la cual almacenaremos su valor.
type : Tipo de dato.
unsaved-value ("any|none|null|id_value"): Valor que contendrá el identificador de la clase si el objeto persistente todavía no se ha guardado en la BBDD.
generator : clase que utilizaremos para generar los oid's. Si requiere de algún parámetro este se informa utilizando el elemento <paramater name="nombre del parámetro">.
Lista 3: Atributos del elemento id
Hibernate proporciona clases que generan automaticamente estos OID evitando al programador recurrir a trucos como coger la fecha/hora del sistema. Entre ellas caben destacar : (3)
vm : Genera identificadores de tipo long, short o int. Que serán únicos dentro de una JVM.
sequence : Utiliza el generador de secuencias de las bases de datos DB2, PostgreSQL, Oracle, SAP DB, McKoi o un generador en Interbase. El tipo puede ser long, short o int.
hilo : Utiliza un algoritmo hi/lo para generar identificadores del tipo long, short o int. Estos OID's son únicos para la base de datos en la cual se generan. En realidad solo se trata de un contador en una tabla que se crea en la BBDD. El nombre y la columna de la tabla a utilizar son pasados como parámetros, y lo único que hace es incrementar/decrementar el contador de la columna con cada nueva creación de un nuevo registro. Así, si por ejemplo decimos tener un identificador único por clase de objetos persistentes, deberíamos pasar como parámetro tabla table_OID y como columna el nombre de la clase myclass_OID.
uuid.string : Algoritmo UUID para generar códigos ASCII de 16 caracteres.
assigned : Por si después de todo queremos que los identificadores los gestione la propia aplicación.
Lista 4: Generadores de OID's presentes en Hibernate
3.1.4.<discriminator>Cuando una clase declara un discriminador es necesaria una columna en la tabla que contendrá el valor de la marca del discriminador. Los conjuntos de valores que puede tomar este campo son definidos en la cada una de las clases o sub-clases a través de la propiedad <discriminator-value>. Los tipos permitidos son string, character, integer, byte, short, boolean, yes_no, true_false.
column: El nombre de la columna del discriminador en la tabla.
type: El tipo del discriminador.
Lista 5: Atributos del elemento discriminator
3.1.5.<property> Declara una propiedad persistente de la clase , que se corresponde con una columna.
name: Nombre lógico de la propiedad.
column: Columna en la tabla.
type: Indica el tipo de los datos almacenados. Mirar la sección 3.1.7 Tipos de datos en Hibernate para ver todos las posibilidades de tipos existentes en Hibernate.
Lista 6: Atributos del elemento property
3.1.6.Tipos de relaciones.(Componentes y Colecciones) En todo diseño relacional los objetos se referencian unos a otros a través de relaciones, las típicas son : uno a uno 1-1, uno a muchos 1-n, muchos a muchos n-m, muchos a uno n-1. De los cuatro tipos, dos de ellas n-m y 1-n son colecciones de objetos las cuales tendrán su propio y extenso apartado, mientras que a las relaciones 1-1 y n-1 son en realidad componentes de un objeto persistente cuyo tipo es otro objeto persistente.
3.1.6.1.<many-to-one>La relación n-1 necesita en la tabla un identificador de referencia, el ejemplo clásico es la relación entre padre - hijos. Un hijo necesita un identificador en su tabla para indicar cual es su padre. Pero en objetos en realidad no es un identificador si no el propio objeto padre, por lo tanto el componente n-1 es en realidad el propio objeto padre y no simplemente su identificador. (Aunque en la tabla se guarde el identificador)
name : El nombre de la propiedad.
column : Columna de la tabla donde se guardara el identificador del objeto asociado.
class: Nombre de la clase asociada. Hay que escribir todo el package.
cascade ("all|none|save-update|delete"): Especifica que operaciones se realizaran en cascada desde el objeto padre.
Lista 8: Atributos de las relaciones n-1
3.1.6.2.<one-to-one>Asociacion entre dos clases persistentes, en la cual no es necesaria otra columna extra. Los OID's de las dos clases serán idénticos.
name : El nombre de la propiedad.
class : La clase persistente del objeto asociado
cascade ("all|none|save-update|delete") : Operaciones en cascada a partir de la asociación.
string : Mapea un java.lang.String a un VARCHAR en la base de datos.
date, time, timestamp : Tipos que mapean un java.util.Date y sus subclases a los tipo SQL : DATE, TIME, TIMESTAMP.
calendar, calendar_date : Desde java.util.Calendar mapea los tipos SQL TIMESTAMP y DATE
big_decimal : Tipo para NUMERIC desde java.math.BigDecimal.
locale, timezone, currency : Tipos desde las clases java.util.Locale, java.util.TimeZone y java.util.Currency. Se corresponden con un VARCHAR. Las instancias de Locale y Currency son mapeadas a sus respectivos códigos ISO y las de TimeZone a su ID.
class : Guarda en un VARCHAR el nombre completo de la clase referenciada.
binary: Mapea un array de bytes al apropiado tipo de SQL.
serializable : Desde una clase que implementa el interface Serializable al tipo binario SQL.
clob, blob: Mapean clases del tipo java.sql.Clob y java.sql.Blob
Tipos enumerados persistentes ( Persistente Enum Types ): Un tipo enumerado es una clase de java que contiene la enumerción a utilizar(ej:Meses, Dias de la semana, etc..). Estas clases han de implementar el interface net.sf.hibernate.PersistentEnum y definir las operaciones toInt() y fromInt(). El tipo enumerado persistente es simplemente el nombre de la clase completo. Ejemplo de clase persistente :
package com.hecsua.enumerations;
import net.sf.hibernate.PersistentEnum
public class Meses implements PersistentEnum {
private final int code;
private Meses(int code) { this.code = code; } public static final Meses Enero = new Meses(0); public static final Meses Febrero = new Meses(1); public static final Meses Marzo = new Meses(2); ... public int to Int() {return code;} public static Meses fromInt(int code){ case 0: return Enero; case 1: return Febrero; case 2: return Marzo; ... default: throw new RuntimeException("Mes no valido.");
} }
Lista 10: Tipos en Hibernate.
3.2. Una primera aproximación hacia las colecciones
Las colecciones de elementos que Hibernate puede tratar como persistentes son : java.util.Set, java.util.SortedMap, java.util.SortedSet, java.util.List, y cualquier array de elementos o valores persistentes. Propiedades del tipo java.util.Collection o java.util.List pueden ser persistentes utilizando la semántica de bag.
Las colecciones persistentes no retienen ninguna semántica añadida por la clase implementada de la interface de colección ( ej :iteradores ordenados de LinkedHashSet). La propiedad persistente que contenga una colección a de ser un interface del tipo Map, Set o List; nunca HashMap, TreeSet o ArrayList.Esta restricción es debida a que Hibernate reemplaza las instancias de Map, Set y List con instancias de sus propias implementaciones de Map, Set o List.(6) Debido al modelo relacional existente por debajo, no soportan valores nulos. (7)
Las instancias de una colección son diferenciadas en la BBDD mediante una clave ajena del objeto relacional al cual pertenecen. Esta clave es denominada la clave de la colección. Esta clave será mapeada con el tag <key>.Las colecciones pueden contener : tipos basicos, entidades y componentes. No se pueden crear colecciones de colecciones.
Hay muchos tipos de mapeados de colecciones, que podrán ser útiles en un desarrollo mas avanzado, pero en este primer tutorial nos centraremos en las relaciones entre las clases persistentes. Las colecciones one-to-many y many-to-many.
3.2.1. Mapeando una colección
Las colecciones son declaradas utilizando <set>, <list>, <map>, <bag>, <array> y <primitive-array>. Los posibles parámetros y sus valores son
name: El nombre lógico de la propiedad. Es útil poner un nombre que nos recuerde el rol de la colección (ej: Administradores, MultasSinPagar, etc.. )
lazy ("true"|"false"): Permite el uso de inicialización "lazy". Este tipo de inicialización hace que los objetos de la colección sean solicitados en demanda y no se carguen todos a la vez. Esto es especialmente útil para optimizar búsquedas, etc... (9)
inverse: Señala esta colección como el fin de una asociación bidireccional. Utilizada en relaciones many-to-many sobre todo.
cascade: Permite las operaciones en cascada hacia los entidades hijas.
sort: Especifica una colección con una ordenación natural o con una clase comparadora dada.
order-by: Columna\s de la tabla que definen el orden de iteración. Puede ser ascendente o descendente.
Lista 11: Atributos de una colección genérica
3.2.1.1. Asociaciones many-to-many
En esta asociación tenemos dos clases A y B. Un elemento de A tiene un conjunto de elementos de B hijos, y un elemento de B tiene otro conjunto distinto o igual de elementos de A.
Figura 5: Relación n-m
Esta estructura se puede diseñar creando una tabla intermedia que relacione los códigos de los elementos de A con los elementos de B. Queda claro por tanto que una colección muchos a muchos se ha de mapear en una tabla a parte con las claves de las dos tablas como claves ajenas.
En este punto no tenemos una columna extra en B que diga los elementos de B que le corresponden a un elemento de A. En vez de eso tenemos una tabla nueva A_By_B que contiene los pares de claves relacionados tanto de A hacia B como de B hacia A. Para que sea bidireccional tiene que ser declara en el mapeo de la clase B como sigue, de paso la definimos como el fin de la relación entre las dos tablas. Cualquier otro parámetro, posible para una colección puede ser utilizado aquí ej: lazy, cascade, etc...
Esta relación pierde algunos conceptos semánticos de los colecciones de Java:
Ningún valor nulo puede ser contenido en un map o set
Una instancia del contenedor no puede pertenecer a mas de una instancia de la colección
Una instancia de las entidades contenidas no pueden aparecer en mas de una vez en el índice de la colección
Lista 14: Diferencias entre las las colecciones de Hibernate y el API Collections
Como en el caso anterior si queremos tener una asociación uno a muchos entre dos tablas, deberemos mapear correctamente las dos. En una crearemos una relación one-to-many y en la otra una many-to-one. Una asociación one-to-many de A hacia B requerirá un nuevo campo en B con el valor del índice de A al que se encuentra asociado. En la tabla A no será necesario ningún nuevo campo, como observamos en la siguiente imagen :
3.2.1.3. Consideraciones comunes a las colecciones.
Se ha de destacar ciertas características de las colecciones en Hibernate:
Inicialización "Lazy": Cuando definimos una colección como "lazy" conseguimos que la carga de datos desde la BBDD sea en demanda de los mismos. Es decir, si de una colección de 50000 objetos solo necesitamos buscar en los 10 primeros no tiene sentido cargarlos todos no?. Por eso los objetos que son devueltos al iterar sobre la colección son cargados a medida que se accede a ellos. Aunque esto puede producir ciertos problemas que serán abordados con posterioridad.
Colecciones ordenadas: Hibernate soporta la implementación de colecciones ordenadas a través de los interfaces java.util.SortedMap y java.util.SortedSet. Si queremos podemos definir un comparador en la definición de la colección. Los valores permitidos son natural, unsorted y el nombre de la clase que implementa java.util.Comparator.
El colector de basura de las colecciones: Las colecciones son automáticamente persistidas cuando son referenciadas por un objeto persistente y también son borradas automáticamente cuando dejan de serlo.
Lista 12: Características de las colecciones
Por último si una colección es pasada de un objeto persistente a otro, sus elementos son movidos de una tabla a la otra. Lo bueno de Hibernate es que no nos tenemos que preocupar de esto, debemos utilizar las colecciones como normalmente lo hemos hecho. Desechándolas cuando sea necesario, Hibernate se ocupará de su gestión.
3.3. Componentes.
Un buen diseño relacional necesitará de la composición de objetos. El nombre de la persona, la dirección, una localidad etc.. son todo estructuras de datos que componen objetos más grandes. Una componente en Hibernate es un objeto persistente contenido dentro de la misma tabla de su propietario. ej: Clásico ejemplo del nombre/dirección de una persona :
Figura 7: Clase Persona y su composición.
El diseño del primer recuadro a parte de ser mucho más claro es muy sencillo de mapear, procedemos de la siguiente manera :
La tabla persona tiene que contener los elementos correspondientes a los objetos name y adress. Así como al resto de las propiedades de persona. Los tipos de estas propiedades pueden ser cualquier tipo de los soportados por Hibernate, incluso más componentes (10) , colecciones y relaciones. Por último destacar que cuando un componente es nulo todas sus propiedades lo son a la hora de guardarlo en la BBDD. En el caso contrario cuando cargamos un objeto a memoria, si todas las propiedades del elemento son nulas el elemento es nulo.
3.4. Creación de Ficheros XML
El siguiente paso es aplicar todo lo anteriormente explicado en un ejemplo. Partiendo del siguiente diseño, crearemos los ficheros XML de acuerdo a las especificaciones anteriormente explicadas:
Figura 8: Ejemplo de Diseño Relacional
3.4.1. Traducir este diseño relacional a ficheros XML siguiendo las especificaciones Hibernate será mucho más sencillo de lo que pueda parecer a primera vista. Para crear el mapeo de Objeto[3], comenzaremos con la definición del fichero XML[4], mediante las dos líneas siguientes :
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "..\..\hibernate\hibernate-mapping-2.0.dtd">
En estas dos líneas declaramos el tipo de codificación del fichero XML así como su DTD.
Después comenzamos a definir nuestro objeto persistente, abrimos el tag <hibernate-mapping>.Una muy buena costumbre es definir un objeto por fichero, ya que hace mucho más legible el código y simplifica su modificación.
3.4.2. El siguiente tag será el class:
<!- Clase persistente que representa un Objeto dentro del proyecto este puede ser una pantalla, un procedimiento un algoritmo, dependerá del proyecto en cuestión--> <class name="com.hecsua.bean.Objeto" table="objeto">
Como podéis observar la clase se denominará Objeto y estará dentro del package com.hecsua.bean. Esta clase hará referencia a la tabla objeto dentro de la BBDD.
3.4.3. El siguiente paso es definir el identificador, el nombre lógico de la propiedad queremos que sea id, que haga referencia a la columna idObject y es un dato de tipo long, el resultado es el siguiente :
<id name="id" column="idobject" type="long">
Para obtener los OID's utilizaremos la clase hilo sobre la tabla uid_table y la columna next_hi_value :
3.4.4. Las propiedades se definen de manera parecida al identificador, con el nombre lógico de la propiedad ( aquí podremos ser tan descriptivos como deseemos ), la columna dentro de la tabla a la que hace referencia y el tipo de dato. En el caso de que este necesite parámetros de longitud u otro tipo también se declararán aquí mediante el parámetro adecuado.
3.4.5. Ahora definimos las relaciones, como se puede ver son todas del tipo muchos a uno, por lo que en realidad son columnas de identificadores ajenos a nuestra tabla. Se definen utilizando la etiqueta many-to-one, el nombre lógico de la propiedad nos ha de recordar el rol de la relación, el parámetro class deberá ser la clase del objeto asociado y la columna que almacenara su identificador.
<!- Relación con la clase persistente Sistema a través de la columna idsistem --> <many-to-one name="sistema" class="com.hecsua.bean.Sistema" column="idsistem" />
<!- Relación con la clase persistente Usuario realizando el rol de Usuario Creador del objeto a través de la columna idusucre --> <many-to-one name="creador" class="com.hecsua.bean.Usuario" column="idusucre" />
<!- Relación con la clase persistente Usuario con el rol de Ultimo Usuario que Modifico el objeto a través de la columna idusumod--> <many-to-one name="modificador" class="com.hecsua.bean.Usuario" column="idusumod" />
3.4.6. Por último tenemos que mapear la relación n-m, esta es una relación circular entre registros de la tabla objeto. Para mapear esta relación utilizaremos la siguiente estructura, dejando como se puede observar los identificadores relacionados en la tabla Obj_By_Obj:
En estas dos relaciones observamos que ambas utilizan la tabla obj_by_obj donde se guardarán las parejas de identificadores relacionados. Una de ellas ha de ser "inverse", con esta etiqueta declaramos cual es el final de la relación circular.
Finalmente cerramos las etiquetas, y acabamos de crear nuestro primer mapeo de un objeto relacional, como podéis observar no es tan complicado como parece, eso sí, siempre que partamos de un buen diseño será mucho mas fácil. Ahora tan solo resta definir el resto de los objetos persistentes en sus correspondientes ficheros XML , generar las clases persistentes asociadas, y comenzar a utilizar Hibernate. Todo esto en el siguiente capitulo Herramientas, Configuración y Uso de Hibernate.
Aún nos faltarían cosas por hacer, que podeis realizar como ejercicio:
Crear y definir ficheros Usuario.hbm.xml, Sistema.hbm.xml y TipoObjeto.hbm.xml.
Modificar Usuario.hbm.xml para que contenga el nombre del usuario, la dirección ( esta a su vez la localidad ) como componentes.
Definir una relación entre Usuario y Sistema. Un Usuario tiene que pertenecer a un Sistema.
Validar mediante DTD de Hibernate que son ficheros XML bien formados
Crear carpetas donde dejarlos, en nuestro caso ./com/hecsua/bean.
Lista 11: Tareas a realizar.
Conclusión
No hemos utilizado ni la mitad de las posibilidades de Hibernate. Este abarca tal cantidad de parámetros, configuraciones, etc.. que lo único que se conseguiría seria perderse entre todo. Por lo tanto tan solo me he limitado a explicar las características básicas del mapeo para crear una pequeña aplicación por la cual empezar. En posteriores versiones o anexos de este documento iré explicando todas las posibilidades, e incluso vosotros mismos me podréis comentar vuestros propios trucos o eso al menos espero.
Notas
(1) Esta primera parte es de introducción al concepto de capa de persistencia, por lo tanto es bastante teórica.
(2) Antes de empezar a escribir una línea debemos tener realizado el análisis de nuestra aplicación y la estructura de datos necesaria para su implementación.
(3) En Hibernate se pueden definir identificadores compuestos, esta parte se tratará en el tutorial avanzado.
(5) Es necesario el conocimiento del framework Collections de java
(6) Hay que tener cuidado al comparar las colecciones directamente con ==
(7) Hibernate no distingue entre una colección nula y una colección vacía
(8) No se utiliza en asociaciones one-to-many
(9) No se puede utilizar con arrays
(10) Un buen ejercicio, antes de continuar con el siguiente capitulo, podría consistir en realizar el mapeo de Localidad (País, Provincia o Estado, Localidad, código ) como una componente de Dirección.
Héctor Suárez González Héctor es un estudiante de 4 de Informática en Gijón. Gracias al proyecto Fin de carrera comenzó a programar en Java. A parte de trabajar y de estudiar en sus ratos libres se dedica a salir de juerga siempre que puede, hacer algo de deporte e intentar en la medida de lo posible facilitar la iniciación en Java a todo el que pueda, al igual que hicieron con él.