Chapter 11. Integrating Groovy

 

We build too many walls and not enough bridges.

 
 --Isaac Newton

One of the biggest advantages of Groovy (even one of the reasons for its inception) is the fact it integrates natively with Java because both languages run on the same platform. It is important to understand what makes Groovy such an attractive option when you need to embed a scripting language in your application.

First of all, from a corporate perspective, it makes sense to build on the same platform that most of your projects are already running on. This protects the investment in skills, experience, and technology, mitigating risk and thus costs.

Where Java isn’t a perfect fit as a language, Groovy’s expressiveness, brevity, and power features may be more appropriate. Conversely, when Groovy falls short because of the inevitable trade-off between agility and speed, performance-critical code can be replaced with raw Java. These balancing decisions can be made early or late with few repercussions due to the close links between the two languages. Groovy provides you with a transparent integration mechanism that permits a one-to-one mix-and-match of Java and Groovy classes. This is not always the case with other scripting solutions, some of which just provide wrappers or proxies that break the object hierarchy contract.

This chapter will show you how to integrate Groovy with Java in various ways. First we’ll examine three facilities provided by Groovy: GroovyShell, GroovyScriptEngine, and GroovyClassLoader. We will then consider the scripting support provided by the Spring framework and Java 6, code-named Mustang.

You will see that by integrating Groovy and Java, you can leverage the vast libraries of available Java classes and also enjoy the benefits of the extremely agile dynamic capabilities Groovy provides. All this can be done with seamless integration of the two languages.

Getting ready to integrate

The interplay between Groovy and Java means that it is easy to make them cooperate in various ways. The most obvious way is to make Groovy code call into Java code, either using one of the command-line tools to load and run Groovy scripts directly, or using groovyc to compile Groovy into normal Java class files. This assumes that all the code is known before the application needs to be compiled. It doesn’t allow for any just-in-time provision of code, whether that’s through users entering expressions as they might into a graphing calculator or developers providing replacement scripts for just the bits of code that require frequent changes within a live system.

As an idea of how widely used this kind of facility can be, consider Visual Basic (VB). We’re not in the business of judging its pros and cons, but it would be hard to deny that VB is popular and has been for a long time. Although many developers write whole applications in VB from scratch, far more use the capability of various products to embed pieces of VB code in order to customize behavior in ways the original developers may never have even considered.

Now consider allowing that kind of flexibility in your application. Instead of hearing people talking about writing VB in Microsoft Office, imagine those same people talking about writing Groovy in your application. Imagine them using your product in ways you never contemplated—making it more and more valuable for them.

Before seeing how this can be done, we should step back and think about why we would need to integrate Groovy in a Java application, the situations in which it’s useful to do so, and the dependencies we need to set up before we get started.

Integrating appropriately

No-one can tell you what your application needs are or what is going to be suitable for your particular situation. You must look carefully at your requirements and consider whether you will benefit from integrating Groovy at all. We can’t make that decision for you—but we hope we can give a few ideas to guide you.

First, it’s worth explicitly acknowledging that not all applications benefit from integrating a scripting language such as Groovy. We can go as far as saying that most don’t need that. If you’re writing an e-Commerce web site, a multimedia player, or an FTP client, chances are that you won’t need a scripting language. But now, suppose you were building an advanced word processor, a spreadsheet application, or a complex risk-calculation module for an even more complicated bank software suite that had to evolve quickly to follow the rapid changes of the market, legislation, or new business rules. These applications might need an extension point where end users can customize them to suit their needs. Figure 11.1 shows one example of where you could integrate Groovy.

One example of an integration solution. Groovy code is entered by the user in the user interface layer and then executed in the business layer.

Figure 11.1. One example of an integration solution. Groovy code is entered by the user in the user interface layer and then executed in the business layer.

For instance, the banking application might require the definition of business rules in a script that could be defined at runtime without requiring a new and tedious development/test/qualification phase, reducing the time to market and increasing the responsiveness to changes in financial practices. Another example could be an office suite of applications offering a macro system to create reusable functions that could be invoked with a keystroke. It becomes obvious that a dichotomy of the software world differentiates monolithic applications, which don’t need to evolve over time and have a fixed functional scope, from more fluid applications whose logic can be extended or modified during their lifespan to accommodate context changes.

Before considering using Groovy in your application, you need to analyze whether you need to customize it, and see whether you want to customize, extend, or amend the logic, and not just simple parameters. If parameterization will fulfill your needs, you may be better off with classic configuration mechanisms such as an administration web interface through a set of web services; or, for more advanced monitoring and action management, you may also consider exposing JMX[1] MBeans. Sometimes, even if the logic has to change, if the choice is between a small and well-defined set of business rules that are known to begin with, you can also embed all those rules within the application and decide through parameterization which one is to be used. Once you have examined your needs and come to the conclusion that a scripting environment is what your application requires, this chapter should provide you with all the information you need to make your application extendable at runtime with logic written in Groovy.[2]

In the following sections, you’ll learn how to use the GroovyShell class to evaluate simple expressions and scripts, as well as the GroovyClassLoader for further loading of Groovy classes. In addition to the techniques provided by Groovy for integrating your scripts in Java, you’ll discover alternatives for leveraging the Spring framework and the scripting API within the upcoming Java 6 release.

Setting up dependencies

In order to use Groovy within your project, you will need to set it up to use the Groovy libraries. This section covers the dependencies required for Groovy integration. The fact that it’s so short should be a source of comfort—there’s little work to do to get up and running. However, problems can sometimes crop up during integration that you wouldn’t see if you were using Groovy by itself. We will discuss these potential issues and how to resolve them.

The Groovy distribution comes with a directory containing all the core libraries that form the Groovy runtime. The minimum for embedding Groovy consists of the three jar files listed in table 11.1.

Table 11.1. The minimal jar files required for integrating Groovy

File

Purpose

groovy-1.0.jar

Groovy core library

antlr-2.7.5.jar

Grammar parser and generator

asm-2.2.jar

Bytecode toolkit used to generate classes

But these three dependencies may sometimes conflict with the other libraries your project uses. In particular, if you are using Hibernate and/or Spring, which both use ASM for generating proxies, you will not be able to use Groovy unless the version of Hibernate or Spring you are using requires the same version of ASM. However, there is a solution to this problem. The Groovy distribution also comes with a specific Groovy jar file that embeds the dependencies in their own packages. This library is often called the embeddable jar file, because you can embed it beside any other library without any conflict. You will find this jar file in the directory named embeddable of your Groovy installation: groovy-all-1.0.jar.

Remember that if your project depends on ASM or Antlr, you can use this “magic” jar file to solve your versioning issues between Groovy and your other dependencies. Also, keep in mind that your project will have to run under a JRE 1.4 or above, which is a requirement for Groovy.

It’s not just Java applications that can benefit from the availability of a scripting engine: You can even integrate custom Groovy scripts and expressions from an application written in Groovy! While explaining the various embedding mechanisms, we will show how the Groovy interpreters and classloaders can be exploited from both sides of the language fence. Now that we have set up our environment, we can look at the first of our three ways of directly integrating with Groovy: GroovyShell.

Evaluating expressions and scripts with GroovyShell

The first Groovy API we’ll examine is GroovyShell. This is in many ways the simplest of the integration techniques, and if it covers your situation, it may well be all you need. With all the libraries in place, we will start dynamically evaluating expressions in a few simple lines of code. We will then move gradually into more complex scenarios, passing data between the calling code and the dynamically executing script, and then creating classes in the script for use outside. We examine different ways of executing scripts—precompiling them or executing them just once—and the different types of scripts that can be run. Finally, we look at ways you can tweak GroovyShell for more advanced uses. Don’t worry if it seems there’s a lot to learn—in simple situations, simple solutions often suffice. Also, much of the information presented here is relevant when looking at the other APIs Groovy provides.

Starting simply

