0% encontró este documento útil (0 votos)
13 vistas58 páginas

Guia Uso MAVEN

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
13 vistas58 páginas

Guia Uso MAVEN

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Caso de estudio

Índice
1 Introducción a Maven...................................................................................................3
1.1 Instalando Maven.....................................................................................................3
1.2 El proceso de build de un proyecto..........................................................................4
1.3 Estructura de un proyecto Maven............................................................................ 5
1.4 POM: Project Object Model.................................................................................... 6
1.5 Repositorios............................................................................................................. 8
1.6 Versiones................................................................................................................10
1.7 Gestión de dependencias........................................................................................11
1.8 El ciclo de vida de Maven......................................................................................12
1.9 Ejecutando tests..................................................................................................... 13
1.10 Plugins y goals..................................................................................................... 14
1.11 Creando proyectos de cero: arquetipos................................................................ 16
1.12 Usando Maven en Eclipse.................................................................................... 19
1.13 Para saber más......................................................................................................22
2 Caso de estudio...........................................................................................................23
2.1 Introducción........................................................................................................... 23
2.2 Ingeniería de Requisitos.........................................................................................23
2.3 Análisis y Diseño OO............................................................................................ 29
3 Implementación.......................................................................................................... 36
3.1 Construcción del proyecto Maven......................................................................... 36
3.2 Ficheros POM........................................................................................................ 41
3.3 Primera iteración....................................................................................................43
3.4 Enumeraciones.......................................................................................................50
3.5 Implementar y completar las clases de entidad......................................................50
3.6 Gestión de las Excepciones....................................................................................51
3.7 Implementación de las Reglas de Negocio............................................................ 52

Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.


Caso de estudio

3.8 Tests....................................................................................................................... 53
3.9 Resumen.................................................................................................................55

2
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

1. Introducción a Maven

Maven es una herramienta Java de gestión del proceso de desarrollo de proyectos


software, que simplifica la complejidad de sus distintas partes: compilación, prueba,
empaquetamiento y despliegue. Es una herramienta muy popular en proyectos open
source ya que facilita la construcción, descarga y distribución tanto de las librerías
(ficheros .jar) como de las dependencias del proyecto.
Maven se origina de hecho en la comunidad open source, en concreto en la Apache
Software Foundation en la que se desarrolló para poder gestionar y minimizar la
complejidad de la construcción del proyecto Jakarta Turbine en 2002. El diseñador
principal de Maven fue Jason van Zyl, ahora en la empresa Sonatype. En 2003 el
proyecto fue aceptado como proyecto de nivel principal de Apache. En octubre de 2005
se lanzó la versión más utilizada en la actualidad de Maven: Maven 2. Desde entonces ha
sido adoptado como la herramienta de desarrollo de software de muchas empresas y se ha
integrado con muchos otros proyectos y entornos.
Maven es una herramienta de línea de comando, similar a las herramientas habituales en
Java como javac, jar o a proyectos como Ant. Aunque es posible utilizar Maven en
IDEs como Eclipse o Glassfish, las interfaces de usuario incluyen sus distintos comandos
en menús de opciones para que puedan seleccionarse de forma gráfica. Es muy útil
conocer la utilización de Maven en línea de comandos porque es la base de cualquier
adaptación gráfica.
Una de las características principales de Maven es su enfoque declarativo, frente al
enfoque orientado a tareas de herramientas tradicionales como Make o Ant. En Maven, el
proceso de compilación de un proyecto se basa en una descripción de su estructura y de
su contenido. Maven mantiene el concepto de modelo de un proyecto y obliga a definir un
identificador único para cada proyecto que desarrollemos, así como declarar sus
características (URL, versión, librerías que usa, tipo y nombre del artefacto generado,
etc.). Todas estas características deben estar especificadas en el fichero POM (Project
Object Model, fichero pom.xml en el directorio raíz del proyecto). De esta forma es
posible publicar el proyecto en un repositorio y ponerlo a disposición de la comunidad
para que otros a su vez puedan usarlo como librería.

1.1. Instalando Maven

Maven ya viene preinstalado en la máquina virtual del especialista. La instalación en


Linux es muy sencilla.
En primer lugar debemos descargar la última versión de la página web oficial:
http://maven.apache.org/download.html y descomprimirla en algún directorio del sistema.
En el caso de la MV, lo hemos instalado en /opt/apache-maven-3.0.3.

3
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Maven es una aplicación Java, y utiliza la variable JAVA_HOME para encontrar el path del
JDK. También es necesario añadir el directorio bin de Maven al PATH del sistema. Se
pueden definir en el fichero de configuración .bashrc de un usuario o en el fichero del
sistema /etc/bashrc para todos los usuarios. En nuestro caso hemos modificado el único
usuario de la MV especialista. El código que hemos añadido ha sido este:
export JAVA_HOME=/opt/jdk1.6.0_27
export MAVEN_HOME=/opt/apache-maven-3.0.3
export PATH=${PATH}:${MAVEN_HOME}/bin

1.2. El proceso de build de un proyecto

Los que hemos programado en C recordamos los ficheros Makefile en los que se
especificaban las dependencias entre los distintos elementos de un proyecto y la secuencia
de compilación necesaria para generar una librería o un ejecutable. En Java, el desarrollo
de aplicaciones medianamente complejas es más complicado que en C. Estamos
obligados a gestionar un gran número de recursos: código fuente, ficheros de
configuración, librerías externas, librerías desarrolladas en la empresa, etc. Para gestionar
este desarrollo es necesario algo de más nivel que las herramientas que proporciona Java
(javac, jar, rmic, java, etc.)
¿En qué consiste el proceso de compilación y empaquetado en Java?. Básicamente en
construir lo que Maven llama un artefacto (terminología de Maven que significa fichero)
a partir de un proyecto Java definido con una estructura propia de Maven (apartado
siguiente). Los posibles artefactos en los que podemos empaquetar un programa Java son:
• Fichero JAR: librería de clases o aplicación standalone. Contiene clases Java
compiladas (.class) organizadas en paquetes, ficheros de recursos y (opcionalmente)
otros ficheros JAR con librerías usadas por las clases. En las aplicaciones enterprise,
los EJB también se empaquetan en ficheros JAR que se despliegan en servidores de
aplicaciones.
• Fichero WAR: aplicación web lista para desplegarse en un servidor web. Contiene un
conjunto de clases Java, librerías, ficheros de configuración y ficheros de distintos
formatos que maneja el servidor web (HTML, JPG, etc.)
• Fichero EAR: aplicación enterprise que se despliega en un servidor de aplicaciones.
Contiene librerías, componentes EJB y distintas aplicaciones web (ficheros WAR).
Además, el ciclo de desarrollo de un proyecto es más complejo que esta construcción, ya
que es necesario realizar un conjunto de tareas adicionales como gestionar las
dependencias con librerías externas, integrar el código en repositorios de control de
versiones (CVS, subversion o Git), lanzar tests o desplegar la aplicación en algún servidor
de aplicaciones.
Podría pensarse que los entornos de desarrollo (Eclipse o Netbeans) pueden dar una
buena solución a la complejidad del proceso de construcción, pero no es así. Son
imprescindibles para el desarrollo, pero no ayudan demasiado en la construcción del

4
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

proyecto. La configuración de las dependencias se realiza mediante asistentes gráficos


que no generan ficheros de texto comprensibles que podamos utilizar para comunicarnos
con otros compañeros o equipos de desarrolladores y que pueden dar lugar a errores. El
hecho de que sean entornos gráficos hacen complicado también usarlos en procesos de
automatización y de integración continua.

1.3. Estructura de un proyecto Maven

La estructura de directorios de un proyecto Maven genérico es la que aparece en la


siguiente figura.

Si observamos el primer nivel, encontramos en la raíz del proyecto el fichero pom.xml, el


directorio src y el directorio target. El fichero pom.xml es el fichero principal de
Maven en el que se describen todas las características del proyecto: nombre, versión, tipo
de artefacto generado, librerías de las que depende, ect. Lo estudiaremos más adelante. El
directorio src contiene todo el código fuente original del proyecto. Y el directorio
target contiene el resultado de la construcción del proyecto con Maven.

Entrando en más profundidad, nos encontramos los siguientes directorios:


• src/main/java: el código fuente de las clases Java del proyecto
• src/main/resources: ficheros de recursos que necesita la aplicación
• src/main/filters: filtros de recursos, en forma de ficheros de propiedades, que
pueden usarse para definir variables que se utilizan en tiempo de ejecución
• src/main/config: ficheros de configuración
• src/main/webapp: el directorio de aplicación web de un proyecto WAR
• src/test/java: código fuente de las pruebas de unidad de las clases que tiene la
misma estructura que la estructura del código fuente en el directorio main/java

5
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

• src/tests/resources: recursos utilizados para los tests que no serán desplegados


• src/tests/filters: filtros de recursos utilizados para los tests
• src/site: ficheros usados para generar el sitio web Maven del proyecto

Los ficheros de recursos son ficheros leídos desde la aplicación. Tal y como hemos visto
en el módulo JHD, estos recursos deben estar contenidos en la raíz del JAR para poder
acceder a ellos utilizando el método getResourceAsStream de la clase Class:
InputStream in =
getClass().getResourceAsStream("/datos.txt");

Maven se encarga de colocar los recursos en la raíz del JAR al empaquetar el proyecto.

1.4. POM: Project Object Model

El elemento más importante de un proyecto Maven, a parte de su estructura, es su fichero


POM en el que se define completamente el proyecto. Este fichero define elementos XML
preestablecidos que deben ser definidos por el grupo de desarrollo del proyecto. Viendo
algunos de ellos podemos entender también más características de Maven.
Vamos a utilizar como ejemplo el primer proyecto de integración jbib-modelo que
construiremos más adelante. Veamos su fichero pom.xml. Al comienzo nos
encontramojbib-modelos con la cabecera XML y la definición del proyecto:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.especialistajee.proyint</groupId>
<artifactId>jbib-modelo</artifactId>
<packaging>jar</packaging>
<version>2011</version>
<name>jbib-modelo</name>
<url>http://web.ua.es/especialistajee</url>

