Proxy A Groovy Ant BuildListener?

In my last post BuildListener using Groovy In Ant Scriptdef, I got a scripted BuildListener to work. Was wondering if there were a way to use a Proxy to stand in for the listener.

See update below for another attempt that succeeds.

In short, I can’t. The first problem was classloader issues, but I think I fixed that by clearing the CLASSPATH:
set CLASSPATH =

Then a host of issues, until finally I give up. I think the big complexity is that BuildListener is an Interface. That means you have to jump hoops to proxy it. I’m sure Groovy can do this, but I don’t see it yet. May need more info on Groovy’s MOP.

Perhaps there is too much indirection being used. Is modern software engineering just ingenious ways to hide a GOTO? Just kidding.

Using commons-proxy library
Apache’s commons-proxy puts a more usable framework around different proxy factories.

Listing 1 – Proxy using Javassist library

import org.apache.commons.proxy.factory.javassist.*
import java.lang.reflect.*
import org.apache.commons.proxy.*
import org.apache.tools.ant.*

class MyListener implements Invoker  {
    static int count = 0;

    Object invoke(Object proxy, Method method, Object[] arguments) 
      throws Throwable{
	new File("finished.run").setText("count: ${count++}")   
    }

}

MyListener proxy = new MyListener()		
java.lang.ClassLoader loader = proxy.class.getClassLoader()

JavassistProxyFactory factory = new JavassistProxyFactory()

Object listener = factory.createInvokerProxy(  
	loader,
	proxy,
	[BuildListener.class] as Class[]
);

project.addBuildListener(listener)		

// end source

Listing 2 – build script

<project name="listener" default="default" basedir=".">
<!--
File: build.xml, author: J.Betancourt,
    date:2011-08-18T2137
-->

<path id="libs">
    <fileset dir="lib">
	<include name="commons-proxy-1.0.jar" />
	<include name="javassist.jar"/>
	<include name="groovy-all-1.8.0.jar"/>
    </fileset>
</path>

<!-- Groovy library -->
<typedef resource="org/codehaus/groovy/antlib.xml" classpathref="libs" />    

<!-- sets a BuildListener to the project -->
<scriptdef name="set-listener" language="Groovy" 
   classpathref="libs" src="lib/BuildListener.groovy">

  <attribute name="endTarget"/>

</scriptdef>

<!-- install the listener -->
<set-listener  endTarget="list"/>    

<target name="default">
    <fail message="doh!"/>    
</target>

</project>
    
   

Listing 3 – stacktrace snippet

C:\temp\ant\groovyListener>ant
Buildfile: C:\temp\ant\groovyListener\build.xml

BUILD FAILED
java.lang.ClassCircularityError: groovy/runtime/metaclass/java/io/FileMetaClass
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.createWithCustomLookup(MetaClassRegistry.java:127)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.create(MetaClassRegistry.java:122)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:165)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:182)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:242)
        at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:751)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallConstructorSite(CallSiteArray.java:71)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:54)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
        at MyListener.invoke(Script1.groovy:10)
        at JavassistUtilsGenerated_0.messageLogged(JavassistUtilsGenerated_0.java)
        at org.apache.tools.ant.Project.fireMessageLoggedEvent(Project.java:2254)
        at org.apache.tools.ant.Project.fireMessageLogged(Project.java:2290)


Update

This works, but just as wordy as the original using a BuildListener class implementation.

import org.apache.tools.ant.*

listenerMap = [
  theTarget : attributes.get("endtarget"),
  buildFinished: { event ->	
  new File("finished.run").
    setText(
     "Build Finished:  message='${event.message}' exception='${event.exception}'"
    )
	
    project.executeTarget(listenerMap.theTarget)
	
  },

  buildStarted : {},
  messageLogged : {},
  targetFinished : {},
  targetStarted : {},
  taskFinished : {},
  taskStarted : {},
]

listener = listenerMap as BuildListener

project.addBuildListener(listener )		

Uses the technique outlined at:
Groovy Way to implement interfaces

Conclusion

Updates

Further Reading

Listing 4 – Full stacktrace

C:\temp\ant\groovyListener>ant
Buildfile: C:\temp\ant\groovyListener\build.xml

