# Appendix B: Jython Cookbook¶

There are a plethora of examples for using Jython that can be found on the web. This appendix is a compilation of some of the most useful examples that we have found. Those that were chosen are focused on topics that are not widely covered elsewhere on the web.

Unless otherwise noted, each of these examples have been originally authored for working on versions of Jython prior to 2.5.x, but we have tested each of them using Jython 2.5.1 and they function as advertised.

## Logging¶

### Using log4j with Jython, Josh Juneau¶

wiki.python.org/jython/JythonMonthly/Articles/August2006/1

Are you still using the Jython print command to show your errors? How about in a production environment, are you using any formal logging? If not, you should be doing so, and the Apache log4j API makes it easy to do so. Many Java developers have grown to love the log4j API, and it is utilized throughout much of the community. That is great news for Jython developers because we’ve got direct access to Java libraries! There are many Python logging libraries, such as the standard logging module. However, sometimes if you are working with Java code it is nice to have the option to integrate with APIs such as log4j.

The most difficult part about using log4j with Jython is the setup. You must ensure that the log4j.jar archive resides somewhere within your Jython PATH (usually this entails setting the CLASSPATH to include necessary files). You then set up a properties file for use with log4j. Within the properties file, you can include appender information, where logs should reside, and much more. For more information, a good place to start is the log4j site manual: logging.apache.org/log4j/1.2/manual.html.

Listing B-1.

log4j.rootLogger=debug, stdout, R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=C:\\Jython\\testlog4j.log

log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n

You are now ready to use log4j in your Jython application. As you can see, if you’ve ever used log4j with Java, it is pretty much the same.

#### Using log4j in a Jython Application¶

First, you must import the log4j packages:

Listing B-2.

from org.apache.log4j import *


Second, you obtain a new logger for your class or module and set up a PropertyConfigurator:

Listing B-3.

self.logger = Logger.getLogger("myClass")
# Assume that the log4j properties resides within a folder named "utilities"
PropertyConfigurator.configure(sys.path[0] + "/utilities/log4j.properties")


Lastly, use log4j:

Listing B-4.

# Example module within the class:
def submitDocument(self, event):
try:
# Assume we perform some SQL here
except SQLException, ex:
self.logger.error("docPanel#submitDocument ERROR: %s" % (ex))

Your logging will now take place within the file you specified in the properties file for log4j.appender.R.File.

Posted to the Jython-users mailing list by Alfonso Reyes on October 14, 2007

wiki.python.org/jython/PoiExample

What follows are a few Apache Poi examples. Apache Poi is a set of Java APIs for creating and manipulating various file formats based on the Office Open XML standards (OOXML) and Microsoft’s OLE 2 Compound Document Format (OLE2). These APIs allow you to do things such as read and write spreadsheet files using Java. These examples require Apache Poi to be installed and on the classpath.

This is based on Java code at officewriter.softartisans.com/OfficeWriter-306.aspx and converted to Jython.

Listing B-5.

#jython poi example. from Jython mailing list

from java.io import FileOutputStream
from java.util import Date
from java.lang import System, Math
from org.apache.poi.hssf.usermodel import *
from org.apache.poi.hssf.util import HSSFColor
# Obtain the start time
startTime = System.currentTimeMillis()
# Create a new workbook, HSSFWorkbook is a high level representation of a workbook
wb = HSSFWorkbook()
# Create file if it doesn't exist
fileOut = FileOutputStream("POIOut2.xls")

# Create 3 sheets
sheet1 = wb.createSheet("Sheet1")
sheet2 = wb.createSheet("Sheet2")
sheet3 = wb.createSheet("Sheet3")
sheet3 = wb.createSheet("Sheet4")

# Create a style used for the first column
style0 = wb.createCellStyle()
font0 = wb.createFont()
font0.setColor(HSSFColor.RED.index)
style0.setFont(font0)

