How to dynamically inject services into a grails custom artefact - grails

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.

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.

programmatically injecting a different bean implementation

I have a requirement, my current project is with ejb3, jpa and jsf. I have a core development project and customer specific project. In the customer specific project, we planned to inherit the core classes and extend or override the core functionality. So we planned to create the customer specific classes with some customer prefix. So in the final war file, we will have the core class and all customer prefix classes. For example, if Authenticator is a core class and XXAuthenticator, YYAuthenticator are customer specific classes exist in the build. So, for example if i have a line of code in a bean like this:
#Inject Authenticator authenticator;
Can i programmatically and/or dynamically inject the inherited classes based on some logic like logged in user has a customer specific functionality.
what i am expecting is, i dont want to change the above line to inject, because it will be big change in every class. But expecting some kind of dynamic logic or configuration file to change the core class injection to customer specific class..
So finally with out touching the #Inject Authenticator authenticator; line. Can I inject the xxAuthenticator or YYAuthenticator through some logic? We dont have Spring in project technology stack.. So please suggest me with out spring only.. Thanks in advance
It sounds like your use case is more around Qualifiers. If a user follows a certain, you should be injecting different qualified versions of classes to use, no?
#Inject
private Instance<SomeService> someServiceInstance;
// later on...
SomeService someService = null;
if(someCondition) {
someService = someServiceInstance.select(new FooLiteral()).get();
}
else {
someService = someServiceInstance.select(new BarLiteral()).get();
}
Where FooLiteral and BarLiteral are annotation literals for #Foo and #Bar, which are qualifiers.
In CDI this is done with "producer methods".
It would look like this:
#ApplicationScoped
public class AuthenticatorProducer {
private Authenticator xxAuthenticator; // = ...
private Authenticator yyAuthenticator; // = ...
#Produces
public Authenticator getAuthenticator() {
if (someCondition) {
return xxAuthenticator;
} else {
return yyAuthenticator;
}
}
}
No need to change injection points and Authenticators don't have to be CDI beans themselves.

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
}
}

Grails and Groovy metaclass package name convention

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.

Is it possible to metaprogram named queries onto a grails domain class?

Is it possible to metaprogram named queries onto a grails domain class? If so, how?
Thanks
Domain classes have a namedQueries property that you can use to add your own named queries. If you want to do this using metaprogramming from within a plugin (rather than by editing the domain class directly), you should do it in the doWithDynamicMethods closure of the plugin's descriptor file.
Something like this should work:
class MyPlugin {
def doWithDynamicMethods = { applicationContext ->
application.domainClasses.each { domainClass ->
boolean domainClassFilter = domainClass as Boolean
if (domainClassFilter) {
domainClass.metaClass.static.myNamedQuery = {->
// implementation of your named query goes here. Here is an example implementation
// that returns all instances with status == 'ready'
String simpleClassName = domainClass.simpleName
domainClass.findAll("from $simpleClassName where status = ?", ['ready'])
}
}
}
}
}
This will add myNamedQuery to every domain class in the application that the plugin is installed in. If you only want to add it to some domain classes, then replace the value of domainClassFilter with a more appropriate test.

Resources