La primera definición project xmlns es común para todos los ficheros pom.xml. En ella
se declara el tipo de esquema XML y la dirección donde se encuentra el fichero de
esquema XML. Se utiliza para que los editores de XML puedan validar correctamente el
fichero. Esta sintaxis depende de la versión de Maven que se esté utilizando.
Después aparece la identificación del proyecto, en la que hay que definir el grupo que
desarrolla el proyecto (groupId), el nombre del artefacto que genera el proyecto
(artifactId), el tipo de empaquetamiento (packaging) y su versión (version). Estos campos
representan las denominadas coordenadas del proyecto (hablaremos de ello más
adelante). En nuestro caso son:
org.especialistajee.proyint:jbib-modelo:jar:2011

Por último, hay que definir el nombre lógico del proyecto (name) y una URL asociada al
mismo url.

6
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

A continuación definimos algunas propiedades del proyecto, que se utilizarán en los


distintos procesos de Maven. En nuestro caso sólo la codificación de caracteres que
estamos utilizando en el código fuente de nuestro proyecto:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

A continuación viene la definición de las dependencias del proyecto: librerías de las que
dependen el proyecto. En nuestro caso:
• JUnit: junit:junit:4.8.1:jar
• Log4j: log4j:log4j:1.2.14:jar
• Commons Logging: commons-logging:commons-logging:1.1.1:jar
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<type>jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>

Por último, definimos algunas características de los procesos de Maven que construyen el
proyecto, definiendo parámetros para los pluging de Maven que se encargan de
ejecutarlos.
En nuestro caso, definimos el nivel de compilación de Java, necesario para que no haya
conflicto al importar el proyecto en Eclipse. Es interesante hacer notar que el plugin se
identifica de una forma similar al proyecto, utilizando el identificador del grupo, el de
proyecto y su número de versión.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>

7
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

</plugins>
</build>
</project>

Es posible definir herencia entre los ficheros POM utilizando el identificador parent. Es
útil para definir elementos comunes y evitar repetirlos en todos los POM. Por ejemplo,
podríamos definir un POM en el que se declaren todas las librerías que se usan
habitualmente por nuestros proyectos e incluir este POM en todos los proyectos
utilizando herencia.
<project>
<parent>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
</parent>
...
</project>

Maven define un super POM que por defecto es el padre de todos los POM. Allí se
definen elementos comunes como la localización de los repositorios o la estructura de
directorios por defecto de Maven. Se puede encontrar este super POM en el fichero
llamado pom-4.0.0.xml en el JAR maven-2.2.1-uber.jar en el directorio lib de
Maven.
Maven resuelve todas las relaciones de herencia entre POMs y genera internamente un
POM efectivo (effective POM) en el que combinan todos los POMs que afectan a un
determinado proyecto. Este POM efectivo es el que se utiliza para realizar la construcción
del proyecto. Es posible consultar este POM efectivo con el comando:
mvn help:effective-pom

También puede consultarse en la pestaña correspondiente del editor POM del plugin de
Ecipse.

1.5. Repositorios

Los proyectos software están relacionados. Los proyectos necesitan de clases y librerías
definidas en otros proyectos. Esos proyectos pueden ser otros desarrollados por nosotros
en la empresa o librerías open source bajadas de Internet.
La tarea de mantener las dependencias de un proyecto es complicada, tanto para las
dependencias entre nuestros proyectos como las dependencias con otros proyectos open
source disponibles en Internet. Por ejemplo, si queremos utilizar un framework como
Spring, tendremos que descargarnos no sólo los JAR desarrollados en el proyecto, sino
también un buen número de otras librerías open source que usa. Cada librería es un
fichero JAR. ¿Qué pasa si alguna de esas librerías ya las estamos usando y las tenemos ya
descargadas? O, peor aún, ¿Qué pasa si estamos usando otras versiones de esas librerías
en nuestros proyectos? ¿Podremos detectar los posibles conflictos?. Maven obliga a
declarar explícitamente estas dependencias en el fichero POM del proyecto y se encarga

8
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

de gestionar estos y otros problemas:


• Descarga las librerías necesarias para construir el proyecto y los ficheros POM
asociados a esas librerías
• Resuelve dependencias transitivas, librerías que dependen de librerías de las que
dependen nuestro proyecto
• Resuelve conflictos entre librerías
Un elemento fundamental para gestionar las dependencias es poder identificar y nombrar
un proyecto. En Maven el nombre de un proyecto se define mediante los siguientes
elementos (que en Maven se denominan coordenadas):
• groupId: El grupo, compañía, equipo, organización, etc. Se utiliza una convención
similar a la de los paquetes Java, comenzando por el nombre de dominio invertido de
la organización que crea el proyecto. Por ejemplo, los groupId de la Apache Software
Foundation comienzan con org.apache.
• artifactId: Identificador único que representa de forma única el proyecto dentro del
groupId
• version: Número de versión del proyecto, por ejemplo 1.3.5 o 1.3.6-beta-01
• packaging: Tipo de empaquetamiento del proyecto. Por defecto es jar. Un tipo jar
genera una librería JAR, un tipo war se refiere a una aplicación web.
En Maven un proyecto genera un artefacto. El artefacto puede ser un fichero JAR, WAR
o EAR. El tipo de artefacto viene indicado en el tipo de empaquetamiento del proyecto.
El nombre final del fichero resultante de la construcción del proyecto es por defecto:
<artifactId>-<version>.<packaging>

Por ejemplo, Apache ha desarrollado el proyecto commons-email que proporciona una


serie de utilidades para la gestión de correos electrónicos en Java. Sus coordenadas son:
org.apache.commons:commons-email:1.1:jar

El artefacto (fichero JAR) generado por el proyecto tiene como nombre email-1.1.jar
Cuando ejecutamos Maven por primera vez veremos que descarga un número de ficheros
del repositorio remoto de Maven. Estos ficheros corresponden a plugins y librerías que
necesita para construir el proyecto con el que estamos trabajando. Maven los descarga de
un repositorio global a un repositorio local donde están disponibles para su uso. Sólo es
necesario hacer esto la primera vez que se necesita la librería o el plugin. Las siguientes
ocasiones ya está disponible en el repositorio local.
La direcciones en las que se encuentran los repositorios son las siguientes:
• Repositorio central: El repositorio central de Maven se encuentra en
http://repo1.maven.org/maven2. Se puede acceder a la dirección con un navegador y
explorar su estructura.
• Repositorio local: El repositorio local se encuentra en el directorio

9
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

${HOME}/.m2/repository.

La estructura de directorios de los repositorios (tanto el central como el local) está


directamente relacionada con las coordenadas de los proyectos. Los proyectos tienen la
siguiente ruta, relativa a la raíz del repositorio:
/<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packaging>

Por ejemplo, el artefacto commons-email-1.1.jar, con coordenadas


org.apache.commons:commons-email:1.1:jar está disponible en la ruta:
/org/apache/commons/commons-email/1.1/commons-email-1.1.jar

1.6. Versiones

El estándar de Maven para los números de versiones es muy importante, porque permite
definir reglas para gestionar correctamente las dependencias en caso de conflicto. El
número de versión de un proyecto se define por un número principal, un número menor y
un número incremental. También es posible definir un calificador, para indicar una
versión alfa o beta. Los números se separan por puntos y el calificador por un guión. Por
ejemplo, el número 1.3.5-alpha-03 define un número de versión principal 1, la versión
menor 3, la versión incremental de 5 y el calificador de "alpha-03".
Maven compara las versiones de una dependencia utilizando este orden. Por ejemplo, la
versión 1.3.4 representa un build más reciente que la 1.0.9. Los clasificadores se
comparan utilizando comparación de cadenas. Hay que tener cuidado, porque "alpha10"
es anterior a "alpha2"; habría que llamar al segundo "alpha02".
Maven permite definir rangos de versiones en las dependencias, utilizando los operadores
de rango exclusivos "(", ")" o inclusivos "[", "]". Así, por ejemplo, si queremos indicar
que nuestro proyecto necesita una versión de JUnit mayor o igual de 3.8, pero menor que
4.0, lo podemos indicar con el siguiente rango:
<version>[3.8,4.0)</version>

Si una dependencia transitiva necesita la versión 3.8.1, esa es la escoge Maven sin crear
ningún conflicto.
Es posible también indicar rangos de mayor que o menor que dejando sin escribir ningún
número de versión antes o después de la coma. Por ejemplo, "[4.0,)" representa cualquier
número mayor o igual que 4.0, "(,2.0)" representa cualquier versión menor que la 2.0 y
"[1.2]" significa sólo la versión 1.2 y ninguna otra.
Cuando dos proyectos necesitan dos versiones distintas de la misma librería, Maven
intenta resolver el conflicto, descargándose la que satisface todos los rangos. Si no
utilizamos los operadores de rango estamos indicando que preferimos esa versión, pero
que podríamos utilizar alguna otra. Por ejemplo, es distinto especificar "3.1" y "[3.1]". En
el primer caso preferimos la versión 3.1, pero si otro proyecto necesitara la 3.2 Maven se

10
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

descargaría esa. En el segundo caso exigimos que la versión descargada sea la 3.1. Si otro
proyecto especifica otra versión obligatoria, por ejemplo "3.2", entonces el proyecto no se
compilará.

1.7. Gestión de dependencias

Hemos visto que una de las características principales de Maven es la posibilidad de


definir las dependencias de un proyecto. En la sección dependencies del fichero POM se
declaran las librerías necesarias para compilar, testear y ejecutar nuestra aplicación.
Maven obtiene estas dependencias del repositorio central o de algún repositorio local
configurado por nuestra empresa y las guarda en el directorio .$HOME/.m2/repository.
Si utilizamos la misma librería en un varios proyectos, sólo se descargará una vez, lo que
nos ahorrará espacio de disco y tiempo. Y lo que es más importante, el proyecto será
mucho más ligero y portable, porque no llevará incluidas las librerías que necesita para su
construcción.
Ya hemos visto en apartados anteriores cómo se declaran las dependencias en el fichero
POM. Cada dependencia se define de forma unívoca utilizando sus coordenadas. El
mecanismo de declaración de las dependencias es el mismo para las dependencias de
librerías externas como para las definidas dentro de la organización.
Para definir una dependencia hay que identificar también el número de versión que se
quiere utilizar, utilizando la nomenclatura del apartado anterior. Por ejemplo, la siguiente
dependencia especifica una versión 3.0 o posterior de hibernate.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>[3.0,)</version>
</dependency>

