Segunda Iteración: Casos de Uso

26/03/2008

Los Diagramas de Casos de Uso correspondientes al análisis de la Segunda Iteración pueden verse en la Forja de cyberHotel y los comentarios que se pueden hacer sobre ellos son similares a lo que se ha comentado para los de la Primera Iteración.

Tenemos igualmente los actores Recepcionista(Manager) y Recepcionista(User), solo que esta vez ambos pueden realizar las mismas acciones, dado que los casos de uso de esta iteración abarcan todas las tareas principales de recepción, esto es, sistema de clientes, reservas, entradas, salidas, cargos y gestión del estado de las habitaciones y es necesario que un usuario corriente pueda realizar estas tareas.


Capa Vista: Patrón Singleton

25/03/2008

El patrón Singleton o Instancia Única asegura que una clase solo tiene una instancia (un único objeto) y proporciona un punto global de acceso a ella.

Es un patrón muy sencillo que impide la creación de varios objetos de una clase dada, lo que trae como consecuencia un importante ahorro de memoria, pues en muchos casos hay clases de las que no es necesario tener varios objetos, esto ocurre en nuestra capa vista para las clases que representan a muchos de los formularios. Muchos de ellos deben de estar presentes en la aplicación una única vez, de forma que el usuario no puede mostrar una determinada ventana varias veces, pues esto, además de carecer de sentido, traería asociado un coste de memoria innecesario.

Particularmente en Java el patrón Singleton se puede implementar de diversas maneras:

Instanciación bajo demanda: Una sentencia condicional en el método de creación del objeto evalúa si este ya existe o no.

Instanciación automática: Se elimina la sentencia condicional y cuando se carga la clase por primera vez en memoria se crea este.

Sin instancia: Java nos permite trabajar con clases sin necesidad de instanciarlas. Esta nueva implementación conserva la idea pero no su estructura, ya que aquí realmente no hay una instancia. El Singleton es una clase con métodos y atributos estáticos y nunca llega a existir un objeto.

Las tres ideas son igualmente válidas para implementar un Singleton en Java, en los dos primeros casos disponemos de un método estático para crear la instancia, y luego accedemos a los métodos, por ejemplo:

Singleton s = Singleton.getInstance();
s.metodo();

En el tecer caso, no podemos guardar referencias al objeto como en los casos anteriores porque el objeto no existe, así que las invocaciones a métodos serán todas del tipo:

Singleton.metodo();

Para los formularios nos hemos decantado por el primer caso de instanciación.

Un ejemplo de uso del patrón Singleton para un formulario:

 

ParticularWindow

Capa Vista: Patrón Observador

18/03/2008

El patrón Observador (Observer) permite definir una dependencia entre objetos de forma que cuando un objeto cambia de estado, todos sus objetos dependientes son notificados y actualizados.Es un patrón que nos permite definir un sujeto determinado sobre el que tenemos uno o varios observadores, y cuando se produce algún cambio en el sujeto, este notifica a sus observadores para que cambien su estado si es necesario. Los observadores suelen consultar el estado del sujeto, pero en muchos casos pueden actualizarse independientemente del estado del sujeto.Para entender con más claridad este patrón vamos a ver como lo hemos utilizado en cyberHotel. Muchos de los formularios de la aplicación disponen de un panel de utilidades que permite añadir un nuevo elemento, editar un elemento que está siendo consultado, borrar dicho elemento, y también acceder al siguiente y al anterior. Pues bien, para que el formulario responda a los eventos de este panel utilizamos el patrón Observador, de forma que el formulario observa lo que hace el panel, quién actúa como sujeto. Cada vez que el panel ejecuta una acción, el formulario actualiza sus datos en pantalla.Podemos representar gráficamente el sistema:

observer


Interacción Vista-Controlador: Patrón Estrategia

18/03/2008

El patrón Estrategia (Strategy) permite que un determinado contexto trabaje con una implementación u otra de un algoritmo sin conocer su implementación concreta.

Para entendernos, pondremos como ejemplo el caso en que utilizamos este patrón en cyberHotel. Muchos de los formularios de la aplicación tienen un botón de Guardar, que nos permite almacenar en base de datos lo que hemos tecleado en el formulario, pero en diversas ocasiones podemos insertar los datos por primera vez, o bien, podemos realizar una actualización de los datos, pues bien, tanto en una ocasión como en la otra el botón simplemente llama a un método que nombramos como save, ¿cómo sabe entonces cuándo guardar y cuándo actualizar? La respuesta es sencilla, simplemente, no lo sabe, lo que ocurre es que este método save funciona mediante el patrón estrategia.

