Dynamic Interaction with Your Web Application
by Lorenzo Puccetti 09/23/2005
Imagine you are working on a web application. A collection of servlets, HTML pages, classes, .jars, and other resources is now shaping into a fully complete application running on a web server. But something is just not right. Perhaps you are trying to investigate why certain forms seem to submit correctly but the database is not updating, or perhaps a generated web page reports that the server is in a state you would bet it cannot be in. Whatever the problem, you know you could gather a better understanding if only you could have access to the running servlet and check the current state of a few objects. Perhaps you could even temporarily fix it while you‘re at it.
In this article I will show you the code of a simple servlet. This servlet accepts just one attribute via the POST method. An equally simple HTML page consisting of a text area and a submit button is written to interact with it. Yet despite the simplicity of these two components, what we will have is a powerful tool to interactively analyze the state of any web application.
Unveiling the Mystery: Introducing the HookServlet
The servlet we want to write needs to be able to hook into any resource provided by the web server and allow the user to inspect any part of it. To be able to gather the required information, it might require flow-control constructs and loops. This leads to one solution: to make the servlet able to execute a script sent by the client (i.e., the browser). The script will have not only the ability to access any server resource, but by manipulating host objects representing a HTTP request and response, it will be capable of communicating back to the client.
There are several scripting languages for Java that would be up to the job, and in this article we will be using Rhino. Of course, if you are a big fan of any of the other many scripting languages for Java, it would not be too hard to port the servlet to an equivalent implementation in Jython, Groovy, or similar.
Rhino is a popular open source JavaScript engine written in Java. Using its API, it is possible with a few lines of code to create a JavaScript interpreter able to evaluate scripts like this:
// Script n.1
// printing the current time on the standard output stream
java.lang.System.out.println(new java.util.Date());
// script n.2
// writing a log file
var FileWriter = Packages.java.io.FileWriter;
var fw = new FileWriter("log.txt");
fw.write("hello from rhino");
fw.flush();
fw.close();
Since JavaScript is used so extensively in HTML pages to manipulate DOM objects, people tend to get confused when it is used in another environment. However, the language itself is platform-neutral. The Rhino implementation gains access to any class by defining two top-level variables named Packages and java . The properties of the variable Packages are all of the top-level Java packages, such as java , org , and com . The variable java , instead, is just a handy shortcut for Packages.java .
Let‘s have a look at how we can integrate the Rhino engine into our servlet.
import java.io.PrintWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.EcmaError;
public class HookServlet extends HttpServlet
{
public void doPost(HttpServletRequest httpRequest,
HttpServletResponse httpResponse) throws IOException
{
PrintWriter out=httpResponse.getWriter();
httpResponse.setContentType ("text/html");
httpResponse.setHeader("Cache-Control","no-cache");
String code=httpRequest.getParameter("serverjavascript");
try
{
Context context= Context.enter();
Scriptable scope=context.initStandardObjects(null);
Scriptable jsArgs1=Context.toObject(out, scope);
Scriptable jsArgs2=Context.toObject(httpRequest, scope);
Scriptable jsArgs3=Context.toObject(httpResponse,scope);
scope.put("out", scope,jsArgs1);
scope.put("httpRequest", scope,jsArgs2);
scope.put("httpResponse",scope,jsArgs3);
context.evaluateString(scope,
code,
"JAVASCRIPT-CODE",
1, null);
// flushes and closes the output stream
out.flush();
out.close();
}
catch(EcmaError e)
{
ByteArrayOutputStream baos =
new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(baos);
e.printStackTrace(pw);
pw.flush();
out.println("<html><body><pre>");
out.println("Exception caused by serverside"+
" script execution:\n");
out.println(new String(baos.toByteArray()));
out.println("</pre></body></html>".getBytes());
out.flush();
out.close();
}
finally
{
Context.exit();
}
}
}
The doPost method is overridden to process the HTML form posting. In it, the following actions are performed:
- From the
httpRequest object, we retrieve the serverjavascript parameter.
- A Rhino
Context is initialized. Context is an environment for the script to run in.
- The variables
out , httpRequest , and httpResponse are made available to the script.
- The script is executed.
The exception handling ensures that the stack trace of any exception caused by the script is passed back to the client.
To interact with the HookServlet on the client side, all we have to do is to create an HTML page with a textarea to host the script, and a button to post it. Figure 1 shows what it looks like:
 Figure 1. The HTML page that interacts with the HookServlet
Installing the HookServlet
Deploying the HookServlet in your servlet container or web server is probably no more work than deploying any other servlet, and can be easily achieved by packaging the various parts into a WAR file. However, to use the servlet to interact with your application, you probably want to install an instance of the HookServlet into your existing WAR file. In this way, the HookServlet will share the same class-loader as your web application and will have access to the same classes and resources.
The rules to remember are:
- The client-side files (the HTML file hookpage.html and the image hook.jpg) are stored in the top-level directory.
- The HookServlet is stored in the WEB-INF/classes directory.
- The Rhino library (consisting of two files: js.jar and xbeans.jar) is added in the WEB-INF/lib directory.
In the deployment descriptor web.xml, we just add a few lines to enable the servlet.
...
<servlet>
<servlet-name>HookServlet</servlet-name>
<servlet-class>HookServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HookServlet</servlet-name>
<url-pattern>/hook</url-pattern>
</servlet-mapping>
...
The full path to access the HookServlet will now depend on the name of your WAR file and the web server‘s URL. For example, if we are running Apache Tomcat on the standard 8080 port and the WAR file is named webapplication.war, the path to the servlet would be:
http://localhost:8080/webapplication/hook
And the path to the HTML page would be:
http://localhost:8080/webapplication/hookpage.html
Running the HookServlet
Once you have the HookServlet installed in your web server or servlet container, you can start exploring the resources, libraries, and API by writing simple programs.
In this section, I will provide two short examples. I will deliberately keep them uncomplicated to avoid generating any confusion, confident that you can see beyond their simplicity and get the gist of this technique.
Example: Getting the System Properties
The first example shows how to get the get System properties with which your web server was started. This is particularly useful when a certain behavior of the system is dependant on a System property that might not have been properly set.
// importing.
var System = java.lang.System;
var Arrays = java.util.Arrays;
// getting the properties and ordering them.
var props = System.getProperties();
var keys = props.keySet().toArray();
Arrays.sort(keys);
// printing the content.
out.println("<HTML><BODY><PRE>");
for (var i=0;i<keys.length;i++)
{
out.println(keys[i]+" --> "+ props.get(keys[i]));
}
out.println("</PRE></BODY></HTML>");
Copy and paste the example above and you will get an answer that looks something like Figure 2:
 Figure 2. Output from the HookServlet: Showing the System Properties
