I have an event controller with a populate() method which adds events from a JSON link to my database. I want this to occur on startup of my server.
I've tried various things in my Bootstrap file. Such as:
def event = new EventController.populate()
You really should move that code into a service and out of your controller. This gives you a lot more options, including injecting the service into your Bootstrap.groovy and calling the method on startup of the application.
That's a much more proper Grails solution.
Related
I am overwriting the redirect method of every controller I wrote. I did that because
a) I need to set some variables before the redirect is actually executed
b) I want to do that globally because it is the same code for every controller and I want to be DRY
I did this in the bootstrap because it is executed when the server starts.
Code:
grailsApplication.controllerClasses.each() { controllerClass ->
if (controllerClass.fullName.startsWith("my.package")){
def oldRedirect = controllerClass.metaClass.pickMethod("redirect", [Map] as Class[])
controllerClass.metaClass.redirect = { Map args ->
// pre-redirect logic
args.put("some", "property")
oldRedirect.invoke delegate, args
// post-redirect logic
}
}
}
Here is the problem:
When I am developing, I use the reloading feature / just in time compiler which recompiles the file without the need to restart the server. In this case the controller is rebuilt and as a result the overwritten redirect method is lost.
Here is the question:
Is there a callback / another way to find out when a class is recompiled in runtime? I would love to check if a controller was rebuild and then overwrite the redirect method again!
Yes, break this functionality out into a plugin and you can then observe reloading of classes and re-apply your changes. The documentation goes into great detail on participating in auto reload events.
This would be the cleanest, and most proper way to accomplish what you are looking to do.
I add two annotations on the service method, after compiled, I found the method were compiled to a new class file, and I decompiled the generated class files and found the #CompileStatic were not work as wished.
Is is right or a bug of grails?
class FoobarService {
#grails.transaction.Transactional
#groovy.transform.CompileStatic
void foobar() {
....
}
}
The grails.transaction.Transactional annotation is a replacement for the traditional Spring org.springframework.transaction.annotation.Transactional annotation. It has the same attributes and features and works essentially the same, but it avoids an unfortunate side effect of using the Spring annotation.
The Spring annotation triggers the creation of a runtime proxy of the annotated class. Spring uses CGLIB to create a subclass of the target class (typically a Grails service) and an instance of the CGLIB proxy is registered as the Spring bean instead of registering a service instance directly. The proxy gets an instance of your service as a data variable.
Each method call is intercepted in the proxy, where it does whatever checks and/or setup is required based on the transaction settings, e.g. joining an existing transaction, creating a new one, throwing an exception because one isn't already running, etc. Once that's done, your real method is called.
But if you call another annotated method with different settings (e.g. the first method uses the default settings from #Transactional but the second should be run in a new separate transaction because it's annotated with #Transactional(propagation=REQUIRES_NEW)) then the second annotations settings will be ignored because you're "underneath" the proxy , inside the real instance of your service that the proxy is intercepting calls to. But it can't intercept direct calls like that.
The traditional workaround for this is to avoid direct calls and instead make the call on the proxy. You can't (at least not conveniently) inject the service bean into itself, but you can access the application context and access it that way. So the call that you would need in that situation would be something like
ctx.getBean('myService').otherMethod()
which works, but is pretty ugly.
The new Grails annotation works differently though. It triggers a reworking of the code via an AST transformation during compilation. A second method is created for each annotated method, and the code from the real method is moved inside there, in a GrailsTransactionTemplate that runs the code using the annotations settings. Once there, the code runs with the required transaction settings, but since every method is rewritten in this way, you don't have to worry about the proxy and where you're calling the methods from - there is no proxy.
Unfortunately there's a side effect that you're seeing - apparently the transformation happens in a way that isn't preserving the #CompileStatic annotation, so the code runs in dynamic mode. Sounds like a bug to me.
I am a newbie to Grails and still learning the ropes! The application that i work on uses services.
My task is to add a new method in one of the services and have it get called from clients.
This new method is going to be pretty long and i don't want all the method body to be in the service class.
I would like to add another method in a place other than this service to do all the calculations for this new method.
Which is the best place to add a method like that? Should i add a new domain? Or just a controller class?
I don't want any of the information in the new method to be saved to database.
A sample code look like this:
class MyService {
String getDomainName(String ID) {
return domainNameGenerator(ID);
}
}
Now i want to put the domainNameGenerator method into another place.
Place your standalone code in src/groovy or src/java depending on the actual language of your code, but there's nothing wrong with putting code in the service class itself. If the new class and the service package is the same, you don't even have to add an import.
I'm having trouble getting the Grails EHCache Plugin to cache service methods. Here is my setup:
Grails 2.4.2, JDK 1.7
BuildConfig.groovy compile ":cache-ehcache:1.0.4"
Config.groovy defines the following cache named "cache"
grails.cache.config = {
cache {
name 'cache'
timeToLiveSeconds 60
}
}
The following controller method properly caches. I have tested by setting a breakpoint in the method, and it only is hit the first time, until the cache expires.
#Cacheable('cache')
def index() {
render "index-$params.id"
}
I can check the keys in the cache with:
grailsCacheManager.getCache('cache').getNativeCache().getKeys()
and see the value:
localhost:GET:/grails-cache-test/cache/index?id=34
So far so good.
The following service method exists:
#Cacheable('cache')
public method1(id) {
"method1+$id"
}
I set a break point in here, and this method is always called, regardless of the #Cacheable annotation. I've tried setting the value and key annotation attributes manually, and no change. I test calling this method from a non-cached controller method, as well as directly from the console plugin. When I get the keys in the service method I see that there are no keys set.
I've looked through examples in the official documentation, code samples online, github, a book I have, everything looks good, so I'm not sure where the problem lies.
Any ideas on why this service method does not cache the value? Thanks!
UPDATE 1
I've been digging into the grails cache-1.1.8 plugin (as well as the associated cache-ehcache-1.0.4 plugin), and believe I've found something helpful. In PageFragmentCachingFilter.doFilter() there are calls to check the controller's annotations - but nothing to check the service. It appears that as a result, the service annotations are never honored. There is a lot of documentation that mentions service methods, so I don't know if there is something elsewhere that handles this, or if it's a less common use case compared to controller methods.
UPDATE 2
It appears that Controllers and Services are handled separately. In CacheAspectSupport.execute() there is a for() loop that will call cachePutRequest.apply(result.get());, which will actually add the entry to the cache. Unfortunately after the entry is added to the request, it is not immediately available to be retrieved. The underlying put() code is part of Spring Source, so at this point I'm not sure if it's a grails plugin issue or a Spring Source issue.
I have created a JIRA issue for this plugin GPCACHEEHCACHE-16
ZF2 question here.
I like the event driven stuff in ZF2.
Here's my goal.
I want to start the session, using a database table, and I want to be thrown to the error/error template if for some reason there is no database connection.
Here are some ways I thought about doing this. I could attach to the application 'route' event and start the session right before the route matching happens, or right after. There are no TRY catches though, in the Mvc\Application.php file so I don't think this is the place to do it.
There IS however a try catch block around the CONTROLLER's dispatch method being called. And I noticed that the controller has it's own internal 'dispatch' event it triggers.
So the other possibility is that I should attach to this internal controller dispatch event and setup my session THEN before the controller's action methods actually execute, and thus before they NEED the session.
So, how can I attach to this internal 'dispatch' method? Or how else can I make it so that any database connection exceptions go to my nice Exception page rather than getting spewed out as a normal php error without any exception handling???
There is no more init() method on the controller because this is functionality events are supposed to provide.
Thank you for the help.
FYI : I tried attaching to different events, such as 'bootstrap', 'loadmodules', 'loadmodules.post'. All I did in the attached method was throw an exception to see if I would end up in the nice error page I have but I didn't have any luck. I ended up debugging it and found this internal controller 'dispatch' method. The controllers get their own internal event manager. At least that's what I gather from my debugging. I might be wrong so correct me please!