The simplest imaginable integration requirement evaluates an expression. For example, some math applications may require users to input arbitrary expressions in a form input field that can’t be hardwired at development time in a function or a closure—for instance, a spreadsheet application where formulas are Groovy expressions. Those applications then ask the runtime to calculate the entered formula. In such situations, the tool of choice for evaluating expressions and scripts is the GroovyShell class. The usage of this class is straightforward and is similar if you are using it from Java or from Groovy. A simple expression evaluator can look like listing 11.1.[3]

Example 11.1. A trivial example of expression evaluation in Groovy

def shell = new GroovyShell()
def result = shell.evaluate("12 + 23")
assert result == 35

The equivalent full Java program is naturally somewhat longer due to the scaffolding code and imports required, but the core logic is exactly the same. Listing 11.2 gives the complete Java code required to perform the evaluation, albeit it with no error handling. Java examples later in the chapter have been cut down to just the code involved in integration. Imports are usually shown only when they are not clear from the context.

Example 11.2. The same trivial example from listing 11.1, in Java this time

// Java
import groovy.lang.GroovyShell;

public class HelloIntegrationWorld {
    public static void main(String[] args) {
        GroovyShell shell = new GroovyShell();
        Object result = shell.evaluate("12+23");
        assert new Integer(35).equals(result);
    }
}

In both cases, we first instantiate an instance of groovy.lang.GroovyShell. On this instance, we call the evaluate method, which takes a string as a parameter containing the expression to evaluate. This evaluate method returns an object holding the value of the expression. We won’t show the Java equivalent for all the examples in this chapter, but we sometimes provide one, as much as anything to remind you of how easy it is.[4]

Among the evaluate overloaded methods present in GroovyShell, here are the most interesting ones:

Object evaluate(File file)
Object evaluate(InputStream in)
Object evaluate(InputStream in, String fileName)
Object evaluate(String scriptText)
Object evaluate(String scriptText, String fileName)

You can evaluate expressions coming from a string, an input stream, or a file. The additional filename parameter is used to specify the name of the class to be created upon evaluation of the script—because Groovy always generates classes for scripts, too.

From Groovy scripts, a shortcut can be used: Scripts are classes extending the Script class, which already has an evaluate method, too. In the context of a script, our previous example can be shortened to the following:

assert evaluate("12 + 23") == 35

The string parameter passed to evaluate can be a full script with several lines of code, not just a simple expression, as you see in listing 11.3.

Example 11.3. Evaluating a multiline script with GroovyShell

def shell = new GroovyShell()
def kineticEnergy = shell.evaluate('''
    def mass = 22.3
    def velocity = 10.6
    mass * velocity**2 / 2
''')
assert kineticEnergy == 1252.814

Building on GroovyShell, the groovy.util.Eval class can save you the boilerplate code of instantiating GroovyShell to evaluate simple expressions with zero to three parameters. Listing 11.4 shows how to use Eval for each case from Groovy (the same applies for Java, of course).

Example 11.4. Eval saves explicitly creating a GroovyShell for simple cases

assert "Hello" == Eval.me("'Hello'")
assert 1 == Eval.x  (1, "x")
assert 3 == Eval.xy (1, 2, "x+y")
assert 6 == Eval.xyz(1, 2, 3, "x+y+z")

The me method is used when no parameters are required. The other methods are used for one, two, and three parameters, where the first, second, and third parameters are made available as x, y, and z, respectively. This is handy when your sole need is to evaluate some simple expressions or even mathematical functions. Next, you will see how you can go further with parameterization of script evaluation with GroovyShell.

Passing parameters within a binding

In listing 11.3, we used a multiline script defining two variables of mass and velocity to compute the kinetic energy of an object of mass 22.3 kilograms with a speed of 10.6 km/h. However, notice that this is of limited interest if we can’t reuse the expression evaluator. Fortunately, it is possible to pass variables to the evaluator with a groovy.lang.Binding object, as shown in listing 11.5.

Example 11.5. Making data available to a GroovyShell using a Binding

Making data available to a GroovyShell using a Binding

To begin with, a Binding object is instantiated. Because Binding extends GroovyObjectSupport, we can directly set variables on it as if we were manipulating properties: The mass and velocity variables have been defined in the binding Making data available to a GroovyShell using a Binding. The GroovyShell constructor takes the binding as a parameter, and further on, all evaluations use variables from that binding as if they were global variables of the script Making data available to a GroovyShell using a Binding. When we change the value of the mass variable, we see that the result of the equation is different Making data available to a GroovyShell using a Binding. This line is particularly interesting because we have redefined the mass variable thanks to the setVariable method on Binding. That is how we could set or modify variables from Java; Java would not recognize binding.mass, because this is a shortcut introduced in Groovy by Binding extending GroovyObjectSupport.

You may have already guessed that if there is a setVariable method available, then getVariable also exists. Whereas the former allows you to create or redefine variables from the binding, the latter is used to retrieve the value of a variable from the binding. The evaluate method can return only one value: the value of the last expression of the evaluated script. When multiple values are needed in the result, the script can use the binding to make them available to the calling context. Listing 11.6 shows how a script can modify values of existing variables, or it can create new variables in the binding that can be retrieved later.

Example 11.6. Data can flow out of the binding as well as into it

Data can flow out of the binding as well as into it

In this example, we create a binding instance to which we add two parameters x and y by passing a map to the Binding constructor Data can flow out of the binding as well as into it. Our evaluated script creates two new variables in the binding by assigning a value to nondefined variables: xSquare and yCube Data can flow out of the binding as well as into it. We can retrieve the values of these variables with getVariable from both Java and Groovy Data can flow out of the binding as well as into it, or we can use the property-like access from Groovy Data can flow out of the binding as well as into it.

Not all variables can be accessed with getVariable because Groovy makes a distinction in scripts between defined variables and undefined variables: If a variable is defined with the def keyword or with a type, it will be a local variable, but if you are not defining it and are assigning it a value without prior definition, a variable will be created or assigned in the binding. Here, "localVariable" is not in the binding, and the call to getVariable would throw a MissingPropertyException:

def binding = new Binding()
def shell = new GroovyShell(binding)
shell.evaluate('''
    def localVariable = "local variable"
    bindingVariable   = "binding variable"
''')

assert binding.getVariable("bindingVariable") == "binding variable"

Anything can be put into or retrieved from the binding, and only one return value can be returned as the evaluation of the last statement of the script. The binding is the best way to pass your domain objects or instances of predefined or prepopulated sessions or transactions to your scripts. Let’s examine a more creative way of returning a value from your script evaluation.

Generating dynamic classes at runtime

Using evaluate can also be handy for generating new dynamic classes on the fly. For instance, you may need to generate classes for a web service at runtime, based on XML elements from the WSDL for the service. A contrived example for evaluating and returning a dummy class is shown in listing 11.7.

Example 11.7. Defining a class in an evaluated script

Defining a class in an evaluated script

In all the examples you’ve seen so far, we have used the evaluate method, which compiles and runs a script in one go. That’s fine for one-shot evaluations, but other situations benefit from separating the compilation (parsing) from the execution, as you will see next.

Parsing scripts

The parse methods of GroovyShell return instances of Script so that you can reuse scripts at will without re-evaluating them each time—hence without compiling them all over again. (Remember our SwingBuilder plotter from chapter 8.) This method is similar to evaluate, taking the same set of arguments; but rather than executing the code, it generates an instance of the Script class. All scripts you can write are always instances of Script.

Let’s take a concrete example. Suppose we’re running a bank, and we have customers asking for a loan to buy a house. We need to compute the monthly amount they will have to pay back, knowing the total amount of the loan, the interest rate, and the number of months to repay the loan. But of course, we want to reuse this formula, and we are storing it in a database or elsewhere on the filesystem in case the formula evolves in the future.

Let’s assume the variables of the algorithm are as follows:

  • amount: The total amount of the loan (the principle)

  • rate: The annual interest rate

  • numberOfMonths: The number of months to reimburse the loan

With these variables, we want to compute the monthly payment. The script in listing 11.8 shows how we can reuse the formula to calculate this important figure.

Example 11.8. Multiple uses of a monthly payment calculator

Multiple uses of a monthly payment calculator