BUILD FAILED
java.lang.ClassCircularityError: groovy/runtime/metaclass/java/io/FileMetaClass
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.createWithCustomLookup(MetaClassRegistry.java:127)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.create(MetaClassRegistry.java:122)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:165)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:182)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:242)
        at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:751)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallConstructorSite(CallSiteArray.java:71)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:54)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
        at MyListener.invoke(Script1.groovy:10)
        at JavassistUtilsGenerated_0.messageLogged(JavassistUtilsGenerated_0.java)
        at org.apache.tools.ant.Project.fireMessageLoggedEvent(Project.java:2254)
        at org.apache.tools.ant.Project.fireMessageLogged(Project.java:2290)
        at org.apache.tools.ant.Project.log(Project.java:470)
        at org.apache.tools.ant.Project.log(Project.java:459)
        at org.apache.tools.ant.AntClassLoader.log(AntClassLoader.java:396)
        at org.apache.tools.ant.AntClassLoader.findClass(AntClassLoader.java:1310)
        at org.apache.tools.ant.AntClassLoader.loadClass(AntClassLoader.java:1064)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.createWithCustomLookup(MetaClassRegistry.java:127)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.create(MetaClassRegistry.java:122)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:165)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:182)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:242)
        at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:751)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallConstructorSite(CallSiteArray.java:71)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:54)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
        at MyListener.invoke(Script1.groovy:10)
        at JavassistUtilsGenerated_0.taskFinished(JavassistUtilsGenerated_0.java)
        at org.apache.tools.ant.Project.fireTaskFinished(Project.java:2206)
        at org.apache.tools.ant.Task.perform(Task.java:364)
        at org.apache.tools.ant.Target.execute(Target.java:390)
        at org.apache.tools.ant.helper.ProjectHelper2.parse(ProjectHelper2.java:180)
        at org.apache.tools.ant.ProjectHelper.configureProject(ProjectHelper.java:82)
        at org.apache.tools.ant.Main.runBuild(Main.java:793)
        at org.apache.tools.ant.Main.startAnt(Main.java:217)
        at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
        at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)

Total time: 1 second
java.lang.ClassCircularityError: groovy/runtime/metaclass/java/io/FileMetaClass
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.createWithCustomLookup(MetaClassRegistry.java:127)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.create(MetaClassRegistry.java:122)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:165)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:182)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:242)
        at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:751)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallConstructorSite(CallSiteArray.java:71)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:54)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
        at MyListener.invoke(Script1.groovy:10)
        at JavassistUtilsGenerated_0.messageLogged(JavassistUtilsGenerated_0.java)
        at org.apache.tools.ant.Project.fireMessageLoggedEvent(Project.java:2254)
        at org.apache.tools.ant.Project.fireMessageLogged(Project.java:2290)
        at org.apache.tools.ant.Project.log(Project.java:470)
        at org.apache.tools.ant.Project.log(Project.java:459)
        at org.apache.tools.ant.AntClassLoader.log(AntClassLoader.java:396)
        at org.apache.tools.ant.AntClassLoader.findClass(AntClassLoader.java:1310)
        at org.apache.tools.ant.AntClassLoader.loadClass(AntClassLoader.java:1064)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.createWithCustomLookup(MetaClassRegistry.java:127)
        at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.create(MetaClassRegistry.java:122)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:165)
        at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:182)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:242)
        at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:751)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallConstructorSite(CallSiteArray.java:71)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:54)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
        at MyListener.invoke(Script1.groovy:10)
        at JavassistUtilsGenerated_0.taskFinished(JavassistUtilsGenerated_0.java)
        at org.apache.tools.ant.Project.fireTaskFinished(Project.java:2206)
        at org.apache.tools.ant.Task.perform(Task.java:364)
        at org.apache.tools.ant.Target.execute(Target.java:390)
        at org.apache.tools.ant.helper.ProjectHelper2.parse(ProjectHelper2.java:180)
        at org.apache.tools.ant.ProjectHelper.configureProject(ProjectHelper.java:82)
        at org.apache.tools.ant.Main.runBuild(Main.java:793)
        at org.apache.tools.ant.Main.startAnt(Main.java:217)
        at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
        at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)
groovy/runtime/metaclass/java/io/FileMetaClass

 

 

 


 

“Timeless” solo 12 string guitar played by Ralph Towner on his “Solo Concert” CD. YouTube

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: