Scripting on the Java platform

Using Groovy, Jython, and JRuby for Java development

1 2 3 4 5 Page 2
Page 2 of 5

Does it walk like a duck?

When using scripting languages such as Python, Ruby, or Groovy you don't have to define an interface like the one shown in Listing 4. Variables can hold references to any object type. When you send a message to a target object, the language's runtime checks whether a matching method exists and calls it. Otherwise, an exception is thrown. There is no need for the target object to implement specific interfaces or extending classes. If the method is there, the runtime will call it. This behavior is also called duck typing, which means "If it looks like a duck and quacks like a duck, it must be a duck."

Listing 5. A callback handler written in Groovy

// the call back implementation (which doesn't implement any interface)
        class SmtpProtocolHandler {
                def onData(nbc) {
                     def session = nbc.attachment
                     //... 
                }
        }

        def server = new MultithreadedServer(new SmtpProtocolHandler())
        server.run()

Quality and performance

When you compare the two small pieces of the handler code shown in Listing 4 and Listing 5, it becomes obvious that scripting languages tend to produce code that is more compact and readable than Java code. This is mainly because you don't have to write all the type declarations in Groovy or JRuby that you do in Java, which is a static, strongly typed language. On the other hand, the missing type information has some disadvantages. Supporters of static typing argue that static, strongly typed languages ensure the robustness of the program, by ensuring that type errors will be detected at compile time. Advocates of dynamic languages argue, conversely, that development techniques like test driven development compensate for the advantages of compile-time checks.

In general, scripting languages tend to run slower than system programming languages , but runtime performance isn't the only issue under consideration. The question is always whether the implementation is fast enough for the target infrastructure. Besides the speed requirements, other quality requirements like reliability and changeability have to be considered. For instance, it is not unusual for maintenance cost to become the biggest part of the total software lifecycle cost. The key to reducing maintenance cost is high reliability and simplicity. Scripting languages, being less complex, often yield better results in these areas than system programming languages like C++ or Java.

Approaches to scripting on the Java platform

Today you do not have to choose between using Java and using a scripting language like Groovy, Ruby, or Python. Your applications can benefit from both the productivity and elegance of scripting languages and the reliability of the Java platform. The key to scripting on the Java platform is knowing where a scripting language is your best choice, and where you are better off using Java code.

In the past, scripting languages have often been seen as a thin layer of glue code to string Java components together. Many Java developers today use scripting languages for most of their work on the Java platform, only relying on the Java libraries for features not supported by their scripting language of choice. (For instance, the Java platform provides many enterprise-level features that are not supported by most scripting language environments, such as transaction management, remoting, or monitoring.)

Regardless of how you approach it, the seamless integration of scripting languages and the Java platform produces a richer development environment, where you are able to choose the right language for the right task.

There are two approaches to realizing what is sometimes called a "polyglot" development environment on the Java platform: You can either run your scripting language on the top of the Java virtual machine, or use the Java Native Interface/inter-process communication to execute the scripting language within a native scripting environment.

Most runtimes of popular scripting languages are C/C++-based. Using JNI allows you to connect your Java environment to the native scripting environment. For Ruby you might use a JNI-based solution like RJB, or an inter-process solution like YAJB. On the downside, most bridging solutions present undesirable restrictions. For instance, inter-process-based solutions use a remote protocol to connect the environments, which can result in performance bottlenecks.

Java-based scripting runtime implementations

Open source projects such as Jython or JRuby have been realized as pure Java-based scripting runtime implementations, enabling you to execute Python or Ruby scripts on the top of the Java virtual machine. That means scripts written in Python or Ruby run on all platforms where a Java SE runtime exists. Java-based scripting runtimes represent the first step toward integrating the scripting languages into the Java platform, and do not offer as much as you might hope for.

Because the original Ruby or Python scripting runtimes are currently faster then the Java-based ones, using the native runtime would still be the first choice to process such scripts. The real value of languages like JRuby and Jython is that they can call Java classes and vice versa. This opens the whole world of Java to scripting languages. The scripting languages have access to everything that is implemented in Java.

From the infrastructure view JRuby or Jython can been seen as Java-based scripting runtimes to execute regular Ruby or Python scripts on top of the Java platform. From the developer's view JRuby or Jython scripts can been seen as enriched scripts that use Java classes and require additional capabilities of the scripting runtime. As consequence, these "J scripts" can not be executed on the native scripting runtime.

Embedding scripts into Java

To run Python, Ruby, or Groovy on the top of the Java virtual machine, you only need to add the jars of the Java-based scripting runtimes to your Java classpath. After this small setup the scripting engine can be instantiated and you can execute scripts within your Java environment. In most cases, the scripting implementation will provide simple engine classes to do this, as shown in Listing 6.

Listing 6. Runtime engines for Ruby, Groovy, and Python

// run a Ruby scripting  (JRuby V1.1b1)
Ruby runtime = Ruby.getDefaultInstance();
runtime.executeScript(scripting, filename);

// run a Groovy scripting (Groovy V1.1)
GroovyShell gs = new GroovyShell();
gs.evaluate(scripting);

// run a Python scripting (jython V2.2)
PythonInterpreter interp = new PythonInterpreter();
interp.exec(scripting)

Most scripting engines also allow you to bind host variables of the Java environment to your script, as well as invoking specific scripting functions. Please note that some scripting engines require additional settings to use extended features. For example system properties like jruby.home and jruby.lib have to be set within JRuby to call gems.

With the release of Java SE 6, a standard interface to host scripting engines has been established as integral part of the Java runtime. JSR 223: Scripting for the Java Platform has standardized functionality like script-engine discovery, binding for Java host variables, and script invocation. The JSR 223 interface requires a JSR 223-compatible scripting implementation. Implementations of major scripting languages can be downloaded from the scripting project homepage.

1 2 3 4 5 Page 2
Page 2 of 5