Trouble with embedding groovy scripts

153 views
Skip to first unread message

argherna

unread,
Jan 26, 2009, 12:22:59 PM1/26/09
to Cernunnos Discussion
Hello all,

I'd like to be able to write a utility class in Groovy and use it in
Cernunnos. I've been reasonably successful with writing a separate
file (BasicLoggingListener.groovy for example) that defines a class.
It works on my laptop, but no one else's (still looking into why).

I thought it might be better to wrap the file in a <groovy> task and
call instances of it using the ${crn()} phrase. But I'm running into
some trouble with that. For example, let's say I have a jar file on
my class path for CVSAdapter and this in a file call get-logger.crn:

<groovy>
<script>
// imports are up here

public class BasicLoggingListener extends CVSAdapter {
// implementation
}
</script>
<subtasks><return value="${groovy(new BasicLoggingListener())}"/></
subtasks>
</groovy>

When I call the script like this:

<with-attribute key="logger" value="${crn(get-logger.crn)}">
<!-- use it here -->
</with-attribute>

I get a stack trace that looks like this:

Caused by: java.lang.RuntimeException: Unable to invoke the specified
script: get-info-logger-adapter.crn
at org.danann.cernunnos.flow.CernunnosTask.perform(CernunnosTask.java:
117)
at org.danann.cernunnos.flow.CernunnosPhrase.evaluate
(CernunnosPhrase.java:70)
at org.danann.cernunnos.runtime.RuntimePhraseDecorator.evaluate
(RuntimePhraseDecorator.java:75)
at org.danann.cernunnos.runtime.ConcatenatingPhrase.evaluate
(ConcatenatingPhrase.java:77)
at org.danann.cernunnos.core.WithTask.perform(WithTask.java:86)
at org.danann.cernunnos.runtime.RuntimeTaskDecorator.perform
(RuntimeTaskDecorator.java:77)
at org.danann.cernunnos.runtime.ScriptRunner$TaskDecorator.perform
(ScriptRunner.java:415)
at org.danann.cernunnos.runtime.ScriptRunner.run(ScriptRunner.java:
267)
at org.danann.cernunnos.flow.CernunnosTask.perform(CernunnosTask.java:
113)
... 18 more
Caused by: org.danann.cernunnos.ManagedException: The Cernunnos
Runtime encountered an error:
Entity Name: <groovy>
Source: /groovy
at org.danann.cernunnos.runtime.RuntimeTaskDecorator.perform
(RuntimeTaskDecorator.java:93)
at org.danann.cernunnos.runtime.ScriptRunner$TaskDecorator.perform
(ScriptRunner.java:415)
at org.danann.cernunnos.runtime.ScriptRunner.run(ScriptRunner.java:
267)
at org.danann.cernunnos.flow.CernunnosTask.perform(CernunnosTask.java:
113)
... 26 more
Caused by: java.lang.RuntimeException: Error while executing the
specified script.
ENGINE_NAME: groovy
SCRIPT (follows):

- - 8< - Implementation of BasicLoggingListener dumped here - 8<- -


at org.danann.cernunnos.script.ScriptTask.perform(ScriptTask.java:
105)
at org.danann.cernunnos.runtime.RuntimeTaskDecorator.perform
(RuntimeTaskDecorator.java:77)
... 29 more
Caused by: javax.script.ScriptException:
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed, Script2.groovy: 86: unable to resolve class
BasicLoggingListenter
@ line 86, column 33.
1 error

at com.sun.script.groovy.GroovyScriptEngine.eval
(GroovyScriptEngine.java:87)
at org.danann.cernunnos.script.ScriptEvaluator.eval
(ScriptEvaluator.java:145)
at org.danann.cernunnos.script.ScriptTask.perform(ScriptTask.java:99)
... 30 more
Caused by:
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed, Script2.groovy: 86: unable to resolve class
BasicLoggingListenter
@ line 86, column 33.
1 error