En estrategia tenemos una jerarquía de clases que implementan la estrategia, un contexto que utiliza la estrategia, y un cliente que establece la estrategia al contexto, pues bien, la estrategia son clases del Controlador que derivan de la clase SaveStrategy, nuestro contexto es el formulario que tiene el botón de guardado, y el cliente es otro formulario que establece la estrategia al formulario de guardado en base a la operación que se decida hacer. Todo esto lo vemos más claro gráficamente:

estrategia2

 

Y la representación del patrón:

strategy

 


Capa Controlador: Clases Utilidad

17/03/2008
En el Controlador en muchos casos hay clases que acceden a las operaciones de las fachadas, para estas lo único que se necesita es un acceso a las operaciones y no es necesario crear objetos de estas clases.

Para este caso echamos mano de clases con métodos static (estáticos) de forma que simplemente accedemos a estas clases de la forma NombreDeLaClase.nombreDelMétodo.

Utilizamos esto para las clases del Controlador que se encargan simplemente de acceder a las operaciones de las fachadas del Modelo que representan a los casos de uso, de esta forma tenemos clases que únicamente llaman a operaciones.

Un ejemplo de estas clases:

AddressController

Capas Vista-Controlador

17/03/2008

Hemos hablado en anteriores ocasiones de una serie de patrones de diseño que utilizamos para implementar la capa modelo de cyberHotel en las distintas iteraciones, vamos a hablar ahora un poco de los patrones de diseño comunes utilizados para la capa controlador, para la capa vista y para la interacción vista-controlador.

Dado que la aplicación se divide en tres capas siguiendo el patrón arquitectónico Modelo-Vista-Controlador, el Modelo debe de estar totalmente desacoplado del conjunto Vista-Controlador, pues si en un futuro se quieren definir distintas vistas (web, interfaz de PDA, …) no será necesario modificar para nada la lógica de negocio que se encuentra en el modelo. Es decir, tendremos un único modelo al que se puede acceder desde distintos tipos de vistas.

La separación entre Vista y Controlador no es tan acusada, pues cada vista suele llevar asociado su propio controlador dependiendo de la naturaleza de esta, ya que no sería lo mismo un controlador para un entorno de ventanas que para un conjunto de páginas web hechas con JSP por ejemplo, por eso no se reutiliza la capa Controlador. Si bien, la capa Controlador accede al modelo a través de la interfaz que proporcionan las fachadas y conoce determinados objetos como los POJO’s y las propias fachadas, la capa Vista no trabaja en absoluto en términos de objetos de la capa Modelo, por este motivo se utilizarán patrones que permitan establecer un protocolo de comunicación entre Controlador y Vista.

Dado que la Vista es una interfaz de ventanas desarrollada en Swing, tanto esta capa como el Controlador están desarrollados íntegramente en Java utilizando patrones de diseño que son comunes a todas las iteraciones.


Segunda Iteración: Capa Vista

17/03/2008

En esta segunda iteración al igual que en la anterior la capa superior o vista está implementada utilizando Java Swing y algunas librerías de SwingX de manera análoga a la primera iteración, pues lo que conseguimos con esta segunda etapa es incrementar la funcionalidad de cyberHotel para la cual necesitamos los formularios del entorno de ventanas que nos permitan realizar todas las funciones relativas a clientes, reservas, entradas, salidas, cargos y planning de habitaciones. Aquí mostramos algunos de estos formularios:

Particulares

particulares

Reservas Individuales

res_ind

Entradas Individuales

alsdjkasd

Cargos

owes2

Planning de Habitaciones

 

asdf


Segunda Iteración: Capa Modelo

09/03/2008

Habíamos dicho que cyberHotel seguía un modelo de desarrollo por iteraciones, generando en cada iteración una parte completa de la aplicación con las tres capas Modelo-Vista-Controlador. En la primera iteración se abarcaron los elementos de configuración del sistema, sin los cuales el resto de la aplicación no puede funcionar.

En la segunda iteración de cyberHotel se abarca todo lo relativo al sistema de reservas, esto es:

