Bonsai Image - Shanti Bithi Wisteria Demo Applet Written in Groovy

Back to the main applet index page

This applet, written in Groovy, prints information about all methods in a given class. The class may be either a Groovy class or a Java class.

Please allow a few moments for this applet to load: the Groovy runtime library (a reduced subset of the full embeddable library, about 900K in size) has to be loaded along with the applet itself (the library will be cached after the first time, so subsequent accesses of this page shouldn't take as long).

You'll be prompted to trust a digital certificate that's been self signed by me. This is normal behavior: to support its dynamic execution model, Groovy has to have some more Java permissions (like finding all methods on a class, etc) than the applet sandbox normally allows.

Try groovy.lang.GroovyObject, groovy.lang.MetaClass, etc

The Groovy Programming Language

Groovy is a dynamic programming language. It has syntax very similar to Java and can be run in an interpreted mode (with the "groovy" or "groovysh" commands), or can be compiled to Java byte code (using "groovyc") and run under a standard Java interpreter.

This applet represents my first exploration of the Groovy language. It demonstrates some of the ways that Groovy can simplify Java coding:

By way of a detailed example, here's the difference between implementing an AWT action listener as an anonymous inner class (the traditional Java way) vs. using a closure:

Anonymous class instance in traditional AWT code:

b.addActionListener( new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        System.out.println("Button Clicked! evt=" + evt.paramString());
    }
} );

Groovy closure:

b.action { evt ->
    println "Button Clicked! evt=${evt.paramString()}"
};

A couple of other things had to be created to support the above streamlined Groovy syntax (a generic implementation of ActionListener that executes any given Groovy Closure and a method definition on Button to set a Closure on it, see the links to the source code below for details), but with these general features implemented, it can be seen that the job of creating AWT action code becomes much easier in Groovy. And the intent of the code is much more clear: some code is being defined, to be executed when an action is performed on an AWT component. All the extra code in the first example, the declaration of the new ActionListener and the definition of the actionPerformed() method, is just mechanics to satisfy Java syntax: it doesn't really pertain to the application code.

And in fact, the effect is just about the same for each of the code samples above: Groovy closures get compiled to Java byte code as anonymous inner classes. This can be seen by listing the jar file that's built for this Groovy applet:

% jar tvf GroovyAWTApplet.jar 
  1017 Mon May 05 20:56:02 EDT 2008 META-INF/MANIFEST.MF
  1102 Mon May 05 20:56:02 EDT 2008 META-INF/AWTDEMO.SF
  1023 Mon May 05 20:56:02 EDT 2008 META-INF/AWTDEMO.DSA
     0 Mon May 05 20:56:04 EDT 2008 META-INF/
   415 Mon May 05 20:56:00 EDT 2008 ActionClosure.class
   724 Mon May 05 20:56:00 EDT 2008 BorderLayoutPanel.class
   555 Mon May 05 20:56:00 EDT 2008 FlowLayoutPanel.class
  1924 Mon May 05 20:56:02 EDT 2008 GroovyAWTApplet$_init_closure1.class
  1925 Mon May 05 20:56:02 EDT 2008 GroovyAWTApplet$_init_closure2.class
  2591 Mon May 05 20:56:02 EDT 2008 GroovyAWTApplet$_init_closure3.class
  2296 Mon May 05 20:56:02 EDT 2008 GroovyAWTApplet$_init_closure4.class
  2154 Mon May 05 20:56:02 EDT 2008 GroovyAWTApplet$_init_closure5.class
 35408 Mon May 05 20:56:02 EDT 2008 GroovyAWTApplet.class
   381 Mon May 05 20:56:00 EDT 2008 KeyPressClosure.class

Each of the "$..._closureN.class" classes above is a Java inner class that corresponds to a Groovy closure.

Signing Groovy for Applet Execution

It's always a great learning experience to try writing Java code that runs in different contexts. Up until now I had been playing with small Groovy applications run under either the "groovy" or "java" interpreters. In writing this applet, I immediately had to confront a new issue that I hadn't anticipated: the Groovy runtime jar file had to be digitally signed! This is because Groovy uses Java introspection in the course of executing the compiled byte code. It's part of how Groovy operates: methods can be accessed dynamically at runtime, but in order to find those methods, Java introspection has to be used, and some introspective methods require more permissions than the Java applet security "sandbox" normally allows.

Signing an applet is pretty easy: create a digital certificate using the 'keytool' command and then use 'jarsigner' to sign the applet jar with it (both commands are part of the Java distribution):

