Grails and Groovy metaclass package name convention - grails

I would like to be able to place my metaclasses in the package groovy.runtime.metaclass according to the convention defined here using the delegating meta class. I have placed MyClassMetaClass in groovy.runtime.metaclass.mypackage. for the concrete class mypackage.MyClass{}. Unfortunately calls to MyClass{} are not intercepted by MyClassMetaClass{}. Perhaps this is related to how grails initializes..?

It is possible to use a delegating meta class in a grails project by changing BootStrap.groovy.
import org.codehaus.groovy.runtime.InvokerHelper
class BootStrap {
def init = { servletContext ->
def myMetaClass = new MyClassMetaClass(MyClass.class)
InvokerHelper.metaRegistry.setMetaClass(MyClass.class, myMetaClass)
}
def destroy = {
}
}
Ofcourse this is not the same as implementing delegating meta classes as mentioned in the question.

Related

GORM Trigger pattern in Grails 2.5.4

I want to implement the concept of Trigger objects in Grails for my domain classes. Grails allows me to define methods like beforeInsert() in my domain classes to handle insert, update and delete events, similar to how SQL databases have the concept of database triggers. But to separate concerns I'd like to move all of the trigger logic outside of the domain class.
Ideally I can simply define a static list of trigger classes in my domain class and then iterate through those in the beforeInsert() method. Sample code shown below.
static beforeInsertTriggers = [AccountNameTrigger, AccountDumpTrigger]
def beforeInsert() {
for (Class<Trigger> triggerClass : beforeInsertTriggers) {
triggerClass.newInstance().using(this).execute()
}
}
I've created a sample Grails 2.5.4 project on GitHub illustrating what I'm trying to do. But the problem is that the triggers literally are standalone islands of logic without the ability to autowire services. How can I better set up this Trigger pattern or something similar? So I may autowire services and other beans into the Trigger instances?
I am also trying to keep the design simple and readable.
Avoid cluttering the domain class with fields and properties that are not related to the data model. To me this means no autowired beans in the domain class.
Define the list of triggers using the trigger class names (or bean names, if need be). This may be overly idealistic, but hey...
For what it's worth, part of my inspiration also comes from how Salesforce implements triggers as distinct units of self-contained code.
Register your Triggers as Singleton Beans and there you can inject other services/beans. You can create your custom beans via resources.groovy.
Lets take the example of AccountDumpTrigger. Lets make a simple change to it:
package grails.domain.trigger.demo.triggers
import grails.domain.trigger.demo.Account
import org.codehaus.groovy.grails.commons.GrailsApplication
/**
* Created by marty on 6/25/16.
*/
class AccountDumpTrigger extends AbstractTrigger<Account> {
GrailsApplication grailsApplication
#Override
void execute() {
println grailsApplication.isInitialised()
println resource.dump()
}
}
And code in resources.groovy or in your plugin's doWithSpring closure:
accountDumpTrigger(grails.domain.trigger.demo.triggers.AccountDumpTrigger) { bean ->
bean.factoryMethod = 'getInstance'
/*
either refer each bean individually or you can use:
bean.autowire = "byType"
OR
bean.autowire = "byName"
*/
grailsApplication = ref("grailsApplication")
}
And inside your domain:
static beforeInsertTriggers = [AccountDumpTrigger]
def beforeInsert() {
for (Class<Trigger> triggerClass : beforeInsertTriggers) {
triggerClass.instance.using(this).execute()
}
}
And instead of writing your code inside beforeInsert you can also do the same by registering an implementation of AbstractPersistenceEventListener. This way you don't have to repeat your code. Also yo can move it to a parent class.

How to dynamically inject services into a grails custom artefact

