Rainy days and Java always get me down

I've Moved My Blog

It's currently located at http://www.urlinone.com/blog

I should say "I'm moving my blog." It's a pretty painful process.

Pebble has blown up on me, and it's been many months since I've been able to blog reliably. I've lost posts. And now I've got to figure out how to migrate my past blog posts from Pebble to my new destination without all the URLs changing, lest external links become 404 Not Founds.

Why does everything in the 21st century have to be a three-day project???

Groovy is one of the hot new things in the Java world. It's a powerful scripting language that integrates both ways, i.e. you can call Groovy scripts from within your Java code, and you can access your Java objects from within your Groovy scripts. In fact, Groovy classes become plain old Java bytecode, so there is ultimately no real distinction between the two. In the Groovy language, you have many powerful constructs including closures.

Here are the steps I took to add a little groovability to my AppFuse 1.5 app. I realize that AppFuse 1.6 is out, but I'm in the midst of a 1.5 development, and I suspect that these steps won't change much, if at all, between 1.5 and 1.6.

  1. Download Groovy from here. Treat yourself to the freshest version available.
  2. Unzip it. FWIW, I unzip all downloaded software to c:\sw.
  3. Create a directory in your AppFuse app for the Groovy distribution. I created c:\projects\optioninsight\lib\groovy-1.0-beta-7.
  4. Copy groovy-1.0-beta-7.jar to your new directory.
  5. Create a lib directory below the new groovy directory.
  6. Copy asm-1.4.3.jar and asm-util-1.4.3.jar from C:\sw\groovy-1.0-beta-7\lib to your lib\groovy-1.0-beta-7\lib directory.
  7. In the top-level lib directory off the root of your appfuse application (in my case, that's c:\projects\optioninsight\lib), edit lib.properties.
  8. At the bottom of lib.properties (or anywhere else you like within the file) add the following
    # Groovy - http://groovy.codehaus.org/
    groovy.version       = 1.0-beta-7
  9. Edit build.xml in the root of your AppFuse application (c:\projects\optioninsight, in my case).
  10. Locate the line </war> in build.xml. Just before that line add the following:
                <lib dir="${groovy.dir}" includes="*.jar"/>
                <lib dir="${groovy.dir}/lib">
                    <include name="asm*.jar"/>
    This will add the jars required for Groovy to your war file during deployment.
  11. Now edit properties.xml, in the same directory as build.xml.
  12. Locate web.compile.classpath within that file. Between the <path> and </path> statements add the following:
        <fileset dir="${groovy.dir}" includes="*.jar"/>
    This adds the Groovy jar to the classpath for compiling the web module. I haven't done this, but I would imagine you have to add the same line to the other classpaths, if you want to compile Groovy into the dao or service layers. In fact, the way I read properties.xml, anything included into dao.compile.classpath will be included in service.compile.classpath, so you could include this line in dao.compile.classpath and have Groovy available in all three AppFuse layers.
  13. At this point, you should be able to access Groovy within your web layer. As a test, I added a bit of Groovy code to StartupListener.java to make sure it was available. Within the contextInitialized() method, I placed the following:
            // Groovy Shell - call groovy expressions from Java code
            Binding binding = new Binding();
            binding.setVariable("foo", new Integer(3));
            GroovyShell shell = new GroovyShell(binding);
            Object value = null;
    		try {
    			value = shell.evaluate("println 'Hello World!'; x = 123; return foo * 10");
    		} catch (CompilationFailedException e1) {
    			// TODO Auto-generated catch block
    		} catch (IOException e1) {
    			// TODO Auto-generated catch block
    		if (log.isDebugEnabled()) {
    			log.debug("Groovy return value: " + value);
    			log.debug("x: " + binding.getVariable("x"));
            // GroovyClassLoader - load an external Groovy script file
            XmlWebApplicationContext ctx =
                (XmlWebApplicationContext) context
            if (ctx == null) {
                // if the context is null, it's likely because the listeners
                // aren't initialized in the same order they're specified in
                // web.xml.  This happens in Tomcat 5.
                ctx = new XmlWebApplicationContext();
                // get the config locations from context parameters
                String configLocations =
                String[] files = configLocations.split(",");
                for (int i=0; i < files.length; i++) {
                    files[i] = files[i].trim();
            LookupManager mgr =
                (LookupManager) ctx.getBean("lookupManager");
            ClassLoader parent = mgr.getClass().getClassLoader();
            GroovyClassLoader loader = new GroovyClassLoader(parent);
            Class groovyClass = null;
    		try {
    			log.debug("Loader: " + loader);
    			groovyClass = loader.parseClass(new File("/sw/tomcat-5.0.19/webapps/optioninsight/scripts/HelloWorld.groovy"));
    		} catch (CompilationFailedException e2) {
    			// TODO Auto-generated catch block
    		} catch (IOException e2) {
    			// TODO Auto-generated catch block
    		//         lets call some method on an instance
            GroovyObject groovyObject = null;
    		try {
    			groovyObject = (GroovyObject) groovyClass.newInstance();
    		} catch (InstantiationException e3) {
    			// TODO Auto-generated catch block
    		} catch (IllegalAccessException e3) {
    			// TODO Auto-generated catch block
    		Object[] args = {};
            groovyObject.invokeMethod("run", args);
    Now, there's quite a bit of ugliness there. Almost of this is related to the fact that I had to find a class to get a ClassLoader from. I ended up copying a bunch of code from setupContext() at the bottom of StartupListener.java. In retrospect, I probably could have found a better place to run my Groovy test, but availability at startup was what I was after.

    One of the trickiest parts of this whole process was figuring out where the classloader was looking for the script file. As far as I can tell, the path is relative to the root of the hard drive, which is not what I expected. I would have thought that it would be based on the root of the web app or Tomcat, but neither seemed to be the case. Keep in mind that it all depends on what classloader you get, and that is dependent upon what class you get it from. I'm still working on understanding this bit of arcane magic.

  14. The contents of HelloWorld.groovy can be whatever you want, of course, but this is what I had to get you started:
    println "Nice cheese, Gromit!"
    println "----------------------- scripts directory ---------------------------"
    I found it helpful, when I was hunting for my script file, to put it in numerous locations with some identifying text, so I knew which one was running.

This entry doesn't actually do anything useful, but it should make Groovy available within your AppFuse environment, so you can start to take advantage of it. Groovy seems like a very powerful tool that can greatly enhance the power of AppFuse. If nothing else, it's a way to make changes without having to repeatedly recompile, redeploy, and restart Tomcat. Once you have the logic down, you can pull the Groovy code into Java, although I'm not sure that's even necessary. It would be nice to hear some Groovy best practices from someone with real world experience.

Yeah baby, yeah!

Add a comment

HTML : b, i, blockquote, br, p, pre, a href="", ul, ol, li
E-mail address
Remember me Yes  No 

E-mail addresses are not publicly displayed, so please only leave your e-mail address if you would like to be notified when new comments are added to this blog entry (you can opt-out later).

TrackBack to http://www.leegrey.com/hmm/addTrackBack.action?entry=1098732842000