Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

Scripting with Java & Python


Oct01: Scripting with Java & Python

Boudewijn is a senior developer at Tryllian in the Netherlands. He can be contacted at [email protected].


There are any number of situations where you might want to add scripting capabilities to applications. Advanced users, for instance, often want to automate actions. Organizations, on the other hand, might want to create complete customized versions of their standard apps. Application scripting comes in many flavors — simple key-recording macros, externally exposed APIs (such as COM or DCop), and complete embedded programming languages. In this article, I'll describe how I embedded a standard language, Python, into a Java application. To do so, I used a Python console window to expose an interface to the application in addition to the complete Python functionality to the application user. A console window such as this is great for quick execution of ad hoc scripts, as well as for controlled execution of larger user scripts.

The Situation

At Tryllian (where I work; http://www.tryllian.com/), we created a toolkit for developing mobile intelligent agent systems. These agent systems consist of thousands of intelligent programs that travel from computer to computer. (Of course, those agents are not hosted by the operating system — that would make them viruses!) An essential component of agent systems is a quasivirtual world where the agents can live. These virtual worlds (habitats) are large server applications that must be administered like any other server application (such as a database); see Figure 1. This is done using special management tools.

Administrative tasks include the division of the agent world into smaller parts, where agents interested in the same topic can meet more selectively, checking load levels, tracing rogue agents, and correcting problems. Most of these tasks can be automated but are dependent upon the server tasks.

To give application administrators maximum flexibility, we included in the management tool a scripting facility called "pyconsole" in the form of a console window where scripts can be loaded and started, and small tasks programmed on-the-fly. (Admittedly, we were inspired by ObjectDomain's Jython console window; see http://www.objectdomain.com/.) While this solution is not suitable for every application, it works very well when the application is intended for programmers or technically advanced server administrators.

Scripting for Java

From completely new languages to tiny implementations of Scheme, there are more than a hundred scripting languages available for Java (see http://grunge.cs.tu-berlin.de/~tolk/vmlanguages.html). However, the maturest scripting language is probably Jython (http://www.jython.org/).

Recall that there are two Python implementations — one in C, the other in Java. The Java implementation of Python has always been called "JPython," but because of some legal wranglings, the name has been changed to "Jython." This Java implementation closely tracks C Python; in fact, most of the C Python 2.0 constructs are available in Jython.

Jython includes a small Swing console application, written in Python, that begs to be included in Java applications. To do that, you must compile the Python code to Java, use the compiled classes in the Java application, and then find a way to communicate between the Jython interpreter running in the console window and the application. Furthermore, if the embedding application uses Java security features — especially the SecureClassLoader — further steps must be taken.

The Python sources that will form pyconsole.jar (available electronically; see "Resource Center," page 5) include:

  • Console.py, the main console interface.
  • Action.py, the implementation of AbstractAction.

  • Keymap.py, which implements keyboard handling.

  • Styles.py, text drawing styles.

Of these, Console.py is the most interesting, since it is the part you need to change so that you can embed the console class into your application (just like any other Java Swing widget).

Exposing the Application API

Of course, one problem you face is exposing the application API and data model to the Python interpreter so that users can add functionality to their applications. Perhaps the best solution to this is to create a facade class that exposes only those parts of the application class model you want exposed to the scripting interface. You can expose methods that create new objects or return existing objects to the Python interpreter. However, if those objects include methods that return unexposed objects, you might have created a security risk.

I have found that the most comfortable way to hand this facade class over to the Python interpreter is to create a Console class constructor that has two parameters — one of the type Object that receives the facade, and another of the type java.lang.String that receives the name of the facade; see Example 1.

Console.py provides a dictionary called "locals" to which this object is added, with the name as key. This dictionary is used by the interpreter (in the class PythonThread) as a repository for added names available to the current interpreter action. The Python statement exec takes the form:

exec compiled_code in dictionary

Jython automatically has access to all public methods and variables present in the passed object; not just to the rather limited interface of the Java Object class. You don't need to cast the adapter Object: Python is as weakly typed as it gets, and doesn't try to hide anything from the user just because an object arrived as Object and not as MyComplicatedFacade (extends Object).

Preparing Jython Code To Be Called From Java

Any Jython code can be compiled to Java source code, which can then be compiled to bytecode that the Java virtual machine can run. However, if the resulting class files are to be used as a package from Java applications, it is necessary to help the compiler by adding signatures to all public functions.

These signatures are codes in the documentation strings of the Python functions that start with the keyword @sig, and give the entire function specification as if it were Java, complete with access modifiers and return values. You have to give the complete package location for every type, except for those in java.lang.

A second requirement is that you must make the Python class Console inherit the Java class Object; otherwise, Java classes won't be able to create a Console instance or call its methods. This exposes an interesting point of Jython programming — creating a second object hierarchy. Python objects in Jython are not automatically Java objects; you can actually create objects that do not descend from Java's Object class.

Compiling Jython Code to a Java JAR

Jython can automatically create a JAR file for you when you give a command like Example 2.

If you use the --package option, you can create a package where there wasn't one before, making it easy to comply with standards. Of course, since this code was originally part of the Jython distribution, something might be said for an org.jython.pyconsole package hierarchy.

Embedding a Jython Swing Component in a Java App

Although the Console class already includes a main method so you can run it on its own, the real fun comes with embedding the console in an application. To do that, you can extend a JFrame, and in the constructor, create a new Console, passing the API facade and creating a new JScrollPane that you pass the text pane from the Console; see Example 3.

Security Problems

There is a clever hack in the Jython libraries: the pawt library, which can be used by Jython programs to construct GUIs that run either with JDK Version 1.1 or 1.2 (and greater). This is done by constructing classes in bytecode on the fly. However, if the application uses the SecureClassLoader from the java.security package, using those classes will give an endless stream of security-related errors.

This is because the class does not come from a JAR file and, therefore, cannot be signed. Such a class does not have any permissions under a strict security regime — it cannot be used to instantiate objects, for instance.

The solution is to eradicate all use of the pawt module and change those instances to direct calls to javax.swing. Jython simply uses the existing Java implementations instead of generating its own bytecode. The external appearance is the same, and nowadays, AWT is of less and less importance for standalone applications.

Conclusion

Apart from the potentially baffling security problems — that are easy to avoid if you're aware of them — it's easy to embed scripting functionality in a Java application. By doing so, you empower advanced users to make better use of the tools you provide.

DDJ


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.