So I created a plugin that introduces a custom artefact "Guard" (guard classes resides in: /grails-app/guards). Right now my plugin works by making the grailsApplication aware of the new artefact. So if I call grailsApplication.getGuardClasses() the behavior performs as expected.
My problem is that I want to be able to dynamically inject services into my guard classes, like so:
Class ExampleGuard {
def exampleService
}
I have found solutions on this website that give a static solution, that either goes of Holders, or the application context to get the bean by name. This is not what I want because I essentially want this to be autowired up to that when people use my plugin they can use dynamic injection of services in the guard classes.
UPDATE:
This is how I was accessing my Guard class.
def guard = grailsApplication.getArtefact("Guard","marketplace.TestGuard").newInstance()
Calling .newInstance() nullifies all fields on the class including the injected spring beans which is why injected classes will be null:
assert guard.sampleService == null
If your plugin discovers all of the Guard classes and adds them to the spring application context, those beans will automatically be subject to dependency injection. This is how all of the built in artifacts work and how artifacts provided by plugins work, Quartz Jobs for example.
EDIT:
As an exmaple...
class GuardsPlugin {
// ...
def doWithSpring = {
application.guardClasses.each { guardClass ->
"${guardClass.propertyName}"(guardClass.clazz) { bean ->
bean.autowire = "byName"
}
}
}
}
Then if you have a class like MySpecialGuard and you reference if from a controller (for example) with something like this...
class MyController {
def mySpecialGuard
def someAction() {
// mySpecialGuard should be DI'd into this
// controller and mySpecialGuard should itself
// have been subjected to DI
}
}
I hope that helps.

Accessing 'grailsApplication' from a plugin

How do I access "grailsApplication" of the main application from a plugin?
An example situation:
I have a class in a plugin, which needs to get a resource link from the main application, which is usually retrieved via "grailsApplication". How do I do that?
SOLUTION
In the plugin class you may simply specify:
import grails.util.Holders
Holders.getGrailsApplication()
In services, you should be able to add
def grailsApplication
and it will be injected into your service.
If your class is a spring bean, then you should be able to inject it inside the
def doWithSpring = { ->
myBean( org.whatever.BeanClass ) {
grailsApplication = ref( 'grailsApplication' )
}
}
block of the plugin main groovy file.
If it's neither of these, have you tried using the Holders class?
def grailsApplication = grails.util.Holders.getGrailsApplication()

Grails: How do I use a request scoped service in a tag library?

I'm relatively new to the Grails community, but I love already what the engine has to offer. Currently, I'm implementing a custom tag library in order to easily facilitate a standard design on our pages. However, I need a way of calling helper functions for utility purposes (e.g. filtering data) and to stash request level meta data about my tags (e.g. counters, parent/child relationships).
I have attempted two solutions:
First: I've created a service, set its scope to "request"
package myapp
class CustomTagService {
static scope = 'request'
def data = []
def add(localData) {
data.add(localData)
}
}
However, when I try to inject it in my tag library
package myapp
class MyTagLib {
def customTagService
def myTag = { attrs, body ->
customTagService.add(attrs)
}
}
The engine yells at me for referencing a request scope (after a long painful stacktrace): "Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton"
Second: I understand the pageScope is available to me inside of a tag closure, and I've exploited it before. However, for the structure I am wanting, encapsulation would be much preferred.
Please let me know if I am going down the wrong path on this. Any suggestions would be much appreciated!
You can't use scoped beans in singleton beans since the singleton beans (including taglibs) are created at startup when there's no request active. Instead use a scoped proxy (a bit complicated) or just get the bean from the ApplicationContext for each use at runtime when there is an active request:
package myapp
class MyTagLib {
def grailsApplication
def myTag = { attrs, body ->
customTagService.add(attrs)
}
private getCustomTagService() {
grailsApplication.mainContext.customTagService
}
}

How to access the g.-namespace in a Domain Class

I would like to make use of the g.message() functionality in the toString method of my domain class, but the g.-namespace is not accessible by default.
I doubt that a import g.* will do the trick.
I already know that I can use the messageSource functionality, but it would be nicer to use the same syntax as in the views.
You can use:
class MyDomain {
def someMethod() {
def g = ApplicationHolder.application.mainContext.getBean( 'org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib' )
return g.message(....)
}
}
or else you can get messageSource directly: ApplicationHolder.application.mainContext.getBean('messageSource')
Using g.render in a grails service has some hints how to use "g:" in a service. I have not tested this, but it should work mostly the same in domain classes, with one important exception: a domain class cannot use InitializingBean since it's not a bean residing in the application context.

Resources