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
Related
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.
Using the Spring Security Plugin for Grails:
Version: 2.0-RC2
For my controllers I am using the #Secured annotation.
Is there a way to access the method parameter from the spring security expression.#paramName does not work for me.
#Secured(['ROLE_ADMIN',"hasRole('ROLE_USER') && #permissionService.updateAllowed( #myInstance )"])
def update(Bug myInstance) {
The problem: myInstance is null!
Software I am using:
Grails: 2.4.3
Intellij 14
JDK 8
I didn't notice that you were doing this in a controller - there's no support for method args in annotated controllers. The reason for this is that in traditional Spring Security, the annotation is applied to Spring Beans and the bean becomes proxied, and the proxy does the security checks before calling the method and only calls the real method if the checks pass. That works well with Spring MVC controllers because they're regular Java classes, and also in Grails services because there isn't much added to services by Grails - they're really just regular Groovy classes that are auto-registered as Spring Beans, and by default are made transactional.
But controllers are weird. There is actually one SpringMVC controller in any Grails app, and it's internally created and used by Grails. It interacts with the rest of SpringMVC, and delegates to the controller that best matches the url mappings rule for the current request to do its work, and it uses that to create the ModelAndView that Spring expects. Additionally, to support databinding, there's an AST transform that runs on your code during compilation which creates a no-arg method for each method with args, and that is what is called from the Grails internal request handling code. It does databinding and type conversions, and calls the "real" method to handle the request.
The support in Spring Security for working with method args depends on debug information being available in the compiled code, and usually this is not available because it's rarely needed - javac connects everything for us at compile time and getting the value of a method arg from outside of the method isn't often needed. Grails does keep that debug info - that's why this works in a service - but it looks like the AST isn't. It might be possible to get that working, but I have no idea if it is or what would be involved, and to be honest it would likely be a lot of work for a feature that wouldn't be used a lot.
But you can rework the check to pass the params to the service and let it lookup the Bug instance and then do its check. You can access the params from the service, so there's no need to pass anything as args:
import org.springframework.web.context.request.RequestContextHolder
...
def params = RequestContextHolder.requestAttributes.params
I've managed to get a workaround for the problem described in the comments to the accepted answer. Use #this in SpEL expression:
#Secured('#securityService.userCanEditOffer(#this)')
def edit(int id) {..}
Then create such methods in your service:
def userCanEditOffer(WebSecurityExpressionRoot webSecurityExpressionRoot) {
UrlMappingInfo urlMappingInfo = Holders.applicationContext.grailsUrlMappingsHolder.match(webSecurityExpressionRoot.request.forwardURI.substring(webSecurityExpressionRoot.request.contextPath.length()))
userCanEditOffer(Integer.valueOf(urlMappingInfo.params.id))
}
#Transactional(readOnly = true)
def userCanEditOffer(Integer id) { .. }
Inside ulrMappingInfo.params you'll have id, action and controller!
With Grails, in UrlMappings.groovy, it seems I can specify the controller and action:
"/someURL" (controller: "Some", action: "someAction")
Or I can specify the view:
"/someURL" (view: "someView")
But I can't specify the controller, action, and view:
"/someURL" (controller: "Some", action: "someAction", view: "someView")
Instead, I have to specify the view in the controller. Is there a way to specify the view in the UrlMappings.groovy? Or is it just not possible?
To do this, you would first need to know that Grails uses Spring Web under the hood. Spring Web is the most complex web framework I can think of (capable of doing anything AFAIK). At any rate, the important thing to know is how Spring Web's Request Life Cycle works. You can get a feel for it by reading the documentation of the "DispatcherServlet" which is the main Servlet in Spring Web (and consequently in Grails):
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/DispatcherServlet.html
Here is a great article from the grails team about how grails is really just spring:
http://spring.io/blog/2010/06/08/spring-the-foundation-for-grails/
The important part relevant to this question are these two lines from that documentation:
Its view resolution strategy can be specified via a ViewResolver implementation, resolving symbolic view names into View objects. Default is InternalResourceViewResolver. ViewResolver objects can be added as beans in the application context, overriding the default ViewResolver. ViewResolvers can be given any bean name (they are tested by type).
If a View or view name is not supplied by the user, then the configured RequestToViewNameTranslator will translate the current request into a view name. The corresponding bean name is "viewNameTranslator"; the default is DefaultRequestToViewNameTranslator.
What you really want to do is create a customized ViewResolver or RequestToViewNameTranslator. The world is quite complex - if a View is supplied by the user in the Grails Controller explicitly, then you would want a ViewResolver. If instead a Map is returned (or some other custom object), then you want a RequestToViewNameTranslator.
Don't forget that grails has customized these two things already, to use the whole "convention over configuration" idea. So, you have to be careful in how you implement yours - I would recommend looking at the grails default implementations of these things.
Source for the GrailsViewResolver is here:
https://github.com/grails/grails-core/blob/master/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/servlet/view/GrailsViewResolver.java
Now, the real fun begins. The grails team didn't just provide custom implementations of spring web's default life cycle, they completely customized the dispatcher servlet as well. This means you need to be aware of how their universe differs from the spring universe (thus rendering many helpful spring forum questions irrelevant). Here is a link to the GrailsDispatcherServlet source code:
https://github.com/grails/grails-core/blob/master/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/servlet/GrailsDispatcherServlet.java
So if you managed to read this far, you can probably envision how to write a customized view resolver to return the view you want, but how to get access to the URL Mappings configuration data, so you can define views in there (however you see fit). The UrlMappings file relates to a spring bean, which will be available to autowire using the property "grailsUrlMappingsHolderBean" - see http://grails.org/doc/2.3.4/ref/Plug-ins/URL%20mappings.html
From that bean, you can access UrlMappings object, which you can get access to all UrlMapping definitions. See:
https://github.com/grails/grails-core/blob/master/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/mapping/UrlMappings.java
https://github.com/grails/grails-core/blob/master/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/mapping/UrlMapping.java
I'm not entirely convinced whether you can just throw anything in there, but since it's groovy I'd think you can. If not, you would have at least 2 options:
Create a new config file for just controller/view mappings your custom view/viewname resolver would use
Customize the URLMappings based on the grails source to interpret your custom configuration
A little off topic, here is an interesting article about removing the default mappings file and home-rolling your own:
http://mrhaki.blogspot.com/2011/12/grails-goodness-customize-url-format.html
Again, I found several posts online where people went down this path, and it ended up being too hard because of the numerous configuration pieces need to make it function. Thus, I highly recommend against it. To a certain degree, I agree with the response on this page (which is what you will see alot trying to do something out of the grails universe):
Bypassing grails view resolvers?
I'm using the resources.groovy to declare a service e.g.
aService(com.foo.OrganizationService)
so that I can tie aService to my controllers instead of using organizationService which could change in the future.
I've noticed that the OrganizationService doesn't get treated special like other services "not" declared in the resources.groovy. For example it doesn't get injected with grailsApplication, and likely a hibernateSession etc and other things I've not hit yet....
Now, I know I can manually wire in stuff to my service but I'd rather not have to maintain that...
Is there a special way to declare a service in the resources.groovy so that gets treated like another service that grails loads up?
TIA
The short answer to your question is "no".
Under the covers, Grails services are driven by some intelligent code that is referencing a specific location and expecting certain properties.
Viewing the source code (especially around the ServicesGrailsPlugin.groovy) is a good way to see the "magic" in how these are wired together.
Is there a reason you wouldn't want to use a bonafide Grails service to solve your problem? If you are expecting things like a grailsApplication, it seems like that use is pretty specific to Grails and would be a good candidate for porting over to a "true" Grails service.
Good luck!
So I've come full circle on this. This is a timing problem. Where services haven't been grails initialized yet.
Basically when you use the resources.groovy to do service wiring you run the risk of using a Service that might initialize itself e.g. afterPropertiesSet method or static initializers that use grails services (log, hibernate session, ..) that haven't been injected yet.
So... What I've turned to instead is to create my own BeanBuilder in a BootStrap.groovy file.
BeanBuilder builder = new BeanBuilder(grailsApplication.parentContext)
def bb = builder.beans {
LoginListener(com.foo.LoginListener) {
springSecurityService = ref("springSecurityService")
userService = ref("userService")
}
}
bb.registerBeans(grailsApplication.mainContext)
I'm currently working on a project with symfony 1.4 and Doctrine 1.2. I'm looking for a proper way to do logging from the model layer.
In some model classes I use the record hook postSave() to create a ZIP file using exec() (since PHP zip doesn't provide for storage method 'Stored'). To be sure that everythings works fine I check the return code and log an error if something goes wrong. My first naive approach was to do it like this:
if ($returnCode != 0) {
sfContext::getInstance()->getLogger()->debug(...);
}
As you know, this doesn't work so well because sfContext belongs to the controller layer and shouldn't be used from the model layer. My next try was to use the model's constructor to pass in an sfLogger instance, but this doesn't work due to Doctrine 1.2 reserving the constructor for internal use (Doctrine 1.2 Documentation).
I'm looking forward for your suggestions!
You can add a setLogger() method to your function, that gets a logger instance in a parameter, and sets it to an internal variable, like $this->logger. Later, when you need to log something, do it like if ($this->logger) { $this->logger->debug(...); }.