at org.codehaus.groovy.control.ErrorCollector.failIfErrors
(ErrorCollector.java:296)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits
(CompilationUnit.java:787)
at org.codehaus.groovy.control.CompilationUnit.compile
(CompilationUnit.java:438)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:
277)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:
248)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:
243)
at com.sun.script.groovy.GroovyScriptEngine.getScriptClass
(GroovyScriptEngine.java:259)
at com.sun.script.groovy.GroovyScriptEngine.eval
(GroovyScriptEngine.java:81)
... 32 more

Can someone help explain what's going on? Thanks.

Andy

Cris J. Holdorph

unread,
Jan 26, 2009, 12:25:07 PM1/26/09
to cernunnos-...@googlegroups.com
I can't help here, but I just thought I would let everyone know, Drew is
in Italy for a week, so he probably will not respond here on the list
during that time.

---- Cris J H

Eric Dalquist

unread,
Jan 26, 2009, 12:34:27 PM1/26/09
to cernunnos-...@googlegroups.com
My guess is this may be due to the implicit caching now going on. With
caching enabled there is a single Groovy script context that is reused,
so when that is called multiple times you keep re-declaring the same class.

A few ideas:

- Disable caching for your groovy script, this will get expensive if it
is called alot: Wrapping your <groovy> task in a <with-attribute
key="Attributes.CACHE_MODEL" value="NONE">

- Cache the declaration of the class, I'm not positive this will work as
expected since the <factory> doesn't actually return anything but all
you're really trying to do here is make sure the class is only declared
once and <cache> will do it in a threadsafe manner. If that fails add a
<return value="dummy"/> after the groovy task just so the cache task has
something to cache.

<cache key="LOGGING_LISTENER" cache-key="groovy.LOGGING_LISTENER"
thread-safe="true">
<factory>

<groovy>
<script>
// imports are up here

public class BasicLoggingListener extends CVSAdapter {
// implementation
}
</script>

</groovy>

</factory>
<subtasks>

<return value="${groovy(new BasicLoggingListener())}"/>

</subtasks>
</cache>

> --~--~---------~--~----~------------~-------~--~----~
> You received this message because you are subscribed to the Google Groups "Cernunnos Discussion" group.
> To post to this group, send email to cernunnos-...@googlegroups.com
> To unsubscribe from this group, send email to cernunnos-discus...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/cernunnos-discussion?hl=en
> -~----------~----~----~----~------~----~------~--~---
>
>

argherna

unread,
Jan 28, 2009, 10:54:19 AM1/28/09
to Cernunnos Discussion


On Jan 26, 11:34 am, Eric Dalquist <eric.dalqu...@doit.wisc.edu>
wrote:
> My guess is this may be due to the implicit caching now going on. With
> caching enabled there is a single Groovy script context that is reused,
> so when that is called multiple times you keep re-declaring the same class.
>

OK.

> A few ideas:
>
> - Disable caching for your groovy script, this will get expensive if it
> is called alot: Wrapping your <groovy> task in a <with-attribute
> key="Attributes.CACHE_MODEL" value="NONE">
>
> - Cache the declaration of the class, I'm not positive this will work as
> expected since the <factory> doesn't actually return anything but all
> you're really trying to do here is make sure the class is only declared
> once and <cache> will do it in a threadsafe manner. If that fails add a
> <return value="dummy"/> after the groovy task just so the cache task has
> something to cache.
>

[ SNIP ]

Thank you for the ideas. I tried both of them out but unfortunately
neither worked. The stack trace given back was virtually the same as
above. Since I'm declaring a class, I wonder if the groovy engine is
looking for a file named BasicLoggingListener.groovy? This line in
the stack trace is what makes me wonder a little:

groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java: 243)

The signature of the method for this line is public Class
parseClass(final InputStream in, final String fileName) throws
CompilationFailedException. So it looks like it's expecting a
filename of some kind?.