Un concepto fundamental en Maven es el de dependencia transitiva. En los repositorios


no solo se depositan los artefactos generados por los proyectos, sino también el fichero
POM del proyecto. Y en ese fichero se definen las dependencias propias del proyecto. Por
ejemplo, junto con el artefacto hibernate-3.0.jar se encuentra el fichero POM
hibernate-3.0.pom.xml en el que se definen sus propias dependencias, librerías
necesarias para Hibernate-3.0. Estas librerías son dependencias transitivas de nuestro
proyecto. Si nuestro proyecto necesita Hibernate, e Hibernate necesita estas otra librería
B, nuestro proyecto también necesita (de forma transitiva) la librería B. A su vez esa
librería B tendrá también otras dependencias, y así sucesivamente ...
Maven se encarga de resolver todas las dependencias transitivas y de descargar al
respositorio local todos los artefactos necesarios para que nuestro proyecto se construya
correctamente.
Otro elemento importante es el ámbito (scope) en el que se define la dependencia. El
ámbito por defecto es compile y define librerías necesarias para la compilación del

11
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

proyecto. También es posible especificar otros ámbitos. Por ejemplo test, indicando que
la librería es necesaria para realizar pruebas del proyecto:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<type>jar</type>
<scope>test</scope>
</dependency>

Otros ámbitos posibles son provided y runtime. Una dependencia se define provided
cuando es necesaria para compilar la aplicación, pero que no se incluirá en el WAR y no
será desplegada. Por ejemplo las APIs de servlets:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>

Las dependencias runtime son dependencias que no se necesitan para la compilación, sólo
para la ejecución. Por ejemplo los drivers de JDBC para conectarse a la base de datos:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>3.1.13</version>
<scope>runtime</scope>
</dependency>

Una herramienta muy útil es el informe de dependencia. Este informe se genera cuando se
ejecuta el objetivo site. Maven construye un sitio web con información sobre el proyecto
y coloca el informe en el fichero target/dependencies.html:
$ mvn site

El informe muestra una lista de dependencias directas y transitivas y su ámbito.

1.8. El ciclo de vida de Maven

El concepto de ciclo de vida es central para Maven. El ciclo de vida de un proyecto


Maven es una secuencia de fases que hay que seguir de forma ordenada para construir el
artefacto final.
Las fases principales del ciclo de vida por defecto son:
• validate: valida que el proyecto es correcto y que está disponible toda la
información necesaria
• process-resources: procesar el código fuente, por ejemplo para filtrar algunos
valores
• compile: compila el código fuente del proyecto
• test: lanza los tests del código fuente compilado del proyecto utilizando el

12
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

framework de testing disponible. Estos tests no deben necesitar que el proyecto haya
sido empaquetado o desplegado
• package: empaqueta el código compilado del proyecto en un formato distribuible,
como un JAR
• integration-test: procesa y despliega el paquete en un entorno en donde se pueden
realizar tests de integración
• verify: lanza pruebas que verifican que el paquete es válido y satisface ciertos
criterios de calidad
• install: instala el paquete en el repositorio local, para poder ser usado como librería
en otros proyectos locales
• deploy: realizado en un entorno de integración o de lanzamiento, copia el paquete
final en el repositorio remoto para ser compartido con otros desarrolladores y otros
proyectos.
Todas estas fases se lanzan especificándolas como parámetro en el comando mvn. Si
ejecutamos una fase, Maven se asegura que el proyecto pasa por todas las fases
anteriores. Por ejemplo:
$ mvn install

Esta llamada realiza la compilación, los tests, el empaquetado los tests de integración y la
instalación del paquete resultante en el repositorio local de Maven.

Nota:
Para un listado completo de todas las opciones se puede consultar la página de Apache Maven
Introduction to the Build Lifecycle

1.9. Ejecutando tests

Los tests de unidad son una parte importante de cualquier metodología moderna de
desarrollo, y juegan un papel fundamental en el ciclo de vida de desarrollo de Maven. Por
defecto, Maven obliga a pasar los tests antes de empaquetar el proyecto. Maven permite
utilizar los frameworks de prueba JUnit y TestNG. Las clases de prueba deben colocarse
en el directorio src/test.
Para ejecutar los tests se lanza el comando mvn test:
especialista@especialista:~/proy-int/jbib-modelo$ mvn test
[INFO] Scanning for projects...
...
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.especialistajee.jbib.model.UsuarioTest
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.082 sec
Running org.especialistajee.jbib.model.OperacionTest
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.141 sec
Tests run: 8, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.018 sec
Running org.especialistajee.jbib.model.AvisoTest

13
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.012 sec


Results :
Tests run: 19, Failures: 0, Errors: 0, Skipped: 0

Maven compilará los tests si es necesario. Por defecto, los tests deben colocarse en el
directorio src/test siguiendo una estructura idéntica a la estructura de clases del
proyecto. Maven ejecutará todas las clases que comiencen o terminen con Test o que
terminen con TestCase.
Los resultados detallados de los tests se producen en texto y en XML y se dejan en el
directorio target/surefire-reports. Es posible también generar los resultados en
HTML utilizando el comando:
$ mvn surefire-report:report

El informe HTML se generará en el fichero target/site/surefire-report.html.

1.10. Plugins y goals

Todo el trabajo que realiza Maven es realizado por módulos independientes que son
también descargados del repositorio global. Estos módulos reciben el nombre de plugins.
Cada plugin tiene un conjunto de goals que podemos lanzar desde línea de comando. La
sintaxis de una ejecución de un goal de un plugin es:
$ mvn <plugin>:goal -Dparam1=valor1 -Dparam2=valor2 ...

Las fases del ciclo de vida vistas en el apartado anterior también se procesan mediante el
mecanismo de plugins. Por ejemplo, la llamada a mvn test realmente genera una llamada
al objetivo test del plugin surefire:
$ mvn surefire:test

Otro ejemplo es el plugin Jar que define el objetivo jar para realizar la fase package:
$ mvn jar:jar

Existen múltiples plugins de Maven que pueden utilizarse para automatizar distintas
tareas complementarias necesarias para la construcción del proyecto. Un ejemplo es el
plugin SQL de Codehaus que permite lanzar comandos SQL utilizando su objetivo
execute:
$ mvn sql:execute

La configuración del plugin se define en el fichero POM. La siguiente configuración


lanza en la fase de construcción process-test-resource dos ficheros de comandos
SQL; el primero inicializa la base de datos y el segundo la llena con datos sobre los que
se van a realizar las pruebas.
<plugin>
<groupId>org.codehaus.mojo</groupId>

14
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

<artifactId>sql-maven-plugin</artifactId>
<version>1.4</version>
<dependencies>
<!-- specify the dependent JDBC driver here -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.8</version>
</dependency>
</dependencies>
<!-- common configuration shared by all executions -->
<configuration>
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://localhost:3306/</url>
<username>root</username>
<password>especialista</password>
</configuration>
<executions>
<execution>
<id>create-db</id>
<phase>process-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<srcFiles>
<srcFile>src/main/sql/biblioteca.sql</srcFile>
</srcFiles>
</configuration>
</execution>
<execution>
<id>create-data</id>
<phase>process-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<srcFiles>
<srcFile>src/test/sql/datos.sql</srcFile>
</srcFiles>
</configuration>
</execution>
</executions>
</plugin>

Vemos que en el apartado dependency se definen las dependencias del plugin. En este
caso el JAR mysql-connector-java-5.0.8 necesario para la conexión a la base de
datos. En el apartado executions es donde se definen los ficheros SQL que se ejecutan y
la fase del ciclo de vida en la que se lanza.
Cuando se llame a la fase process-test-resoures de Maven (o a cualquiera posterior)
se ejecutaran los ficheros SQL:
$ mvn process-test-resources
[INFO] Scanning for projects...
...
[INFO] [sql:execute {execution: create-db}]
[INFO] Executing file: /tmp/biblioteca.2081627011sql

15
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

[INFO] 24 of 24 SQL statements executed successfully


[INFO] [sql:execute {execution: create-data}]
[INFO] Executing file: /tmp/datos.601247424sql
[INFO] 27 of 27 SQL statements executed successfully
[INFO]
------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO]
------------------------------------------------------------------------
[INFO] Total time: 3 seconds
[INFO] Finished at: Wed Oct 06 06:16:02 CEST 2010
[INFO] Final Memory: 8M/19M
[INFO]
------------------------------------------------------------------------

La siguiente figura muestra un resumen de los conceptos vistos hasta ahora de fases de
build y plugins:

Diagrama de Actividad para la entrada al sistema

1.11. Creando proyectos de cero: arquetipos

Es tedioso crear todo un proyecto Maven desde cero. Implica crear toda una estructura de
directorios y algunos ficheros de configuración y clases Java vacías. Maven puede
hacerlo automáticamente con el plugin Archetype, que permite construir un proyecto
vacío a partir de plantillas estándar. El proyecto construido contiene la estructura estándar
de directorios así como algunos ficheros de ejemplo que ilustran las convenciones y
buenas prácticas de Maven. El modelo de arquetipo por defecto creará un proyecto que
construye una librería JAR. Es posible utilizar otras plantillas, como proyectos web,
proyectos JPA, etc.
Por ejemplo, supongamos que somos una empresa de desarrollo de software llamada
PrensaSoft, especializada en dar soporte a grupos editoriales y que estamos desarrollando
un módulo de recomendaciones de noticias que llamamos RecomendBackend. Todas las
clases del módulo queremos que se creen en el paquete

16
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

es.prensasoft.backend.recomend. Definimos entonces el proyecto Maven con las


siguientes coordenadas:
• groupId: es.prensasoft
• artifactId: recomend-backend
• version: 2011
• package: es.prensasoft.backend.recomend
Para construir el esqueleto inicial del proyecto llamamos entonces al objetivo
archetype:generate de la siguiente forma:
$ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart
-DgroupId=es.prensasoft -DartifactId=recomend-backend
-Dversion=2011 -Dpackage=es.prensasoft.backend.recomend

