Desde Cero - con Spring e Hibernate - draft 0.1 - Español

36
  Cero con Spring e Hibernate Nicolás Cornaglia http://nikofactory.blogspot.com 2004

Transcript of Desde Cero - con Spring e Hibernate - draft 0.1 - Español

DesdeCero con Spring e Hibernate Nicols Cornaglia http://nikofactory.blogspot.com 2004 Capitulo 1 - ntroduccin 1-2 Contenidos 1Introduccin 1-4 2Preparacin del entorno 2-5 2.1Directorios 2-5 2.2Instalacin SDK 2-5 2.3Instalacin Eclipse 2-5 3El proyecto 1parte 3-7 3.1Anlisis 3-7 3.2Creacin del proyecto en eclipse 3-8 3.3Un aproximacin a la arquitectura 3-9 3.4Test driven development 3-10 3.4.1Anlisis 3-10 3.4.2JUnit 3-10 3.4.3El primer caso de prueba 3-10 3.5Cosmtica 3-16 3.5.1Fonts 3-16 3.5.2Tabs 3-16 3.5.3JavaDocs 3-17 3.6Mas desarrollo 3-18 3.6.1Refinamiento de Project 3-18 3.6.2Mas clases 3-19 4Persistencia 4-23 4.1Introduccin a Hibernate 4-23 4.2Xdoclet 4-25 4.3Ant 4-29 4.4MySQL 4-29 4.5Test Cases 4-29 4.5.1DBUnit 4-29 5Uniendo todo con Spring 5-30 5.1Inyeccin de dependencia 5-30 5.2Spring 5-30 5.3El Contexto 5-30 6Coverage 6-31 6.1.1Emma 6-31 7Documentacin 7-32 7.1.1Javadoc 7-32 7.1.2java2html 7-32 8ACEGI 8-33 9CVS 9-34 Capitulo 1 - ntroduccin 1-3 9.1WinCVS 9-34 10Continuous Integration 10-35 11El proyecto 2parte (Web) 11-36 11.1Tomcat 11-36 11.2El proyecto 11-36 11.3Spring MVC 11-36 11.4Sitemesh 11-36 11.5Test Cases 11-36 11.5.1jWebUnit 11-36 Capitulo 1 - ntroduccin 1-4 1Introduccin El presente libro sera una guia rapida para comenzar un proyecto de desarrollo de soItware, utilizando Java, varias tecnicas bien conocidas, varios productos del mercado open source y patterns estandar, pero de ninguna manera pretende ser la unica o mejor Iorma de hacer las cosas, es solo una mas. Al mismo tiempo que discurren los capitulos se creara, desde cero, una aplicacion totalmente Iuncional. Esta aplicacion es parte de otro proyecto open source llamado 'MwM, una herramienta de planiIicacion y control de iteraciones para proyectos de desarrollo de soItware. Por lo tanto, este libro no explicara con largos capitulos dedicados a la teoria, las tecnicas utilizadas, sino que aplicara el 'ensear con el ejemplo, con un lenguaje coloquial, que tanto hace Ialta a los recien iniciados para no abrumarse con la cantidad de conocimientos necesarios para ser un buen desarrollador de soItware. Utilizaremos Spring Framework para el middleware y el web tier, e Hibernate para la persistencia, pero la aplicacion se complementara con otros productos del mercado. Antes de comenzar, un especial reconocimiento a Matt Raible (http://raibledesigns.com/page/rd), por su constante esIuerzo de divulgacion, y porque este libro no seria posible sin su ejemplo y motivacion con AppFuse (http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse) y Spring Live (http://www.springlive.com). Capitulo 2 - Preparacin del entorno 2-5 2Preparacin del entorno Se presume que utilizaremos Windows para el desarrollo, por lo que se utilizara siempre / para los paths, y no \ como deberan utilizar los usuarios Linux / Unix. 2.1Directorios La estructura de directorios elegida para ordenar nuestro trabajo sera la siguiente:

