Jython Is Just Too Useful

A colleague just came to me asking about Java serialization and output options. We’re going to store some partially filled Serializable DTOs in a BLOB in our database so he needed some info. Our talk then turned to options for storage and such. He already knew about using ObjectOutputStream on top of a FileOutputStream, but I also told him how to get a byte array from the object using a ByteArrayOutputStream. To illustrate, I fired up Jython in interactive mode and typed the following:

[c:tmp] jython
*sys-package-mgr*: processing modified jar, 'C:AspectJ1.1libaspectjrt.jar'
Jython 2.1 on java1.3.1_02 (JIT: null)
Type "copyright", "credits" or "license" for more information.
>>> from java.io import *
>>> from java.util import*
>>> m = ArrayList()
>>> m.add("Foo")
>>> m.add("Bar")
>>> m
[Foo, Bar]
>>> baos = ByteArrayOutputStream()
>>> oos = ObjectOutputStream(baos)
>>> oos.writeObject(m)
>>> oos.close()
>>> dir(baos.class)
['__init__', 'reset', 'size', 'toByteArray', 'toString', 'write', 'writeTo']
>>> baos.toByteArray()
array([-84, -19, 0, 5, 115, 114, 0, 19, 106, 97,
  118, 97, 46, 117, 116, 105, 108, 46, 65, 114, 114,
  97, 121, 76, 105, 115, 116, 120, -127, -46, 29,
  -103, -57, 97, -99, 3, 0, 1, 73, 0, 4, 115, 105,
  122, 101, 120, 112, 0, 0, 0, 2, 119, 4, 0, 0, 0,
  10, 116, 0, 3, 70, 111, 111, 116, 0, 3, 66, 97,
  114, 120], byte)
>>> bais = ByteArrayInputStream(baos.toByteArray())
>>> ois = ObjectInputStream(bais)
>>> x = ois.readObject()
>>> x
[Foo, Bar]
>>> m
[Foo, Bar]

There are lots of cool things there, but specifically, notice the bits in red. I couldn’t remember the method to call to get the byte array, so by using the Python dir() method on the class of the object, I got a list of available methods. toByteArray() was the ticket and you can see both the array itself and then that I went further and deserialized the byte array using a ByteArrayInputStream. Think about how many lines of Java code I would have had to write to show him the same thing. But even if the syntax were just as verbose as Java, not having an edit-compile-run cycle made the demo far faster and productive than it would have otherwise been.

Cool Use of Jython

I just had to share this. I am working on a very large project using BEA‘s WebLogic 7. This project takes a good 10 minutes to go through an entire compile/deploy cycle. This is a real hassle when I need to noodle something out, test some idea, etc. I use Jython for all manner of nifty things including testing things from the client side of my app, but what if I wanted to test something from within the container? Sure I could write a Cactus test (and I have written many), but adding/changing a Cactus test results in a compile/deploy cycle. What I needed was something better.

What I came up with is a truly (dirty) hack that is totally insecure yet really useful. (IOW, don’t put it on a production server.)

I embeded a Jython interpreter inside an Apache Axis web service. I then have a short Jython script on the client side that sends an arbitraty script to the server, which is executed and then the stdout/stderr are bundled up and sent back in the SOAP response. I think this is really cool.

The files involved are

The web service is where the real work occurs, but it’s brain-dead simple. Here’s JythonWebService

package com.joeygibson.soap;

import java.io.StringWriter;

import org.python.util.PythonInterpreter;
import org.python.core.*;

public class JythonWebService
    private PythonInterpreter interp =
        new PythonInterpreter();
    Writer out = new StringWriter();
    Writer err = new StringWriter();

    public JythonWebService()


    public String exec(String script)

        StringBuffer results =
            new StringBuffer(
                "----- StdOut -----nn");
            "nn----- StdErr -----nn");

        return results.toString();

Simple, eh? We create the Jython interpreter and then give it two StringWriters that will capture stdout and stderr, respectively. Then in the exec method we accept the script from the SOAP envelope, let the interpreter execute it, and then bundle up the stdout and stderr with nice little markers to differentiate them. That then goes back over the wire to the caller.

Next is remote.py that executes the service from the client side.

import string, sys
from java.io import *
from org.apache.axis import *
from org.apache.axis.client import *
from javax.xml.namespace import QName

global service, call

service = Service()
call = service.createCall()
    QName("JythonWebService", "exec"))

f = open(sys.argv[1])
scriptLines = f.readlines()

script = string.join(scriptLines, "")

ret = call.invoke([script])
print ret

Here we first import the necessary packages/classes from both Java and Jython. We then create the Axis Service and Call objects, setting the endpoint and operation name on the call. Next we load up the specifed file (this could easily be changed to support multiple scripts from the command line), concatenate each line into one big string, and then execute the web service. The script is then passed as the sole argument (wrapped in an array) to the exec method of Call, which executes the remote call. Finally the result is printed.

Next in line is remote.bat the batch file I used to execute the client. It just sets up a reasonable classpath and then invokes Jython.


set CLASSPATH=<jars from the axis/lib directory>
call jython remote.py %*

This adds all the jar files in the axis/lib directory to the classpath and then runs our remote.py script through Jython. You may have to get creative with how you set your classpath. I use 4NT as my command prompt, which has much longer command line allowances. The setting of the classpath can be a pretty long string and CMD.exe may barf on it. YMMV.

Finally we need to test something. Here’s test.py that will run on the server via our web service

from javax.naming import *

ic = InitialContext()
vv = ic.lookup("ejb/VVLookup").create()
l = vv.getValidValuesForFieldNumber(1558)

for i in l: print i

Obviosly you would have to tailor this for your setup since it’s doubtful that you have a stateless session bean deployed at ejb/VVLookup… Anyway, you can see that I create an InitialContext (with no parameters since we’re inside the container) do a lookup, execute a method that returns a collection and then iterate over it, printing them out. Since print goes to stdout, the output will be captured and then returned to the client.

That’s it! If anyone want’s a copy, let me know. It’s so simple, though, that you could just do it yourself.