Maven muestra la siguiente información y nos pide confirmar. Pulsamos INTRO y


Maven crea toda la estructura de directorios del proyecto.
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO]
------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO] task-segment: [archetype:generate] (aggregator-style)
[INFO]
------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Interactive mode
[INFO] Using property: groupId = es.prensasoft
[INFO] Using property: artifactId = recomend-backend
[INFO] Using property: version = 2011
[INFO] Using property: package = es.prensasoft.backend.recomend
Confirm properties configuration:
groupId: es.prensasoft
artifactId: recomend-backend
version: 2011
package: es.prensasoft.backend.recomend
Y:

Otra posible forma de crear el proyecto es ejecutar el comando sin especificar los
parámetros. En este caso Maven los va pidiendo de forma interactiva y sugiriendo
opciones.
Por último, una tercera forma de crear un proyecto Maven es utilizando el plugin de
Eclipse. Incluye un asistente que permite introducir todas las opciones utilizando
ventanas, menús y diálogos.
El proyecto se creará en el subdirectorio con el mismo nombre que el del artefacto
(recomend-backend). El groupId y el artifactId se utilizarán para colocar la librería JAR
generada en el repositorio de Maven. El nombre de paquete es el paquete raíz en el que se
definen todas las clases del proyecto. Se crearán los directorios correspondentes bajo
src/main/java (en nuestro caso es/prensasoft/backend/recomend).

También se creará un fichero POM mínimo. En nuestro caso será este:

17
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>es.prensasoft</groupId>
<artifactId>recomend-backend</artifactId>
<packaging>jar</packaging>
<version>2011</version>
<name>recomend-backend</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

Existen muchos arquetipos posibles que pueden utilizarse para crear distintos tipos de
proyectos. Por ejemplo, para crear una aplicación web debemos utilizar el arquetipo
maven-archetype-webapp que creará un proyecto WAR vacío.

Existen también un gran número de arquetipos disponbiles de otros tipos de aplicaciones


y stacks, como Struts, Spring, JSF, Hibernate, etc. Todos ellos se pueden encontrar en el
página web de Codehaus.
Un proyecto muy interesante es AppFuse que proporciona un conjunto de arquetipos con
aplicaciones ejemplo listas para ser ejecutadas. Veámoslo rápidamente. Podemos
construir una aplicación web basada en Hibernate, Spring y JSF con el arquetipo
appfuse-basic-jsf:
$mvn archetype:generate -DarchetypeGroupId=org.appfuse.archetypes
-DarchetypeArtifactId=appfuse-basic-jsf-archetype
-DarchetypeVersion=2.1.0-M1 -DgroupId=org.especialistajee
-DartifactId=prueba-jsf -Dversion=2011

Esto creará una aplicación web ejecutable y con un fichero POM completo. Se intentará
conectar la base de datos local MySQL utilizando el usuario "root" y sin password.
Podemos ejecutarla utilizando el plugin de Jetty (un servidor web, similar a Tomcat).
Descargará todas las librerías necesarias (cuidado, serán muchas), compilará el proyecto,
pasará los tests y desplegará la aplicación en el servidor jetty:
$ cd prueba-jsf
$ mvn jetty:run
...
mvn jetty:run-war
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'jetty'.
[INFO]
----------------------------------------------------------------------------
[INFO] Building AppFuse JSF Application
[INFO] task-segment: [jetty:run-war]
[INFO]
----------------------------------------------------------------------------
...

18
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

2007-10-10 21:30:48.410::INFO: Started


[email protected]:8080
[INFO] Started Jetty Server

Podemos consultar la aplicación conectándonos a http://localhost:8080 y entrando con


nombre de usuario y contraseña "admin".

1.12. Usando Maven en Eclipse

El plugin de Eclipse m2eclipse permite la utilización de Maven desde el entorno de


programación. Ha sido desarrollado por la compañía Sonatype y se distribuye de forma
gratuita. El plugin permite importar proyectos Maven en Eclipse, editar y explorar el
fichero POM del proyecto, explorar repositorios de Maven o lanzar builds de Maven
desde el propio entorno.
El documento Sonatype m2eclipse es un excelente manual de uso del plugin. Os
remitimos a él para conocer en profundidad todas sus características. Aquí sólo haremos
un rápido repaso.
El plugin permite importar un proyecto Maven en Eclipse y trabajar con él manteniendo
su estructura de directorios. El plugin configura automáticamente los ficheros de
configuración de Eclipse (los ficheros .project y .classpath) para que utilicen esa
estructura de directorios y para que se actualicen las dependencias entre los proyectos y
las librerías JAR.

19
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Una vez importado el proyecto el desarrollador puede seguir trabajando en él como lo


haría con cualquier proyecto Eclipse. Puede lanzar añadir código, ejecutarlo, lanzar los
tests o compartirlo por CVS. En el caso en que fuera un proyecto web, podrá también
desplegarlo en el servidor instalado en Eclipse.
El plugin m2eclipse proporciona un editor especializado para trabajar con los ficheros
POM. En la parte inferior de la imagen se pueden observar pestañas para acceder a los
distintas elementos configurados en el POM: general, dependencias, plugins, informes,
jerarquía de dependencias, grafo de dependencias, POM efectivo y código XML.

Por ejemplo, la pestaña de dependencias del POM muestra el siguiente aspecto.

Desde esa pestaña es posible editar las dependencias del POM y añadir nuevas. Una
ventana de diálogo permite explorar todos los artefactos del repositorio de Maven.

20
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Es posible activar una vista especial que permite hojear los repositorios. Se activa en la
opción Window > Show View > Other... y buscando Maven y seleccionando Maven
Repositories.

Es posible también lanzar builds predeterminados de Maven y configurar esas


ejecuciones.

21
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

1.13. Para saber más

Las siguientes referencias son de mucho interés para aprender más sobre Maven o como
referencia para consultar dudas:
• Maven in 5 minutes: Introducción rápida a Maven en la que se muestra cómo
construir, empaquetar y ejecutar una sencilla aplicación.
• Maven by Example: Libro de introducción a Maven realizado por Sonatype, la
compañía creada por Jason Van Zyl el desarrollador principal de Maven. Disponible
también en PDF en esta dirección.
• Maven, the complete reference: Otro libro muy recomendable de Sonatype.
Disponible también en PDF en esta dirección.
• Java Power Tools: Excelente libro sobre 30 herramientas que ayudan en el desarrollo
de software Java. El capítulo 1 está dedicado a Ant y el 2 a Maven.
• Maven: Página principal del proyecto Maven

22
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

2. Caso de estudio

2.1. Introducción

A partir de un supuesto básico de la gestión de una biblioteca, vamos a crear un caso de


estudio completo que evolucionará conforme estudiemos las diferentes tecnologías de la
plataforma Java Enterprise.
El objetivo de esta sesión es introducir el caso de estudio que vamos a desarrollar, obtener
una visión global del proyecto, fijando los casos de uso y requisitos principales y
definiendo el esqueleto inicial del problema.

2.2. Ingeniería de Requisitos

El Instituto de Educación Secundaria "jUA" nos ha encargado que desarrollemos una


aplicación para la gestión de los préstamos realizados en la biblioteca del centro, lo que
implica tanto una gestión de los libros como de los alumnos y profesores que realizan
estos prestamos.
Tras una serie de entrevistas y reuniones con diferente personal del centro, hemos llegado
a recopilar las siguientes funcionalidades a informatizar.
• La aplicación será utilizada por bibliotecarios y usuarios de la biblioteca.
• Un usuario administrador puede realizar acciones relacionadas con la configuración
de la aplicación: dar de alta nuevos usuarios, modificar ciertos parámetros, etc.
• Tanto bibliotecarios como usuarios podrán realizar con la aplicación acciones sobre
los libros: consultar su disponibilidad, reservarlos, prestarlos, etc. Las acciones
estarán limitadas al rol.
• Un bibliotecario se encargará de la gestión de préstamos y libros. La aplicación le
permitirá registrar los préstamos y devoluciones que realiza en el mostrador de la
biblioteca, así como consultar el estado de un determinado libro o usuario. Podrá
también dar de alta libros, modificar su información y darlos de baja.
• El sistema guardará todas las operaciones realizadas por los usuarios. Diferenciará
entre operaciones activas (préstamos o reservas) y operaciones históricas (préstamos
que ya se han devuelto o reservas que se han cancelado o convertido en préstamos).
• Los profesores y alumnos van a poder realizar las siguientes acciones con la
aplicación:
• Reservar un libro que está disponible en sala
• Prereservar un libro prestado a otro usuario
• Consultar el estado de los libros: un libro puede estar prestado (y no
pre-reservado), reservado en sala, pre-reservado y disponible.
• Además podrán hacer las siguientes acciones físicas:
• Pedir un préstamo al bibliotecario

23
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

• Devolver un libro
• Para realizar un préstamo tanto los profesores como los alumnos deberán personarse
en la biblioteca, coger el libro y solicitar su préstamo al bibliotecario. El bibliotecario
utilizará la aplicación para asignar el préstamo del libro al usuario. El número de
libros que puede tener en préstamo un usuario dependerá de si es profesor o alumno.
• Los usuarios profesores pueden solicitar préstamos en depósito. En esta modalidad, el
profesor puede quedarse el libro hasta que otro usuario (profesor o alumno) solicite
una reserva.
• Los usuarios pueden reservar libros con la aplicación:
• Si el libro está disponible en sala, no podrá ser prestado a ningún otro usuario
durante un número determinado de días.
• Si el libro está prestado, se pondrá en estado de 'prereserva': cuando el usuario
prestatario devuelva el libro, el bibliotecario lo dejará en la sala para consulta,
pero quedará reservado durante un número de días (dependiendo del tipo de
usuario que ha hecho la reserva). En el momento de la devolución la aplicación
enviará un aviso al usuario que ha hecho la reserva y el libro pasará a estado
'reservado'. Si el usuario prestatario es un profesor que tiene el libro EN depósito,
se le enviará un aviso para solicitar su devolución.
• El estado por defecto de un usuario es activo. Cuando el usuario se retrasa en la
devolución de un préstamo pasa a estado moroso. En ese estado no puede pedir
prestado ni reservar ningún otro libro. Cuando devuelve el libro se le crea una multa y
pasa a estado multado.
• De la multa nos interesa saber la fecha de inicio y de finalización de la misma. La
finalización de la multa dependerá del tipo de usuario. Nos han comunicado que
quieren mantener un histórico de las multas que ha tenido un usuario. Cuando pasa la
fecha de finalización, el estado del usuario vuelve a activo.
Estas funcionalidades las vamos a ir implementando a lo largo del curso, conforme vaya
avanzando el proyecto de integración.

