...making Linux just a little more fun!
By Rob Tougher
This article discusses Jython, a software project that aims to provide seamless integration between Java and Python. This article requires a basic understanding of both languages.
There are many different programming languages. The Language List, a comprehensive database of computer languages, puts the number at around 2500. Having different languages is advantageous to developers - each language has features that are well-suited to certain classes of problems. For example, when I'm transforming XML, XSLT is my tool of choice (this is a popular method of rendering HTML for dynamic web sites). When coding server-based applications, I prefer languages such as Java, C++ and Python. I think the general advice for programmers is to "use the right tool for the job".
One noticeable drawback in this abundance of languages is the inability (or extreme difficulty) in reusing code written in one language from another language. For example, say you had written a database library in Java, and wanted to reuse that library in Python. You could write a glue layer, using a technology like COM, CORBA, sockets, or SOAP, but that layer would take time to write. It would be nice if this glue layer already existed, ready to be consumed with little or no effort expended.
Enter Jython. The goal of the Jython project is to provide seamless integration between Java and Python. The project contains two main tools:
This article provides a basic introduction to Jython. First I'll describe installation, next I'll talk about the jython interpreter, and I'll finish up with a discussion of the jythonc compiler. I'll use the following naming conventions when referring to the different interpreters, compilers, and projects:
To use Jython on your system you need two pieces of software: the Java SDK, and the Jython distribution.
You can get Sun's latest Java SDK for Linux (1.4.2) at the main Java site. Sun distributes the SDK as a single binary file that you can download and run on your Linux machine. After the install completes, the remaining step is to create an environment variable named JAVA_HOME, and set its value to the root directory of the Java installation. I set this variable as part of my ~/.bashrc file:
# # For the 1.4.2 sdk # export JAVA_HOME=~/apps/j2sdk1.4.2_01 export PATH=~/apps/j2sdk1.4.2_01/bin:$PATH
Notice that I set the PATH environment variable also - I do this so that I can access the Java command line tools (java, javac, jar, etc) from any directory.
The latest release of Jython (2.1) is distributed from the main Jython site. The Jython project provides a graphical installer written in Java and packaged as a single Java *.class file. When you run the installer you are presented with a graphical setup wizard, which asks you to specify the installation type, agree to the license terms, and specify the target directory for installation. When the install completes, you are ready to use Jython on your machine. It is useful to update your PATH and CLASSPATH variables to point at the newly installed Jython distribution. I do this in my ~/.bashrc file:
# # For Jython # export JYTHON_HOME=~/jython-2.1/ export PATH=$JYTHON_HOME:$PATH export CLASSPATH=$JYTHON_HOME/jython.jar:$CLASSPATH
To check that your installation succeeded, type "jython" at the command prompt:
prompt$ jython Jython 2.1 on java1.4.2_01 (JIT: null) Type "copyright", "credits" or "license" for more information. >>>
If you see the above, you've successfully installed Jython.
The jython interpreter is a Python interpreter implemented in 100% Java. It allows you to write Python code that accesses Java classes.
The latest stable version of jython, released in December of 2001, implements features of Python 2.1. Python, however, has already reached version 2.3. This means that Python features unique to versions 2.2 and 2.3 are unavailable in the current stable version of jython:
An alpha version of jython, available for download at the Jython site, implements a mixture of Python 2.1 and 2.2. The Jython group characterizes this alpha version as an unstable and experimental release that contains significant known issues. In other words, use the alpha version at your own risk.
Besides lacking recent Python language features, jython is missing some Python modules in its library implementation. On top of that, there is little documentation describing which modules are supported and which are not. If you want to know if a module is supported, the FAQ suggests attempting to import the module in question. If the import fails, you can try to copy over the corresponding *.py module from the CPython implementation. As a last effort you can request help on the public mailing lists.
While the Python support in jython is restricted to version 2.1, the Java support is completely up-to-date. You can use _any_ Java code from inside the jython interpreter. This includes the standard Java 1.4.2 libraries, libraries written by third parties, and your own custom libraries.
For example, you could use Java's Abstract Window Toolkit (AWT). The AWT is a graphical windowing library that provides widgets for creating user interfaces (windows, buttons, text areas, etc). You could write Python code that accessed the AWT, and then run that code using the jython interpreter.
Here's an example of using AWT functionality from within Python:
# # file: AWTTest.jy # # # Import the AWT classes. # from java.awt import Frame from java.awt import Panel from java.awt import Button from java.awt import TextArea from java.awt.event import ActionListener # # Define the TestButtonAction class. TestButtonAction # inherits from the Java ActionListener interface. # class TestButtonAction(ActionListener): def actionPerformed(self, e): textArea.append("Test Button Clicked!\n") # # Create the Frame, Panel, Button, # TextArea, and TestButtonAction objects. # frame = Frame("Hello World") panel = Panel() button = Button("Test Button") buttonAction = TestButtonAction() textArea = TextArea() # # Put everything together and show # the window. # button.addActionListener(buttonAction) panel.add(button) panel.add(textArea) frame.add(panel) frame.pack() frame.show()
You can run this using the jython interpreter:
prompt$ jython AWTTest.jy
Running this code should produce a window similar to the following:
The example creates a window and adds a Button and a TextArea to it. When you click the button, the text "Test Button Clicked!" is appended to the TextArea's contents. The example displays a few key features of Jython:
The second tool that the Jython project provides is jythonc. jythonc compiles Python source code into Java bytecode. This Java bytecode can be executed using a standard Java Virtual Machine.
(Java bytecode is the intermediate language that the Java Virtual Machine executes. When you compile a Java source file using javac, the compilation output is a file with a *.class extension. This file contains Java bytecode, which you can execute using the Java Virtual Machine. For more information about Java bytecode and the JVM, check out The Java Virtual Machine Specification )
jythonc suffers from the same feature lag as the jython interpreter - the latest jythonc release implements features from Python 2.1. Furthermore, the alpha version of Jython contains a jythonc compiler that is basically unchanged since the last release. It looks like jythonc will be stuck at version 2.1 for a while.
When compiling a Python class with jythonc, you need to provide extra information about each publically accessible method in your class. This information includes the return type, arguments, argument types, throws clause, and access control declaration (private, public, or protected). You can provide this information in one of two ways:
For example, you could write a Java Servlet in Python (servlets are Java classes that run inside servlet containers, like Tomcat and Jetty, and respond to web page requests). You could create a Python class that derives from HttpServletRequest, compile that class into bytecode using the jythonc compiler, and run that bytecode inside of a servlet container.
The following is a simple servlet written in Python:
# # file HelloWorldFromJython.py # import os from javax.servlet.http import HttpServlet class HelloWorldFromJython(HttpServlet): def service(self, request, response): response.setContentType("text/html") out = response.getOutputStream() print >>out, """<html> <head> <title>Hello World Servlet</title> </head> <body> <p>Hello World From Jython!</p> <p>os.getcwd() == """ + str(os.getcwd()) + """</p> </body> </html>"""
You can run this example using Tomcat. Tomcat installation is pretty straightforward - it only requires downloading the distribution and extracting it to your hard drive. You should create an environment variable named TOMCAT_HOME and set its value to the Tomcat root directory:
# # For Tomcat. # export TOMCAT_HOME=~/apps/jakarta-tomcat-4.1.27/
The next step is to compile the Python servlet with the jythonc compiler (note that the CLASSPATH environment variable needs to be updated to include the servlet.jar archive):
prompt$ export CLASSPATH=$TOMCAT_HOME/common/lib/servlet.jar:$CLASSPATH prompt$ jythonc --deep HelloWorldFromJython.py processing HelloWorldFromJython processing javaos processing string processing UserDict processing copy processing repr processing javapath processing re processing sre processing sre_constants processing sre_compile processing copy_reg processing sre_parse Required packages: java.lang org.python.core java.io javax.servlet.http Creating adapters: Creating .java files: sre_constants module javaos module sre module javapath module re module string module sre_compile module copy_reg module HelloWorldFromJython module HelloWorldFromJython extends javax.servlet.http.HttpServlet UserDict module sre_parse module repr module copy module Compiling .java to .class... [snip]
The jythonc compiler creates a directory named "jpywork" in your current directory. This directory contains the *.class file output of the jythonc compilation, along with supporting files.
The next step is to deploy the binary *.class files to the Tomcat server's webapps directory. Normally you would create a new web application for your servlets, but for this example you can use the existing "examples" web application that ships with Tomcat. Create a new directory inside of that web application and copy the class files to it:
prompt$ mkdir $TOMCAT_HOME/webapps/examples/WEB-INF/classes/HelloWorldFromJython prompt$ cp jpywork/*.class $TOMCAT_HOME/webapps/examples/WEB-INF/classes/HelloFromJython/
Next add the jython.jar archive to the webapp's lib directory (if the directory doesn't exist, create it):
prompt$ mkdir $TOMCAT_HOME/webapps/examples/WEB-INF/lib prompt$ cp $JYTHON_HOME/jython.jar $TOMCAT_HOME/webapps/examples/WEB-INF/lib/
Now that the Python servlet has been compiled and deployed to the Tomcat server, and the jython.jar archive has been included in the lib directory, you can run the Tomcat server:
prompt$ $TOMCAT_HOME/bin/startup.sh Using CATALINA_BASE: /home/robt/apps/jakarta-tomcat-4.1.27 Using CATALINA_HOME: /home/robt/apps/jakarta-tomcat-4.1.27 Using CATALINA_TMPDIR: /home/robt/apps/jakarta-tomcat-4.1.27/temp Using JAVA_HOME: /home/robt/apps/j2sdk1.4.2_01
You should be able to access your Python servlet using the following URL:
The servlet will produce output similar to the following:
prompt$ wget https://yourmachine:8080/examples/servlet/HelloWorldFromJython/HelloW orldFromJython prompt$ cat HelloWorldFromJython <html> <head> <title>Hello World Servlet</title> </head> <body> <p>Hello World From Jython!</p> <p>os.getcwd() == /home/robt/apps/jakarta-tomcat-4.1.27/bin</p> </body> </html>
This article served as an introduction to the Jython project. For more information about the subjects presented in this article, check out the following links:
Rob is a software developer in the New York City area.