After defining our formula, we parse it with GroovyShell.parse to retrieve an instance of Script. We then set the variables of the script binding for our three variables. Note how we can shorten script.binding.someVariable to script.someVariable because Script implements GroovyObject and overrides its setProperty method. Once the variables are set, we call the run method, which executes the script and returns the value of the last statement: the monthly payment we wanted to calculate in the first place.

To reuse this formula without having to recompile it, we can reuse the script instance and call it with another set of values by defining a new binding, rather than by modifying the original binding as in the first run.

Running scripts or classes

The run methods of GroovyShell can execute both scripts and classes. When a class is parsed and recognized as extending GroovyTestCase, a text test runner will run the test case.

The three main run method signatures can take a String, a File, or an InputStream to read and execute the script or class, a name for the script, and an array of Strings for the arguments:

run(String script, String[] args)
run(File scriptFile, String scriptName, String[] args)
run(InputStream scriptStream, String scriptName, String[] args)

The execution of run is a bit different than that of evaluate. Whereas evaluate evaluates only scripts, run can also execute classes with a main method as well as unit tests. The following rules are applied:

  • If the class to be run has a main(Object[] args) or main(String[] args) method, it will be run. Note that a script is a normal Java class that implements Runnable and whose run method is called by a main method.

  • If the class extends GroovyTestCase, a JUnit test runner executes it.

  • Otherwise, if the class implements Runnable, it is instantiated with a constructor taking a String array, or a default constructor, and the class is run with its run method.

Further parameterization of GroovyShell

We used the Binding class to pass variables to scripts and to retrieve modified or new variables defined during the evaluation of the script. We can further configure our GroovyShell instance by passing two other objects in the constructor: a parent ClassLoader and/or a CompilerConfiguration.

For reference, here are the constructor signatures available in GroovyShell:

public GroovyShell()
public GroovyShell(Binding binding)
public GroovyShell(Binding binding,
                   CompilerConfiguration config)
public GroovyShell(CompilerConfiguration config)
public GroovyShell(ClassLoader parent)
public GroovyShell(ClassLoader parent,
                   Binding binding)
public GroovyShell(ClassLoader parent,
                   Binding binding,
                   CompilerConfiguration config)

Choosing a parent classloader

Groovy uses classloaders to load Groovy classes. The consequence is that you must have a minimal understanding of how classloaders work when integrating Groovy. Alas, mastering classloaders is not the most trivial task on a Java developer’s journey. When you’re working with libraries generating classes or dynamic proxies at runtime with bytecode instrumentation, or with a complex hierarchy of classloaders to make critical code run in isolation in a secured sandbox, the task becomes even trickier. It is important to understand how the hierarchy of classloaders is structured.

A common use case is represented in figure 11.2.

Tree classloader structure

Figure 11.2. Tree classloader structure

A class loaded by classloader B can’t be seen by classloader C. The standard way classloaders load classes is by first asking the parent classloader if it knows the class, before trying to load the class. Classes are looked up by navigating up the classloader hierarchy; however, a class loaded by C won’t be able to see a class loaded by B, because B is not a parent of C. Fortunately, by cleverly setting the parent classloader of C to be B, the problem is solved, as shown in figure 11.3. This can be done by using GroovyShell’s constructors, which permits you to define a parent classloader for the scripts being evaluated.

Linear classloader structure

Figure 11.3. Linear classloader structure

To specify GroovyShell’s classloader, specify the parent classloader to flatten your hierarchy:

def parentClassLoader = objectFromB.classloader
def shellForC = new GroovyShell(parentClassLoader)

If you have classloader issues, you will get a ClassNotFoundException or, worse still, a NoClassDefFoundError. To debug these issues, the best thing to do is to print the classloader for all affected classes and also print each classloader’s parent classloader, and so on up to the root of all classloaders. You’ll then have a good picture of the whole classloader hierarchy in your application, and the final step will be to set parent classloaders accordingly to flatten the hierarchy—even better, try to make classes be loaded by the same classloaders if possible.

Configuring the compilation

In the list of constructors of the GroovyShell class, you will have noticed the CompilerConfiguration parameter. An instance of this class can be passed to GroovyShell to customize various options of the compilation process. You will also see how to take advantage of this class with the GroovyClassLoader in a following section.

Without studying all the options available, let’s review the most useful ones, as shown in table 11.2.

Table 11.2. The most useful methods in CompilerConfiguration

Method signature

Description

setClasspath (String path)

Define your own classpath used to look for classes, allowing you to restrict the application classpath and/or enhance it with other libraries

setDebug (boolean debug)

Set to true to get full, unfiltered stacktraces when exceptions are written on the error stream

setOutput(PrintWriter writer)

Set the writer compilation errors will be printed to

setScriptBaseClass(String clazz)

Define a subclass of Script as the base class for script instances

setSourceEncoding (String enc)

Set the encoding of the scripts to evaluate, which is important when parsing scripts from files or input streams that use a different encoding than the platform default

setRecompileGroovySource (boolean b)

Set to true to reload Groovy sources that have changed after they have been compiled—by default, this flag is set to false

setMinimumRecompilationInterval (int millis)

Set the minimum amount of time to wait before checking if the sources are more recent than the compiled classes

Of these methods, setScriptBaseClass is particularly worthy of note. If you want all of your scripts to share a common set of methods, you can specify a base class extending groovy.lang.Script that will host these methods and then be available inside the scripts. Sharing methods among scripts is a good technique to inject hooks to your own framework services. Let’s consider a base script class that extends Script and whose role will be to inject a global multiplication function[5] into all scripts evaluated by GroovyShell:

abstract class BaseScript extends Script {
    def multiply(a, b) { a * b }
}

BaseScript extends Script, which is an abstract class, so the class must be declared abstract, because the run method is abstract. When compiling or interpreting scripts, Groovy will extend this base script and will inject the script’s statements in the run method.

To make this class the base class of your scripts, you now need to pass a org.codehaus.groovy.control.CompilerConfiguration instance to GroovyShell’s constructor, as explained by the following Groovy example:

def conf = new CompilerConfiguration()
conf.setScriptBaseClass("BaseScript")
def shell = new GroovyShell(conf)
def value = shell.evaluate('''
    multiply(5, 6)
''')
assert value == 30

This is not the only way to inject functions in all your scripts. Another trick to share functions between scripts is to store closures in the binding of GroovyShell without needing to use CompilerConfiguration. This can be seen in listing 11.9.

Example 11.9. Using the Binding to share functions between scripts

Using the Binding to share functions between scripts

However, you also need to be able to write the same code in Java, so we must be able to create closures and put them in the binding. From Java, creating a closure is not as neat as in Groovy. You must create a class that derives from groovy.lang.Closure and implement an Object doCall(Object arguments) method. An alternative technique is to create an instance of org.codehaus.groovy.runtime. MethodClosure, which delegates the call to a multiplication method on a custom multiplicator class instance:

// Java
MethodClosure mclos = new MethodClosure(multiplicator, "multiply");
Binding binding = new Binding();
binding.setVariable("multiply", mclos);
GroovyShell shell = new GroovyShell(binding);
shell.evaluate("multiply(5, 6)");

We have now fully covered how GroovyShell can be operated both from Java and from Groovy to extend your application. GroovyShell is a nice utility class to create extension points in your own code and to execute logic that can be externalized in scripts stored as strings, on the filesystem, or in a database. This class is great for evaluating, parsing, or running scripts that represent a single and self-contained unit of work, but it is less easy to use when your logic is spread across dependent scripts. This is where the GroovyScriptEngine and GroovyClassLoader can help. These are the topics of the next two sections.

Using the Groovy script engine

The GroovyShell class is ideal for standalone and isolated scripts, but it can be less easy to use when your scripts are dependent on each other. The simplest solution at that point is to use GroovyScriptEngine. This class also provides the capability to reload scripts as they change, which enables your application to support live modifications of your business logic. We will cover the basic uses of the script engine and show you how to tell the engine where to find scripts.

Setting up the engine