2.2.1. Requisitos de Información (IRQ)

Los requisitos de información resumen la información persistente que nos interesa


almacenar relacionada con el sistema.
• Respecto a un usuario, nos interesa almacenar:
• Login y password
• Nombre y apellidos
• Tipo de usuario / Rol: Bibliotecario, profesor, alumno
• Estado de un usuario: activo, moroso o multado
• Correo electrónico
• Datos referentes a su dirección, como son calle, número, piso, ciudad y código
postal.
• Si el usuario es alumno, necesitaremos guardar quién es su tutor

24
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

• Si el usuario es profesor, necesitaremos su departamento


• Cuando un usuario se retrase en la devolución de un libro, se le creará una multa, de
la cual nos interesa saber la fecha de inicio y de finalización de la misma. Nos han
comunicado que quieren mantener un histórico de las multas que ha tenido un usuario.
• Respecto a un libro, nos interesa almacenar:
• Título y autor
• ISBN
• Número de páginas
• Fecha de alta del libro
• Respecto a los préstamos, tras muchas entrevistas deducimos que tanto las reservas,
como los prestamos tienen características comunes, como son:
• Tipo: préstamo normal, préstamo depósito o reserva
• Fecha de inicio y finalización
• Usuario de la operación
• Libro de la operación
• Por último, las pre-reservas se van a almacenar sólo mientras no se hayan convertido
en reservas. En cada reserva guardaremos:
• Usuario que realiza la pre-reserva
• Libro
• Fecha de inicio

2.2.2. Casos de Uso

En un principio, el número de casos de uso es muy limitado. A lo largo del proyecto nos
vamos a centrar en el desarrollo de los siguientes casos de uso:

25
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Diagrama de Casos de Uso Principal


Destacar que la validación de usuarios para todos los actores se considera una
precondición que deben cumplir todos los casos de uso, y por lo tanto no se muestra en el
diagrama. Entendemos también que la realización de una reserva por parte de un usuario
A continuación vamos a mostrar en mayor detalle los casos de uso separados por el tipo
de usuario, de modo que quede más claro cuales son las operaciones que debe soportar la
aplicación.

Un poco de UML...
Recordar que las relaciones entre casos de uso con estereotipo ‹include› representan que el caso
de uso incluido se realiza siempre que se realiza el caso base. En cambio, el estereotipo ‹extend›
representa que el caso de uso extendido puede realizarse cuando se realiza el caso de uso padre (o
puede que no).

2.2.2.1. Bibliotecario

El tipo de usuario bibliotecario es el más complejo de nuestra aplicación. Como se puede


observar, es el que va a poder realizar un mayor número de casos de uso:

26
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Diagrama de Casos de Uso detallado para el Bibliotecario


Claramente en el centro podemos observar como el caso "Consultar Libros" es el eje de
la aplicación. A partir del listado de libros, ya sean disponibles, reservados o prestados,
este tipo de usuario podrá gestionar los libros (alta, baja o modificación) y realizar las
operaciones de reserva, préstamo o devolución (en nombre de un determinado usuario
registrado). Finalmente, también tiene la posibilidad de consultar un histórico de
operaciones, tanto de reservas como de prestamos realizados.

2.2.2.2. Alumno o Profesor

En cuanto a un usuario cuyo tipo sea alumno o profesor, y por tanto, sea un usuario
registrado en el sistema, las operaciones que puede realizar son las siguientes:

27
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Diagrama de Casos de Uso detallado para el Usuario Registrado


En cierta medida, este tipo de usuario va a poder realizar las mismas consultas que un
bibliotecario, pero sólo desde su punto de vista (sus reservas, sus prestamos), sin poder
visualizar que usuarios tienen reservado/prestado un determinado libro.
Además, solamente podrá reservar libros. Para formalizar el prestamo, deberá acudir a la
biblioteca, donde el bibliotecario realizará el préstamo en su nombre.
Más adelante, conforme cambien los requisitos del cliente (que siempre cambian), puede
que el sistema permita renovar los prestamos a los usuarios registrados, que éstos puedan
modificar su información de usuario, que los bibliotecarios obtengan informes sobre
libros más prestados y/o reservados, etc...

2.2.3. Requisitos de Restricción (CRQ)

Respecto a las restricciones que se aplicarán tanto a los casos de uso como a los requisitos
de información, y que concretan las reglas de negocio, hemos averiguado:
• Diferencias a la hora de realizar una operación tanto por parte de un profesor como de
un alumno:
Número Máximo Días de Reserva Días de Prestamo
de Libros

Alumno 3 5 7

28
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Profesor 10 10 30

Según esta información, un alumno solo puede reservar un máximo de 3 libros,


teniendo 5 días para recoger el libro. Si a los 5 días de realizar la reserva no ha
acudido a la biblioteca a formalizar el préstamo, se anulará la reserva, de modo que el
libro quedará disponible. En cuanto a los prestamos, deberá devolver el libro como
mucho una semana después.
• En el momento que un usuario tenga una demora en la devolución de un préstamo, se
considerará al usuario moroso y se le impondrá una penalización del doble de días de
desfase durante los cuales no podrá ni reservar ni realizar préstamos de libros.

El equipo directivo del "jUA" nos ha confirmado que para la primera versión de la
aplicación se van a cumplir las siguientes premisas:
• No se permite más de una existencia de un libro. Es decir, sólo hay un ejemplar de
cada libro, y la aplicación no permite libros repetidos.
• Un libro sólo tiene un autor.

2.3. Análisis y Diseño OO

A partir de esta captura de requisitos inicial, vamos a plantear los elementos que van a
formar parte de la aplicación, comenzado por el modelo de clases.

2.3.1. Modelo de Clases Conceptual

A partir de los requisitos y tras unas sesiones de modelado, hemos llegado al siguiente
modelo de clases conceptual representado mediante el siguiente diagrama UML:

29
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Diagrama de Clases
El elemento central de nuestro sistema va a ser una clase Operacion, el cual,
dependiendo de un atributo enumerado, nos indicará si el objeto es un préstamo, un
depósito o una reserva. Además, cada operación se compone de un Libro y de un
Usuario. La clase tendrá dos subclases, Activa y Historica, para reflejar la distinta
cardinalidad de la relación con Libro. La relación entre Libro y Activa es uno-a-uno (un
libro sólo puede estar una operación activa), mientras que entre Libro y Historica es
uno-a-muchos.

Alternativa
Otra forma de modelar este problema sería mediante una relación de herencia entre una clase
abstracta Operacion, del cual tuviésemos las clases extendidas de Reserva y Prestamo,
pero realmente para la lógica de nuestra aplicación, no nos interesa esta separación.
La decisión de desnormalizar esta jerarquía se debe a que realmente estas dos entidades no tienen
ningún atributo diferenciador, ni se prevé que vayamos a necesitar almacenar algún dato
específico de alguna entidad que lo haga diferenciarse una de la otra.

Definimos también una clase Usuario con tres subclases: Bibliotecario, Profesor y
Alumno.

Todas las entidades tienen un campo identificador que permitirá indentificarlas de forma
única. No usaremos claves primarias naturales (por ejemplo, el isbn de un libro o el login

30
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

de un usuario) porque hacen que el modelo sea demasiado rígido.

2.3.2. Modelo de Datos Conceptual

Siguiendo las mismas pautas que en el modelado de clases, llegamos a un modelo


conceptual de datos muy similar al anterior. Podemos observar que ambos modelos
representan el mismo problema y son casi semejantes.

Diagrama Conceptual de Datos

Por donde empezamos


¿ Datos o clases ? Podemos empezar modelando los datos o las clases, y ambos modelos serán
casi semejantes. Normalmente, la elección viene dada por la destreza del analista, si se siente más
seguro comenzando por los datos, o con el modelo conceptual de clases. Otra opción es el
modelado en paralelo, de modo que al finalizar ambos modelos, podamos compararlos y validar
si hemos comprobado todas las restricciones.

2.3.3. Diagramas de Estado

A continuación podemos visualizar un par de diagramas que representan los diferentes


estados que puede tomar tanto los libros (por medio de las operaciones) como los usuarios
(mediante las acciones que conllevan algunas operaciones).

2.3.3.1. Estados de un libro

En el caso de un libro, su estado determina las operaciones que se pueden realizar con él.

31
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Para saber el estado actual de un libro, tendremos que consultar en la base de datos las
relaciones que tiene con operaciones y con pre-reservas:
• Si no tiene ninguna operación activa ni está pre-reservado: disponible
• Si tiene una pre-reserva: pre-reservado
• Si tiene una operación activa de tipo reserva: reservado en sala
• Si tiene una operación activa de tipo préstamo o depósito: prestado
Las operaciones que hacen que un libro cambie de un estado a otro son las siguientes:

Diagrama de Estados de un Libro

2.3.3.2. Estados de un usuario

Del mismo modo, los estados de un usuario dependen de si el usuario realiza sus
operaciones dentro de las reglas de negocio permitidas. Si un usuario devuelve un libro
con fecha caducada, se le multará y pasará a ser moroso. Destacar que si un usuario posee
un libro con fecha de devolución caducada, hasta que el usuario no devuelve el libro, no
se le considera moroso, ya que no podemos calcular la cuantía de la multa.

32
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Diagrama de Estados de un Usuario


Esta lógica se puede tratar de diferentes modos, pero por ahora, como veremos a
continuación, cuando un usuario entra al sistema, comprobaremos tanto si es moroso
como si tiene libros pendientes de devolución cuya fecha ya ha caducado.