# Create the style used for dates.
styleDates = wb.createCellStyle()
styleDates.setDataFormat(HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm"))

# String value
cell0.setCellValue("Name")

# numbers
for i in range(0, 8):
cell.setCellValue("Data " + str( (i + 1)) )

# Date
cell10.setCellValue("Date")
# Populate the columns of the spreadsheet
for i in range(0, 100):
# create a new row
row = sheet1.createRow(i + 2)
for j in range(0, 10):
# create each cell
cell = row.createCell(j)
# Fill the first column with strings
if j == 0:
cell.setCellValue("Product " + str(i))
cell.setCellStyle(style0)
# Fill the next 8 columns with numbers.
elif j < 9:
cell.setCellValue( (Math.random() * 100))
# Fill the last column with dates.
else:
cell.setCellValue(Date())
cell.setCellStyle(styleDates)
# Summary row
rowSummary = sheet1.createRow(102)
sumStyle = wb.createCellStyle()
sumFont = wb.createFont()
sumFont.setBoldweight( 5)
sumFont.setFontHeightInPoints(12)
sumStyle.setFont(sumFont)
sumStyle.setFillPattern(HSSFCellStyle.FINE_DOTS)
sumStyle.setFillForegroundColor(HSSFColor.GREEN.index)
cellSum0 = rowSummary.createCell( 0)
cellSum0.setCellValue("TOTALS:")
cellSum0.setCellStyle(sumStyle)

# numbers
# B
cellB = rowSummary.createCell( 1)
cellB.setCellStyle(sumStyle)
cellB.setCellFormula("SUM(B3:B102)")


This Jython code will open and read an existing Excel file.

Listing B-6.

"""    read.py
Read an existing Excel file (Book1.xls) and show it on the screen
"""
from org.apache.poi.hssf.usermodel import *
from java.io import FileInputStream
# Open an existing file and use HSSFWorkbook object to store it
file = "H:Book1.xls"
print file
fis = FileInputStream(file)
wb = HSSFWorkbook(fis)
# Obtain reference to the first sheet in the workbook
sheet = wb.getSheetAt(0)

# get No. of rows
rows = sheet.getPhysicalNumberOfRows()
print wb, sheet, rows

cols = 0 # No. of columns
tmp = 0

# This trick ensures that we obtain the data for future use even if it
# doesn't start from first few rows
for i in range(0, 10):
row = sheet.getRow(i)
if row:
tmp = sheet.getRow(i).getPhysicalNumberOfCells()
if tmp > cols:
cols = tmp
print cols

for r in range(0, rows):
row = sheet.getRow(r)
print r
if(row != None):
for c in range(0, cols):
cell = row.getCell(c)
if cell != None:
print cell

wb.close()
fis.close()


## Jython and XML¶

### Writing and Parsing RSS with ROME, Josh Juneau¶

wiki.python.org/jython/JythonMonthly/Articles/October2007/1

RSS is an old technology now. It has been around for years. However, it is a technology that remains very useful for disseminating news and other information. The ROME project on java.net is helping to make parsing, generating, and publishing RSS and Atom feeds a breeze for any Java developer.

Because I am particularly fond of translating Java to Jython code, I’ve taken simple examples from the Project ROME Wiki and translated Java RSS reader and writer code into Jython. It is quite easy to do, and it only takes a few lines of code.

Keep in mind that you would still need to build a front-end viewer for such an RSS reader, but I think you will get the idea of how easy it can be just to parse a feed with Project ROME and Jython.

#### Setting up the CLASSPATH¶

In order to use this example, you must obtain the ROME and JDOM jar files and place them into your CLASSPATH:

Listing B-7.

set CLASSPATH=C:\Jython\Jython2.2\rome-0.9.jar;%CLASSPATH%
set CLASSPATH=C:\Jython\Jython2.2\jdom.jar;%CLASSPATH%

OSX:

export CLASSPATH=/path/to/rome-0.9.jar:/path/to/jdom.jar

#### Parsing Feeds¶

Parsing feeds is easy with ROME. Using ROME with Jython makes it even easier with the elegant Jython syntax.

We took the FeedReader example from the ROME site and translated it into Jython (see the following). You can copy and paste the code into your own FeedReader.py module and run it to parse feeds. However, the output is unformatted and ugly. Creating a good looking frontend is up to you.

Listing B-8.

########################################
#
# This module can be used to parse an RSS feed
########################################
from java.net import URL
from java.lang import Exception
from java.lang import Object
from com.sun.syndication.feed.synd import SyndFeed
from com.sun.syndication.io import SyndFeedInput

def __init__(self, url=None):
self.inUrl = url

#####################################
# If url passed in is blank, then use a default
#####################################
rssUrl = self.inUrl if self.inUrl else

#####################################
# Parse feed located at given URL
#####################################
try:
input = SyndFeedInput()
####################################
# Do something here with feed data
####################################
print(feed)

except Exception, e:
print 'An exception has occurred', e

if __name__== "__main__":
print '****************Command Complete...RSS has been parsed*****************'

#### Creating Feeds¶

Similar to parsing a feed, writing a feed is also quite easy. When one creates a feed, it appears to be a bit more complex than parsing, but if you are familiar with XML and its general structure, then it should be relatively easy.

Creating a feed is a three step process. You must first create the feed element itself, then you must add individual feed entries, and lastly you must publish the XML.

Listing B-9.

########################################
# File: FeedWriter.py
#
# This module can be used to create an RSS feed
########################################
from com.sun.syndication.feed.synd import *
from com.sun.syndication.io import SyndFeedOutput
from java.io import FileWriter
from java.io import Writer
from java.text import DateFormat
from java.text import SimpleDateFormat
from java.util import ArrayList
from java.util import List
from java.lang import Object

class FeedWriter(Object):
####################################
# Set up the date format
####################################
def __init__(self, type, name):
self.DATE_PARSER = SimpleDateFormat('yyyy-MM-dd')
self.feedType = type
self.fileName = name

def writeFeed(self):

try:
################################
# Create the feed itself
################################
feed = SyndFeedImpl()
feed.feedType =self.feedType
feed.title = 'Sample Feed (created with ROME)'
feed.description = 'This feed has been created using ROME and Jython'

###############################
# Add entries to the feed
###############################
entries = ArrayList()
entry = SyndEntryImpl()
entry.title = 'ROME v1.0'
entry.publishedDate = self.DATE_PARSER.parse("2004-06-08")
description = SyndContentImpl()
description.type = 'text/plain'
description.value = 'Initial Release of ROME'
entry.description = description

entry = SyndEntryImpl()
entry.title = 'ROME v2.0'
entry.publishedDate = self.DATE_PARSER.parse("2004-06-16")
description = SyndContentImpl()
description.type = 'text/plain'
description.value = 'Bug fixes, minor API changes and some new features'
entry.description = description

entry = SyndEntryImpl()
entry.title = 'ROME v3.0'
entry.publishedDate = self.DATE_PARSER.parse("2004-07-27")
description = SyndContentImpl()
description.type = 'text/plain'
description.value = '<p>More Bug fixes, mor API changes, some new features and some Unit testing</p>'
entry.description = description

feed.entries = entries
###############################
# Publish the XML
###############################
writer = FileWriter(self.fileName)
output = SyndFeedOutput()
output.output(feed,writer)
writer.close()

print('The feed has been written to the file')

except Exception, e:
print 'There has been an exception raised',e

if __name__== "__main__":
####################################
# You must change his file location
# if not using Windows environment
####################################
writer.writeFeed()
print '****************Command Complete...RSS XML has been created*****************'


After you have created the XML, you’ll obviously need to place it on a web server somewhere so that others can use your feed. The FeedWriter.py module would probably be one module among many in an application for creating and managing RSS Feeds, but you get the idea.

#### Summary¶

As you can see, using the ROME library to work with RSS feeds is quite easy. Using the ROME library within a Jython application is straightforward. As you have now seen how easy it is to create and parse feeds, you can apply these technologies to a more complete RSS management application if you’d like. The world of RSS communication is at your fingertips!

## Working with CLASSPATH¶

### Using the CLASSPATH, Steve Langer¶

wiki.python.org/jython/JythonMonthly/Articles/January2007/3

During October and November of 2006, there was a thread in the Jython-users group called “adding JARs to sys.path.” More accurately, the objective was to add JARs to the sys.path at runtime. Several people asked the question, “Why would you want to do that?” Well there are at least two good reasons. The first is if you want to distribute a Jython or Java package that includes non-standard Jars in it. Perhaps you want to make life easier for the target user and not demand that they know how to set environment variables. A second even more compelling reason is when there is no normal user account to provide environment variables.

“What?” you ask. Well, in my case I came upon this problem in the following way. I am working on an open source IHE Image Archive Actor and needed a web interface. I’m using AJAX on the client side to route database calls through CGI to a Jython-JDBC enabled API. Testing the Jython-JDBC API from the command line worked fine; I had the PostgreSQL driver in my CLASSPATH. But when called via the web interface, I got “zxJDBC error, PostgreSQL driver not found” errors. Why? Because APACHE was calling the API and APACHE is not a normal account with environment variables.

#### What to Do?¶

The Jython-users thread had many suggestions, but none were found to work. Chapter 11 of O’Reilly’s Jython Essentials mentions under “System and File Modules” that “to load a class at runtime, one also needs an appropriate class loader.” Of course, no mention is made beyond that. After a while, it occurred to me that perhaps someone in the Java world had found a similar problem and had solved it. Then all that would be required is to translate that solution. And that is exactly what happened.

#### Method¶

For brevity, I will not repeat the original Java code here. The following shows how I call the Jython class (note that one can use either addFile or addURL depending on whether the Jar is on a locally accessible file system or remote server).

Listing B-10.

import sys
from com.ziclix.python.sql import zxJDBC

d,u,p,v = "jdbc:postgresql://localhost/img_arc2","postgres","","org.postgresql.Driver"

try :
# if called from command line with .login CLASSPATH setup right,this works
db = zxJDBC.connect(d, u, p, v)
except:
# if called from Apache or account where the .login has not set CLASSPATH
# need to use run-time CLASSPATH Hacker
try :
db = zxJDBC.connect(d, u, p, v)
except :
sys.exit ("still failed \n%s" % (sys.exc_info()))


And here is the class “classPathHacker” which is what the original author called his solution. In fact, you can simply Google on “classPathHacker” to find the Java solution.

Listing B-11.

class classPathHacker :
##########################################################
#
# Author: SG Langer Jan 2007 translated the above Java to this
#       Jython class
# Purpose: Allow runtime additions of new Class/jars either from
#       local files or URL
######################################################
import java.lang.reflect.Method
import java.io.File
import java.net.URL
import jarray

#############################################
# Purpose: If adding a file/jar call this first
#       with s = path_to_jar
#############################################

# make a URL out of 's'
f = self.java.io.File (s)
u = f.toURL ()
return a

##################################
# Purpose: Call this with u= URL for
#       the new Class/jar to be loaded
#################################

parameters = self.jarray.array([self.java.net.URL], self.java.lang.Class)
a = method.setAccessible(1)
jar_a = self.jarray.array([u], self.java.lang.Object)
return u


#### Summary¶

That’s it. Depressingly short for what it does, but then that’s more proof of the power of this language. I hope you find this as powerful and useful as I have. It allows the possibility of distributing Jython packages with all their file dependencies within the installation directory, freeing the user or developer from the need to alter user environment variables, which should lead to more programmer control and thus higher reliability.

## Ant¶

The following Ant example works with Jython version 2.2.1 and earlier, only due to the necessary jythonc usage. jythonc is no longer distributed with Jython as of 2.5.0. This example could be rewritten using object factories to work with current versions of Jython.

### Writing Ant Tasks with Jython, Ed Takema¶

Ant is the current tool of choice for Java builds. This is so partially because it was the first Java-oriented build tool on the scene and because the reigning champion None was getting long in the tooth and had fallen out of favor with the Java crowd. But Java builds are getting more and more difficult, and these days there is general dissatisfaction with Ant. Note particularly Bruce Eckel’s comments and Martin Fowler’s further comments. The comments to Bruce Eckel’s posting show similar frustrations. Fowler summarizes the issues like this:

Simple builds are easy to express as a series of tasks and dependencies. For such builds the facilities of Ant/Make work well. But more complex builds require conditional logic, and that requires more general programming language constructs. And that’s where Ant/Make fall down. Ken Arnold’s article, “The Sum of Ant,” led me to Jonathon Simon’s article, “Scripting with Jython Instead of XML,” and got me thinking about extending Ant with Jython. Simon’s article presents a technique to drive Ant tasks, testing, etc., all from Jython. What I am presenting is a technique to embed Jython scripts into Ant which is admittedly backwards from Simon’s approach, but hopefully adds power and flexibility to Ant builds.

My experience working with large builds automated through Ant is not dissimilar to what Fowler is referring to. Eventually, builds need to do either a lot of odd conditional logic in the xml file and ends up burying the logic in scripts, or in a large number of custom tasks written in Java. This is particularly the case if your builds include non-Java source that Ant just isn’t smart about building. In one case in particular, the set of custom tasks for the build is really its own system with maintenance and staff costs that are quite substantial. A large number of scripts can quickly become a problem for enterprise build systems as they are difficult to standardize and cross platform issues are always looming.

Spille, in his article, “ANT’s Finally a Real Build Tool,” demonstrates that the new <import> tag now allows build managers to write truly modular and standardized build systems based on Ant! As Ant grows up, more and more of these issues will get resolved.

always had was the ability to easily call scripts and command utilities.

This is something that is definitely possible with Ant script/exec tasks, but it feels very un-Java. What we need is an elegant way to add ad-hoc behavior to Ant builds.

What I think can do the job is to take a more considered approach to using a scripting tool inside an Ant build. Rather than just create a mishmash of scripts that are called from exec or script tasks, I suggest that we write custom Ant build tasks in a high level scripting language. In this case, Jython.

Writing custom Ant tasks allows a build manager to leverage the huge number of already written tasks in their builds, while writing what naturally belongs in a more flexible tool in custom Ant tasks that can themselves then be reused, and are as cross-platform as Java itself, and wholly integrated into Ant. Because Ant uses Java introspection to determine the capabilities of custom tasks, Jython is the perfect tool to accomplish this. All we need to do is ensure that the methods that Ant expects are present in the Jython classes and Ant won’t notice the difference.

What we will implement is the perennial SimpleTask which is nothing more than a “Hello World” for ant. It should be sufficient to demonstrate the key steps.

#### Setup Development Environment¶

To compile the Jython source you will need to add the ant.jar file to your classpath. This will make it available to Jython to extend which we’ll do in the following. To do that, define your classpath:

Listing B-12.

<DOS>
set CLASSPATH=c:\path\to\ant\lib\ant.jar;%CLASSPATH%
<UNIX>