The scripting engine has several constructors to choose from when you instantiate it. You can pass different arguments to these constructors, such as an array of paths or URLs where the engine will try to find the Groovy scripts, a classloader to be used as the parent classloader, or a special ResourceConnector that provides URLConnections. In our examples, we will assume that we are loading and running scripts from the filesystem:

def engine = new GroovyScriptEngine(".")

or with an array of URLs or of strings representing URLs:

def engine = new GroovyScriptEngine([".", "../folder "])

The engine assumes that strings represent filesystem locations. If your scripts are to be loaded from somewhere other than the filesystem, you should use URLs instead:

def engine = new GroovyScriptEngine(
    ["file://.", "http://someUrl"]*.toURL() as URL[])

The engine will search the resource following each URL sequentially until it finds the script.

The various constructors can also take a classloader, which will then be used by the engine for the parent classloader of the compiled classes:

def engine = new GroovyScriptEngine(".", parentCL)

The parent classloader can also be defined with the setParentClassLoader method.

Once you have instantiated the engine, you can eventually run your scripts.

Running scripts

To run a script, the primary mechanism is the run method of GroovyScriptEngine. This method takes two arguments: the name of the script to run as the relative path of the file and the binding to store the variables that the script will need to operate. The method also returns the value of the last expression evaluated by the script, as GroovyShell does.

For instance, if you intend to run a file named MyScript.groovy situated in the test folder relative to the current directory, you might run it as shown here:

def engine = new GroovyScriptEngine(".")
def value  = engine.run("test/MyScript.groovy", new Binding())

Loaded scripts are automatically cached by the engine, and they are updated whenever the resource is updated. The engine can also load script classes directly with the loadScriptByName method; it returns a Class object representing the class of the script, which is a derived class of groovy.lang.Script. There is a pitfall to watch out for with this method, however: It takes a script with a fully qualified class name notation rather than the relative path of the file:

def engine = new GroovyScriptEngine(".")
def clazz  = engine.loadScriptByName("test.MyScript")

This example returns the class of the myScript.groovy script situated in the test folder. If you are not using the filesystem, you will be using URLs instead of files, and in that case it is mandatory to use a special resource connector that is responsible for loading the resources.

Defining a different resource connector

If you wish to load scripts from a particular location, you may want to provide your own resource connector. This is done by passing it as an argument to the constructor of GroovyScriptEngine, either with or without the specification of a parent classloader. The following example shows both overloaded methods:

def myResourceConnector = getResourceConnector()
def engine  = new GroovyScriptEngine(myResourceConnector)
def engine2 = new GroovyScriptEngine(myResourceConnector, parent)

To implement your own connector, you have to create a class implementing the groovy.util.ResourceConnector interface, which contains only one method:

public URLConnection getResourceConnection(String name)
    throws ResourceException;

The getResourceConnection method takes a string parameter representing the name of the resource to load, and it returns an instance of URLConnection. If you are also creating your own URLConnection, at least three methods need to be implemented properly (you could potentially leave the others aside and throw UnsupportedOperationException or UnknownServiceException, like some JDK classes from the java.net package do):

public long        getLastModified()
public URL         getURL()
public InputStream getInputStream() throws IOException

Although usually you’ll store your script on the filesystem or inside a database, implementing your own ResourceConnector and URLConnection allows you to provide a handle on scripts coming from any location: from a database, a remote file system, an XML document, or an object data store.

GroovyScriptEngine is perfect for dealing with scripts, but it falls short for more complex manipulation of classes. In fact, both GroovyShell and GroovyScriptEngine rely on a single mechanism for loading scripts or classes: the GroovyClassLoader. This special classloader is what we will discuss in the following section.

Working with the GroovyClassLoader

The GroovyClassLoader is the Swiss-army knife with all possible tools for integrating Groovy into an application, whether explicitly or via classes such as GroovyShell. This class is a custom classloader, which is able to define and parse Groovy classes and scripts as normal classes that can be used either from Groovy or from Java. It is also able to compile all the required and dependent classes. Let’s see how you can compile a Groovy class.

This section will take you through how to use the GroovyClassLoader, from the simplest uses to more involved situations. We examine how to get around circular dependency issues, how to load scripts that are stored outside the local filesystem, and finally how to make your integration environment safe and sandboxed, permitting the scripts to perform only the operations you wish to allow.

Parsing and loading Groovy classes

Say we have a simple Groovy class Hello like the following:

class Hello {
    def greeting() { "Hello!" }
}

We want to parse and load this class with the GroovyClassLoader. In Groovy, we can do it like so:

def   gcl = new GroovyClassLoader()
Class greetingClass = gcl.parseClass(new File("Hello.groovy"))
assert "Hello!" == greetingClass.newInstance().greeting()

Note

Instantiating GroovyClassLoader—In our example, we use the default constructor. But this class offers more constructors. GroovyClassLoader (ClassLoader loader) lets you define a parent classloader to avoid problems with a complex hierarchy, as we explained in the section about GroovyShell. The constructor GroovyClassLoader(ClassLoader loader, CompilerConfiguration config) gives you more control over the behavior of the classloader, as explained in the section about GroovyShell, thanks to the parameterization of CompilerConfiguration.

An instance of GroovyClassLoader is created, and its parseClass method is called and passed our Hello.groovy file. The method returns a Class object that can then be instantiated by using Class’s newInstance method, which invokes the default constructor of Hello. Once Hello is instantiated, because Groovy supports duck typing, we can directly call the greeting method defined in Hello. However, in a strongly typed language, you could not directly call the method. So, from Java, to invoke a method, you have to either use reflection explicitly—which is usually pretty ugly—or rely on the fact that all Groovy classes automatically implement the groovy.lang.GroovyObject interface, exposing the invokeMethod, getProperty, and setProperty methods.

Duck Typing

As coined by the dynamic language community, “If it walks like a duck and quacks like a duck, it must be a duck.” Weakly typed languages usually let you call any method or access any property on an object, even if you don’t know at compile-time or even at runtime that the object is of a known type that contains that method or property. This means you know the kind of objects you expect will have the relevant signature or property. It’s an assumption. If you can call the method or access the property, it must be the type you were expecting—hence, it’s a duck because it walks and quacks like a duck!

Duck typing implies that as long as an object has a certain set of method signatures, it is interchangeable with any other object that has the same set of methods, regardless of whether the two have a related inheritance hierarchy.

Whereas getProperty and setProperty are responsible for accessing properties of your Groovy class from Java, invokeMethod allows you to call any method on Groovy classes easily from Java:

// Java
GroovyClassLoader gcl = new GroovyClassLoader();
Class greetingClass = gcl.parseClass(new File("Hello.groovy"));
GroovyObject hello  = (GroovyObject) greetingClass.newInstance();
Object[] args   = {};
assert "Hello!".equals(hello.invokeMethod("greeting", args));

The invokeMethod method takes two parameters: The first one is the name of the method to call, and the second corresponds to the parameters to pass to the method we’re trying to call. If the method takes only one parameter, pass it directly as an argument; otherwise, if several parameters are expected, they have to be wrapped inside an array of Objects, which becomes the argument. For instance, if you wish to call a method that adds two objects together with a signature like add(a,b), you call it like this:

a.invokeMethod("add", new Object[] {obj1, obj2}); // Java

However, if a method you want to call requires an array as its single parameter, you also have to wrap it inside an array:

a.invokeMethod("takesAnArray", new Object[] {anArray}); // Java

Despite the fact that it is possible to call any method in a Groovy class from Java with invokeMethod, doing so is not Java-friendly because the Java compiler will not know these classes exist and will not let you use the greeting method directly—unless you precompiled your Groovy classes and packed them up inside a jar file. Fortunately, there is a workaround to circumvent this shortcoming of javac. To make Java understand your Groovy classes, both Groovy and Java have to find a common ground of agreement. This is what we call the chicken and egg problem.

The chicken and egg dependency problem

Groovy and Java both have no problem accessing, extending, or implementing compiled classes or interfaces from the other language. But at the source code level, neither compiler is really aware of the other language’s source files. If you want to work seamlessly between the two languages, the trick is to always compile dependent classes using the appropriate compiler prior to compiling a class that uses a dependent class.

