Sean McGrath
http://www.propylon.com
http://seanmcgrath.blogspot.com
10 October 2004
Here is what we are going to cover in this section of the tutorial:
Download Jython from www.jython.org/download.html
Jython is shipped as a single class file which you run in order to install it on your system.
The installation instructions are straighforward: www.jython.org/install.html
As always, there are platform-specific nuances. Check out your platform on /www.jython.org/platform.html.
My setup is that I have Jython installed in d:\jython-2.1. I have added that directory onto my Windows path so that I can invoke Jython from the command line from any directory.
When you first fire up Jython from a command window it will search through your classpath and create a cache of all the stuff it finds there.
You should see something like this: (click for large version)
You will find yourself at the Jython command prompt:
Welcome to interactive Java :-)
Note to emacs users. Jython works just fine from the emacs shell. Unlike CPython, it does not require the "-i" switch in order to recognize an interactive session. No, I don't know why that is.
Now we can do something predictable and boring:
You are stunned into silence, I know.
To get out of Jython's interactive shell you can press ^c twice or press ^d once. I prefer the former because the latter causes Emacs to close its interactive shell window. ^z doesn't work for me on Windows. No, I don't know why that is.
Pedants, purists and epicures may prefer:
Which closes Jython gracefully.
Now for something more interesting. Fire up Jython again and try this:
Nothing happens. That's good. You have now succesfully loaded the Java String class into Jython. Because we have an interactive shell, we can poke around to find stuff. Try this:
This time you will get output. Something like this:
This is a list of all the attributes of the java.lang.String class that Jython can see. Now lets make use of that information:
First, create a java.lang.String object called S. Initialize it to the obligatory "Hello world":
Now convert the string to lowercase using the toLowerCase method:
Cute eh? This is the sort of seamless integration with Java classes that brings so much power to Jython and greases the wheels of application development and debugging something wonderfull.
So now that Jython is up and running, we turn our attention to Tomcat.
You can download Tomcat from jakarta.apache.org/tomcat/
The version I used is Tomcat 5-0-28. I have installed mine in
d:/data/tomcat-5-0-28. You need to set the CATALINA_HOME environment variable to point to
the root of your Tomcat install. You also need the JAVA_HOME
environment variable pointing at your Java install but you probably
already have that. Start up Tomcat by executing the startup command in the bin subdirectory of your Tomcat install. You should see something like this: Tomcat fires up a second window where all subsequent action takes place. It should look something like this: Now to point a web browser at it. By default, Tomcat fires up on port 8080. Point at browser at localhost:8080 and you should see this: So far, so far. Now lets proceed to create a Java servlet the
classical (baroque?) way in order to make sure that all our Java kit
is functioning as required.
First things first. We need to ensure that we can run Java servlets before we
venture into Jython servlets.
Make sure that your Java compiler can see the javax.servlet jar file that Tomcat
provides. It lives in common\lib\servlet-api.jar. You can put this on your CLASSPATH or you can specify it on the command line to javac like this: Create a subdirectory in %CATALINA_HOME\webapps called jythondemo. Create a WEB-INF subdirectory and then create a classes subdirectory of WEB-INF. In the classes directory, create a Java file called ServletTest.java with this code: This thorougly unexciting Servlet simply creates a HTML test page
to be sent back to the browser. Compile it into a .class file. By default, the .class file will be
in the same directory. That is fine for our purposes. Now we need to
tell Tomcat about our jythondemo application. We do this by creating a
web.xml file in the WEB-INF subdirectory of the jythondemo
directory. Here are the required contents of the web.xml file:
Shutdown your Tomcat process if you have not already done so and start it up again. The shutdown command is:
When you bring Tomcat back up again, the following URL should work :
localhost:8080/jythondemo/ServletTest. All going well, you will see this: Now we can proceed to create the Jython version of this
servlet. Jython servlets work by means of an intermediate Java servlet
know as PyServlet. Simply put, this is the servlet that Tomcat runs
and it, in turn, invokes Jython programs. Got it? So, the first thing we need
to do is tee up PyServlet. PyServlet lives in jython.jar. The preferred way to make jython.jar
available to you webapps it to put it in a WEB-INF/lib subdirectory of
your context - in this case in a lib sub directory of the jythondemo
directory : jythondemo/WEB-INF/lib. Now we tell Tomcat about PyServlet and tell it that PyServlet is to
be invoked whenever a request for a resource matching *.py is made. To
do that, we make the following additions to the web.xml file: The full web.xml now looks like this:
Now it is time to create a Jython equivalent of the Java Servlet above. Here it is (JythonServlet1.py):
Is that it? I hear you say? Yes. Put it into the jythondemo subdirectory. Restart your Tomcat one more time just as before. Now this URI
should work: localhost:8080/jythondemo/JythonServlet1.py
Same output as before right? Now comes the fun part. Change the servlet in some trivial way. e.g. change the text in the HTML page it produces. What do you need to do to re-deploy the changed Jython servlet. These three things:
What do you need to do in order to deploy a second Jython servlet, called, says JythonServlet2.py? Apart from creating the file and putting it into the jythondemo directory, you have to do these three things: Welcome to Java rapid development :-) You might want to take a moment or two to contemplate the
significance of the simplcity of all this. Think how easy you can make
it to change stuff in installations of your software by making
some/all of the servlets .py files. "Configuration files" takes on a
whole new meaning doesn't it?
Python (and thus Jython) takes the concept of application testing very
seriously indeed. As well as being sound engineering practice,
application testing is critical in dynamically typed programming
languages because so much of the language machinery executes at run
time. (There is actually a compile-time step in Jython
execution. Behind the scences, the jython interpreter creates JVM byte
code on the fly. You don't see it happening though.) We won't get into a debate about the merits/de-merits of dynamic
typing. I'm a firm advocate of dynamic typing and my shortest argument as to why I advocate it is this:-
Now you either believe this or you don't. If you don't - nothing I
could say here will convince you otherwise. All I can say is, if you
have never tried a dynamic typing approach, stick with me until the
end of this tutorial. At least try it once. You will not be
sorry. What is the worst that can happen? You will end up with more
ammunition to fight the dynamic typing zealots. How bad can that be?
A useful device for testing servlets is to be able to run them "in
batch" without requiring the machinery of a servlet engine. Setting up a scenario in which servlets can be executed standalone is very simple with Jython. Take a look at the following Jython Servlet: JythonServlet2.py:
The last 5 lines are a test harness for the servlet. Simply put, when Jython executes this program from the command line it will execute these 4 lines: If it isn't - either because this program has been imported into another program or because it is being executed by a servlet engine - these lines are not executed. What do these lines do? In English this is what is going on:
There is no need for Tomcat to be running for this to work. We are
faking it in the interests of having a simple, robust testing strategy for servlets So, all the magic to make this work must be in the JythonServletUtils module right? Well, here it is, there is no magic: All I have done is fake up a couple of classes and implemented the
few methods that my servlets actually use. Obviously, I can extend
this with more methods from the HttpRequest/HttpResponse classes as
required. I have complete flexibility in what these fake methods do so
I can tee them up to fit by test strategy.
In this case the key thing I have done is to say that calling
getWriter on the HttpResponse object will return stdout and thus my
servlets can run standalone writing their output to stdout rather than
to servlet containers.
Jython ships with a bevvy of useful modules. These, combined with
all the class files and jar files of the entire world create the vista
of code re-use opportunities perused by the discerning Jythoneer.
Take Jython's calendar module for example. It prints nicely formatted calendars. I can never remember the details of what classes/methods it has. I don't need to, to be honest. I just fire up Jython and poke around:
Lets fire up Jython... I know the module is called calendar. Lets take a look... The calendar thing looks promising. I wonder what it is? Hmmm. Its a function. Sounds promising. Any docstrings I wonder? Sounds good. Lets have one of them... Oops! It needs at least one argument. What are the chances that the first parameter is a year? So far, so good. What type is c? Houston? We have a string! Lets take a look...
So, how hard would it be to invoke this function from within a Servlet? No problem at all as long as Tomcat knows where the Jython library of goodies lives. It is a good idea to create self-contained
servlet contexts - it makes them more portable. To this end, we will hoof all the Jython library stuff into the jythondemo context. The place to put it all is jythondemo\WEB-INF\lib\Lib I normally just xcopy over the entire \jython2-1\lib directory and suggest you do the same. You should at this stage have the following directory structure: To test that it we have access to the Jython library, here is a
servlet JythonServlet3.py that returns a calendar for the current year
as its response. Notice the use of the test harness mentioned
previously. This allows me to test the servlet outside of Tomcat. Note
also the use of the Jython time module which provides a localtime
function. The first element in the list returned by localtime is the
current year.
Pointing a webbrowser at localhost:8080/JythonServlet3.py should product this output:
In this section we have seen how to set up Jython to work within
Tomcat. The same procedure - with a few tweaks - will make it work in
any Servlet container. We have seen how easy it is to modify existing
servlets and add new ones once Jython is properly set up. We have seen
how to set up servlets so that they can easily be tested outside of a
servlet container environment. Finally, we have seen a few examples of
how poking around with Jython's interactive mode really speeds up finding stuff and finding out how it works.
A full treatment of Jython Servlets would take a whole book. Some of the fun stuff that we have not covered:
In the next section of this tutorial, we will look at accessing the rich and varied and mission critical world of asynchronous messaging via the JMS API from Jython. Actually, we might do some XML work first. I haven't decided yet.
Installing Tomcat
Configuring Tomcat to run Jython Servlets
Servlet Test
");
}
}
Servlet Test
")
Running Jython Servlets from the command line
Static typing prevents certain types of failures but, in so doing,
it prevents certain types of successes.
Servlet Test 2
")
if __name__ == "__main__":
JS2 = JythonServlet2()
dummyRequest = DummyHttpRequest()
dummyResponse = DummyHttpResponse()
JS2.doPost (dummyRequest,dummyResponse)
"If I'm executing as the main program, create an instance of the servlet, fake up a couple of request/response objects and run the POST method of the servlet."
When executed this servlet produces the following output:
Servlet Test 2
Accessing the Jython library
Calendar
%s
" %
calendar.calendar(time.localtime()[0]))
if __name__ == "__main__":
JS3 = JythonServlet3()
dummyRequest = DummyHttpRequest()
dummyResponse = DummyHttpResponse()
JS3.doPost (dummyRequest,dummyResponse)
Summary and pointers to other stuff