2.3.4. Validación de Usuarios

Dados los diferentes tipos de usuarios y la compleja lógica de entrada a la aplicación,


hemos dedicado una sesión de modelado a estudiar cual debe ser el comportamiento de la
aplicación cuando un usuario se valida en el sistema.
El siguiente diagrama de actividad representa toda la posible casuística:

33
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Diagrama de Actividad para la entrada al sistema

2.3.5. Reserva/Prestamo de un Libro

Tanto las operaciones de reserva como de préstamo de un libro conllevan una serie de
comprobaciones que hemos definido en el siguiente diagrama:

34
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Diagrama de Actividad para la reserva de un libro

35
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

3. Implementación

El objetivo de la sesión de hoy es crear el proyecto jbib-modelo, módulo inicial en el


que vamos a incluir todas las clases de dominio que implementan las entidades de la
aplicación, y las clases auxiliares (tipos enumerados y clases auxiliares). Vamos a
construirlo utilizando Maven. A lo largo de las siguientes sesiones del proyecto iremos
construyendo nuevos módulos necesarios para la aplicación.
Al ser un proyecto formado por múltiples módulos, utilizaremos una estructura Maven de
multiproyecto, en el que un directorio padre con un POM define las características
comunes y los módulos y contiene a los distintos módulos en subdirectorios. Cada
subdirectorio define un módulo y contiene su propio fichero POM que describe sus
características.

3.1. Construcción del proyecto Maven

Vamos a crear el módulo inicial del proyecto de integración. Todos los módulos los
crearemos en un espacio de trabajo eclipse llamado proy-int dentro de
/home/especialista. Para ello, seleccionamos un espacio de trabajo con ese nombre. Si
no existe el directorio, Eclipse lo crea.

Espacio de trabajo proyint


Vamos a utilizar el asistente de Eclipse para crear proyectos Maven. Pulsamos con el
botón derecho en el panel de proyectos la opción New > Project... > Maven > Maven
Project:

36
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Nuevo proyecto Maven


Vamos a crear el proyecto padre de todos los módulos que iremos desarrollando más
adelante. Seleccionamos la opción skip archetype selection para no basar el proyecto
Maven en ningún arquetipo. Eclipse únicamente generará el proyecto con la estructura de
directorios Maven adecuada y el POM mínimo con su descripción.

Skip archetype selection


Introduce los datos del proyecto necesarios para crear el POM inicial de Maven,
escribiendo tu login en el nombre del proyecto:
• GroupId: org.especialistajee
• ArtifactId: login-proyint-jbib
• Version: 2011
• Packaging: POM
• Name: login-proyint-jbib

Datos proyecto padre


Eclipse creará un proyecto nuevo en el que existirá un directorio de fuentes (src) y el
fichero POM que descibre este proyecto padre. En el icono del proyecto puedes ver una

37
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

pequeña "M" que indica que se trata de un proyecto Maven y que el plugin Maven de
Eclipse lo ha reconocido como tal.

Proyecto padre
Podemos abrir el fichero POM para comprobar que el XML se ha creado correctamente:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.especialistajee</groupId>
<artifactId>pperez-proyint-jbib</artifactId>
<version>2011</version>
<packaging>pom</packaging>
<name>pperez-proyint-jbib</name>
<description>Proyecto padre de los módulos del proyecto de
integración Biblioteca Java</description>
</project>

Procedemos a continuación a crear el módulo con el que vamos a trabajar en esta sesión:
jbib-modelo (precedido de tu login). Lo hacemos también utilizando el asistente de
Eclipse. Seleccionamos con el botón derecho la opción New > Project... > Maven >
Maven Module:

Creando el módulo jbib-modelo


Marcamos también la opción de saltar la selección del arquetipo y escribimos el nombre
del módulo y del proyecto padre:

38
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Nombre módulo y proyecto padre


Introducimos a continuación los datos del módulo para crear su POM
• GroupId: org.especialistajee
• ArtifactId: login-jbib-modelo
• Version: 2011
• Packaging: jar
• Name: login-jbib-modelo
Es importante el tipo de empaquetamiento. El módulo se va a empaquetar como un JAR
conteniendo todas las clases del dominio y las clases de utilidad. Hay que definir esta
opción. Ya veremos más adelante como Maven automatiza el proceso de compilación,
prueba y empaquetamiento del JAR.

Datos del módulo jbib-modelo


Podemos comprobar ahora que el proyecto se ha creado correctamente y que su estructura
corresponde con la de un proyecto Maven:

39
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Estructura proyecto jbib-modelo


Vemos que se ha creado un directorio de fuentes src/main, y otro directorio de tests
src/tests. También vemos un directorio target donde Maven colocará los ficheros
.class compilados y el JAR resultante del empaquetado del proyecto.
Si revisas los ficheros POM veremos que en el del proyecto padre se ha añadido el
nombre del módulo recién creado. El POM del módulo contiene los datos introducidos:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>pperez-proyint-jbib</artifactId>
<groupId>org.especialistajee</groupId>
<version>2011</version>
</parent>
<groupId>org.especialistajee</groupId>
<artifactId>pperez-jbib-modelo</artifactId>
<version>2011</version>
<name>pperez-jbib-modelo</name>
<description>Paquete JAR que implemeta el modelo de dominio
Biblioteca Java</description>
</project>

Por último, para comprobar que la estructura de directorios es correcta, podemos abrir el
explorador de archivos y asegurarnos de que se ha creado un directorio padre con el
proyecto padre y un subdirectorio hijo con el módulo jbib-modelo:

40
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Estructura proyecto en el sistema de ficheros

3.2. Ficheros POM

Hay que añadir algunos elemenots a los ficheros POM para configurar correctamente los
proyectos
En primer lugar, podemos ver que el plug-in de Maven interpreta incorrectamente la
versión de la máquina virtual Java del proyecto. En el proyecto aparece la J2SE-1.5, en
lugar de la que está configurada por defecto en Eclipse, la 1.6. Para solucionar el aviso,
indicamos en el POM del proyecto padre explícitamente que el proyecto va a trabajar con
la versión 1.6 del compilador Java.
También indicamos que la codificación de los ficheros de código fuente que componen el
proyecto es UTF-8 (la versión de Eclipse de la máquina virtual está configurado de esa
forma, se puede comprobar en Windows > Preferences > General > Workspace > Text
file encoding).
Para ello añadimos el siguiente código al fichero POM del proyecto padre
(login-proyint-jbib/pom.xml). Para que el plugin de Maven actualice los proyectos,
hay que pulsar con el botón derecho la opción Maven > Update project configuration.
Hazlo en el proyecto hijo jbib-modelo y verás que se actualiza la versión de Java y
desaparece el aviso.
<project>
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>

41
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

</configuration>
</plugin>
</plugins>
</build>
</project>

Por último, añadimos en el proyecto padre las dependencias de algunas librerías que
vamos a usar en todos los módulos del proyecto:
• Librería de pruebas junit: junit-4.8.1
• Librerías de gestión de logs commons-logging y log4j: commons-logging-1.1.1 y
log4j-1.2.12

...
</properties>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<type>jar</type>
<scope>test</scope>
</dependency>
</dependencies>
<build>
...

El proyecto se actualizará automáticamente, y podremos ver las librerías importadas bajo


las Maven Dependencies:

42
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Estructura proyecto en el sistema de ficheros

Nota:
También es posible añadir dependencias utilizando el asistente de Eclipse, que permite ademas
buscar por nombre y versión.

Las librerías descargadas se guardan en el directorio /home/especialista/.m2


(repositorio local de Maven). Puedes explorar el directorio con el navegador de archivos
para comprobar que los ficheros JAR se encuentran allí. En el repositorio exiten más
librerías porque las hemos descargado al montar la máquina virtual para que sea más
rápida la construcción de los proyectos.

3.3. Primera iteración

3.3.1. Primera clase entidad

Las clases de dominio representan las entidades que van a relacionarse en la aplicación.
En las siguientes sesiones, cuando veamos JPA, veremos cómo se podrán definir la capa
de persistencia de la aplicación directamente a partir de estas clases. Serán también
objetos que podremos utilizar como Transfer Objects (TOs) dentro del sistema,
realizando funciones de meros contenedores y viajando por las capas de la aplicación.
Para asegurarnos que todos nuestros objetos de dominio tienen una estructura común,
definimos una clase abstracta, que será la clase padre de todas las clases de dominio. La
hacemos serializable para asegurar que los objetos pueden transmitirse entre capas físicas
de la aplicación (por ejemplo, entre la capa de presentación y la capa de lógica de
negocio) y definimos los métodos equals() y hashCode() para obligar a que las clases
hijas implementen la redefinan la igualdad. Estos métodos son muy útiles en el caso en el
que los objetos se guarden y queramos buscarlos en colecciones.
package org.especialistajee.jbib.model;

43
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

import java.io.Serializable;
/**
* Padre de todos los objetos de dominio del modelo. Los objetos del
dominio
* están relacionados entre si y se hacen persistentes utilizando
entidades JPA.
* Pulsando F4 en Eclipse podemos ver la jerarquía. En la clase definimos
los
* métodos abstractos que deben implementar todas las clases del dominio.
Los
* objetos de dominio participan entre ellos en relaciones uno-a-uno,
* uno-a-muchos y muchos-a-uno y estan relacionados mediante
referencias. Tendrán
* una clave única que permite identificarlos en la BD. Una Direccion no
es un
* objeto de dominio.
*/
public abstract class DomainObject implements Serializable {
private static final long serialVersionUID = 1L;
public abstract boolean equals(Object object);
public abstract int hashCode();
}

Todas las entidades las vamos a definir dentro del paquete


