Interceptores y eventos
Frecuentemente es útil para la aplicación reaccionar a ciertos eventos que ocurran dentro de Hibernate.
Esto permite la implementación de ciertos tipos de funcionalidade genérica, y extensión de la
funcionalidad de Hibernate.
Interceptores
La interface Interceptor provee callbacks desde la sesión a la aplicación
permitiendo a ésta última inspeccionar y/o manipular las propiedades de un objeto persistente
antes que sea salvado, actualizado, borrado o cargado. Un uso posible de esto es seguir la pista
de información de auditoría. Por ejemplo, el siguiente Interceptor establece
automáticamente el createTimestamp cuando un Auditable es
creado y actualiza la propiedad lastUpdateTimestamp cuando un
Auditable es acutalizado.
El interceptor podría ser especificado cuando se crea la sesión:
Puedes además establecer un interceptor a un nivel global, usando la Configuration:
Sistema de eventos
Si tienes que reaccionar a eventos particulares en tu capa de persistencia, puedes también la
arquitectura de eventos de Hibernate3. El sistema de eventos puede ser usado
en adición o como un remplazo a los interceptores.
Esencialmente todos los métodos de la interface Session se correlacionan
con un evento. Tienes un LoadEvent, un FlushEvent, etc
(consulta el DTD del fichero de configuración XML o el paquete org.hibernate.event
para la lista completa de tipos de evento definidos). Cuando se hace una petición de uno de estos
métodos, la Session de Hibernate genera un evento apropiado y se lo pasa
al oyente (listener) de eventos configurado para ese tipo. De fábrica, estos oyentes implementan
el mismo procesamiento en los que siempre resultan aquellos métodos. Sin embargo, eres libre de
implementar una personalización de una de las interfaces oyentes (es decir, el
LoadEvent es procesado por la implementación registrada de la interface
LoadEventListener), en cuyo caso su implementación sería responsable
de procesar cualquier petición load() hecha a la Session.
Los oyentes deben ser considerados efectivamente singletons; quiere decir, que son compartidos
entre las peticiones, y por lo tanto no guardan ningún estado en variables de instancia.
Un oyente personalizado debe implementar la interface apropiada para el evento que quiere procesar y/o
extender una de las clases base de conveniencia (o incluso los oyentes de eventos por defecto
usados por Hibernate de fábrica al ser éstos declarados non-final para este propósito). Los
oyentes personalizados pueden ser registrados programáticamente a través del objeto
Configuration, o especificados en el XML de configuración de Hibernate
(la declaración declarativa a través del fichero de propiedades no está soportada).
He aquí un ejemplo de un oyente personalizado de eventos load:
Necesitas además una entrada de configuración diciéndole a Hibernate que use el
oyente en vez del oyente por defecto:
...
]]>
En cambio, puedes registrarlo programáticamente:
Los oyentes registrados declarativamente no pueden compartir instancias. Si el mismo nombre de clase es
usado en múltiples elementos <listener/>, cada referencia resultará en una instancia
separada de esa clase. Si necesitas la capacidad de compartir instancias de oyentes entre tipos de oyente
debes usar el enfoque de registración programática.
¿Por qué implementar una interface y definir el tipo espcífico durante la configuración?
Bueno, una implementación de oyente podría implementar múltiples interfaces de oyente
de eventos. Teniendo el tipo definido adicionalmente durante la registración lo hace más
fácil para activar o desactivar oyentes personalizados durante la configuración.
Seguridad declarativa de Hibernate
Usualmente, la seguridad declarativa en aplicaciones Hibernate es manejada en una capa de fachada
de sesión. Ahora, Hibernate3 permite que ciertas acciones sean permitidas vía JACC, y autorizadas vía
JAAS. Esta en una funcionalidad opcional construída encima de la arquitectura de eventos.
Primero, debes configurar los oyentes de eventos apropiados, para habilitar el uso de
autorización JAAS.
]]>
Seguido, aún en hibernate.cfg.xml, liga los permisos a roles:
]]>
Los nombres de role son los roles entendidos por tu proveedor de JACC.