Discussions

General J2EE: Embedded Jython and Spring

  1. Embedded Jython and Spring (2 messages)

    Disclimer: I'm not a python or jython programmer. If you know a better way to do what I've done don't hold it against me :)

    Problem: While designing/writing RSS aggregator one of the clients was a BREW-enabled mobile phone that was only capable of displaying US-ASCII characters. Some feeds contained MS Word special characters (e.g. curly quotes) that needed to be translated to close ASCII equivalent.

    Possible Solution: Find existing package to do the translation

    More Problems: Quick search on Google didn't yield any existing libraries to help me with the task at hand. However I found two widely used utilities written in languages other than Java - Demoronizer (Perl) and AsciiDammit (Python)

    Solution: I decided against Perl and opted for Python script because I knew that there's a Jython - Python interpreter written in Java that I can use to run Python code within my Java app

    Pre-reqsI do my programming using Eclipse as IDE and utilizing Spring 1.2 but the following steps can be easily replicated with any other IDE/environment

    How to do it?

    Step 1: Download and install Jython distribution from http://www.jython.org/download.html. Yes, that download is not a Jython itself but rather installation program

    Step 2: Download AsciiDammit.py and install it so it will be accessible from the Classpath of your app. I put mine in src/scripts/AsciiDammit.py

    Step 3: Setup embedded Jython. This is actually two-step process. First add jython.jar from the Jython distribution to your lib directory (e.g. WEB-INF/lib). Second - create Lib directory under directory where you just placed jython.jar and copy all the files from <jython distribution root>/Lib there. Note that Lib starts with uppercase L.

    Step 3: You are ready to use embedded Jython from your app. Now, as I found out initializing Jython Interpreter is a pretty expensive and lengthy operation. So it is wise to create instance of org.python.util.PythonInterpreter as a singleton. If you are using Spring, add the following to your applicationContext.xml:


    <bean id="demoronizer" class="com.qualcomm.util.Demoronizer">
        <property name="python">
            <ref bean="python" />
        </property>
    </bean>
    <bean id="python" class="org.python.util.PythonInterpreter" singleton="true" />


    Step 4: I created simple POJO and called it Demoronizer. It's short so I'll simply put its code at the end of this article.

    Code comments:
    If you're not using Spring, you would have to initialize and set PythonInterpreter elswhere. Since it has no parameter constructor that should be easy.
    Get content of AsciiDummit.py into a String. I'm using jakarta IO commons IOUtils to do it.
    PythonInterpreter has number of public methods to execute Python scripts and obtain results, however I couldn’t use eval() because it was generating script errors. So here what I did:
    1. Run exec(String) which feeds AsciiDummit.py into interpreter and stops at the last line
    2. Now, simply run exec(<line of script>) to execute something from the script, in my case I want to execute “demoronizer” method by feeding original, “uncleaned” text and capturing the result into some python variable. I do it in this line: python.exec("txt = demoronize('" + text + "')");
    3. Now I need to extract the result into Java variable. For that I use interpreter’s get(String) method that returns value of specified argument as PyObject. So in my case I do: PyObject result = python.get("txt");
    4. And finally, result.toString() gets me a modified, “clean” version of the original text

    One last disclaimer: This code illustrates how to execute embedded Jython from within your code. For this particular example I ended up not using it because it wasn’t cleaning text the way I expected: It finds curlies but replaces these with nothing or some garbage.


    package com.bostone.util;

    import org.apache.commons.io.IOUtils;
    import org.python.core.PyObject;
    import org.python.util.PythonInterpreter;

    /**
     * Runs python script (AsciiDammit.py) to convert windows style UTF-8 chars such
     * as curly quotes to ASCII
     *
     * @author bostone
     */
    public class Demoronizer {
    public static final String SCRIPT = "/scripts/AsciiDammit.py";
    PythonInterpreter python;

    /**
    * Cleans windows special chars and returns the result
    *
    * @param text
    * @return
    */
    public String cleanIt(String text) {
    try {
    String code = IOUtils.toString(Demoronizer.class
    .getResourceAsStream(SCRIPT));
    python.exec(code);
    python.exec("txt = demoronize('" + text + "')");
    PyObject result = python.get("txt");
    System.out.println(result);
    } catch (Exception e) {
    e.printStackTrace();
    }
    return text;
    }
    public PythonInterpreter getPython() {
    return python;
    }
    public void setPython(PythonInterpreter python) {
    this.python = python;
    }
    }

    Threaded Messages (2)

  2. Embedded Jython and Spring[ Go to top ]

    Well, here comes a typo:
    python.exec("txt = demoronise('" + text + "')");
  3. A little cleaner way[ Go to top ]

    python.execfile(fileName); PyFunction func = (PyFunction) python.get("demoronize", PyFunction.class); String output = ((PyString) func.__call__(new PyString(input))) .toString();