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.


Definición de la SessionFactory

05/03/2008

La SessionFactory es aquella que se encarga de decir al sistema, donde se encuentran todos los ficheros de mapeo de Hibernate, el dialecto de Hibernate a utilizar (varía según el gestor de base de datos, pero no para nosotros, sino para el sistema, nosotros siempre utilizamos HQL), y también va a ser la encargada de asociar los DAO dentro de las Fachadas. Incluye lo siguiente:

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

<bean id=”factory class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean“>

<property name=”mappingResources“>

<list>

<value>gz/cyberbrain/cyberhotel/model/room/to/roomTo.hbm.xml</value>
<value>gz/cyberbrain/cyberhotel/model/client/to/clientTo.hbm.xml</value>
<value>gz/cyberbrain/cyberhotel/model/address/to/addressTo.hbm.xml</value>

</list>

</property>

<property name=”hibernateProperties“>
<
props>

<prop key=”hibernate.dialect“>org.hibernate.dialect.SQLServerDialect</prop>
<prop key=”hibernate.show_sql“>false</prop>

</props>
</property>

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

</bean>

<!– Transaction manager for a single Hibernate SessionFactory (alternative to JTA) –>

<bean id=”transactionManager class=”org.springframework.orm.hibernate3.HibernateTransactionManager“>

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

</bean>

factory: Aquí se indican en una lista todos los ficheros de mapeo con su ruta completa desde la raíz. Se indica cual es la clase de Spring que realiza el trabajo de la factoría, para saber cual utilizar es necesario acudir a la documentación de Spring.

hibernateProperties: Tiene dos propiedades a destacar que son hibernate.dialect el dialecto que usará Hibernate para comunicarse con la base de datos, viene en la documentación de hibernate, y la propiedad hibernate.show_sql que si ponemos a true nos muestra por consola todas las sentencias SQL que hibernate ejecutó sobre la base de datos, es muy útil a la hora de depurar.

dataSource: aquí indicamos el datasource del que hablamos en el apartado anterior.

transactionManager: Se indica la clase que actúa como manejador de transacciones para Spring sobre Hibernate, es necesario mirar en la documentación. En la propiedad sessionManager indicamos la factoría que definimos antes.


Definición del DataSource

05/03/2008

Lo primero que suele aparecer en el fichero de configuración es un apartado en el cual definimos el DataSource, esto es, el origen de datos, y en él indicamos lo siguiente:

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

<bean id=”dataSource
class
=”org.apache.commons.dbcp.BasicDataSource
destroy-method
=”close“>

<property name=”driverClassName“>
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>

<property name=”url“> <value>jdbc:jtds:sqlserver://localhost:4492/hotel</value>
</property>

<property name=”username“>
<value>cyberhotel</value>
</property>

<property name=”password“>
<value>cyberhotel</value>
</property>

<property name=”defaultAutoCommit“>
<value>false</value>
</property>

</bean>

driverClassName: Es el driver utilizado para conectar con la base de datos, en este caso utilizamos Sql Server 2005, existe un driver proporcionado por Microsoft pero suele dar problemas con hibernate, por lo que se suele utilizar el driver JTDS para este gestor de base de datos.

url: Es una ruta que comienza con una firma determinada, en este caso jdbc:jtds:sqlserver:, esta firma nos viene indicada en la documentación del driver. A continuación de la firma se indica la ruta de la base de datos a utilizar, en este caso está en localhost (máquina local) en el puerto 4492 y la base de datos se llama hotel por este motivo escribimos //localhost:4492/hotel.

username: Indicamos el nombre de usuario para la base de datos.

password: Indicamos la contraseña para ese usuario en la base de datos.

defaultAutoCommit: Indicamos que se hagan los commit de las transacciones automáticamente o no. Se suele dejar a false pues como veremos más adelante en las transacciones se pueden dar excepciones, en cuyo caso es necesario un rollback.


Archivo de configuración

05/03/2008

En apartados anteriores vimos que cyberHotel está construído utilizando una serie de tecnologías basadas en Java que se utilizaban para facilitar diversas tareas. El manejo de la base de datos se simplificaba mediante Hibernate para no tener que insertar sentencias SQL en el código Java, pero en Hibernate el manejo del sistema de transacciones suele ser engorroso y repetitivo de forma que en nuestro código hay que introducir muchas instrucciones que se repiten una y otra vez y que además cuesta leer, para simplificar esto utilizábamos Spring, que nos permite realizar todo el manejo transaccional desde un fichero de configuración de forma que no hay que introducir nada en nuestro código, tan sólo había que hacer que los DAO heredasen todos de una clase de Spring llamada HibernateDaoSupport de forma que las instrucciones que se lanzan son instrucciones de Hibernate pero filtradas a través de Spring. Todo esto está muy bien pero si no hay que meter código de Spring en Java para las transacciones… ¿cómo puede funcionar? Pues bien, la respuesta a esta pregunta está en el fichero de configuración, que habíamos dicho que se solía llamar applicationContext.xml. Este fichero es un fichero de configuración en formato XML, y en él se recoge casi toda la información que la aplicación necesita para funcionar utilizando Spring e Hibernate, (decimos casi, pues debemos recordar que el mapeo de Hibernate se realiza en los ficheros .hbm.xml que se situaban en el mismo paquete y directorio que cada uno de los POJO’s que se asocian a las tablas de la base de datos).

Este fichero de configuración se guarda en el directorio raíz de la aplicación, aquel del que parten todos los directorios que estarán contenidos en los paquetes Java.

En los siguientes comentarios vamos a explicar como se realiza la configuración de este fichero con detalle, explicando cada uno de los apartados, necesarios para el correcto funcionamiento de la aplicación.


cyberHotel con vistas al swing

19/02/2008

 

Para ver por fin la capa superior de cyberHotel mostramos a continuación una serie de capturas de pantalla de la interfaz gráfica de usuario desarrollada con Swing, las librerías más populares de Java para entornos de escritorio y utilizando también componentes de SwingX.

Algunas pantallas que podemos ver en la primera iteración de cyberHotel son las siguientes:

Direcciones

direcciones

Bancos

bancos

Habitaciones

habitaciones

Tarifas

tarifas

Temporadas

temporadas