Channels ▼
RSS

Tools

JSR 223: Scripting for the Java Platform


We have all heard heated arguments between developers who use scripting languages and developers who use Java. One of the reasons for the war between these two factions is that the process of integrating the two was so difficult that developers on both sides were almost forced to choose one or the other. Java Specification Request (JSR) 223 addresses this issue. In this article, I present examples of how the standard framework and API defined by JSR 223 makes it easy for Java programmers to take advantage of the benefits of using a scripting language while retaining the benefits of using Java.

The Scripting API

The entire scripting API is contained in the package javax.script, which was first delivered with Java 6. This lightweight package contains six interfaces:

  • Bindings
  • Compilable
  • Invocable
  • ScriptContext
  • ScriptEngine
  • ScriptEngineFactory

five classes:

  • AbstractScriptEngine
  • CompiledScript
  • ScriptEnginemanager
  • SimpleBindings
  • SimpleScriptContext

and a single exception:

  • ScriptException

Rather than describing each of these interfaces, classes and exceptions, I present a series of five Java programs and five scripts in three languages to show just how little effort is required to make them work together.

Scripting Engines

The ScriptEngine interface, which lies at the heart of any implementation of JSR 223, defines methods that provide basic scripting functionality. These methods provide mechanisms for executing scripts and for getting and setting values that are shared between Java and a scripting language. The methods defined by the ScriptEngine interface form the framework that brings uniformity to interoperating with different scripting languages.

Although it does not mandate any specific scripting engine, Java 6 includes the Mozilla Rhino engine for the JavaScript language. If you visit https://scripting.dev.java.net, the home of the scripting project, you will see an impressive list of more than two dozen scripting engines that have been implemented to date.

ListScriptingtEngines.java (Listing One) displays a list of scripting engines available to the JVM in which it runs. I start by creating an instance of ScriptEngineManager. The documentation for this class states that it implements a discovery and instantiation mechanism for ScriptEngine classes and also maintains a collection of key/value pairs storing state shared by all engines created by the Manager. It does this by using the service provider mechanism to enumerate all implementations of ScriptEngineFactory. The service provider mechanism is described in the JAR file Specification.

package ca.tremblett;

import java.util.List;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

/**
 *
 * @author ptremblett
 */
public class ListScriptingEngines {

    public static void main(String[] args) {
        ScriptEngineManager manager = new ScriptEngineManager();
        List<ScriptEngineFactory> engines = manager.getEngineFactories();
        if (engines.isEmpty()) {
            System.out.println("No scripting engines were found");
            return;
        }
        System.out.println("The following " + engines.size() +
            " scripting engines were found");
        System.out.println();
        for (ScriptEngineFactory engine : engines) {
            System.out.println("Engine name: " + engine.getEngineName());
            System.out.println("\tVersion: " + engine.getEngineVersion());
            System.out.println("\tLanguage: " + engine.getLanguageName());
            List<String> extensions = engine.getExtensions();
            if (extensions.size() > 0) {
                System.out.println("\tEngine supports the following extensions:");
                for (String e : extensions) {
                    System.out.println("\t\t" + e);
                }
            }
            List<String> shortNames = engine.getNames();
            if (shortNames.size() > 0) {
                System.out.println("\tEngine has the following short names:");
                for (String n : engine.getNames()) {
                    System.out.println("\t\t" + n);
                }
            }
            System.out.println("=========================");
        }
    }
}

 

Listing One

After creating the instance of EngineManager, I invoke its getEngineFactories() method. This method returns a List of all the ScriptEngineFactory classes found by the discovery mechanism. For each ScriptEngineFactory in the list, I obtain metadata describing the engine class by calling methods such as getEngineName(), getEngineVersion(), getLangugeName(), getExtensions(), and getNames(). I then simply display this metadata.

If you run the ListScriptingEngines program, you will see the following output displayed:


The following 1 scripting engines were found:

Engine name: Mozilla Rhino
        Version: 1.6 release 2
        Language: ECMAScript
        Engine supports the following extensions:
                js
        Engine has the following short names:
                js
                rhino
                JavaScript
                javascript
                ECMAScript
                ecmascript
=========================

If you are using OS-X and have Java 6 from Apple installed, the output from the program looks like this:


The following 1 scripting engines were found:

Engine name: AppleScriptEngine
_Version: 1.0
_Language: AppleScript
_Engine supports the following extensions:
__scpt
__applescript
__app
_Engine has the following short names:
__AppleScriptEngine
__AppleScript
__OSA
=========================

Remember, Java 6 does not mandate any specific scripting engine and Apple has chosen to deliver an engine for their AppleScript.

Since the examples I present in subsequent sections of this article use Ruby, Python, and Groovy, I needed to make these engines available also. To do so, I went to the scripting project site previously mentioned and download jsr223-engines.tar.gz from the "Documents & files" link (there is also a .zip file if you are using a platform that doesn't deal with tar balls). When expanding the file, I observe that there is one directory for each language; this directory contains a build subdirectory that contains a JAR file that is the engine for the language. I add this jar to my classpath. In addition to making the engine available, I must also make all of the JAR files used by the scripting language implementation available on my classpath. The README.TXT file in each language's directory contains a URL from which this implementation can be downloaded if you do not already have the language installed. The following is the content of the README.TXT for groovy:


This is JSR-223 script engine for the <a href="http://groovy.codehaus.org">Groovy language</a>. We have built and tested Groovy version 1.5.6.

If you examine the "Libraries" section of the NetBeans project JavaScriptingDemo (see Listing Six), you will see that supporting the three languages I'm using requires these JAR files:

  • antlr-2.7.6.jar
  • asm-2.2.jar
  • groovy-1.5.7.jar
  • groovy-engine.jar
  • jruby-engine.jar
  • jruby.jar jython-engine.jar
  • jython.jar

As a convenience, I have included the aforementioned JAR files in the JavaScriptingDemo NetBeans project in the required_jars directory. These are snapshot of the files at the time this article was being written. I recommend that you obtain the latest versions of these JAR files.

If you run ListScriptingEngines with the appropriate JAR files on the classpath, the program generates output that is too lengthy to include here but which you can see in Listing Two. Since I ran the code under OS-X, notice that the AppleScript engine is present.

The following 4 scripting engines were found

Engine name: JRuby Engine
	Version: 1.1.4
	Language: ruby
	Engine supports the following extensions:
		rb
	Engine has the following short names:
		jruby
		ruby
=========================
Engine name: AppleScriptEngine
	Version: 1.0
	Language: AppleScript
	Engine supports the following extensions:
		scpt
		applescript
		app
	Engine has the following short names:
		AppleScriptEngine
		AppleScript
		OSA
=========================
Engine name: groovy
	Version: 1.5.7
	Language: groovy
	Engine supports the following extensions:
		groovy
	Engine has the following short names:
		groovy
=========================
Engine name: jython
	Version: 2.2.1
	Language: python
	Engine supports the following extensions:
		jy
		py
	Engine has the following short names:
		jython
		python
=========================

Listing Two


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video