I'll need to try something else for now, but I'd like to keep this
discussion going. I'm hopeful Drew can comment on this when he
returns.

Eric Dalquist

unread,
Jan 28, 2009, 11:05:27 AM1/28/09
to cernunnos-...@googlegroups.com
So why not just declare a real Class?

argherna wrote:
[ SNIP ]

Thank you for the ideas.  I tried both of them out but unfortunately
neither worked.  The stack trace given back was virtually the same as
above.  Since I'm declaring a class, I wonder if the groovy engine is
looking for a file named BasicLoggingListener.groovy?  This line in
the stack trace is what makes me wonder a little:

groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java: 243)

The signature of the method for this line is     public Class
parseClass(final InputStream in, final String fileName) throws
CompilationFailedException.  So it looks like it's expecting a
filename of some kind?.

I'll need to try something else for now, but I'd like to keep this
discussion going.  I'm hopeful Drew can comment on this when he
returns.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Cernunnos Discussion" group.
To post to this group, send email to cernunnos-...@googlegroups.com

Andy Gherna

unread,
Jan 28, 2009, 11:28:52 AM1/28/09
to cernunnos-...@googlegroups.com
On Wed, Jan 28, 2009 at 10:05 AM, Eric Dalquist
<eric.d...@doit.wisc.edu> wrote:
> So why not just declare a real Class?
>

Like a java class? I was going to do that next in a jar file and add
that to my classpath.

Andrew Wills

unread,
Feb 10, 2009, 11:07:52 AM2/10/09
to cernunnos-...@googlegroups.com
On Wed, Jan 28, 2009 at 8:54 AM, argherna <argh...@gmail.com> wrote:
>
>
> [ SNIP ]
>
> Thank you for the ideas. I tried both of them out but unfortunately
> neither worked. The stack trace given back was virtually the same as
> above.

I've done some experiments, and what I've seen has been a surprise.
After reading the emails I figured the issue was going to be basically
what Eric described: the Groovy context/engine didn't like being
asked to compile the same class twice. My testing (admittedly
shallow) suggests that this is not a problem.

This works for me:

*****

test.crn
-----------
<for-each items="${groovy(['A', 'B', 'C'])}">
<echo-ln>${Attributes.OBJECT}</echo-ln>
<with-attribute key="sayIt" value="${crn(test2.crn)}">
<groovy><script>sayIt.sayHello()</script></groovy>
</with-attribute>
</for-each>

test2.crn
-----------
<groovy>
<script>

public class SayIt {
public void sayHello() {
println 'Hello World!'
}
public static void main(String[] args) {}
}

</script>
<subtasks><return value="${groovy(new SayIt())}"/></subtasks>
</groovy>

*****

NOTICE: The groovy/jsr-223 stack insisted that I add the main()
method. Before I had that I was getting...