This sounds simple, but in practice, there are many tricky scenarios, such as compiling a Java file that depends on a Groovy file that depends on a Java file. Before you know it, you can quickly end up with intricate dependencies crossing the boundaries of each language. In the best scenario, you may have to alternate back and forth between the two language compilers until all the relevant classes are compiled. A more likely scenario is that it will become difficult to determine which compiler to call when. The worst case scenario—and it’s not uncommon—occurs when you have circular dependencies. You will reach a deadlock where neither language will compile because it needs the other language to be compiled first.

Example problem

This is the chicken and egg problem: Java classes depending on Groovy classes in turn depending on Java classes! To solve this puzzle, you can rely on a simple remedy: depending on Java base classes or interfaces.

To illustrate the problem, consider the following Java application:

// Java
public class ShapeInfoMain {
     public static void main(String[] args) {
         Square s = new Square(7);
         Circle c = new Circle(4);
         new MaxAreaInfo().displayInfo(s, c);
         new MaxPerimeterInfo().displayInfo(s, c);
    }
}

Suppose that the Square and MaxPerimeterInfo classes are written in Java and the Circle and MaxAreaInfo classes are written in Groovy. We might be tempted to try using javac on all the *.java source files followed by groovyc on all the *.groovy files. However, this won’t work because the displayInfo method in MaxPerimeterInfo requires Circle to be compiled first. We can’t swap the order around, either, because we will have the reverse problem with MaxAreaInfo if Square is not compiled first.

The dependencies between the files are shown in figure 11.4.

Java class with a direct dependency on Groovy classes

Figure 11.4. Java class with a direct dependency on Groovy classes

Removing the dependency cycle

The trick is to first compile Square and Circle using their respective compilers. Next, compile MaxAreaInfo and MaxPerimeterInfo. Finally, compile ShapeInfoMain. Usually, using an interface written in Java is the easiest way to make these dependencies less cumbersome. In our example, Circle and Square should both implement Shape, whereas MaxPerimeterInfo and MaxAreaInfo should implement ShapeInfo. Adding these interfaces results in the dependencies illustrated in figure 11.5.

Java classes and interfaces with Groovy implementations of the interfaces

Figure 11.5. Java classes and interfaces with Groovy implementations of the interfaces

Listing 11.10 shows what the Circle class might look like, implementing the Shape interface.

Example 11.10. Groovy class implementing a Java interface

Groovy class implementing a Java interface

The following is what MaxAreaInfo might look like. This time, we’re implementing the ShapeInfo interface:

import common.Shape
import common.ShapeInfo

class MaxAreaInfo implements ShapeInfo {
    void displayInfo(Shape s1, Shape s2) {
        print "The shape with the biggest area is: "
        println s1.area() > s2.area() ? s1.class.name :
                                        s2.class.name
    }
}

Building the solution in phases

Once the work of decoupling the concrete types from their interfaces is done, the Java compiler will be able to compile the Java classes first, and then groovyc will be able to compile the Groovy classes. It is a good practice to divide such a codebase into three modules: the Java code, the Groovy code, and the shared Java interfaces. The shared interfaces need to be compiled first. After that, you can javac the Java code and groovyc the Groovy code in either order.

Until the Java compiler is aware of classes not yet compiled in other languages, you have to use intermediary interfaces or abstract classes in Java to make the interaction between Java and Groovy smoother during the compilation process. Let’s hope some day the Java compilers will provide hooks for interacting with foreign compilers of alternative languages for the JVM.

In the meantime, we usually compile scripts and classes found on the filesystem of our computer; your sources may lie on a different medium—that’s particularly true when you are embedding Groovy in your application. A common scenario is when your sources are stored inside a database. In that case, you will have to provide your own resource loader to the GroovyClassLoader in the form of an instance of GroovyResourceLoader, as explained in the following section.

Providing a custom resource loader

The GroovyClassLoader has various methods to let you parse and load Groovy classes from different origins: from a file, from an input stream, or from a string. Here are a few of the methods to explicitly ask the classloader to load a given class:

public Class parseClass(File file)
     throws CompilationFailedException
public Class parseClass(String text, String fileName)
     throws CompilationFailedException
public Class parseClass(InputStream in, String fileName)
     throws CompilationFailedException

If you are storing your sources in a database, a possible solution is to retrieve them as a String or as an InputStream. Then, you can use the classloader’s parseClass methods to parse and load your classes. But rather than explicitly implementing the plumbing and the lookup and parsing yourself, Groovy provides a better solution, in the form of a groovy.lang.GroovyResourceLoader. The resource loader is an interface that you have to implement to specify where your sources are to be found: Give it a name of a resource, and a URL is returned that points at the location of the resource. This is done by a single method from that interface:

URL loadGroovySource(String filename) throws MalformedURLException

An implementation of the resource loader in Java will look something like the following class:

public class MyResourceLoader extends GroovyResourceLoader {
    public URL loadGroovySource(final String filename)
        throws MalformedURLException {
        URL url = ... // create the URL pointing at the resource
        return url;
    }
}

Note

Extending URL and URLConnectionAs was the case with GroovyScriptEngine, if you are creating your own URL and URLConnection derived classes, make sure your URL overrides its openConnection method, which returns an instance of URLConnection; and make sure you also override the getLastModified, getURL, and getInputStream methods of the returned URLConnection.

Once you have defined this class, you have to register it in your classloader before use:

GroovyClassLoader gcl = new GroovyClassLoader();
gcl.setResourceLoader(new MyResourceLoader());

Your classloader will now use your resource loader to find the resources it needs from wherever you want! At this point, you may find that you have less control than you like over what code is executed. You may need to lock down how much access the code has to the rest of the system, depending on how much you know about the code’s origins. This is where the Java and Groovy security model come into play, as you’ll see in the next section.

Playing it safe in a secured sandbox

When packaging an application, you know all your source code is trusted. When you open the doors for some dynamic code that might evolve over time, such as changing business rules due to a legislation change, you have to be sure that this code can be trusted too. Only trusted users should be able to change the dynamic code by logging in and providing the relevant credentials. But even with authentication and authorization in place, you’re never sheltered against human mistakes. That is why Groovy provides a second level of confidence in dynamic code in the form of a secured sandbox that you can set up to load this foreign code.

Modifying, loading, and executing dynamic code at runtime is a nice way to extend your application in an agile way, lessening the time required to adapt it as necessary. Long and tedious repackaging, requalifying, and redeployment scenarios can vanish in no time. This is not a subject to take lightly, and of course, you will always have to hand over your application to the acceptance team and pass the relevant integration tests; but embedding code from a scripting language in your application can help you to be more versatile when the requirements are changing.

The Java security model

However cool embedding a scripting or dynamic language can be, and however well designed your system is in terms of security, you can potentially add another layer of trust by letting this code run in a secured sandbox. Java provides the infrastructure for securing source code through its security model with the help of a security manager and the associated policy that dictates what permissions are granted to the code. For a simple example of what harm can happen to your application, imagine a user uploads a script containing System.exit(1): Your whole system could go down in a second if it’s not secured correctly! Fortunately, with some setup, it is possible to protect yourself from such malicious code.

Java Security

Covering the whole Java security model with its security managers, permissions, and policy files is beyond the scope of this chapter. We assume that you are already familiar with these concepts. If this is not the case, we recommend that you look at the online resources provided on Sun’s web site to get an in-depth view of how security works on the Java platform.

In the Java security model, code sources are granted permissions according to their code source. A code source is composed of a codebase in the form of a URL from which the source code was loaded by the classloader, and potentially a certificate used to verify the code when it is obtained from a signed jar file.

There are two cases you have to consider. If all your Groovy sources are compiled first into .class files and eventually bundled in a jar file, the standard security mechanisms apply. Those classes are like normal Java compiled sources, so you can always use the same security managers as normal. But when you are compiling Groovy sources on the fly, through the various integration means we have studied so far, extra steps need to be followed.