Gestión de clientes: Alta, modificación y borrado de los distintos tipos de clientes, en este caso, particulares, agencias y empresas.

Gestión de reservas: Alta, modificación y borrado de reservas individuales y reservas de grupo.

Gestión de entradas y salidas: Alta, modificación y borrado de entradas de grupo y entradas individuales. Formalización del fin de estancia mediante salidas individuales y salidas de grupo.

Gestión de cargos: Alta, modificación y borrado de los cargos asociados a clientes por habitación, tanto cargos de estancia como cargos adicionales (minibar, garage, teléfono, …).

Planning de Habitaciones: Consulta y modificación de los estados de ocupación y limpieza de las habitaciones.

Para el desarrollo de la capa modelo, el conjunto de patrones de arquitectura del sistema es análogo al de la primera iteración. Tenemos un conjunto de POJO’s cuyo acceso a datos es controlado por una serie de DAO’s, que quedan ocultos bajo una Fachada que en este caso engloba los casos de uso relacionados con el sistema de reservas.

Todo el sistema de asociación de DAO’s a la Fachada y el control de transacciones se realiza a través de Spring, que como vimos en la configuración, se hace de manera declarativa.


Ficheros de Mapeo

09/03/2008

En varias ocasiones hemos dicho que Hibernate utiliza unos ficheros de mapeo para relacionar tablas con objetos Java, hemos dicho también que estos ficheros están en formato XML y que tienen extensión .hbm.xml. Vamos a ver entonces uno de estos ficheros para entrar en detalle y tener al menos una idea de cómo funcionan.

En cyberHotel tenemos una clase que representa una dirección, por lo tanto podemos crear objetos dirección a partir de ella, esta clase dado que es un POJO tiene unos atributos y unos métodos get y set para acceder a los mismos.

Hemos llamado AddressTo a esta clase y addressTo.hbm.xml al fichero de mapeo, que como comentamos en otras ocasiones, se guarda en el mismo directorio de la clase de forma que está en su mismo paquete Java.

Esta es la estructura de addressTo.hbm.xml:

<?xml version=”1.0″ encoding=”UTF-8″?>

<!DOCTYPE hibernate-mapping PUBLIC
“-//Hibernate/Hibernate Mapping DTD 3.0//EN”
“http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd”>

<hibernate-mapping package=”gz.cyberbrain.cyberhotel.model.address.to“>

<class name=”AddressTo table=”direccion“>

<id name=”addressId column=”idDireccion type=”java.lang.Long unsaved-value=”null“>
<generator class=”increment“/>
</id>

<property name=”country column=”pais type=”string“/>
<property name=”province column=”provincia type=”string“/>
<property name=”locality column=”localidade type=”string“/>

</class>

<query name=”allAddresses“>from AddressTo</query>
<
query name=”findByCountry“>from AddressTo address where address.country = ?</query>
<query name=”findByProvince“>from AddressTo address where address.country = ? and address.province = ?</query>
<query name=”findByLocality“>from AddressTo address where address.country = ? and address.province = ? and address.locality = ?</query>

</hibernate-mapping>

hibernate-mapping: Todos los ficheros de mapeo comienzan y acaban con esta etiqueta. Al comienzo indicamos en el atributo package el paquete Java donde se encuentra la clase.

class: Esta etiqueta engloba a la clase con sus atributos, indicando siempre el mapeo a la tabla de la base de datos, así indicamos en name el nombre de la clase y en table el nombre de la tabla a la que representa este objeto. Dentro de class distinguimos la etiqueta id en la cual se indica en name el campo que representa al atributo clave en la clase y en column su nombre sobre la tabla, en type el tipo de datos Java, esto es común para el resto de atributos, pero en id además tenemos la propiedad generator que indica la naturaleza del campo clave que en este caso es increment con lo que estamos diciendo que es un identificador autogenerado por la base de datos, si fuese asignado por el usuario sería assigned. Para más detalle se puede consultar la documentación de Hibernate.

El resto de atributos se indican en las etiquetas property asociando igualmente nombre del campo de la clase con nombre de columna sobre la tabla y el tipo de datos Java.

query: Aquí se indican las consultas que se quieren hacer sobre este objeto, escritas en código HQL (el SQL de Hibernate).


Definición de los DAO y las Fachadas

07/03/2008

Si utilizamos los patrones DAO y Fachada para implementar la capa modelo, Spring nos provee un sistema para poder establecer estos correctamente sobre el fichero de configuración.