Caused by: groovy.lang.MissingMethodException: No signature of
method: SayIt.main() is applicable for argument types:
([Ljava.lang.String;) values: {[]}

Also notice how (because of the <for-each>) the test2.crn XML file is
being invoked more than once.

Andy --

I know it took me forever to respond... do you still have the original
groovy class? I'd like to try to match up the BasicLoggingListener
impl with the following message (from your stack trace):

Caused by: javax.script.ScriptException:
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed, Script2.groovy: 86: unable to resolve class
BasicLoggingListenter
@ line 86, column 33.
1 error

What is it saying about line 86, column 33?

drew wills

Andy Gherna

unread,
Feb 10, 2009, 9:29:58 PM2/10/09
to cernunnos-...@googlegroups.com
Here's a copy of my script to look at.
get-info-logger-adapter.crn

Andrew Wills

unread,
Feb 11, 2009, 10:41:58 AM2/11/09
to cernunnos-...@googlegroups.com
On Tue, Feb 10, 2009 at 7:29 PM, Andy Gherna <argh...@gmail.com> wrote:
> Here's a copy of my script to look at.
>

Heh. I'm not sure what to say... this example works perfectly for me:

*****

test.crn
-----------
<for-each items="${groovy(['A', 'B', 'C'])}">

<with-attribute key="sayIt" value="${crn(test2.crn)}">

<echo-ln>${Attributes.OBJECT}</echo-ln>
<groovy><script>println sayIt.toString()</script></groovy>
</with-attribute>
</for-each>

test2.crn
-------------
<groovy>
<script>

import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory

import org.netbeans.lib.cvsclient.event.BinaryMessageEvent
import org.netbeans.lib.cvsclient.event.CVSAdapter
import org.netbeans.lib.cvsclient.event.EnhancedMessageEvent
import org.netbeans.lib.cvsclient.event.FileAddedEvent
import org.netbeans.lib.cvsclient.event.FileInfoEvent
import org.netbeans.lib.cvsclient.event.FileRemovedEvent
import org.netbeans.lib.cvsclient.event.FileToRemoveEvent
import org.netbeans.lib.cvsclient.event.FileUpdatedEvent
import org.netbeans.lib.cvsclient.event.MessageEvent
import org.netbeans.lib.cvsclient.event.TerminationEvent

/**
* Logs CVS events at INFO to the named logger.
*
* The logger is from Apache commons-logging since Cernunnos itself uses it for
* its own logging.
*/


public class BasicLoggingListener extends CVSAdapter {

private final logger
static final CR = "\r"
static final LF = "\n"

public BasicLoggingListener(String name) {
logger = LogFactory.getLog(name)
}

private strip(msg) {
msg.replaceAll(CR, "")
msg.replaceAll(LF, "")
return msg
}


/**
*/
public void commandTerminated(TerminationEvent tEvent) {
def buffer = new StringBuilder()

buffer.append("CVS Command Terminated")

if (tEvent.isError()) {
buffer.append(" in error")
} else {
buffer.append(" successfully")
}
logger.info(strip(buffer.toString()))
}


/**
*/
public void messageSent(MessageEvent mEvent) {
if (mEvent instanceof EnhancedMessageEvent) {
return
}

def buffer = new StringBuilder()

if (!mEvent.isTagged()) {
if (mEvent.getMessage().length() > 1) {
buffer.append(mEvent.getMessage())
}
} else {

def taggedMsgBuffer = new StringBuffer()

// Gather the msg into a StringBuffer until we have a complete line.
def line =
MessageEvent.parseTaggedMessage(taggedMsgBuffer, mEvent.getMessage())
if (line != null &amp;&amp; line.length() > 0) {
buffer.append(line)
}
}

if (mEvent.isError()) {
logger.error(strip(buffer.toString()))
} else {
logger.info(strip(buffer.toString()))
}
}
}

System.out.println(BasicLoggingListener.class)

</script>
<subtasks><return value="${groovy(new

BasicLoggingListener('foo'))}"/></subtasks>
</groovy>

*****

Here's the only other thing that comes to mind: looking at the stack trace...

Caused by: javax.script.ScriptException:
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed, Script2.groovy: 86: unable to resolve class
BasicLoggingListenter
@ line 86, column 33.
1 error

looks as though It's pointing to the last line:

System.out.println(BasicLoggingListener.class)

But it also says "MultipleCompilationErrorsException" -- I wonder if
the reason it can't find the BasicLoggingListener class is b/c it
didn't compile, and the fact that it didn't compile is causing the
"unable to resolve class BasicLoggingListenter" error. I wonder,
furthermore if they only have room to report 1 error on the stack
trace in the case of "MultipleCompilationErrors" and they're just
choosing the last one.

Maybe try changing that last line to

System.out.println('TEST')

And see if another compilation error comes to light in the stack trace.

drew

Reply all
Reply to author
Forward
0 new messages