$ keytool -genkey -keystore awtdemo.keystore -alias awtdemo -validity 3650
...
$ jarsigner -keystore awtdemo.keystore groovy-subset-1.5.4-signed.jar awtdemo

Since this is a "self signed" certificate and not one that is verified by a certificate that was bought from a certificate authority, the browser will prompt to ask whether the certificate should be trusted before allowing the applet to run.

Originally, I thought I had to sign both the applet and the Groovy jar file, but a little experimentation showed that it was really only the Groovy jar file itself that had to be signed: it's the code that's performing a privileged action that has to be signed. The stack trace of the security exception showed that the exception was occurring in the Groovy runtime jar file itself - it seems there's some code that's part of the Groovy implementation that tries to access methods of application classes, and that is a secure operation that must be permitted in the Applet sandbox. So creating a signed version of the Groovy jar file was sufficient.

Below is a link to the Ant build file used to build this applet; this includes a target for for generating the keystore with the signed certificate and creating a signed version of the Groovy jar file.

Reducing the Size of the Groovy Runtime Code

Another issue I addressed was the size of the code required to run this applet with Groovy. The Groovy runtime all comes in one jar file; as of Groovy 1.5.4, this jar file was 2.9 megabytes in size. This jar includes everything needed to run Groovy in any environment, things like the groovyc compiler, Ant tasks for building groovy code, the Groovy console GUI and shell, etc, things that really aren't needed to run a simple applet. And it does take a long time to load that jar file when running the applet for the first time in a browser. So I went through the exercise of creating a jar file holding a reduced subset of the Groovy code, just enough to let this demo applet run.

I wrote an Ant target to create the subset jar file because it's easy to include and exclude entire subdirectories of files in the Ant <jar> task. Eventually, I captured the complete process of subsetting the jar file in Ant: unjar the full Groovy jar file to a directory, create the subset jar file, digitally sign the jar file, and clean up after. This target is included in the Ant build file below, but here is the summary of the classes that were excluded from the subset (as well as a few that I found I really had to include after all):

<exclude name="groovy/inspect/swingui/**/*.class"/>
<exclude name="groovy/lang/GroovyShell*.class"/>
<exclude name="groovy/mock/**/*.class"/>
<exclude name="groovy/model/**/*.class"/>
<exclude name="groovy/servlet/**/*.class"/>
<exclude name="groovy/sql/**/*.class"/>
<exclude name="groovy/swing/**/*.class"/>
<exclude name="groovy/ui/**/*.class"/>
<exclude name="groovy/text/**/*.class"/>
<exclude name="groovy/time/**/*.class"/>
<exclude name="groovy/util/ConfigSlurper*.class"/>
<exclude name="groovy/util/slurpersupport/*.class"/>
<exclude name="groovy/xml/**/*.class"/>
<exclude name="groovyjarjarantlr/**/*.class"/>
<exclude name="groovyjarcommonscli/**/*.class"/>
<exclude name="org/codehaus/groovy/ant/**/*.class"/>
<exclude name="org/codehaus/groovy/antlr/**/*.class"/>
<exclude name="org/codehaus/groovy/classgen/**/*.class"/>
<exclude name="org/codehaus/groovy/groovydoc/**/*.class"/>
<exclude name="org/codehaus/groovy/tools/groovydoc/**/*.class"/>
<exclude name="org/codehaus/groovy/tools/javac/**/*.class"/>
<exclude name="org/codehaus/groovy/tools/shell/**/*.class"/>

<!-- The following are required for the applet to run and could not be excluded: -->
<!-- Required: name="org/codehaus/groovy/control/**/*.class"/ -->
<!-- Required: name="groovyjarjarasm/**/*.class"/ -->
<!-- Required: name="org/codehaus/groovy/ast/**/*.class"/ -->
<!-- Required: name="org/codehaus/groovy/vmplugin/**/*.class"/ -->
With the above classes excluded, the subset Groovy jar file came in at 955K, 32% of the size of the full jar file. I did a pretty coarse-grained job of it, only selecting entire packages for exclusion. I could probably have fine-tuned the process a little further, excluding individual class files, but this first pass probably got 90% of the unused classes out, and further work probably wouldn't gain that much more benefit. Running with the subset Groovy jar file definitely makes applet load time a lot shorter!

Source Code:
demoapplet.groovy
ActionClosure.java
KeyPressClosure.java
BorderLayoutPanel.java
FlowLayoutPanel.java
build.xml (Ant build file that compiles code and signs applet jar)

[Back to the Applets Page] Back to my Applets page.