2009-12-24 19 views
7

Estoy escribiendo un plugin de grills y necesito engancharme en el método save() del dominio para hacer un poco de lógica después del guardado. Necesito hacer esto en múltiples clases de dominio. Estoy tratando de evitar eventos de hibernación en los casos en que un usuario de un complemento no esté utilizando Hibernate con GORM.Enlazando en Grails Objeto save()

He intentado muchas cosas, pero a continuación es lo que creo que debería haber tenido la mejor oportunidad de trabajar. En todos los casos grailsSave es null. ¿Cómo puedo hacer esto?

def doWithDynamicMethods = { ctx -> 
    application.domainClasses.each { dc -> 
     def grailsSave = dc.metaClass.pickMethod('save', [Map] as Class[]) 

     domainClass.metaClass.save = { Map params -> 
     grailsSave.invoke(delegate, [params] as Object[]) 
     println "Saved object, now do my thing" 
     //... 
     } 
    } 
} 

Tengo el siguiente puesto en mi * Clase Plugin.groovy:

def dependsOn = [domainClass: '1.1 > *', hibernate: '1.1 > *'] 
def loadAfter = ['hibernate'] 

Respuesta

6

No pude obtener con éxito una referencia a los métodos save() durante la inicialización del complemento/aplicación; No sé por qué. En cambio, decidí crear un oyente para los eventos de hibernación después de insertar, actualizar y eliminar. Esta post de Sean Hartsock con respecto al plugin Audit Logging fue una guía perfecta para hacerlo.

Aquí es la esencia del Oyente:

class MyListener implements PostInsertEventListener, PostUpdateEventListener, PostDeleteEventListener, Initializable { 

     public void onPostInsert(final PostInsertEvent event) { 
      // logic after insert 
      return 
     } 

     public void onPostUpdate(final PostUpdateEvent event) { 
      // logic after update 
      return 
     } 

     public void onPostDelete(final PostDeleteEvent event) { 
      // logic after delete 
      return 
     } 


     public void initialize(final Configuration config) { 
      return 
     } 
    } 

Luego, en el GrailsPlugin.groovy *:

def doWithApplicationContext = { applicationContext -> 

    // add the event listeners for reindexing on change 
    def listeners = applicationContext.sessionFactory.eventListeners 
    def listener = new MyListener() 

    ['postInsert', 'postUpdate', 'postDelete'].each({ 
     addEventTypeListener(listeners, listener, it) 
    }) 

} 


// copied from http://hartsock.blogspot.com/2008/04/inside-hibernate-events-and-audit.html 
private addEventTypeListener(listeners, listener, type) { 
    def typeProperty = "${type}EventListeners" 
    def typeListeners = listeners."${typeProperty}" 

    def expandedTypeListeners = new Object[typeListeners.length + 1] 
    System.arraycopy(typeListeners, 0, expandedTypeListeners, 0, typeListeners.length) 
    expandedTypeListeners[-1] = listener 

    listeners."${typeProperty}" = expandedTypeListeners 
} 

bastante simple al final del día ...

+0

Shawn y su plugin Audit Logging Rocks. –

+0

¡Gracias por compartir! He estado en perezoso para buscar esto por mi cuenta. – Kimble

1

¿No esta mejor se añadirá a la clase de servicio que posee la unidad de trabajo? Ahí es donde el idioma usual de Spring/Grails tendría tal lógica. No necesita modificar el guardado en absoluto.

+0

Aunque estoy construyendo un pluging para ser usado por otros. Mi lógica bien podría estar en un servicio, pero el punto que necesita disparar es el de guardar. Gracias – mbrevoort

+0

La idea de delegar un montón de lógica directamente relacionada con el dominio a otro nivel es una de las mayores molestias en Spring, y es por eso que Java tiene una reputación de fetichizar la complejidad. –

+0

¿Cómo se puede saber un objeto de dominio individual cuando forma parte de una unidad de trabajo mayor y cuando no lo es? – duffymo

2

Hay tres versiones diferentes de Save añadido a la metaclase,

save(Map) 
save(Boolean) 
save() 

Cuál está llamando en su prueba? Necesitarás agregar tu código a cada uno.

Otra cosa a comprobar es si su plugin se ejecuta después de que el plug-in de hibernación que se suma a los tres métodos a los MetaClass

aplausos

Lee

+0

Gracias Lee, Creo que estoy teniendo problemas forzando el complemento a cargar después de la hibernación. Si ejecuto doWithDynamicMethods todos los intentos de llamar a pickMethod son nulos. Si corro en la consola de Grails, no son nulos. Tengo esto en mi plugin pero no tuve suerte: def dependsOn = [domainClass: '1.1> *', hibernate: '1.1> *'] def loadAfter = ['hibernate'] – mbrevoort

+0

Hmmm loadAfter es el que desea - ¿necesita ser carga estáticaAfter = ['hibernate'] – leebutts

+0

static tampoco funcionó. Extraño Acabo de notar que Robert Fischer había intentado hacer cosas similares con save() en su plugin GORM Labs pero que había comentado el código en versiones anteriores y que no existe en el más reciente. ¿Alguna idea de cómo abordar esto de manera diferente? – mbrevoort

2

echar un vistazo a la Falcone Util plugin. Este complemento le permite conectar eventos Hibernate (consulte la documentación en la parte inferior de la página). No sé si esto es exactamente lo que quieres, pero es posible que obtengas algunos consejos.

Ps! No creo que el complemento funcione aún con Grails 1.2.

+0

Gracias amigo, ese complemento se ve excelente. Sería increíble si este tipo de capacidad de eventos estuviera disponible en el núcleo. – mbrevoort

2

Este es un problema de optimización prematura: las versiones anteriores de Groovy penalizaban seriamente el maquinado de MetaClass, por lo que GORM no agrega toda su magia hasta que detecta la necesidad de hacerlo.

La solución más fácil es hacer que su complemento dependa de GORM Labs (lo soluciono allí). La solución alternativa es activar MethodMissing manualmente (lo que duplicaría el trabajo que hice). Consulte la documentación de GORM Labs para obtener detalles sobre cómo lo logré.

1

Los métodos GORM adicionales se inicializan con pereza en la primera llamada a cualquiera de ellos. inicializarlas en doWithDynamicMethods simplemente llamar a uno de los métodos estáticos en la clase de dominio (ES):

def doWithDynamicMethods = { ctx -> 

    application.domainClasses.each { dc -> 

     // call any static method to initialize dynamic gorm methods 
     dc.clazz.count() 

     def grailsSave = dc.metaClass.pickMethod('save', [Map] as Class[]) 
     //... 
    } 
} 

Su método Save() estará disponible ahora. Como esto se llama al inicio, una sola cuenta no debería ser un gran problema.

Cuestiones relacionadas