org.especialistajee.jbib.model, y utilizaremos el sufijo Domain a modo de
nomenclatura para indicar que un objeto de la aplicación es una entidad.
Cada entidad se compone de sus atributos, relaciones y de todos los getter/setter que
encapsulan al objeto. Así pues, por ejemplo, la representación del Domain Object
LibroDomain sería:
package org.especialistajee.jbib.model;
import java.util.Date;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class LibroDomain extends DomainObject {
private static final long serialVersionUID = 1L;
private Long id;
private String isbn;
private String titulo;
private String autor;
private Integer numPaginas;
private Date fechaAlta;
private Set<HistoricaDomain> historicas = new
HashSet<HistoricaDomain>();
private ActivaDomain activa;
private PrereservaDomain prereserva;
static Log logger = LogFactory.getLog(LibroDomain.class);
// Definimos un hashCode basado en un campo que no cambia y que
existe en el
// momento de la creación con new, ya que el id autogenerado por
la base de

44
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

// datos no existe en ese momento


@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + isbn.hashCode();
return result;
}
// Definimos equals dos distintos niveles: a nivel de referencia, y a
nivel
// de identificador de base de datos. Dos objetos que tienen la misma
referencia
// son simpre equals. Dos objetos con distintas referencias también
pueden ser
// equals si contienen el mismo identificador (generado por la base de
datos).
@Override
public boolean equals(Object obj) {
if (id == null)
return this == obj;
else {
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LibroDomain other = (LibroDomain) obj;
return id.equals(other.getId());
}
}
public LibroDomain() {
}
public LibroDomain(String isbn) {
this.isbn = isbn;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getAutor() {
return autor;
}
public void setAutor(String autor) {
this.autor = autor;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public Integer getNumPaginas() {
return numPaginas;
}

45
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

public void setNumPaginas(Integer numPaginas) {


this.numPaginas = numPaginas;
}
public String getTitulo() {
return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public Date getFechaAlta() {
return fechaAlta;
}
public void setFechaAlta(Date fechaAlta) {
this.fechaAlta = fechaAlta;
}
public void setHistoricas(Set<HistoricaDomain>
operacionesHistoricas) {
this.historicas = operacionesHistoricas;
}
public void addOperacionHistorica(HistoricaDomain historica) {
if (historica == null)
throw new IllegalArgumentException("Null
operacion");
historicas.add(historica);
// se actualiza la parte inversa de la relación
historica.setLibro(this);
}
public Set<HistoricaDomain> getHistoricas() {
return historicas;
}
public void setActiva(ActivaDomain activa) {
this.activa = activa;
}
public ActivaDomain getActiva() {
return activa;
}
public void setPrereserva(PrereservaDomain prereserva) {
this.prereserva = prereserva;
}
public PrereservaDomain getPrereserva() {
return prereserva;
}
}

Es interesante hacer notar la forma en que están implementados los métodos hashCode y
equals. Son métodos muy importantes porque son los que se utilizan para buscar en las
colecciones. Dos importante ideas relacionadas con estos métodos (ver el capítulo 3 de
Effective Java de Joshua Bloch):
• Si dos objetos son equals deben tener el mismo hashCode, pero no tiene por qué ser
al revés. En nuestro caso, el método hashCode se basa en el campo isbn. Si dos libros

46
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

son equals puede ser porque: a) tengan la misma referencia o b) tengan el mismo
identificador. En ambos casos van a tener el mismo isbn. Puede ser que al revés no.
Supongamos dos libros que tienen el mismo isbn pero distinto identificador (dos
ejemplares de un mismo libro). Tendrían el mismo hashCode pero no serían equals.
Esto es posible, ya que el hashCode define la posición en una tabla hash, pero en una
posición puede haber más de un elemento.
• El método hashCode debe devolver un valor estable, que no cambie en el tiempo que
un objeto está en una colección. En nuestro caso también es correcto, ya que basamos
el hashCode en un campo que no se modifica, el isbn del libro (una clave natural).

3.3.2. Eliminando errores

Definimos las clases vacías necesarias para eliminar los errores de la clase Libro:
• Clase abstracta OperacionDomain y sus clases hijas ActivaDomain y
HistoricasDomain.
• Clase PrereservaDomain

3.3.3. Ficheros de recursos

Añadimos los ficheros de recursos necesarios para el funcionamiento de los logs.


Fichero src/main/resources/commons-logging.properties:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

Fichero src/main/resources/log4j.properties:
# Coloca el nivel root del logger en DEBUG (muestra mensajes de DEBUG
hacia arriba)
# Añade appender A1
log4j.rootLogger=DEBUG, A1
# A1 se redirige a la consola
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.Threshold=INFO
# A1 utiliza PatternLayout
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{dd/MM/yyyy HH:mm:ss} - %p -
%m %n

3.3.4. Primer test

Definimos el primer test con la clase


org.especialistajee.jbib.model.LibroDomainTest en el directorio
src/test/java, con el que probamos el funcionamiento correcto de la igualdad:
• Si no se ha definido el identificador del libro (de tipo Long), equals se comporta
como la igualdad de referencia.
• En cuanto se definen el identificador del libro, equals compara estos identificadores.

47
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

package org.especialistajee.jbib.model;
import static org.junit.Assert.*;
import org.junit.Test;
public class LibroDomainTest {
@Test
public void testEquals() {
LibroDomain lib1 = new LibroDomain("123456789");
LibroDomain lib2 = new LibroDomain("123456789");
LibroDomain lib3 = lib1;
assertFalse(lib1.equals(lib2));
assertTrue(lib1.equals(lib3));
lib1.setId(1L);
lib2.setId(1L);
assertTrue(lib1.equals(lib2));
lib2.setId(2L);
assertFalse(lib1.equals(lib2));
}
}

Ejectuamos el test con el botón derecho sobre la clase o el paquete: Run As > JUnit Test y
debe aparecer en verde:

Datos proyecto padre

3.3.5. Construcción con Maven

Abrimos un terminal y ejecutamos los comandos Maven para construir el JAR que
contiene el proyecto:
$ cd /home/especialista/proyint/pperez-proyint-jbib
$ mvn clean
$ mvn install

Todos los comandos Maven los ejecutamos en el directorio del proyecto principal, que
contiene el subproyecto jbib-modelo. Cuando añadamos más subproyectos los
empaquetaremos de la misma forma.
El comando Maven clean borra todos los ficheros .class que puedan haber sido creados
anteriormente. El comando install realiza secuencialmente las siguientes acciones:
• Compila todos los módulos del proyecto principal
• Ejecuta todos los tests
• Si los tests son correctos, empaqueta el subproyecto pperez-jbib-modelo en el
fichero JAR pperez-jbib-modelo-2011.jar
• Copia el fichero JAR en el repositorio local de Maven (directorio .m2) para dejarlo
como una librería disponible para otros proyectos.

48
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

La última parte de la salida del comando debe ser esta:


-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.especialistajee.jbib.model.LibroDomainTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.144 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ pperez-jbib-modelo
---
[INFO] Building jar:
/home/especialista/proyint/pperez-proyint-jbib/pperez-jbib-
modelo/target/pperez-jbib-modelo-2011.jar
[INFO]
[INFO] --- maven-install-plugin:2.3.1:install (default-install) @
pperez-jbib-modelo ---
[INFO] Installing
/home/especialista/proyint/pperez-proyint-jbib/pperez-jbib-modelo/
target/pperez-jbib-modelo-2011.jar to /home/especialista/.m2/repository/
org/especialistajee/pperez-jbib-modelo/2011/pperez-jbib-modelo-2011.jar
[INFO] Installing
/home/especialista/proyint/pperez-proyint-jbib/pperez-jbib-modelo/
pom.xml to
/home/especialista/.m2/repository/org/especialistajee/pperez-jbib-modelo/2011/
pperez-jbib-modelo-2011.pom
[INFO]
------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] pperez-proyint-jbib ............................... SUCCESS
[0.369s]
[INFO] pperez-jbib-modelo ................................ SUCCESS
[1.342s]
[INFO]
------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO]
------------------------------------------------------------------------
[INFO] Total time: 1.882s
[INFO] Finished at: Sat Oct 08 08:07:18 CEST 2011
[INFO] Final Memory: 4M/15M
[INFO]
------------------------------------------------------------------------

Todos los ficheros .class y JAR se guardan en el directorio target del proyecto. Puedes
explorar el sistema de archivos para comprobarlo.
Esto lo podemos hacer también desde el asistente de Eclipse situándonos en el proyecto
principal y pulsando con el botón derecho la opción Run As > Maven instal. Puede ser
que la salida de la consola sea ligeramente distinta, porque Eclipse usa una versión de
Maven instalada en el propio entorno.
Para usar la misma versión que cuando la lanzamos desde línea de comandos, podemos
seleccionar la opción Window > Preferences > Maven > Installations y añadir la ruta en
la que se encuentra Maven en el sistema operativo: /opt/apache-maven-3.0.3.

49
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

3.3.6. Repositorio SVN

Terminamos esta primera iteración subiendo el proyecto al repositorio SVN.

Aviso:
Los directorios target no deben subirse al repositorio SVN, ya que sólo debemos colocar allí
los ficheros fuentes. Podemos configurar Eclipse de forma que haga que Subversion los ignore.
Debemos entrar en la opción Window > Preferences > Team > Ignored Resources y añadir el
patrón target. De esta forma el cliente de Subversion no subirá ni el directorio ni sus
contenidos.

Pulsamos con el botón derecho sobre el proyecto padre la opción Team > Share project
y creamos la conexión SVN con la URL
svn+ssh://server.jtech.ua.es/home/svn/pperez/proyint. Después escojemos la
opción Advanced Mode para espeficicar la localización del proyecto. La localización que
debe aparecer en la parte inferior del asistente es:
svn+ssh://server.jtech.ua.es/home/svn/pperez/proyint/trunk/pperez-proyint-jbib

Subiendo a SVN el proyecto padre, se suben también todos los subproyectos.

3.4. Enumeraciones

En cuanto a las enumeraciones, Java (desde su versión 5.0) permite su creación mediante
la clase java.lang.Enum. En nuestro caso, por ejemplo, la enumeración de
EstadoUsuario quedaría del siguiente modo:
package org.especialistajee.jbib.model;
public enum EstadoUsuario {
ACTIVO, MOROSO, MULTADO
}

Definimos al menos las enumeraciones:


• EstadoLibro
• EstadoMulta
• EstadoUsuario
• TipoOperacion

3.5. Implementar y completar las clases de entidad

