Es útil para la aplicación reaccionar a ciertos eventos que ocurren dentro de Hibernate. Esto permite la implementación de funcionalidades genéricas y la extensión de la funcionalidad de Hibernate.
La interfaz
Puede implementar el
Hay dos clases de interceptores: incluído en
Se especifica un interceptor incluído
Un interceptor incluido en
Interceptor
brinda callbacks desde la sesión a la aplicación, permitiendole a ésta última inspeccionar y/o manipular las propiedades de un objeto persistente antes de que sea guardado, actualizado, borrado o cargado. Un uso posible de esto es seguir la pista de la información de auditoría. Por ejemplo, el siguiente Interceptor
establece automáticamente el createTimestamp
cuando se crea unAuditable
y se actualiza la propiedad lastUpdateTimestamp
cuando se actualiza un Auditable
.Puede implementar el
Interceptor
directamente o extender el EmptyInterceptor
.package org.hibernate.test; import java.io.Serializable; import java.util.Date; import java.util.Iterator; import org.hibernate.EmptyInterceptor; import org.hibernate.Transaction; import org.hibernate.type.Type; public class AuditInterceptor extends EmptyInterceptor { private int updates; private int creates; private int loads; public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { // do nothing } public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { if ( entity instanceof Auditable ) { updates++; for ( int i=0; i < propertyNames.length; i++ ) { if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) { currentState[i] = new Date(); return true; } } } return false; } public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if ( entity instanceof Auditable ) { loads++; } return false; } public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if ( entity instanceof Auditable ) { creates++; for ( int i=0; i<propertyNames.length; i++ ) { if ( "createTimestamp".equals( propertyNames[i] ) ) { state[i] = new Date(); return true; } } } return false; } public void afterTransactionCompletion(Transaction tx) { if ( tx.wasCommitted() ) { System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads); } updates=0; creates=0; loads=0; } }
Hay dos clases de interceptores: incluído en
Session
- e incluído en SessionFactory
.Se especifica un interceptor incluído
Session
cuando se abre una sesión utilizando uno de los métodos SessionFactory.openSession() sobrecargados aceptando un Interceptor
.Session session = sf.openSession( new AuditInterceptor() );
Un interceptor incluido en
SessionFactory
se encuentra registrado con el objeto Configuration
antes de construir el SessionFactory
. En este caso, el interceptor proveido será aplicado a todas las sesiones abiertas desde ese SessionFactory
; a menos de que se abra una sesión especificando explícitamente el interceptor a utilizar. Los interceptores SessionFactory
incluidos deben ser a prueba de hilos. Asegúrese de no almacenar un estado especifico a la sesión ya que múltiples sesiones utilizarán este interceptor potencialmente de manera concurrente.new Configuration().setInterceptor( new AuditInterceptor() );
Si tiene que reaccionar a eventos particulares en su capa de persistencia, también puede utilizar la arquitectura de eventos de Hibernate3. El sistema de eventos se puede ser utilizar además de o como un remplazo para los interceptores.
Todos los métodos de la interfaz
Los escuchas se deben considerar como singletons. Esto significa que son compartidos entre las peticiones y por lo tanto, no deben guardar ningún estado como variables de instancia.
Un escucha personalizado implementa la interfaz apropiada para el evento que quiere procesar y/o extender una de las clases base de conveniencia (o incluso los escuchas de eventos predeterminados utilizados por Hibernate de fábrica al declararlos como no-finales para este propósito). Los escuchas personalizados pueden ser registrados programáticamente a través del objeto
También necesita una entrada de configuración diciéndole a Hibernate que utilice el oyente en vez del oyente por defecto:
En cambio, puede registrarlo programáticamente:
Los oyentes registrados declarativamente no pueden compartir instancias. Si se utiliza el mismo nombre de clase en múltiples elementos
¿Por qué implementar una interfaz y definir el tipo específico durante la configuración? Una implementación de escucha podría implementar múltiples interfaces de escucha de eventos. Teniendo el tipo definido adicionalmente durante la registración hace más fácil activar o desactivar escuchas personalizados durante la configuración.
Todos los métodos de la interfaz
Session
se correlacionan con un evento. Tiene un LoadEvent
, unFlushEvent
, etc. Consulte el DTD del archivo de configuración XML o el paquete org.hibernate.event
para ver la lista completa de los tipos de eventos definidos. Cuando se realiza una petición de uno de estos métodos, la Session
de Hibernate genera un evento apropiado y se lo pasa al escucha (listener) de eventos configurado para ese tipo. Tal como vienen, estos escuchas implementan el mismo procesamiento en aquellos métodos donde siempre resultan . Sin embargo, usted es libre de implementar una personalización de una de las interfaces escuchas (por ejemplo, el LoadEvent
es procesado por la implementación registrada de la interfaz LoadEventListener
), en cuyo caso su implementación sería responsable de procesar cualquier petición load()
realizada a la Session
.Los escuchas se deben considerar como singletons. Esto significa que son compartidos entre las peticiones y por lo tanto, no deben guardar ningún estado como variables de instancia.
Un escucha personalizado implementa la interfaz apropiada para el evento que quiere procesar y/o extender una de las clases base de conveniencia (o incluso los escuchas de eventos predeterminados utilizados por Hibernate de fábrica al declararlos como no-finales para este propósito). Los escuchas personalizados pueden ser registrados programáticamente a través del objeto
Configuration
, o especificados en el XML de configuración de Hibernate. No se soporta la configuración declarativa a través del archivo de propiedades. Este es un ejemplo de un escucha personalizado de eventos load:public class MyLoadListener implements LoadEventListener { // this is the single method defined by the LoadEventListener interface public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException { if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) { throw MySecurityException("Unauthorized access"); } } }
También necesita una entrada de configuración diciéndole a Hibernate que utilice el oyente en vez del oyente por defecto:
<hibernate-configuration> <session-factory> ... <event type="load"> <listener class="com.eg.MyLoadListener"/> <listener class="org.hibernate.event.def.DefaultLoadEventListener"/> </event> </session-factory> </hibernate-configuration >
En cambio, puede registrarlo programáticamente:
Configuration cfg = new Configuration(); LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() }; cfg.EventListeners().setLoadEventListeners(stack);
Los oyentes registrados declarativamente no pueden compartir instancias. Si se utiliza el mismo nombre de clase en múltiples elementos
, cada referencia resultará en una instancia separada de esa clase. Si necesita compartir instancias de oyentes entre tipos de oyentes debe usar el enfoque de registración programática.¿Por qué implementar una interfaz y definir el tipo específico durante la configuración? Una implementación de escucha podría implementar múltiples interfaces de escucha de eventos. Teniendo el tipo definido adicionalmente durante la registración hace más fácil activar o desactivar escuchas personalizados durante la configuración.
Usualmente, la seguridad declarativa en aplicaciones Hibernate se administra en una capa de fachada de sesión. Hibernate3 permite que ciertas acciones se permitan por medio de JACC y las autoriza por medio de JAAS. Esta es una funcionalidad opcional construída encima de la arquitectura de eventos.
Primero, tiene que configurar los oyentes de eventos apropiados, para habilitar la utilización de autorización JAAS.
A continuación, todavía en
Los nombres de los roles son comprendidos por su proveedor de JACC.
Primero, tiene que configurar los oyentes de eventos apropiados, para habilitar la utilización de autorización JAAS.
<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/> <listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/> <listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/> <listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>
A continuación, todavía en
hibernate.cfg.xml
, enlace los permisos a los roles:<grant role="admin" entity-name="User" actions="insert,update,read"/> <grant role="su" entity-name="User" actions="*"/>
Los nombres de los roles son comprendidos por su proveedor de JACC.
No hay comentarios.:
Publicar un comentario