Example: Listing the .jars to Start up Tomcat
The second example assumes you are running Apache Tomcat as your web server. The code first gets the ClassLoader instance responsible for loading the HttpResponse class, and then (because it knows the classLoader instance is a subclass of the URLClassLoader ) gets and prints each URL in it.
var loader = httpResponse.getClass().getClassLoader();
var urls = loader.getURLs();
out.println("<pre>");
for (var i=0;i<urls.length;i++)
{
out.println ( urls[i] );
}
out.println("</pre>");
This produces an output like Figure 3:
 Figure 3. Output from the HookServlet: .jars used to start up Tomcat
Conclusions
In this article, we have shown a powerful technique that allows the developer to interact dynamically with any Java web application. The technique is based on the idea of sending scripts from the client side to run on the server side. The implementation we presented uses JavaScript to interpret the server-side scripts, although with a little effort it could be easily adapted to use a different scripting language for Java.
The final result is a useful tool to help you working with any Java web application at any stage of the development: the HookServlet.
A final observation: the HookServlet is so intrinsically powerful that almost any servlet could be replaced by it ("almost" because in our current implementation the JavaScript can only override the doPost method and none of the other methods in the servlet). All of the work would therefore be done in the HTML page that would embed both the client-side and the server-side scripts. While this might not be the best solution in many cases, there‘s much to be said about having client-side and server-side code in one unique place and treating the server-side as a collection of .jars and other resources ready to be exploited.
Resources
Lorenzo Puccetti is a software developer/architect living and working in London, England.

View all Articles.
What do you think of this debugging approach?
Showing messages 1 through 9 of 9.
- nice one.
2005-09-26 04:08:20 seth_j [Reply | View]
In our project we use jython for scripting java objects and customizing properties. We all are very familar with the power of scripting languages and quite often we use them to interrogate (=debug) the application on the fly. I really like the HookServlet but I would recommend to take it away at deployment time.
- Have you thought of trying a telnet server?
2005-09-25 10:56:44 mattlarge [Reply | View]
For our web framework a collegue of mine implemented TelnetD a Java Telnet Daemon. The Content Managment System is the filesystem you can browse and for each resource he has implemented a command to let us dig into the object hierarchy. As well as being really useful it‘s is much fun to extend. So far he‘s implemented a simple Text editor, ftp client, most of the core UNIX like commands and Beanshell for scripting.
- Not so much for debugging, but...
2005-09-23 14:06:50 doj [Reply | View]
I have been considering using Rhino to separate out business logic from an enterprise application I‘m working on that has very rapidly changing, and fluid logic changes (due to the nature of the business it serves).
I‘d love to know if anyone has taken this approach before and if you‘ve had any success? Certainly the ability to script logic blocks together to form the "system" is highly attractive, be it for functionality, or diagnostic purposes.
- Not so much for debugging, but...
2005-09-27 10:09:03 jbetancourt [Reply | View]
I agree with the suggestion to use a Rules Engine. Also, some rule engines, like Drools, allow one to use an embedded script language like Beanshell or Groovy.
- Not so much for debugging, but...
2005-09-26 21:03:30 kleite [Reply | View]
Take a look at OpenMocha at: http:// I don‘t know much about it personally but looks interesting. "OpenMocha is an open source Javascript website application server and development framework. Quick soft-coding and clean hard-coding in Javascript on the client-side AND the server-side."
- Not so much for debugging, but...
2005-09-26 09:22:18 gerryg [Reply | View]
doj -- I‘d recommend a business rules engine instead. Check http://www./blog/stuff/rule_engines/view for a long list. DROOLS seems to be a good one that I‘m considering for an app rewrite in the near future. Mandarax is also worth investigating. Another engine not on the list that some people like is JESS.
- Security
2005-09-23 10:06:57 gerryg [Reply | View]
Anyone who uses this method should take security into account. Not sure how often I‘d need to use the available information. I‘d probably want to save scripts and have them ready for re-use on the page instead of having to type them in again or copy/paste from a text file, but then why not just avoid security issues and write a servlet to do a one-shot dump of everything? What kinds of things would vary enough to warrant having a dynamic script interpreter to introspect things on-the-fly and potentially risk a security hole on your server? Just my initial thoughts and not a detailed analysis...
- Security
2005-09-27 06:38:23 finn0013 [Reply | View]
I‘d have to agree with gerryg. While this could be a good tool for development work care should be taken to make sure it never makes it into a production environment. A good logging system can produce the same results if implemented correctly as well with a significantly reduced security risk.
|