November 12, 2005

40 line Java web app

I discovered something yesterday that is just so cool; it's cooler than cool; it's ice cold. Those clever Jython folks implemented the python module BaseHTTPServer - I didn't realise this the last time I looked at Jython (which I thought was pretty clever just as a scripting language for Java).

A 40 line java web app1

Sometimes it's useful to get data out of a database and put it on a web page. (If you don't know what I'm talking about - that's what Enterprise IT is). Sometimes it's useful to do this just for development, independent of the actual production code. For example: for tools, visualisation, testing, system debugging, setting up test data etc.

1In Ruby on Rails or Django (see A comparison of Django with Rails) it would be less, but that's not what this article is about.

Using Jython's BaseHTTPServer you can write handy little Web Apps in hardly any code, really quickly, still using your Java Enterprise Heavy Duty IT code if you need.

Here's an example (which I hope will also be useful to someone out there). I've got Jython 2.1 installed, MySql running, and the MySql JDBC driver on the classpath2.

This creates a web app that shows you the contents of any table in the database. Run this code (having configured database, user, password to suit), open a web browser on "http://localhost:8000/table/foo" to see the contents of table "foo". Note - this has no protection against sql injection attacks so be careful where you run this. This code is provided under the GNU Lesser General Public License and has NO WARRANTY.


import BaseHTTPServer, urllib, java.lang, java.sql

java.lang.Class.forName('com.mysql.jdbc.Driver')
url = 'jdbc:mysql://localhost:3306/database'

class DBHandler(BaseHTTPServer.BaseHTTPRequestHandler):
	def do_GET(self):
		path = urllib.unquote(self.path[1:]).split('/')
		
		self.send_response(200)
		self.send_header("Content-type", "text/html") 
		self.end_headers() 
		
		if path[0] != 'table' or len(path) != 2:
			self.wfile.write("don't understand "+str(path))
		else:		
			con = java.sql.DriverManager.getConnection(url,'user','password')
			s = con.createStatement()
			table = path[1]			
			r = s.executeQuery("select * from "+table)
			
			html = java.lang.StringBuffer("<html><head></head><body><table border=1>")

			numCols = r.getMetaData().getColumnCount()
			while(r.next()):
                                values = [str(r.getString(i)) for i in range(1, numCols+1)]
				html.append("<tr><td>")				
				html.append("</td><td>".join(values))
				html.append("</td></tr>")

			r.close()
			s.close()
			con.close()
			html.append("</table></body></html>")
			self.wfile.write(html.toString())

server_address = ('', 8000)
httpd = BaseHTTPServer.HTTPServer(server_address, DBHandler)
httpd.serve_forever()

An example of it's use, (having done the Django tutorial in case you recognise the table name or data - although this has got nothing to do with Django as such), http://localhost:8000/table/polls_polls shows me:

11Not much3
21The sky1

Adding column names is left as an exercise for the interested reader.

2Note that jython didn't like it when the classpath contained a directory "mysql-connector-java-3.1.11" - it didn't like the mix of "-" and ".". I don't know if this is a known issue - I'll look into it.

What's the Big Deal?

Someone read this and asked what the big deal was. He mostly uses Microsoft technologies rather than Java; I've added this section to answer the question.

In Java, you'd usually have to have an application server installed, configured and running, and write a servlet or equivalent and compile/deploy into the application server.

Using the code shown here, you're not having to do any of this. The code shown is all you need - it's the whole server thing - the whole database access thing too - no separate application server or configuration or deployment. Just run that code - it starts it's own server almost instantly. Just starting up some application servers takes a minute. Installing multiple application servers so you can have a lighter weight one for tools is an option, but configuring them can be lots of hassle. There are exceptions, like Orion, which is relatively straightforward, but even in that, it's more hassle than copying and pasting the code I've shown and editing to suit. At some places, there would be techno-political issues of installing another application server. Installing Jython for scripting tools is less likely to be objected too - in that sense, in some cases, it could be considered partially a technical solution to a techno-political problem.

If you were using .NET I guess you'd usually have IIS already installed. In many ways, this is an example of the classic Microsoft vs Java technical differences. Microsoft stuff often being very simple for simple things but eventually getting horrible for difficult things (for example, being difficult to script IIS configuration) and Java sometimes being less simple for simple things, but with more things configurable and capable of doing more difficult things. (For some things Java is also very simple for simple things - but probably less so, on average, than Microsoft equivalents, but I probably shouldn't have even started along that line as I'll probably get lots of "my technologies better than yours" comments).

Final words

I was so impressed to find that BaseHTTPServer is implemented for Jython. It makes it really easy to create a HTTPServer.

Just to clarify, in case you haven't used Jython - you can import any of your existing Java code and use it in a jython program like the example shown.

The example code isn't how I'd normally look at the contents of a table in a database; I'd usually use something like SQuirreL - this is just an example that I hope you find useful as a starting point for implementing other useful things.

Posted by ivan at November 12, 2005 11:38 AM
Copyright (c) 2004-2008 Ivan Moore
Comments

You know you're going a bit mad when you comment on your own blog, but, here I go anyway; Hey Ivan, you should have used groovy http://groovy.codehaus.org/

Posted by: ivan at November 14, 2005 1:25 PM

Yes, Groovy is an option, but take a look at CherryPy and then checkout this other Java project called OOWeb that takes its inspiration from CherryPy. It is not only possible to write compact webapps with these, but also keep them very object oriented.

I don't know if us Java folks will want to look at webapps with a fresh perspective like the Python and Ruby folks are doing, given how much we have already invested in Struts, Spring, etc.

Posted by: Raj at November 14, 2005 9:19 PM

Looks nice. At least for the embedded web server there is with jetty (http://jetty.mortbay.org/jetty/tut/overview.html#http) also an easy and fast java only solution.

Posted by: jmau at November 15, 2005 7:58 PM

But it still needs html.append("...");

There is a comparable (and IMHO even superior) scripting janguage Juso (http://www.judoscript.com) that provides also templating technology.

Web app is smaller in this case.

Posted by: Vladimir Kovalchuk at November 16, 2005 1:43 PM