In Grails (at least up to the current version 2.2), taglibs are closures. For certain taglib closures, I'd like to use some "around" type advice / wrap the closure in an interceptor.
To put it another way, let's say there is this taglib straight from the Grails doc:
class SimpleTagLib {
def emoticon = { attrs, body ->
out << body() << (attrs.happy == 'true' ? " :-)" : " :-(")
}
}
Now, without modifying the taglib code, I'd like to time how long "emoticon" takes to execute.
Spring AOP (and all other AOP I can find) only seems to work on Java methods - and taglibs are always based on closures. An "around" pointcut would be perfect for this, but I can't figure out how to make it work.
I've written something similar which I put as a public closure in a category I then mixin to services:
// TimingCategory.groovy
/**
* Provides common AOP timing functionality to Services which mixin this category.
*/
class TimingCategory {
static Closure timer = { String label = "The call", Closure closure ->
Long start = System.currentTimeMillis()
def result = closure.call()
Long end = System.currentTimeMillis()
Long duration = end - start
log.warn "${label} took ${duration} ms"
return result
}
}
In other classes, you just reference the timer closure as such:
#Mixin(TimingCategory)
public class WhateverService {
public String doSomeWork() {
timer "Doing a lot of work", {
1000.times { doSomething() }
someMethodWithAStringReturnValue()
}
}
}
That will give you log output of "WARN: Doing a lot of work took nn ms" and return the value of the inner closure as the return value of the doSomeWork method.
For your taglib instance, just wrap the out << ... in the
timer "Writing an emoticon", {
// your code
}
code.
If you don't care about passing through the internal return value, you could instead return the duration as the result of the closure invocation.
Update:
I might have misread -- you're asking how to wrap the taglib execution without modifying the taglib code at all? What about creating a custom taglib which accepts the body and passes it to the other taglibs for execution?
I haven't tried this, but something like:
class TimedTagLib {
static namespace = "timer"
def timedTag = { attrs, body ->
timer "Executing the timed tag", {
out << body()
}
}
}
And invoking it like
<timer:timedTag><g:emoticon whatever="something">Text</g:emoticon></timer:timedTag>
Update 2:
Ok, so I tried it. Works fine. My final code (I added a second timer closure which returns the duration):
// TimedTagLib.groovy
#Mixin(TimingCategory)
class TimedTagLib {
static namespace = "timer"
def timedTag = { attrs, body ->
def duration = returnTimer "Printing the timed tag", {
out << body()
}
out << "Took ${duration} ms to print"
}
}
And the view:
// someView.gsp
<timer:timedTag>
<g:formatLocalDate date="${LocalDate.now()}" />
</timer:timedTag>
The resulting HTML is:
03/19/2013
Took 6 ms to print
And it also wrote to the log.
Related
I wrote service for manual requeuing events from one queue to another.
public class ReQueueService {
private final RabbitTemplate rabbitTemplate;
public void retry() {
InfoLog infoLog;
while (rabbitTemplate != null &&
(infoLog = (InfoLog) rabbitTemplate.receiveAndConvert(EVENT_WAITING_FOR_REQUEUE)) != null
) {
rabbitTemplate.convertAndSend(SOME_QUEUE, infoLog.getSomeEvent());
}
}
}
The problem I am facing is getting:
Too many invocations for:
1 * rabbitTemplate.convertAndSend(SOME_QUEUE, _ as SomeEvent) >> {
arguments ->
assert infoLog.getSomeEvent() == arguments[1]
} (2 invocations)
Matching invocations (ordered by last occurrence):
2 * rabbitTemplate.convertAndSend(SOME_QUEUE, ...
while my code in test looks like this:
class ReQueueServiceTest extends Specification {
def "should resend single event to some queue" () {
given:
InfoLog infoLog = Fixtures.createInfoLog()
def rabbitTemplate = Mock(RabbitTemplate){
receiveAndConvert(EVENT_WAITING_FOR_REQUEUE) >> { infoLog }
}
ReQueueService reSyncService = new ReQueueService(rabbitTemplate)
when:
reSyncService.retry()
then:
1 * rabbitTemplate.convertAndSend(SOME_QUEUE, _ as SomeEvent) >> {
arguments ->
assert infoLog.getSomeEvent() == arguments[1]
}
}
}
The question is why I have 2 invocations, if I stubb only one event?
EDIT:
link to repo with example: https://gitlab.com/bartekwichowski/spock-too-many
Thanks for the repo link. As soon as I could run the test and inspect the behaviour live, it was pretty easy to find out what was wrong. First I will make an educated guess about what you actually want to test:
The mock's receiveAndConvert method should return str when it is called first and then null when called again.
Subsequently you want to verify that the while loop runs exactly 1 iteration, i.e. that convertAndSend is called with exactly the parameters you expect.
This can be achieved by
receiveAndConvert("FOO") >>> [str, null]
1 * rabbitTemplate.convertAndSend("BAR", str) (no need for ugly assertions inside a stubbed method, the parameters are verified against your parameter constraints already)
If I refactor your specification a little bit for prettier variable names and less verbosity, it looks like this:
class ReSyncServiceTest extends Specification {
def "should resend single event to resource sync queue"() {
given:
def message = "someValue"
def rabbitTemplate = Mock(RabbitTemplate) {
receiveAndConvert("FOO") >>> [message, null]
}
when:
new ReSyncService(rabbitTemplate).retry()
then:
1 * rabbitTemplate.convertAndSend("BAR", message)
}
}
P.S.: Your version with the assertion inside does not return anything explicitly, but implicitly the result of the last assertion. Be careful with that. With >> { ... } you are stubbing the method result! It would always return true in the version you have in Git and the test only terminates because you added the 1 * limit. If it was not there, you would have an endless loop. Your code did not do what you thought it did. Maybe the Spock manual can help you there. :-)
P.P.S.: Maybe you want to refactor your application code to be a bit easier to understand and maintain and to be a little less "smart". Also there is no need to check that rabbitTemplate != null in every iteration, once should be enough. How about this?
#Slf4j
#Service
#AllArgsConstructor
public class ReSyncService {
private final RabbitTemplate rabbitTemplate;
public void retry() {
if (rabbitTemplate == null)
return;
String event;
while (null != (event = getEventFromQueue()))
rabbitTemplate.convertAndSend("BAR", event);
}
protected String getEventFromQueue() {
return (String) rabbitTemplate.receiveAndConvert("FOO");
}
}
I am stuck somewhere in Grails 3 spock Testing for Taglibs.
I want to test a closure of taglib, which looks like:
ATagLib.groovy:
Closure a = {attrs ->
java.util.TimeZone utc = java.util.TimeZone.getTimeZone(FraudnetConstants.TIMEZONE_UTC)
if (attrs.somevar) {
out << "${g.message(code: 'some.code')} ${g.formatDate([date: attrs.date, format: "h:mma", timeZone: utc])}"
} else if (attrs.freq == SomeConstants.VAL || attrs.freq == SomeConstants.VAL) {
out << g.formatDate([date: attrs.date, format: "E '#' h:mma", timeZone: utc])
} else {
out << "${g.message(code: 'some.other.code')} ${g.formatDate([date: attrs.date, format: "h:mma", timeZone: utc])}"
}
}
My ATagLibSpec.groovy looks like:
#TestFor(ATagLib)
class ATagLibSpec {
def setup() {
java.util.TimeZone.metaClass.'static'.getTimeZone = {a -> return null }
}
void 'testmethod'() {
expect:
taglib.a()
}
}
The exception i am getting while running testcases is:
java.lang.NullPointerException: Cannot invoke method getTimeZone() on null object at org.grails.plugins.web.taglib.FormatTagLib$_closure2.doCall(FormatTagLib.groovy:170) at groovy.lang.Closure.call(Closure.java:414)
at org.grails.taglib.TagOutput.captureTagOutput(TagOutput.java:64)
at org.grails.taglib.TagLibraryMetaUtils.methodMissingForTagLib(TagLibraryMetaUtils.groovy:138)
at org.grails.taglib.NamespacedTagDispatcher.methodMissing(NamespacedTagDispatcher.groovy:59)
Can someone point here, what's wrong with the above way of prepopulating getTimeZone.
instead of using metaprogramming, it is best to inject a TimezoneFactoryService into your taglib. Having to metaprogram in a test is in my experience an indication of code smell: your code uses a static method to instantiate an object, instead of dependency injection.
Your code could look like this:
Closure a = {attrs->
java.util.TimeZone utc = timezoneFactoryService.getTimeZone(FraudnetConstants.TIMEZONE_UTC)
}
This will allow you to mock your factory service in your spec in a way more convenient way, by using a regular Spock Mock.
#TestFor(ATagLib)
class ATagLibSpec {
def setup() {
taglib.timezoneFactoryService=Stub(TimezoneFactoryService) {
getTimeZone(_) >> null
}
}
void 'testmethod'() {
expect:
taglib.a()
}
}
If you still want to use metaprogramming, be aware that the signature of the method has to match fully (also the parameter types), so:
java.util.TimeZone.metaClass.'static'.getTimeZone = {a -> return null }
java.util.TimeZone.getTimeZone("America/Los_Angeles")
This code will get the timezone for America/Los Angeles, but
java.util.TimeZone.metaClass.'static'.getTimeZone = {String a -> return null }
java.util.TimeZone.getTimeZone("America/Los_Angeles")
this one will return null as we have modified the method properly via metaprogramming.
Be also aware that you have to use the injected variable tagLib not taglib.
My goal is to execute groovy script with binding, where functions are predefined and interceptor log out execution time and result of closure evaluation. My sample code is:
binding.login = { ->
binding.event.appname=='login'
} def gse = new GroovyScriptEngine("src/main/resources/rules")
gse.run('DSL.groovy', binding)
Inside my script I am making a call to login method. Everything works except I can't fugure out how to intercept it using MetaClass. My attempts like
Binding.metaClass.invokeMethod = { String name, args ->
println ("Call to $name intercepted... ")
did not work. Later I figured out that closure is a property of the binding, not a method.
Is there any way to perform interception in this scenario and how to do it? What would be a correct object for metaclass? As of note, my closure executed inside another nested closures.
Thanks
I don't know if it's the better solution, but i managed to do what you wanted by decorating the closures in the binding
binding = new Binding([
login : { -> println "binding.login called" },
echo : { String text -> println "test for $text" },
foo : { a, b, c -> println "$a $b $c" }
])
binding.variables.each { key, value ->
if (value instanceof Closure)
{
binding.variables[key] = { Object[] args ->
long t0 = System.currentTimeMillis()
value( *args )
print "[$key method"
print " args: $args "
println " time: ${System.currentTimeMillis() - t0}]"
}
}
}
def gse = new GroovyScriptEngine(".")
gse.run('Bind.groovy', binding)
And this is my Bind.groovy:
println " ** executing bind"
login()
echo("echo")
foo("test", 4, "echo")
println " ** bind script done"
You could also try/catch a MissingMethodException if you didn't defined the method as a closure in the binding.
I also recommend you Laforge's slideshare in creating DSLs:
http://www.slideshare.net/glaforge/going-to-mars-with-groovy-domainspecific-languages
In this slideshare, Laforge shows binding using a class that extends script; i think that's a good approach. More OO.
Update
Take a look at mrhaki's suggestion to delegate method calls to a base Script class (also in Guillaume' slideshare):
http://mrhaki.blogspot.com.br/2011/11/groovy-goodness-create-our-own-script.html
I just used it to implement a DSL over JFugue and it worked right away.
Lets assume that I have the following configuration in my conf/InjectionConfig.groovy file:
x {
a = { attrs, body -> out << "hello" }
b = { attrs, body -> out << "goodbye" }
}
and that I have a simple taglib such as
class XTagLib {
static namespace = "x"
}
What I want to do is that when I type <x:a /> to any of my views, it would print hello. I've already tried to inject these to the metaclass of the taglib as both property and method but neither seem to work. As an example, here's basically what I'm doing right now in a service:
public void afterPropertiesSet() throws Exception {
GroovyClassLoader classLoader = new GroovyClassLoader(getClass().classLoader)
def slurper = new ConfigSlurper(GrailsUtil.environment)
ConfigObject xConfig
try {
xConfig = slurper.parse(classLoader.loadClass('InjectionConfig'))
}
catch (e) {
e.printStackTrace()
}
xConfig.x.each({
if ( !XTagLib.metaClass.hasMetaProperty(it.key) ) {
XTagLib.metaClass.registerBeanProperty(it.key, { args ->
def attrs = args[0], body = args[1]
it.value.call(attrs, body)
}
}
})
}
Am I just doing it wrong or is this even possible currently?
Well, this
def shell = new GroovyShell() // or get a GroovyClassLoader
Class yTagLibClass = shell.evaluate("class YTagLib { static namespace = 'x' }; return YTagLib")
yTagLibClass.metaClass.a = { attrs, body -> delegate.out << 'blabla' }
grailsApplication.addArtefact(TagLibArtefactHandler.TYPE, yTagLibClass)
<x:a/> nearly worked for me - registered a tag, except for it didn't output anything. You still need to make the closure resolve out against Grails' taglib's out property.
I don't see a pretty way to do it, as there's no access to instance variables, and out is an instance variable. See Grails source, JspInvokeGrailsTagLibTag.doStartTagInternal() - you might find a way.
EDIT: I added delegate. prefix that should resolve out property of target object. Now I believe I deserve an acceptance :)
What I want to do is that when I type
to any of my views, it would
print hello
I think there's an alternative way to do what you intend: combine template & tagLib. First, create a template, then add it in your TagLib (with no complex configuration).
In my opinion, it's more simple than your approach.
Please take a look at this tutorial:
http://jan-so.blogspot.com/2008/02/example-of-template-and-taglib-with.html
I don't know how to use binding with closures in Groovy. I wrote a test code and while running it, it said, missing method setBinding on the closure passed as parameter.
void testMeasurement() {
prepareData(someClosure)
}
def someClosure = {
assertEquals("apple", a)
}
void prepareData(testCase) {
def binding = new Binding()
binding.setVariable("a", "apple")
testCase.setBinding(binding)
testCase.call()
}
This works for me with Groovy 1.7.3:
someClosure = {
assert "apple" == a
}
void testMeasurement() {
prepareData(someClosure)
}
void prepareData(testCase) {
def binding = new Binding()
binding.setVariable("a", "apple")
testCase.setBinding(binding)
testCase.call()
}
testMeasurement()
In this script example, the setBinding call is setting a in the scripts binding (as you can see from the Closure documentation, there is no setBinding call). So after the setBinding call, you can call
println a
and it will print out "apple"
So to do this in the class, you can set the delegate for the closure (the closure will revert back to this delegate when a property cannot be found locally) like so:
class TestClass {
void testMeasurement() {
prepareData(someClosure)
}
def someClosure = { ->
assert "apple" == a
}
void prepareData( testCase ) {
def binding = new Binding()
binding.setVariable("a", "apple")
testCase.delegate = binding
testCase.call()
}
}
And it should grab the value fro a from the delegate class (in this case, a binding)
This page here goes through the usage of delegate and the scope of variables in Closures
Indeed, instead of using a Binding object, you should be able to use a simple Map like so:
void prepareData( testCase ) {
testCase.delegate = [ a:'apple' ]
testCase.call()
}
Hope it helps!
This is really strange behaviour: removing the "def" in front of someClosure declaration makes the script work in JDK1.6 Groovy:1.7.3
Update: This was posted in the answer above. My mistake to repeat it.
Update: Why it works? Without a def first line is taken as a property assignment which calls setProperty and makes the variable available in binding, which is resolved later.
a def should have worked as well as per (http://docs.codehaus.org/display/GROOVY/Groovy+Beans)
someClosure = {
assert "apple", a
print "Done"
}
void testMeasurement() {
prepareData(someClosure)
}
void prepareData(testCase) {
def binding = new Binding()
binding.setVariable("a", "apple")
testCase.setBinding(binding)
testCase.call()
}
testMeasurement()
I could reproduce the problem you mention by following code. But i am not sure if this is the correct way to use Binding. GroovyDocs says they are to be used with scripts. Could you point me to documentation which suggests such usage of Binding with Closures.
class TestBinding extends GroovyTestCase {
void testMeasurement() {
prepareData(someClosure)
}
def someClosure = {
assertEquals("apple", a)
}
void prepareData(testCase) {
def binding = new Binding()
binding.setVariable("a", "apple")
//this.setBinding(binding)
testCase.setBinding(binding)
testCase.call()
}
}
This was answered on groovy mailing list:
In a script, def foo will create a local variable, not a property
(private field + getter/setter).
Think of a script a bit like if it's the body of a run() or main() method.
That's where and how you can define local variables.