GroovyCodeSource and the security manager

When scripts and classes are loaded from the filesystem, they are loaded by a GroovyClassLoader, which searches the classpath for Groovy files and gives them a code source constructed from a codebase built from the URL of the source file. When Groovy sources are loaded from an input stream or from a string, no particular URL is associated with them. However, it is possible to associate a codebase with Groovy sources to be compiled by specifying a GroovyCodeSource—as long as the caller loading sources has the permission to specify the codebase. The codebase you associate with the sources need not refer to a real physical location. Its importance is to the security manager and policy, which allocate permissions based on URLs.

A concrete example is always better than long explanations. Say we are running an application on a server, and this application loads Groovy scripts that need to be sandboxed and should only be allowed to access the file.encoding system property. The server application should have all possible permissions; however, we have to restrict the loaded Groovy script reading the property. We write a policy file explicitly indicating those rules:

grant codeBase "file:${server.home}/classes/-" {
    permission java.security.AllPermission;
};

grant codeBase "file:/restricted" {
    permission java.util.PropertyPermission "file.encoding", "read";
};

The first part grants all permissions to our server application, whereas the second part only allows the scripts from the file:/restricted codebase to access the file.encoding property in read-only mode. This policy file should be available in the classpath of the application, and the system property java.security.policy defining the policy file to use should be specified either on the command line that launches the JVM or in code.

A script requesting to read the system property would include code such as:

def encoding = System.getProperty("file.encoding")

Your server application will load and evaluate the script using GroovyShell, using the methods that take a GroovyCodeSource to wrap the script and define its code source:

def script = '''
    System.getProperty("file.encoding")
'''
def gcs = new GroovyCodeSource(script, "ScriptName", "/restricted")
def shell = new GroovyShell()
println shell.evaluate(gcs)

A GroovyCodeSource can be built in various ways depending on how you retrieve the source code: from a string, a file, an input stream, or a URL. Here are the four constructors that allow you to build a GroovyCodeSource:

public GroovyCodeSource(String script, String name, String codeBase)
public GroovyCodeSource(InputStream inputStream, String name,
                        String codeBase)
public GroovyCodeSource(File file) throws FileNotFoundException
public GroovyCodeSource(URL url) throws IOException

In order for the calling application to be able to create a GroovyCodeSource with a specific codebase, it must be granted permission by the policy. The specific permission required is a groovy.security.GroovyCodeSourcePermission, which the calling application implicitly has because the policy file granted it the java.security.AllPermission, which grants all possible rights.

GroovyShell and GroovyClassLoader with GroovyCodeSource

Both GroovyShell and GroovyClassLoader allow you to specify GroovyCodeSources to wrap scripts or classes that must be secured—but GroovyScriptEngine doesn’t at the time of writing. If the Groovy source code is not wrapped inside a GroovyCodeSource, the policy will not be enforced, thus letting untrusted code run within the application.

In the sections related to GroovyShell and GroovyClassLoader, we enumerated several methods that allow you to evaluate, parse, or run Groovy scripts and classes. Let us mention now the methods that take a GroovyCodeSource, which you can use to make integrating dynamic code safer.

GroovyShell has two methods that take a GroovyCodeSource, one for evaluating scripts, and the other for parsing scripts:

public Object evaluate(GroovyCodeSource codeSource)
    throws CompilationFailedException
public Script parse(GroovyCodeSource codeSource)
    throws CompilationFailedException

GroovyClassLoader also has two methods; both parse classes, but the latter also provides an option to control whether the parsed class should be put in the classloader cache:

public Class parseClass(GroovyCodeSource codeSource)
    throws CompilationFailedException
public Class parseClass(GroovyCodeSource codeSource,
                        boolean shouldCache)
    throws CompilationFailedException

Armed with different means of integrating Groovy securely in your application, you can build extremely flexible applications. Of course, those mechanisms are specific to Groovy. These aren’t the only means available, however. If you are using the Spring framework as a common base for your application, or if you are living on the edge and already using the pre-release builds of the next generation Java platform (JDK 6.0—Mustang), you can use the mechanisms provided in these platforms to load your dynamic code in a way that would make it easy to move away from Groovy, should you ever wish to.[6]

Spring integration

As it says on the tin, Spring is an innovative layered Java/J2EE application framework and lightweight container invented by Rod Johnson, which matured while Rod was writing the book Expert One-on-One J2EE Design and Development. Spring generalized the concepts and patterns of Inversion of Control (IoC) and Dependency Injection (DI) and is built from two main building blocks: its IoC container and its Aspect Oriented Programming (AOP) system. The framework brings an additional abstraction layer that wraps common APIs such as transactions, JDBC, or Hibernate to help the developer focus on the core business tasks; gives access to AOP; and even provides its own Model View Controller (MVC) technology. The Spring framework can be used as a whole or piece by piece as needs arise.

Spring lets you wire your application components through dependency injection by instantiating, configuring, and defining the relationships between your objects in a central XML configuration file. Your objects are usually Plain Old Java Objects (POJOs), but they can also be Plain Old Groovy Objects (POGOs) because Groovy objects are also standard JavaBeans! This section explores how you can inject Groovy dependencies in your application object model, with options for letting beans refresh themselves automatically and specifying the bodies of scripts directly in the configuration file.

Spring 2.0 introduces support for integrating beans written in various scripting languages. Spring supports Groovy, BeanShell, and JRuby—some of the best known and proven scripting languages for the JVM. With this support, any number of classes written in these languages can be wired and injected in your application as transparently as if they were normal Java objects.

Note

Spring Framework documentation—It is beyond the scope of this section to explain how Spring can be installed, used, or configured. We are assuming that the interested reader is already familiar with the framework. If this is not the case, the creators of Spring have comprehensive and detailed online documentation at http://www.springframework.org/documentation that should be ideal for discovering what it is all about.

We will explain how you can wire up POGOs in Spring, discuss reloading Groovy source code on the fly, and finally cover how Groovy source can be specified directly in the configuration file, where appropriate. Let’s start with the simplest situation before working our way toward more complicated scenarios.

Wiring GroovyBeans

Let’s take the shape information classes from section 11.4 as an example.

We are going to use Spring’s bean factory to create the Groovy objects that our main program needs. All the definitions for our class are captured declaratively in a Spring configuration file, sometimes referred to as a wiring XML file. This is illustrated in figure 11.6.

Spring’s BeanFactory reads an XML configuration file and creates instances of the JavaBeans and GroovyBeans specified within it.

Figure 11.6. Spring’s BeanFactory reads an XML configuration file and creates instances of the JavaBeans and GroovyBeans specified within it.

We would normally wire both Java and Groovy classes in the wiring file and also indicate the dependencies between the different parts of our system in this file. In this case, though, we are going to keep it simple. We are going to specify simple definitions in the file to illustrate integration between Spring and Groovy. For now, we assume that all of our Groovy files are precompiled.

Here is what the Spring definition file, called beans.xml in our case, looks like:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
  <bean id="circle" class="spring.groovy.Circle">
    <constructor-arg value="4"/>
    <property name="color" value="Black"/>
  </bean>
  <bean id="maxareainfo" class="spring.groovy.MaxAreaInfo"/>
</beans>

In our Groovy source file, we have the same constructor that we had previously, and we have also added a color property to our Circle class. In the Spring definition file, the nested constructor element indicates the value to pass to the constructor during creation of our Circle. The property element indicates that the color property should also be set as part of initialization. To make use of these definitions, we need to change our main method in ShapeInfoMain to become

try {
    ApplicationContext ctx =
        new ClassPathXmlApplicationContext("beans.xml");
    Shape s = new Square(7);
    Shape c = (Shape) ctx.getBean("circle");
    ShapeInfo info = (ShapeInfo) ctx.getBean("maxareainfo");
    info.displayInfo(s, c);
    new MaxPerimeterInfo().displayInfo(s, c);
} catch (Exception e) {
    e.printStackTrace();
}

Spring provides a number of mechanisms to create beans for you. In this instance, we use what is called the application context. It has a getBean method that allows us to ask for a bean by name.