Para implementar nuestras clases, tendremos que codificar todas las clases y relaciones
expuestas en el Modelo de Clases Conceptual.
Hay que tener especial cuidad con las relaciones de herencia. Tenemos dos: la clase
UsuarioDomain y las clases hijas BibliotecarioDomain, ProfesorDomain y

50
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

AlumnoDomain. También la clase OperacionDomain y sus clases hijas ActivaDomain e


HistoricaDomain. En ambos casos la clase padre es abstracta.

Algunas características comunes a todas las clases de entidad:


• En todas se define un identificador de tipo Long que será generado por la base de
datos y que constítuirá la clave primaria de la entidad. El método equals se define en
base a este idenficador de la misma forma que hemos hecho con la clase Libro.
• En todas las clases el método hashCode se basa en un campo que debe siempre estar
definido en el objeto. En todas las clases debemos definir un constructor público que
contenga un número mínimo de campos, entre los que estará el campo usado para el
número hash. Por ejemplo el login en la clase UsuarioDomain o el usuario en la
clase MultaDomain.
• Las relaciones X-a-muchos las definimos del tipo Set. De esta forma nos aseguramos
que no existen objetos duplicados en las relaciones. La identidad en un conjunto se
define con el método equals.
Definimos también la clase Direccion que será una clase no entidad y se utilizará en la
entidad UsuarioDomain.

Nota:
No olvides implementar un método getEstado en la clase Libro. El estado del libro se puede
calcular a partir de sus relaciones.

3.6. Gestión de las Excepciones

Todas las aplicaciones empresariales definen una política de gestión de las excepciones
de aplicación.
En nuestro caso, conforme crezca el proyecto, iremos creando nuevas excepciones. Como
punto de partida, y como buena norma de programación, vamos a definir una excepción
genérica de tipo unchecked (BibliotecaException), que será la excepción padre de
todas las excepciones de aplicación de la biblioteca. El hecho de que la excepción se
unchecked remarca el carácter de que estamos definiendo excepciones relacionadas con el
mal uso del API. En general, un método debe realizar su funcionalidad y terminar
correctamente cuando todo ha funcionado bien. Se lanzará una excepción si algo falla.
Por ejemplo, cuando definamos un método prestar(libro,usuario) lanzaremos
excepciones cuando no se cumplan las condiciones que hacen que el libro pueda ser
prestado al usuario. Al lanzar excepciones no chequeadas permitimos que el programador
chequee las condiciones antes de llamar al método y no tenga que obligatoriamente
capturar una excepción que sabemos que no se va a producir.
Definimos las excepciones en el paquete global org.especialistajee.jbib
package org.especialistajee.jbib;

51
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

public class BibliotecaException extends RuntimeException {


private static final long serialVersionUID = 1L;
public BibliotecaException() {
super();
}
public BibliotecaException(String message) {
super(message);
}
public BibliotecaException(String message, Throwable cause) {
super(message, cause);
}
}

Podemos observar como, al sobrecargar el constructor con los parámetros {String,


Throwable}, nuestra excepción permitirá su uso como Nested Exception.

3.7. Implementación de las Reglas de Negocio

Es común agrupar las reglas de negocio de una aplicación en una o más clases
(dependiendo de los diferentes subsistemas de la aplicación), para evitar que estén
dispersas por la aplicación y acopladas a un gran número de clases.
En nuestro caso, vamos a crear un Singleton, al que llamaremos BibliotecaBR (BR =
Business Rules). En principio, los valores estarán escritos directamente sobre la clase,
pero en un futuro podríamos querer leer los valores de las reglas de negocio de un fichero
de configuración).
El esqueleto de nuestras reglas de negocio será el siguiente:

package org.especialistajee.jbib;
// faltan los imports
/**
* Reglas de Negocio de la Biblioteca
* BR = Business Rules
*
* Lo implementamos como un singleton por si algun dia queremos leer
* las constantes desde un fichero de configuración, lo podemos
* hacer desde el constructor del singleton
*/
public class BibliotecaBR {
private static BibliotecaBR me = new BibliotecaBR();
private BibliotecaBR() {
}
public static BibliotecaBR getInstance() {
return me;
}
/**
* Calcula el número de dias de plazo que tienen un usuario para

52
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

* realizar una reserva (Socio = 5 , Profesor = 10)


* @param tipo tipo del usuario
* @return número de dias de reserva
* @throws BibliotecaException el tipo del usuario no es válido
*/
public int calculaNumDiasReserva(TipoUsuario tipo)
throws BibliotecaException {
// TODO Completar
}
/**
* Calcula el número de dias de plazo que tienen un usuario para
* realizar un prestamo (Socio = 7 , Profesor = 30)
* @param tipo tipo del usuario
* @return número de dias del prestamo
* @throws BibliotecaException el tipo del usuario no es válido
*/
public int calculaNumDiasPrestamo(TipoUsuario tipo)
throws BibliotecaException {
// TODO Completar
}
/**
* Valida que el número de operaciones realizadas por
* un determinado tipo de usuario se inferior al cupo definido
* @param tipo tipo del usuario
* @param numOp número de operación que ya tiene realizadas
* @throws BibliotecaException el cupo de operacion esta lleno,
* o el tipo del usuario no es el esperado
*/
public void compruebaCupoOperaciones(TipoUsuario tipo, int numOp)
throws BibliotecaException {
// TODO Completar
}
}

Podemos observar que vamos a tener un método por cada regla de negocio, y que estos
métodos lanzarán excepciones de aplicación en el caso de un comportamiento anómalo.

3.8. Tests

Vamos a definir dos tipos de tests, unos relacionados con las clases del modelo y otros
con las reglas de negocio.
Los tests se deben colocar dentro de la carpeta test, en el mismo paquete que la clase a
probar.
Tests de reglas de negocio:
package org.especialistajee.jbib;
import static org.junit.Assert.*;
import org.especialistajee.jbib.model.TipoUsuario;
import org.junit.Test;
/**
* Pruebas jUnit sobre las reglas de negocio de la biblioteca
*/
public class BibliotecaBRTest {

53
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

@Test
public void testCalculaNumDiasReservaProfesor() {
int diasProfesor = BibliotecaBR.getInstance()
.calculaNumDiasReserva(TipoUsuario.PROFESOR);
assertEquals(diasProfesor, 10);
}
@Test
public void testCalculaNumDiasReservaSocio() {
int diasAlumno = BibliotecaBR.getInstance()
.calculaNumDiasReserva(TipoUsuario.ALUMNO);
assertEquals(diasAlumno, 5);
}
@Test
public void testCalculaNumDiasPrestamoProfesor() {
int diasProfesor = BibliotecaBR.getInstance()
.calculaNumDiasPrestamo(TipoUsuario.PROFESOR);
assertEquals(diasProfesor, 30);
}
@Test
public void testCalculaNumDiasPrestamoSocio() {
int diasAlumno = BibliotecaBR.getInstance()
.calculaNumDiasPrestamo(TipoUsuario.ALUMNO);
assertEquals(diasAlumno, 7);
}
@Test
public void testCompruebaCupoOperacionesProfesorCorrecto() {
try {
BibliotecaBR.getInstance()
.compruebaCupoOperaciones(
TipoUsuario.PROFESOR, 4);
BibliotecaBR.getInstance()
.compruebaCupoOperaciones(
TipoUsuario.PROFESOR, 0);
} catch (BibliotecaException e) {
fail("No debería fallar - el cupo de operaciones del PROFESOR es
correcto");
}
}
@Test(expected = BibliotecaException.class)
public void testCompruebaCupoOperacionesProfesorIncorrecto()
throws BibliotecaException {
BibliotecaBR.getInstance().compruebaCupoOperaciones(
TipoUsuario.PROFESOR, 11);
}
@Test
public void testCompruebaCupoOperacionesAlumnoCorrecto() {
try {
BibliotecaBR.getInstance()
.compruebaCupoOperaciones(
TipoUsuario.ALUMNO, 2);
BibliotecaBR.getInstance()
.compruebaCupoOperaciones(
TipoUsuario.ALUMNO, 0);
} catch (BibliotecaException e) {
fail("No debería fallar - el cupo de operaciones del ALUMNO es
correcto");
}
}

54
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

@Test(expected = BibliotecaException.class)
public void testCompruebaCupoOperacionesAlumnoIncorrecto()
throws BibliotecaException {
BibliotecaBR.getInstance().compruebaCupoOperaciones(
TipoUsuario.ALUMNO, 4);
}
}

En los tests de las clases del modelo debemos de comprobar:


• Relaciones de igualdad.
• Actualizaciones de las relaciones entre entidades. Por ejemplo, podemos crear una
operación, un libro y un usuario, asociar la operación al libro y al usuario y
comprobar que los métodos get devuelven correctamente las relaciones.

3.9. Resumen

En esta sesión vamos a preparar la base para el resto de sesiones. Por ellos, debemos crear
un proyecto padre Maven, al que llamaremos login-proyint-jbib, que contendrá al
módulo login-jbib-modelo con el modelo de dominio de la aplicación:
1. modelo de objetos dentro del paquete org.especialistajee.jbib.model,
implementando cada entidad con los atributos representados en el diagrama UML, sus
relaciones, y teniendo en cuenta la relación de herencia con la clase DomainObject y
los constructores necesarios y los métodos de acceso.
2. clase BibliotecaBR con las reglas de negocio, implementada como un singleton, la
cual debe pasar las pruebas JUnit aportadas. Para implementar esta clase, es necesaria
la clase BibliotecaException.
3. tests de las clases de dominio y de las reglas de negocio que realicen algunas
comprobaciones de los métodos equals y de las actualizaciones de las relaciones.
Las siguientes imágenes muestran todos los archivos que debe contener el proyecto
Eclipse:

55
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

Estructura de Proyecto I Estructura de Proyecto II

Debemos utilizar la etiqueta entrega-proyint-modelo El plazo final de entrega será el


jueves 20 de octubre. Se realizará una sesión on-line de dudas el lunes 17 de 19:00 a
21:00.

56
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

57
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.
Caso de estudio

58
Copyright © 2011-2012 Dept. Ciencia de la Computación e IA All rights reserved.

También podría gustarte