One of the biggest challenges programmers are going to face is that how fast can a new service be introduced. The service is an additional capability coexisting with existing applications, possibly replacing a part of the application. In this context, 'scripting' languages like Python, Ruby can be extremely valuable. Even if the final code will be in another language, these tools can help speed up the process of getting the algorithm right. It can help a programmer go home by 7 instead of after 10. He can have a life outside office. We will explore using Jython as the tool for writing servlets. Jython, the Python compiler in Java, has revived after a fairly long period of hibernation. Even though modern IDE's make hot-deployment of revised servlets a breeze, there is still a saving in effort by just creating a new servlet in Jython and using it. Keep it open in any editor. Make a change, save and refresh the browser page. Any person who has not worked with servlets will find it much easier to get started with Jython. A J2EE expert should know enough about Jython to intelligently decide whether it will speed up development. We will use the servlet examples which are distributed with Apache Tomcat as the reference and see how the same tasks can be implemented using Jython. Let us explore the examples with as much brevity as possible. Let us create a directory jython-servlets in webapps in Tomcat home. First, we need to inform Tomcat that any request with a python file for this application should be handled by PyServlet. We do so in a file web.xml in WEB-INF directory. The contents of the web.xml file are: <web-app> <servlet> <servlet-name>PyServlet</servlet-name> <servlet-class> org.python.util.PyServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>PyServlet</servlet-name> <url-pattern>*.py</url-pattern> </servlet-mapping> </web-app> As usual, an XML file is a non-Pythonic way of telling Tomcat to load PyServlet on start and let it handle all requests which end with a '.py' extension. Wouldn't it be nice if we could write: web-app servlet servlet-name=PyServlet servlet-class=org.python.util.PyServlet load-on-startup=1 servlet-mapping servlet-name=PyServlet url-pattern=*.py As may be expected, PyServlet is not a part of J2EE framework but rather a part of Jython. So, we need Tomcat to be able to find it. The easiest way is to create a directory lib in WEB-INF. We copy jython.jar and the Lib (note the case!) directory from the Jython installation into the lib directory. We are all set to write the first servlet in webapps/jython-servlets. Following the pattern of the servlets-examples but removing the obvious, we will call it HelloWorld.py. The code looks like from javax.servlet.http import HttpServlet class HelloWorld(HttpServlet): def doGet(self, req, res): res.setContentType("text/html") out = res.getWriter() out.println("""<html><body> <h1>Hello World. Uses PyServlet!</h1> </body></html>""") This is just a translation of the corresponding Java code. The absence of type declarations and the ability to use a long string makes the code more readable. We start the tomcat server and use the url http://localhost:8080/jython-servlets/HelloWorld.py. If we have set the libraries correctly and have not made spelling mistake in the code, the welcome message should show up. Fortunately, the error messages are also not too frightening. Our next example is the viewing of request information from a client. Let us create RequestInfo.py: from javax.servlet.http import HttpServlet class RequestInfo(HttpServlet): def doGet(self,req,res): res.setContentType("text/html") out = res.getWriter() info = "Method: " + req.getMethod() + "<br>"\ + "Request URI: " + req.getRequestURI() + "<br>"\ + "Protocol: " + req.getProtocol() + "<br>"\ + "PathInfo: " + req.getPathInfo().__repr__() + "<br>"\ + "Remote Address: " + req.getRemoteAddr() out.println(self.makeHTML(info)) def doPost(self,req,res): self.doGet(req,res) # HTML Code def makeHTML(self,data): return """<html><body> <h3>Request Information Example</h3> """ + data + "</body></html>"
This page will show us the method, the url, the path and the remote ip address. Again, the code closely follows the Java version though we have used a helper function makeHTML to isolate the html code and improve readability. In live applications, we would prefer to use a template tool to isolate the html code from the application. Incidentally, we just use the url http://localhost:8080/jython-servlets/RequestInfo.py. There is no need to restart tomcat. The live application may need us to know more information from the request header. Let us create RequestHeader.py as follows: from javax.servlet.http import HttpServlet class RequestHeader(HttpServlet): def doGet(self,req,res): res.setContentType("text/html") out = res.getWriter() info = "" for name in req.getHeaderNames(): value = req.getHeader(name) info += name + ": " + value + "<br>" out.println(self.makeHTML(info)) def makeHTML(self, data): return a formatted HTML page Working with enumerations is somewhat easier in Python. The key point to note is that we get client specific information easily and the server code can deal with any variations required appropriately. E.g. we need not write code for Firefox only. We can tolerate IE as well. Let us now consider how to get data from a user. We next write the RequestParam.py as follows: from javax.servlet.http import HttpServlet class RequestParam(HttpServlet): def doGet(self,req,res): res.setContentType("text/html") out = res.getWriter() out.println(self.makeHTML("<br>No Parameters, Please enter some")) def doPost(self,req,res): res.setContentType("text/html") out = res.getWriter() params = "" for name in req.getParameterNames(): value = req.getParameter(name) params = params + "<br>" + name +" = " + value out.println(self.makeHTML(params)) def makeHTML(self, data): will return a properly formatted HTML page with a form Calling http://localhost:8080/jython-servlets/RequestParam.py will call the doGet method. The HTML code contains a form which will call the page with the POST method. In the absence of the HTML code, the code looks very simple and straightforward. Since HTML is a stateless protocol, a solution for keeping track of a users activities across pages is via cookies. Let us consider the code for Cookie.py. We will use the same form as before but keep track of the various entries. from javax.servlet import * class Cookie(http.HttpServlet): def doGet(self,req,res): res.setContentType("text/html") out = res.getWriter() params ="" # get the cookies cookies = req.getCookies() if cookies != None: for cookie in req.cookies: name = cookie.getName() value = cookie.getValue() params = params + "<br>" + name + " = " + value # set a cookie using the parameters name = req.getParameter("name") if name != None and len(name) > 0: value = req.getParameter("value") res.addCookie(http.Cookie(name,value)) params = params + "<br> New cookie " + name + " = " + value out.println(self.makeHTML(params)) def makeHTML(self,data): will return a properly formatted HTML page with a form
In Jython, we do not have to worry about type declarations. (Dynamic typing is really useful inspite of what we learn in our first course, usually, in C.) In the above example, there is no doPost function; hence, the form in the HTML page also uses the GET method. Getting and setting cookies is not difficult. The rest is up to the imagination of the programmer. A final step is that we should be able to control sessions. If the
past is any indication, the code for doing so should not be hard. Let
us look at Session.py.
def doGet(self,req,res): res.setContentType("text/html") out = res.getWriter() session = req.getSession(True) # print the session information created = Date(session.getCreationTime()) accessed = Date(session.getLastAccessedTime()) params = "ID " + session.getId() params = params + "<br>Created: " + str(created) params = params + "<br>Last Accessed: " + str(accessed) # set session information if needed dataName = req.getParameter("dataname") if dataName != None and len(dataName) > 0: session.setAttribute(dataName, req.getParameter("datavalue")) try: for name in session.getAttributeNames(): params = params + "<br>" + name + " = " + str(session.getAttribute(name)) except: params = params + "<br> No Attributes" out.println(self.makeHTML(params)) def doPost(self,req,res): self.doGet(req,res) def makeHTML(self,data):will return a formatted HTML page with 2 forms – one using POST and 2nd using GET We get the session information but create a new session if none exists. We have a page with 2 forms – one which uses the POST method and one which uses the GET method. The difference is only in the way the parameters are passed. The code is identical. In the examples above, the number of lines of code is not substantially different between Java and Jython versions. However, the absence of type declarations and parentheses makes it more readable and easier to explore. There is no better way than be actually trying. All you need is about half a day's effort. I am convinced that Python can help one write better code faster. Of course, if Python code is not properly indented, it won't even work. So, no beautifier is needed. The implication is obvious. |
Other Articles >