As we mentioned earlier, we are assuming here that all of our Groovy classes are precompiled. So, what have we gained? We have begun the process of removing explicit dependencies from our codebase. Over time, we could start moving more dependency information into the wiring file and allow our system to be configured more readily. As a consequence, our design also becomes more flexible, because we can swap our concrete implementations readily. This is particularly important for unit testing, where we might replace concrete implementations with mock implementations.

There is more we can do, though: Spring supports dynamic compilation of our Groovy scripts through a special Groovy factory class. Here is how we would use it. We would extend our bean configuration file as follows:

...
<lang:groovy id="maxareainfo2"
        script-source="classpath:MaxAreaInfo.groovy">
    <lang:property name="prefix" value="Live Groovy says" />
</lang:groovy>
...

Spring 2.0 supports a number of dynamic scripting languages through special language-specific factories. The namespace lang:groovy accesses the special Groovy factory automatically. Now we can use maxareainfo2 as the name we pass to the bean factory when creating our bean, and Spring will automatically compile the necessary Groovy source files.

Note that unlike the previous wiring file, which could mix setter and constructor-based injection, at the time of writing, only setter-based injection is supported when using the lang:groovy mechanisms.

Refreshable beans

Another feature that Spring provides is the ability to dynamically detect when Groovy source files change and automatically compile and load the latest version of any Groovy file during runtime. The concept is known as refreshable beans and is enabled in our definition file using the refresh-check-delay attribute as follows (in this case, setting the delay to five seconds):

...
<lang:groovy id="maxareainfo2"
        refresh-check-delay="5000"
        script-source="classpath:MaxAreaInfo.groovy">
    <lang:property name="prefix" value="Live Groovy says" />
</lang:groovy>
...

Refreshing beans on the fly can make development faster, but you should consider disabling it again for production systems—restarting the system after a change has been made tends to avoid confusing situations where for some period of time (however brief) only part of the system has seen the refresh.

Inline scripts

Although it’s arguably a bad idea to put code inside Spring’s configuration file, Spring offers another way to define scripted beans by inlining them—including the source directly in the configuration file. The Spring documentation mentions some scenarios for such a case, such as sketching and defining validators for Spring MVC controllers or scripting controllers for quick prototyping or defining logic flow.

In listing 11.11, we inline a variation of MaxAreaInfo (we need to change our factory getBean call to use maxareainfo3).

Example 11.11. Spring configuration with inline Groovy class

Spring configuration with inline Groovy class

In this case, because the content is hard-coded, setting the refreshable attribute of the script factory doesn’t apply for those inline scripted beans. One last remark: If your script contains a less-than sign (<), the XML Spring configuration will be invalid, because the XML parser will think it is the start of a new tag. To circumvent this problem, you should wrap the whole scripted bean in a CDATA section.

This has been a brief introduction to the scripting bean capabilities of Spring 2.0. For further details and more in-depth explanations, we suggest you refer to the project documentation available at http://www.springframework.org.

Spring isn’t the only recent technology to embrace scripting, however. The following section looks forward to the next release of the Java platform and explores what support will be provided for Groovy integration.

Riding Mustang and JSR-223

Scripting and dynamic languages are in fashion again thanks to Groovy, Asynchronous JavaScript And XML (AJAX) as popularized by Google, and the Ruby on Rails web framework. This frenzy led Sun to recognize that for certain tasks, scripting languages can help to simplify the development of applications. New Java Specification Requests have been accepted by the Java Community Process to standardize languages such as Groovy and BeanShell, and to create a common API allowing access to various scripting engines from your Java applications.

This section guides you through running Groovy scripts in the new “Java standard” way, highlighting the features of the new API as well as some ways in which it is unavoidably clunky.

Introducing JSR-223

JSR-223, titled “Scripting for the Java Platform,” provides a set of classes and interfaces used to hold and register scripting engines and to represent scripts, namespaces of key/value pairs available to scripts, or execution contexts. Like all JSRs, JSR-223 provides three key deliverables: a specification document, a reference implementation (RI) implementing the specification, and a test compatibility kit that can be used to check that the specification is accurately and fully implemented. The RI is already usable and can be downloaded from the dedicated web site as long as you are using at least Java 5. It offers an elegant and simple API that supports a few scripting languages—Groovy being one of them. Out of the box, the RI doesn’t provide the runtime environments of those engines except for Rhino’s JavaScript, so in order to use the Groovy engine, you will have to download Groovy and its JSR-223 engine from http://scripting.dev.java.net. A disadvantage of the RI is that it might not always be in sync with Mustang’s scripting APIs, so you will have to check the potential differences in the APIs. Here, we’ll focus on the ones delivered by Mustang, rather than the RI. But if you need to use the latest javax.script.* classes from Mustang, it will also mean you must develop and deploy your applications with JDK 6, whereas the RI allows you to use JDK 5.

Before studying what JSR-223 brings to the table, we should mention that this API is particularly important because it is included by default in Mustang, the next version of the Java Platform—Java SE 6. This means that scripting finds its way in the JDK and will certainly become the preferred way for integrating scripting languages in your applications. This is also why we haven’t covered the use of Apache Bean Scripting Framework (BSF), because although it provides a similar API in terms of functionality, it will progressively be abandoned in favor of JSR-223.

Mustang already provides support for the new javax.script.* interfaces and classes. It also distributes a new command-line tool called jrunscript to run scripts, which is a bit like Groovy’s own groovy and groovysh commands. Here is the usage of this new tool:

Usage: jrunscript [options] [arguments...]
where [options] include:
-classpath, -cp <path>  Specify where to find user class files
-D<name>=<value>  Set a system property
-J<flag>                Pass <flag> directly to the runtime system
-l <language>           Use specified scripting language
-e <script>             Evaluate given script
-encoding <encoding>    Specify character encoding used by script files
-f <script file>        Evaluate given script file
-f -                    Interactive mode, read script from
                        standard input
-q                      List all scripting engines available and exit

Although the command line enables you to execute Groovy through the new API without writing any code to do so, if your application is going to embed Groovy, you’ll be using the API directly rather than relying on the tool. Let’s meet the core classes involved in running scripts through JSR-223.

The script engine manager and its script engines

The main entry point of the JSR-223 API is javax.script.ScriptEngineManager. To get started, create an instance of this class from your Java application:

ScriptEngineManager manager = new ScriptEngineManager();

The manager is able to retrieve script engines through different lookup mechanisms: by file extension, by mime type, or by name, with three dedicated methods:

ScriptEngine getEngineByExtension(java.lang.String extension)
ScriptEngine getEngineByMimeType (java.lang.String mimeType)
ScriptEngine getEngineByName     (java.lang.String shortName)

So, if you want to retrieve the Groovy script engine supplied with the reference implementation, you can look it up by name:

ScriptEngine gEngine = manager.getEngineByName("groovy");

With a ScriptEngine, you can evaluate Groovy expressions and scripts provided through an instance of Reader or of a String with the set of eval methods, which return an Object as the result of the evaluation. You can evaluate a simple expression as follows:

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine gEngine = manager.getEngineByName("groovy");
String result = (String)gEngine.eval("'+-----' * 3 + '+'");

Here are the other eval methods available:

Object eval(java.io.Reader   reader)
Object eval(java.io.Reader   reader, Bindings b)
Object eval(java.io.Reader   reader, ScriptContext context)
Object eval(java.lang.String script)
Object eval(java.lang.String script, Bindings b)
Object eval(java.lang.String script, ScriptContext context)

They can throw a ScriptException, which can contain a root exception cause, a message, a filename, and even a line number and column number where an error occurred, particularly when the error is a compilation error. The optional ScriptContext parameters correspond to the environment within which a script is evaluated, and a Bindings is a special map containing an association between a key and an object you want to pass to your scripts. These affect what information is available to your scripts and how different scripts can pass each other data. See the detailed JSR-223 documentation for more information on this topic.

Compilable and invocable script engines

