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;
}
}
-
Embedded Jython and Spring (2 messages)
- Posted by: Robert Stone
- Posted on: May 31 2005 17:23 EDT
Threaded Messages (2)
- Embedded Jython and Spring by Robert Stone on May 31 2005 17:38 EDT
- A little cleaner way by rahul somasunderam on October 12 2009 20:41 EDT
-
Embedded Jython and Spring[ Go to top ]
- Posted by: Robert Stone
- Posted on: May 31 2005 17:38 EDT
- in response to Robert Stone
Well, here comes a typo:
python.exec("txt = demoronise('" + text + "')"); -
A little cleaner way[ Go to top ]
- Posted by: rahul somasunderam
- Posted on: October 12 2009 20:41 EDT
- in response to Robert Stone
python.execfile(fileName); PyFunction func = (PyFunction) python.get("demoronize", PyFunction.class); String output = ((PyString) func.__call__(new PyString(input))) .toString();