Puede estar en cualquier disco duro y dentro de cualquier otra carpeta, pero de aqui en adelante nos reIeriremos a work\ como nuestra carpeta principal para simpliIicar. En vuestra conIiguracion, deberan reemplazar todas las apariciones de work\ con el path completo que han elegido, por ejemplo C:\work\. En ella estaran las demas carpetas, donde instalaremos las aplicaciones (apps), desplegaremos las apis necesarias (extracts) y guardaremos nuestro(s) proyecto(s) (workspace). 2.2Instalacin SDK Por supuesto que (si no lo han hecho ya) deberemos descargar e instalar el SDK de Java. Para ello iremos a la web de Sun (http://java.sun.com/), buscar el vinculo 'J2SE 1.4.2 SDK, seguir las pantallas de conIirmacion y descargarlo en work\downloads. No es necesario descargarnos tambien el netBeans, ya que hemos elegido eclipse para nuestro desarrollo, asi que deberemos tener cuidado en elegir bien el vinculo. Hay que asegurarse tambien que bajamos la version correspondiente a nuestro sistema operativo, y que elegimos la opcion 'oIIline, lo que nos permitira descargarnos el SDK entero y tenerlo para Iuturas ocasiones. Una vez bajado el .exe, lo ejecutaremos para instalarlo en work\jdks, en una carpeta con el mismo nombre de la version del SDK. Si hemos bajado la version 1.4.2-05 por ejemplo, lo instalaremos en la carpeta work\jdks\j2sdk1.4.2_05. Mas adelante podremos obtener e instalar aqui diIerentes versiones de Java e incluso maquinas virtuales de diIerentes vendedores para comparar perIormance y compatibilidad.Tambien crearemos la variable de entorno JAVA_HOME=work\jdks\j2sdk1.4.2_05 y agregaremos %JAVA_HOME%\bin a la variable de entorno PATH. 2.3Instalacin Eclipse El IDE elegido para trabajar es eclipse (http://www.eclipse.org), aunque IntelliJ IDEA (http://www.jetbrains.com/idea/) y netBeans (http://www.netbeans.org/) son dos opciones viables. Capitulo 2 - Preparacin del entorno 2-6 Luego de haber bajado el eclipse de la web, descompactaremos el .zip en work\apps\eclipse, y crearemos un acceso directo a eclipse.exe, agregandole el parametro '-data work\workspace, para indicarle cual sera la carpeta de trabajo donde guardara nuestros proyectos. Si ejecutamos el acceso directo, la primer pantalla que veremos sera la siguiente: Cerrando esta vista, veremos la perspectiva por deIecto de eclipse: Resources. Capitulo 3 - El proyecto 1parte 3-7 3El proyecto 1 parte Un poco de analisis no viene mal, ni siquiera para un desarrollador.Ironias aparte, diremos que nuestra aplicacion debera proveer a sus usuarios una interIaz web para mantener un proyecto de desarrollo de soItware utilizando la metodologia XP (Extreme Programming). En esta metodologia (http://www.extremeprogramming.org), una buena parte de los esIuerzos corresponden a asignar las diIerentes User Stories a las iteraciones en las cuales se desarrollaran (Iteration Planning) y a los releases en los que estaran disponibles para el usuario Iinal (Release Planning). Es aqui donde nuestra aplicacion oIrecera sus servicios. Si ser muy Iormales, diremos que los User Stories son escenarios de uso del sistema, escritos por el cliente y que sirven para estimar el esIuerzo necesario. Luego de obtener un numero razonable de User Stories (haciendo que el usuario las escriba con o sin nuestra 'ayuda), los desarrolladores estiman cuanto tardaran, en tiempo ideal, en desarrollar la Iuncionalidad. En base a estas estimaciones sabremos cuantas podemos agrupar para no pasarnos de nuestra 'velocity, termino por el cual se conoce al indice de productividad. Las User Stories se agrupan luego en iteraciones, periodos de tiempo predeIinidos todos iguales entre si, en los cuales las desarrollaremos. Y por ultimo, las stories se agrupan en releases, o versiones de nuestra aplicacion para mostrar al cliente. Por ejemplo, si en la iteracion anterior hemos hecho 5 stories de 3 dias cada una, mas 2 stories de 5 dias, tendremos una velocidad de 5*32*525. Por lo que en la siguiente iteracion, la suma de las estimaciones no debera superar 25. 3.1Anlisis Tal vez parezca recursivo, pero podemos utilizar XP para analizar nuestra aplicacion XP, por lo que comenzaremos a deIinir nuestros propios User Stories de la siguiente Iorma: S01Creacion de un proyecto. El usuario debe crear un proyecto, asignandole nombre, y Iechas de inicio y Iinalizacion (entre otros). Se quiere una interIaz web. S02 Creacion de una iteracion. Se crea una iteracion para un proyecto, con Iechas de inicio y Iin. S03 Creacion de un release. Se necesita crear y modiIicar un release, con sus Iechas. S04 Creacion de un story. El Cliente hace un story, por lo que es necesario agregarla al sistema. Contiene un nombre y, opcionalmente, el release, iteracion, estimado en tiempo y tareas asociadas. S05 Asignacion de un story a una iteracion. Una vez decidido en que iteracion haremos este story, se ingresa en el sistema. S06 Asignacion de un story a un release. Una vez decidido en que release haremos este story, se ingresa en el sistema. S07 Se requiere un listado de las iteraciones de un proyecto, con el esIuerzo estimado, actual y restante. Capitulo 3 - El proyecto 1parte 3-8 Como se puede ver, la Iorma de escribirlos diIiere de un User Story a otro, ya que los clientes son los encargados de hacerlo, y su Iorma de expresarse no siempre es la misma. Pero con esto tenemos suIiciente como para comenzar nuestro proyecto. Deberiamos ahora estimar cada Story y asignarla a una iteracion. Pero como este no es un libro sobre XP, sino una guia rapida para comenzar a desarrollar, asumiremos que tenemos tiempo inIinito e iremos escogiendo stories para hacer a medida que necesitemos. Y como seremos nuestro propio cliente, las reuniones Iormales con el cliente, para que nos detalle cada story, las asumiremos como realizadas. 3.2Creacin del proyecto en eclipse Vamos pues a lo que nos interesa, que es crear el proyecto en eclipse. Tanto desde la perspectiva por deIecto de eclipse Resources como desde mi preIerida, Java, podemos utilizar el menu y crear un proyecto: File/New/Project/Java Project. Con lo que tendremos la pantalla inicial para especiIicar el nombre de proyecto, en este caso mwm: En la siguiente pantalla agregaremos una carpeta src para nuestros Iuentes: Capitulo 3 - El proyecto 1parte 3-9 y conIirmaremos la caja de dialogo que nos presenta eclipse para actualizar la carpeta de salida a bin: con lo que Iinalizaremos la creacion, obteniendo el siguiente resultado en la perspectiva Java: 3.3Un aproximacin a la arquitectura Sabemos que sera una aplicacion con un componente web (S01), que requerira una base de datos para guardar proyectos, iteraciones, etc. (S01, S02, S03, etc.), una jerarquia de clases simple por ahora, pero con componentes muy interesantes: proyecto (S01)iteracion (S02)story (S04)tarea (S04) y ciertos calculos sobre los datos de estas clases (S07). En base estos requerimientos y a nuestra experiencia podemos saber que contendra ciertos componentes: Clases java contenidas en paquetes. Persistencia en base de datos. InterIaz web. Una capa de componentes de negocio. Capitulo 3 - El proyecto 1parte 3-10 3.4Test driven development El primer impulso es comenzar con un public class Project{} como siempre, pero esta vez intentaremos una aproximacion diIerente a nuestra Iorma de desarrollar soItware: TDD - Test driven development (http://www.testdriven.com). En lugar de escribir codigo y luego comprobar su Iuncionamiento, TDD establece que primero se escriben los casos de prueba (unit tests), y luego se crea el codigo necesario para satisIacerlos. Esto Iuerza el tener todos (o casi todos) los casos de prueba para nuestro codigo y un alto desacoplamiento del codigo al tener las clases (como minimo) dos usuarios desde el inicio: la aplicacion cliente y los casos de prueba. 3.4.1Anlisis Que datos podemos obtener de nuestra primer user story (S01)?Que necesitamos modelar una jerarquia de objetos tal que nos permita oIrecer al usuario una Iorma de crear proyectos. Y que estos proyectos tienen unas propiedades, hasta ahora 'dueo, 'Iecha de inicio y 'Iecha de Iinalizacion. Separando por ahora la parte de interaccion web con el usuario, podemos asegurar, con bastante conIianza, que necesitaremos una clase a la que podriamos llamar Project, a la cual le deberiamos podemos asignar las propiedades antes mencionadas. Pues bien, hagamos un caso de prueba que compruebe esta Iuncionalidad. Para ello necesitaremos una herramienta que Iacilite las comprobaciones, y la que utilizaremos sera JUnit. 3.4.2JUnit JUnit (http://www.junit.org) es una herramienta Java para pruebas unitarias y de regresion, que provee una jerarquia de clases y deIine un lenguaje comun para escribir y ejecutar casos de prueba repetibles. Mediante reIlexion, examina las clases de prueba y ejecuta los metodos sealados, examinando el resultado de los mismos. Muchos de los IDEs actuales proveen soporte para JUnit, considerado ya el estandar para pruebas unitarias en Java. En la practica, tendremos que crear una clase heredada de TestCase, agregarle metodos llamados test* para contener el codigo de prueba, y utilizar 'Assertions para comprobar el resultado del mismo (assertNull(), AssertEquals(). Tambien podremos agrupar casos de prueba en 'Suites, para ejecutar en Iorma conjunta diIerentes casos de prueba con elementos en comun. 3.4.3El primer caso de prueba Si bien podriamos hacerlo desde cero, utilizaremos las Iuncionalidades de eclipse para crear nuestro primer caso de prueba. Antes que nada crearemos una nueva carpeta Iuente a la que llamaremos test para nuestros casos de prueba, desde el menu File/New/Source Folder: Capitulo 3 - El proyecto 1parte 3-11 Esto no lleva tambien a querer modiIicar las propiedades del proyecto, con el botn derecho/Properties/Java Build Path, para cambiar el orden de nuestro Java Build Path y poner la carpeta test en segundo lugar, luego de src. Finalmente accederemos al menu File/New/JUnit Test Case y Eclipse nos propondra en este momento que agreguemos al build path el .jar necesario para la ejecutar las clases de prueba: Luego de elegir la opcion Yes, aparecera la caja de dialogo donde elegiremos las opciones de eclipse para crear el caso de prueba: Capitulo 3 - El proyecto 1parte 3-12 En el Source Folder pondremos el recien creado test, como nombre de package com.mwm.model y como nombre ProjectTest. Tambien haremos que nos cree los metodos setUp() y tearDown(), poniendo las marcas necesarias. Luego de aceptar las opciones con Finish, el resultado Iinal en la perspectiva Java sera el siguiente: Y el codigo generado para com\mwm\model\ProjectTest.java es el siguiente: /* * Created on Oct 14, 2004 * Capitulo 3 - El proyecto 1parte 3-13 * TODO To change the template for this generated file go to * Window - Preferences - Java - Code Style - Code Templates */ package com.mwm.model; import junit.framework.TestCase; /** * @author ncornag * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates */ public class ProjectTest extends TestCase { /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { super.setUp(); } /* * @see TestCase#tearDown() */ protected void tearDown() throws Exception { super.tearDown(); } } Crearemos ahora un metodo capaz de comprobar la creacion de un objeto de la clase Project, y la asignacion de sus correspondientes propiedades. Lo que primero haremos sera tener siempre disponible una propiedad del caso de prueba de tipo Project, creandola en el metodo setUp(), metodo que se ejecutara antes de ejecutar cada metodo de prueba. Tambien aprovecharemos el metodo tearDown() para 'limpiar los cambios que pudieramos haber hecho y dejar todo listo para la ejecucion del siguiente metodo de test. Luego, crearemos el metodo testNewProject(), con la Iuncionalidad necesaria para asegurarnos el correcto Iuncionamiento de la clase Project. El resultado Iinal es el siguiente (sin comentarios por simplicidad): public class ProjectTest extends TestCase { private Project project; protected void setUp() throws Exception { super.setUp(); project = new Project(); } protected void tearDown() throws Exception { super.tearDown(); project = null; Capitulo 3 - El proyecto 1parte 3-14 } public void testNewProject() throws Exception { project.setName("Mi primer proyecto"); project.setStartDate(new Date(0)); project.setEndDate(new Date(0)); assertEquals("Name", "Mi primer proyecto", project.getName()); assertNotNull("StartDate", project.getStartDate()); assertNotNull("EndDate", project.getEndDate()); } } Lo que estamos haciendo en este metodo de prueba testNewProject(), es utilizar la instancia de Project creada inmediatamente antes en el metodo setUp(), inicializar sus propiedades, y asegurarnos luego que podemos recuperar la inIormacion. Para veriIicar el nombre del proyecto, utilizamos el metodo assertEquals(String arg0, Object arg1, Object arg2) de JUnit, donde indicaremos en el primer argumento un string para ser visualizado en caso de error, el objeto esperado en el segundo argumento y el objeto a comprobar en el tercero. Para las Iechas, por ejemplo, utilizaremos assertNotNull(String arg0, Object arg1), donde utilizaremos de la misma Iorma el primer argumento, y en el segundo enviaremos el objeto a comprobar su no nulidad. Si alguno de los metodos 'assert Ialla, el metodo se da por Iinalizado y Iallado. Pero lo que tenemos en este punto es una clase de prueba que ni siquiera compila. Pero ese es el punto. Ahora estamos 'obligados a hacer una clase Project, con los metodos necesarios para asignarle ciertas propiedades, tal y como establece nuestro S01. Por lo tanto, crearemos una nueva clase (File/New/Class), con el minimo codigo necesario para satisIacer los requerimientos del caso de prueba: /* * Created on Oct 14, 2004 * * TODO To change the template for this generated file go to * Window - Preferences - Java - Code Style - Code Templates */ package com.mwm.model; import java.util.Date; /** * @author ncornag * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates */ public class Project { //~ Properties ============================================================= private String name; private Date startDate; private Date endDate; Capitulo 3 - El proyecto 1parte 3-15 //~ Getter/Setters ========================================================= /** * @return Returns the endDate. */ public Date getEndDate() { return endDate; } /** * @return Returns the name. */ public String getName() { return name; } /** * @return Returns the startDate. */ public Date getStartDate() { return startDate; } /** * @param endDate The endDate to set. */ public void setEndDate(Date endDate) { this.endDate = endDate; } /** * @param name The name to set. */ public void setName(String name) { this.name = name; } /** * @param startDate The startDate to set. */ public void setStartDate(Date startDate) { this.startDate = startDate; } } Nuestro caso de prueba compila ahora correctamente, ya que hemos creado la nueva clase en com.mwm.model (el mismo package que el caso de prueba aunque bajo la carpeta Iuente src). Solo nos queda comprobar su correcto Iuncionamiento, eligiendo la clase ProjectTest con el boton de la derecha, y eligiendo la opcion del menu Run/Junit Test. Se nos abrira la vista Junit, en la cual podemos observar que todo ha Iuncionado tal como era de esperar (una barra verde nos lo indica): Capitulo 3 - El proyecto 1parte 3-16 Se podria decir que no tiene mucho sentido comprobar los accesores/mutadores (getters/setters) de una propiedad por lo trivial de los metodos, y se tendria razon por lo que en adelante no comprobaremos mas que los metodos 'realmente Iuncionales. Sin embargo, al hacerlo hemos aprendido los Iundamentos de TDD y la utilizacion de JUnit, asi como las capacidades de eclipse al respecto. 3.5Cosmtica Aprovecharemos esta instancia del proyecto, donde tenemos ya deIinidas algunas clases, para cambiar ciertas caracteristicas del entorno en el que trabajamos. 3.5.1Fonts Personalmente preIiero tener mucho espacio en la ventana de edicion de codigo, para lo cual es necesario cambiar, en las preIerencias, la Iuente por deIecto del editor. 3.5.2Tabs Los espacios deberian ser la Iorma elegida de identar, ya que aseguran una correcta visualizacion de nuestro codigo en diIerentes sistemas operativos, y para ello deberemos marcar la opcion Insert spaces for tab: Capitulo 3 - El proyecto 1parte 3-17 3.5.3JavaDocs Los JavaDocs son una Iorma estandar de documentar nuestro codigo, y eclipse nos provee plantillas para que al momento de creacion de una clase o metodo, se inserte el correspondiente cometario. Lo que haremos ahora es modiIicar algunos detalles de estas plantillas en Window/Preferences/Java/Code Style/Code Templates/Comments: Para las clases (Types), agregaremos un link al nombre de la clase java, pero con extension .html, para permitiros mas adelante generar paginas html con el codigo Iuente y tenerlas vinculadas a los javadocs. Tambien agregaremos nuestro nombre delante del tag @author, (aqui podemos poner una direccion de correo electronico con los tags adecuados:Nombre), y unos tags especiales para el CVS (mas sobre esto adelante). No esta de mas reIorzar en este momento la idea de documentacion, con tres simples palabras: documentar, documentar, documentar. Unas lineas de comentario en los javadocs y algunas en lugares estrategicos del codigo no consume ningun tiempo extra, y ayudara a los demas (y a nosotros mismos) a entender el codigo resultante. En los metodos sobrescritos (Overriding methods) pondremos: /** * ${see_to_overridden} */ Capitulo 3 - El proyecto 1parte 3-18 En los nuevos archivos de clase (Code/New Java Files) suprimiremos los comentarios, quedandonos con: ${package_declaration} ${typecomment} ${type_declaration} Y por ultimo el Catch block body podemos dejarlo como esta por ahora, y cambiarlo mas adelante por: log.error("Error: " + ${exception_var}.getMessage()); si decidimos utilizar Log4J para las trazas de errores (mas sobre esto adelante). Por ultimo, no debemos olvidar de modiIicar los comentarios ya generados por eclipse para nuestras dos clases Project y ProjectTest (Alt+Shift+J sobre el nombre de metodo o clase), asi como tambien cambiar los tabs de ambos Iicheros a espacios (Alt+Shift+F sobre el codigo). 3.6Mas desarrollo Este metodo de escribir el caso de prueba y luego escribir el minimo codigo (KISS) que lo satisIaga (TDD), lo continuaremos practicando a lo largo de todo el ciclo de vida del proyecto. KISS son las siglas de 'Keep It Simple Stupid (Mantenlo simple estupido) 3.6.1Refinamiento de Project Continuaremos ahora nuestro desarrollo agregando propiedades que sabemos (el cliente nos ha dicho) son del proyecto. Por ejemplo, la interIaz debera ser accesible por diIerentes empresas, por lo que cada proyecto debera tener asociado una. Para ello, deberiamos hacer un metodo que pruebe la asignacion y posterior recupero de esta propiedad en la clase Project.Pero hemos elegido no hacer casos de prueba sobre estos metodos, por lo que tenemos tres caminos:1.Ignorar este requerimiento y no hacer algo que quizas no necesitemos, siguiendo la practica YAGNI de XP. YAGNI son las siglas de 'You Aren`t Gonna Need It (No lo vas a necesitar) 2.Agregamos las propiedades necesarias en la clase, sin su metodo de veriIicacion. 3.Revemos nuestra politica y agregamos metodos de veriIicacion para los accesores y mutadores. YAGNI no signiIica que no hagamos diseo para nuestra aplicacion, y al disear la clase Project, sabemos positivamente que necesitaremos ciertas propiedades. Y tambien estamos convencidos de no hacer pruebas sobre metodos triviales, por lo que optaremos por la opcion 2, y agregaremos company y description a la clase Project: private String description; private Company company; con sus correspondientes accesores y mutadores, utilizando eclipse para crearlos como ya hemos visto anteriormente. Para que este ultimo cambio compile correctamente, nos veremos necesitado de crear una clase Company, que por ahora contendra solo su mas obvia propiedad, el nombre: package com.mwm.model; Capitulo 3 - El proyecto 1parte 3-19 /** * * View Source * * * @author Nicolas Cornaglia * @version $Revision:$ $Date:$ */ public class Company { //~ Properties =========================================================== private String name; //~ Getters/Setters ====================================================== /** * @return Returns the name. */ public String getName() { return name; } /** * @param name The name to set. */ public void setName(String name) { this.name = name; } } 3.6.2Mas clases Segun lo que sabemos del story S02 tenemos una entidad llamada iteracion asociada de 0..n al proyecto. Esta iteracion tiene como propiedades el nombre, la descripcion y las Iechas de inicio y de Iin. Comenzaremos pues, agregando un metodo de prueba a nuestro ProjectTest: /** * Test put & remove a Iteration* @throws Exception */ public void testPutRemoveIteration() throws Exception { Long id = new Long(1); Iteration iteration = new Iteration(); iteration.setId(id); project.addIteration(iteration); assertEquals("Iteration", iteration, project.getIteration(id)); assertEquals("Iteration project", project, project.getIteration(id).getProject()); project.removeIteration(iteration); assertNull("Iteration not removed", project.getIteration(id)); } Capitulo 3 - El proyecto 1parte 3-20 En este punto nuestra clase no compila, ya que no existe todavia la clase Iteration, y la clase Project no tiene los metodos addIteration(), getIteration() ni removeIteration(). Tambien hemos agregado un identiIicador de iteracion, para permitirnos obtener y remover cada instancia de la clase. Nos queda pues hacer lo necesario para satisIacer el caso de prueba que hemos diseado, crear la clase Iteration: public class Iteration { //~ Properties =========================================================== private Long id; private String name; private String description; private Project project; private Date startDate; private Date endDate; //~ Getter/Setters ======================================================= . . . } y agregar la relacion con Project (con sus respectivos accesores y mutadores), y los metodos Ialtantes para administrar las iteraciones: private Map iterations = new HashMap(); public Iteration getIteration(Long id) { return null; } public void addIteration(Iteration iteration) { } public void removeIteration(Iteration iteration) { } con lo que nuestra clase de prueba compilara, pero dara error al ejecutarse: Capitulo 3 - El proyecto 1parte 3-21 porque los metodos que hemos creado eran solo plantillas de lo que necesitaremos, y getIteration(id) devuelve null, haciendo que JUnit nos muestre un error en la linea 52: junit.framework.AssertionFailedError: Iteration expected: com.mwm.model.Iteration@3ee284 but was: , indicando que la sentenciaassertEquals("Iteration", iteration, project.getIteration(id)); ha Iallado. Hagamos entonces que estos metodos realicen algo util: /** * @param id * @return */ public Iteration getIteration(Long id) { return (Iteration)iterations.get(id); } /** * @param key * @param iteration */ public void addIteration(Iteration iteration) { iteration.setProject(this); iterations.put(iteration.getId(), iteration); } /** * @param key */ public void removeIteration(Iteration iteration) { iterations.remove(iteration.getId()); } y obtendremos la 'deseada barra verde al ejecutar el caso de prueba: Otra Iorma de crear una clase o un metodo que no existen todavia, es hacer clic sobre el icono de error de la izquierda del codigo y utilizar las ayudas que oIrece eclipse: Capitulo 3 - El proyecto 1parte 3-22 Capitulo 4 - Persistencia 4-23 4Persistencia 4.1Introduccin a Hibernate Las clases persistentes son aquellas que estan relacionadas con tablas en la base de datos. Supongamos una version simpliIicada de nuestra clase Project: package com.mwm.model; public class Project { private Long id; private String name; private Company company; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Company getCompany() { return company; } public void setCompany(Company company) { this.company = company; } } en ella tenemos tres atributos: el nombre, una reIerencia a Company y un identiIicador de instancia que hemos agregado. El identiIicador, en este caso un Long, podria haber sido cualquier objeto y nos permitira acceder a la clave primaria en la base de datos. Este y resto de los atributos tiene sus respectivos accesores / mutadores como cualquier JavaBean y la clase tiene deIinida implicitamente el constructor por deIecto (sin argumentos) necesario para que Hibernate pueda ejecutar Constructor.newInstance(). Estas caracteristicas de nuestras clases persistentes, hacen que se no dependa especiIicamente de ninguna tecnologia de persistencia, clases o interIaces tal y como sucede con EJB y los entity beans. Por lo que podemos instanciar y comprobar el Iuncionamiento de la clase aIuera de cualquier contenedor, tal como ya comprobamos en ProjectTest. La siguiente clase, Company, la deIiniremos asi: package com.mwm.model; public class Company { private Long id; Capitulo 4 - Persistencia 4-24 private String name; public Long getId() { return id; } public void setId() { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } Como hacemos para que Hibernate persista estas clases? DeIiniendo (manualmente o con ayuda de herramientas) un Iichero XML por clase donde especiIicaremos la inIormacion necesaria, y utilizando las interIaces Session y Transaction de Hibernate. El Iichero XML (XML mapping document) deIine de que manera las propiedades de la clase Project se corresponden con columnas de la tabla project de la base de datos. Para Project crearemos Project.hbm.xml en el classpath: Y para Company crearemos Company.hbm.xml: Asumiendo que existe en nuestro classpath un Iichero hibernate.properties con los parametros de conexion a la base de datos (entre otros posibles), podremos crear un proyecto y persistirlo: import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Transaction; import net.sf.hibernate.cfg.Configuration; ... Configuration cfg = new Configuration(); cfg.addResource("Project.hbm.xml"); cfg.addResource("Company.hbm.xml"); SessionFactory sf = cfg.buildSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); Company company = new Company(); company.setName("Mi empresa"); Project project = new Project(); project.setName("MwM"); project.setCompany(company); s.save(project); tx.commit(); s.close(); con lo cual Hibernate generara las siguientes sentencias SQL: insert into company (id, name) values (1, Mi empresa); insert into project (id, name, id_company) values (1, MwM, 1); Como se puede ver, simplemente guardando Project Hibernate guarda tambien , mediante cascade save, los objetos dependientes como Company. 4.2Xdoclet Una gran tarea a realizar en un proyecto de esta clase, es el mantenimiento de los descriptores de Hibernate. Para ayudarnos a automatizar esta tarea utilizaremos XDoclet Capitulo 4 - Persistencia 4-26 (http://xdoclet.sourceIorge.net/xdoclet/), una herramienta de generacion de codigo que permite la programacion orientada a atributos. Con ella, podemos agregar meta-data (atributos) en Iorma de tags a los Iuentes java, para luego post procesarlos y obtener codigo adicional, por ejemplo: /** * * View Source * * * @author Nicolas Cornaglia * @version $Revision:$ $Date:$ * * @hibernate.class table="project" */ public class Project { agregando el atributo @hibernate.class a Project.java, justo antes de la deIinicion de la clase, le decimos a XDoclet que en el momento de la generacion de los descriptores (ya veremos mas adelante como), genere el siguiente tag dentro del descriptor Project.hbm.xml: Los tags tienen diIerentes opciones que podemos conIigurar, como por ejemplo el nombre de la tabla en la base de datos (table=project) para el tag @hibernate.class. Tambien vemos como XDoclet agrega valores por deIecto a los atributos del descriptor. El siguiente paso es especiIicarle a XDoclet cual es nuestro id de clase agregando @hibernate.id column="id" a getIteration(), que lo genere la base de datos: generator-class="native" y que los valores null del id identiIican las clases no persistidas: unsaved-value="null". /** * @param id * @return * * @hibernate.id column="id" generator-class="native" unsaved-value="null" */ public Iteration getIteration(Long id) { return (Iteration) iterations.get(id); } Podriamos por supuesto haber elegido otra tactica para la generacion de ids, por ejemplo generarlos nosotros mismos, o utilizar otro valor para identiIicar los ids no persistidos, pero por ahora veamos el resultado: Agregando el tag @hibernate.property al getter de la propiedad name, similar a lo que haremos para description, startDate y endDate: /** * @return Returns the name. * * @hibernate.property not-null="true" */ public String getName() { return name; } obtenemos el siguiente tag en el descriptor: que hara que la propiedad name de nuestra clase corresponda con la columna name de la tabla, a la vez que impide insertar valores en null. Para la empresa asociada al proyecto, tendremos que utilizar un @hibernate.many-to-one, ya que una empresa puede tener varios proyectos al mismo tiempo: /** * @return Returns the company. * * @hibernate.many-to-one column="company_id" not-null="true" *class="com.mwm.model.Company" *outer-join="true" */ public Company getCompany() { return company; } para obtener: Capitulo 4 - Persistencia 4-28 Y nuestro ultimo y mas complicado caso que nos lleva a agregar las opciones para generar el descriptor de la propiedad iterations: /** * @return Returns the iterations. * * @hibernate.map name="iterations" inverse="true" lazy="false" *cascade="all-delete-orphan" * @hibernate.collection-one-to-many class="com.mwm.model.Iteration" * @hibernate.collection-key column="project_id" * @hibernate.collection-index column="id" type="long" */ public Map getIterations() { return iterations; } Donde le diremos que persista nuestra coleccion de iteraciones con @hibernate.map, que obtenga la coleccion cuando se instancie el proyecto y no recien cuando se acceda a la propiedad con lazy="false",que borre las iteraciones cuando se borre el proyecto con cascade="all-delete-orphan", que se puede navegar en Iorma inversa, desde la iteracion al proyecto con inverse="true", que la relacion es uno a muchos con @hibernate.collection-one-to-many, que la clave del Map donde guardaremos las iteraciones es el id de la iteracion con @hibernate.collection-index column="id" type="long"y que la clave para saber que iteraciones son de este proyecto, dentro de la tabla donde se guarden las iteraciones es el id de proyecto con @hibernate.collection-key column="project_id". Solo nos queda hacer lo mismo con los tags de las clases restantes: Company e Iteration. Capitulo 4 - Persistencia 4-29 4.3Ant Utilizacion de Ant para la generacion de los descriptores. 4.4MySQL Descargar MySQL 4.x de http://www.mysql.com, e instalar en work\apps\mysql 4.5Test Cases 4.5.1DBUnit Capitulo 5 - Uniendo todo con 8pring 5-30 5Uniendo todo con Spring 5.1Inyeccin de dependencia Inyeccion de dependencia, tambien conocido por su nombre mas generico inversion de control, es un pattern (patron) de creacion de objetos, es decir que es un pattern que dice algo acerca de como un objeto es creado. Si tenemos dos clases que dependen una de la otra, hay varias Iormas de establecer ese tipo de dependencia. La Iorma mas simple es hacer que la clase A que depende de B, instancie B. Pero eso acopla mucho las clases entre si. Hay otro pattern muy popular usado Irecuentemente en J2EE llamado 'service locator, que basicamente establece que la clase A busca la clase B en un service locator para su utilizacion. Esto Iavorece un acoplamiento menos Iuerte que el metodo anterior, pero este sigue existiendo. Inyeccion de dependencia en cambio, hace que la clase que necesita algo no lo cree, ni lo busque en algun lugar, sino que lo obtenga por inyeccion, mediante un constructor o un mutador (setter).Podriamos deIinir por consiguiente a la inyeccion de dependencia como un termino utilizado para describir el desacoplamiento entre la implementacion de un objeto y la construccion de otro objeto del cual depende. Siendo mas Iormales y utilizando la literatura al respecto (Expert One-on-One J2EE Development without EJB, Rod Johnson y Juergen Hoeller, 2004, Wiley Publishing, Inc.), podemos utilizar el siguiente esquema para mostrar los diIerentes tipos de inversion de control: Contenedores todo~ 5.2Spring 5.3El Contexto Inversi nde Cont rolEl framework es responsable del ciclo devida del obj etoBsquedade DependenciasEl objeto implementa una API especfica del contenedorInyecci nde DependenciasNo hay dependencias a una API especfica del contenedorInyecci npormedi o de Const r uc t oresLos objetos son asignados mediante argumentos de constructoresInyecci npormedi o de Mut adoresLos objetos son asignados mediante propi edades JavaBeanCapitulo 6 - Coverage 6-31 6Coverage 6.1.1Emma Capitulo 7 - Documentacin 7-32 7Documentacin 7.1.1Javadoc 7.1.2java2html Capitulo 8 - ACEG 8-33 8ACEGI Por que hace un salto de pagina ? Capitulo 9 - CV8 9-34 9CVS 9.1WinCVS Capitulo 10 - Continuous ntegration 10-35 10 Continuous Integration Capitulo 11 - El proyecto 2parte {Web} 11-36 11 El proyecto 2 parte (Web) 11.1 Tomcat Descargar Tomcat 5.x de http://jakarta.apache.org/tomcat, e instalar en work\apps\tomcat 11.2 El proyecto MVC Struts, Spring, Webwork 11.3 Spring MVC 11.4 Sitemesh 11.5 Test Cases 11.5.1jWebUnit