Beyond the basic script-evaluation capabilities, the Groovy engine also implements two other interfaces: javax.script.Compilable and javax.script.Invocable. The first lets you precompile and reuse scripts, and the latter lets you execute a method, a unit of execution, rather than executing a whole script as you do with the eval method. Implementing these interfaces is not mandatory, but the Groovy engine provides this feature:

// Java
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine gEngine  = manager.getEngineByName("groovy");
Compilable compilable = (Compilable)gEngine;
compilable.put("name", "Dierk");
CompiledScript script = compilable.compile("return name");
String dierksName     = script.eval();
compilable.put("name", "Guillaume");
String guillaumesName = script.eval();

Once you’ve got a handle on the Compilable engine (by casting the engine to the Compilable interface), you can call two compile methods that either take a reader or a string containing the script to precompile. These methods return an instance of CompiledScript, which holds a precompiled script that you can execute several times at will without the need to reparse or recompile it. Then, the CompiledScript can be evaluated with three eval methods: one without any parameters, one taking a Namespace, and the last taking a ScriptContext.

Even after precompiling a script, you still can’t directly call methods declared in that script. The javax.script.Invocable interface makes this possible in a manner reminiscent of calling normal Java methods with reflection.

Imagine we have a script whose role is to change a string parameter into its uppercase representation:

// Java
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine gEngine = manager.getEngineByName("groovy");

Invocable invocable  = (Invocable)gEngine;
invocable.eval("def upper(s) { s.toUpperCase() }");
Object s = invocable.invokeFunction("upper", "Groovy");

invocable.eval("def add(a, b) { a + b }");
invocable.invokeFunction("add", new Integer(1), new Integer(2));

assertTrue(invocable.invokeMethod(s, "endsWith", "Y"));

The script is evaluated and retained in the script-execution context; then, the defined function can be called with the invokeFunction method, which takes the name of the function to call and a vararg list of objects to pass to the underlying scripted function as parameters. Be careful, though, because you can only invoke functions defined in the last evaluated script. An invokeMethod method goes further and lets you call arbitrary methods on objects resulting from the execution of scripts. This is how we call the endsWith method on the string returned by the first function invoked and pass it the letter Y as an argument.

Of course, in the last case, we could have cast the return value of upper to String directly. Although this may seem obvious, it’s possible because Groovy plays nicely with Java, returning real and normal classes. Some other scripting languages would return some kind of proxy or wrapper, making the integration with Java trickier.

Despite the convenience of being able to call any function defined in a script, it is not yet as Java friendly as we might hope. Nevertheless, the Invocable interface gives you another handy method for your toolbox: the getInterface method. With this method, you can create a proxy of a given interface that will delegate all method invocations to methods defined in the script.

Say we have a Java interface representing a business service like the following one:

// Java
interface BusinessService {
    void   init();
    Object execute(Object[] parameters);
    void   release();
}

We create a script that contains functions mapping the same signatures as the ones provided in the BusinessService interface:

// Groovy
void init() { println "init" }
Object execute(Object[] objs) { println "execute" }
void release() { println "release" }

We can make such a script appear to implement the BusinessService interface by calling the getInterface method of the invocable script engine:

// Java
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine gEngine = manager.getEngineByName("groovy");
Invocable invocable = (Invocable)gEngine;
invocable.eval(scriptAsAString);
BusinessService service =
      invocable.getInterface(BusinessService.class);

service.init();
Object result = service.execute(new Object[] {});
service.release();

First, we evaluate the script shown earlier, then we call the getInterface method with the class of the implementation we want our script to implement, and then we retrieve an instance implementing that interface. Our script doesn’t even have to explicitly implement the BusinessService interface, but through the proxy mechanism, it appears as if it were the case. With such a mechanism, you can manipulate scripts as if they were normal Java beans, without having to call some kind of invoke method.

You now know about the native Groovy techniques to integrate Groovy in your Java application and the more language-neutral solutions using Spring or JSR-223. The great thing about this is that it presents you with a choice. The downside is that you need to make a decision, so we provide some guidance in the last section of this chapter.

Choosing an integration mechanism

This section is similar to the first one in the chapter, in that we can’t make any decisions for you. Good guidance tends to be right more than it’s wrong, but there will always be cases that appear to fit one pattern but that benefit more from another after close examination. We don’t know what your needs are, so we can’t make that close examination. All we can do is give suggestions and reasons for them.

To give a good rule of thumb, if your application is built on Spring, you should prefer using the Spring integration. If you are able to use Java 6 and want to be able to change or mix various scripting languages at the same time, or you have the freedom to change at will, using the scripting integration of JSR-223 makes perfect sense. But if you want to do more advanced things or if you are concerned about the potential security hole opened by dynamic code, you should probably choose some of the standard Groovy mechanisms for embedding and executing Groovy code with GroovyShell, GroovyScriptEngine, or the almighty GroovyClassLoader. Table 11.3 shows a summary of the pros and cons of each integration mechanism.

Table 11.3. The sweet spots and limitations of the different integration mechanisms

Mechanism

Sweet spot

Limitations

GroovyShell

Perfect for single-line user input and small expressions

Supports reloading

Robust security available

Will not scale to dependent scripts

GroovyScriptEngine

Nice for dependent scripts

Supports reloading

Does not support classes

Does not support security

GroovyClassLoader

Most powerful integration mechanism

Supports reloading

Robust security available

Trickier to handle in the case of a complex classloader hierarchy

Spring scripting support

Integrates well with Spring

Lets you switch languages easily

Supports reloading

Requires Spring

JSR-223

Lets you switch languages easily

Requires Java 6

Does not support security

Does not support reloading

Bean Scripting Framework

Lets you switch languages easily

Doesn’t require Java 6

Does not support security

Does not support reloading

More limited capabilities than JSR-223

The basis of Groovy’s integration is its excellent compatibility with Java. We’ve listed the most common ways of integrating Groovy with Java, but anywhere that Java can be integrated, Groovy can work too. Some databases allow stored procedures to be written in Java, for instance—so Groovy can be used in the same way. Additional integration mechanisms may well appear over time in various guises—don’t assume that the options given here are exhaustive!

Summary

This chapter has given you glimpses into how you might allow your applications to become more flexible, giving appropriate users the ability to customize behavior in a way that may enable them to solve the exact problem they are facing, rather than the one that was as close as you could imagine when designing the application.

The means of integrating Groovy into your application broadly fall into two camps: those provided directly by the Groovy libraries and those provided in a language-neutral fashion by Spring and Java 6 through JSR-223. As is often the case, the more specific solutions prove to be the most powerful ones, at the cost of language neutrality.

As bookends to the chapter, we discussed the kinds of applications that benefit from this sort of integration and gave some guidance as to which integration mechanism might be best for your situation.

Scripting languages in one form or another have always been common on various systems, from DOS’s command shell to the widespread Perl on many Unix and Linux systems. They give a good return on investment because of their ease of use and because they do what you need them to do with less deployment overhead and reduced boilerplate code. But they have often failed to become general-purpose languages for building enterprise applications. With scripting languages coming to a JVM near you, you can benefit from the advantages of both worlds: You can build big and scalable enterprise applications while still using scripting languages for the customization logic, allowing you to profit from their agility through their expressiveness and advanced power features.



[2] Of course, we don’t wish to discourage you from reading the chapter even if you don’t have any integration needs right now. Gaining knowledge is a worthy pursuit in and of itself.

[3] You might wonder why we choose to integrate from Groovy to Groovy. Well, we would be more likely to do it from Java, but using Groovy simplifies our examples. Doing so can be handy even from Groovy, so that you can organize utility code in external scripts, run scripts with certain security policies in place, or execute user-provided input at runtime.

[4] It’s rarely quite as easy as the Groovy equivalent, but by now you should realize that this has nothing to do with the features being shown and everything to do with Groovy making life easier in general.

[5] Multiplication is easy to demonstrate in a book, but real-world examples might include handling transactional resources, configuration, and logging.

[6] Not that we can think of any reason why you’d want to, but we like the principle of avoiding vendor lock-in where possible.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.181.47