Para configurar los DAO debemos de hacer lo siguiente:

<!– ======= Definition of the DAOs =======–>

<bean id=”addressDao class=”gz.cyberbrain.cyberhotel.model.address.dao.AddressSpringDao“>

<property name=”sessionFactory“>
<ref bean=”factory“/>
</property>

</bean>

<bean id=”roomDao class=”gz.cyberbrain.cyberhotel.model.room.dao.RoomSpringDao“>

<property name=”sessionFactory“>
<ref bean=”factory“/>
</property>

</bean>

Es decir, tenemos una entrada para cada DAO en la que indicamos:

id: nombre para la entrada, debemos utilizar un nombre significativo.

class: ruta de paquetes donde se encuentra la clase con implementación del DAO, ponemos el nombre de la clase sin la extensión .java.

Tiene una propiedad sessionFactory, en ella indicamos la factoría explicada en el apartado anterior, de esta forma Spring sabe buscar para cada DAO los elementos de mapeo necesarios.

Para las fachadas la configuración es muy completa y en ella indicamos para los métodos que utilizamos, que aislamiento transaccional deseamos, pues es cada caso de uso implementado en la fachada el que se ejecuta en un entorno transaccional:

<!– ======= Definition of the Facades =======–>

<bean id=”configurationFacadeDelegate
class
=”org.springframework.transaction.interceptor.TransactionProxyFactoryBean“>

<property name=”transactionManager“>
<ref bean=”transactionManager“/>
</property>

<property name=”target“>
<ref local=”configurationTarget“/>
</property>

<property name=”transactionAttributes“>
<props>
<prop key=”show*“>readOnly</prop>
<prop key=”find*“>readOnly</prop>
<prop key=”maxPriceId“>readOnly</prop>
<prop key=”create*“>PROPAGATION_REQUIRED,ISOLATION_DEFAULT, -java.lang.Exception</prop>
<prop key=”update*“>PROPAGATION_REQUIRED,ISOLATION_DEFAULT, -java.lang.Exception</prop>
<prop key=”delete*“>PROPAGATION_REQUIRED,ISOLATION_DEFAULT, -java.lang.Exception</prop>
<prop key=”register*“>PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
<prop key=”change*“>PROPAGATION_REQUIRED,ISOLATION_DEFAULT, -java.lang.Exception</prop>
<prop key=”remove*“>PROPAGATION_REQUIRED,ISOLATION_DEFAULT, -java.lang.Exception</prop>
<prop key=”usersList“>readOnly</prop>
<
prop key=”rolesList“>readOnly</prop>

</props>
</property>

</bean>

<bean id=”configurationTarget class=”gz.cyberbrain.cyberhotel.model.configurationfacade.spring.ConfigurationSpringFacadeDelegate“>

<property name=”addressDao“>
<ref local=”addressDao“/>
</property>

<property name=”roomDao“>
<ref local=”roomDao“/>
</property>

</bean>

id: Indicamos un nombre significativo para la entrada.

class: Clase que actúa como proxy para las transacciones, la buscamos en la documentación de Spring.

Tiene una serie de propiedades, en transactionManager indicamos el manejador de transacciones explicado en el apartado anterior, en target indicamos una entrada donde estará definida la clase de la fachada así como todos los DAO que utilizará, en transactionAttributes indicamos todos los métodos que se usan en la fachada que implementan los casos de uso, para los cuales se pueden usar expresiones regulares como por ejemplo * para cualquier carácter, así si ponemos find* damos a entender a Spring que todos los métodos que empiezan por find tienen las propiedades transaccionales definidas, por ejemplo en el fichero vemos:

<prop key=”find*“>readOnly</prop>

Con ello estamos diciendo que todos los métodos que empiezan por find son de sólo lectura y por lo tanto no necesitan transaccionalidad.

También vemos por ejemplo:

<prop key=”delete*“>PROPAGATION_REQUIRED, ISOLATION_DEFAULT, -java.lang.Exception</prop>

Estamos indicando a Spring que los métodos que comienzan por delete utilizan el método de propagación PROPAGATION_REQUIRED y el aislamiento por defecto ISOLATION_DEFAULT y que cuando ocurre una excepción de la clase java.lang.Exception o cualquiera de sus subclases, se realice un rollback de la transacción.