The Problem
JSP is a very good tool for manipulating texts - it is format-independent,
and it contains the full and beautiful functionality of Java, and it is easily
parameterized. It would be great to use these features for text generation
in an "industrial environment". See how easy it could be: e.g. we want to
produce a "year-dependent" copyrigh notice; the following code could do it:
"Copyright (c) My Precious Company 1970-<%= new java.util.Date().getYear() + 1900 %>"
can produce something like
Copyright (c) My Precious Company 1970-2003
In real life, though, text generation, in most cases, depends on environment
- typically, one has to specify target platform, code version, product name,
and the like. These can be stored in a database, but, most frequently, are
passed to other applications that process documents via environment variables.
Now, how can one pass an environment variable to a JSP? The only conceivable
way is to pass them through GET or POST parameters, so that the JSP could
analyze them or just include into the generated text, e.g.:
"Copyright (c) <%= request.getParameter("COMPANY_NAME")%>
1970-<%= new java.util.Date().getYear() + 1900 %>.
<%= request.getParameter("WHAT_IS_RESERVED")%> rights reserved."
This JSP would produce something like when the correct arguments are passed:
Copyright (c) Evil Empire 1970-2003. All your base rights reserved.
There is one obstacle, though: JSP are supposed to work on the web servers,
not on your desktop machine. What a pity, cannot we fix it? Yes, we can.
To do this, we will have to launch a JSP server, Tomcat, for instance, on
our local machine and pass it our JSP code for execution, together with parameters,
intercepting the output.
The Program
Let us assume that there is a program that does just that: passes a JSP
to Tomcat for execution. Its can be called using the following command line:
jsp.exe -. "// Copyright (c) My Precious Company 1970-<%= new java.util.Date().getYear() + 1900 %>"
> MyFinalProgram.java
On Linux the following command would probably make more sense:
cat `jsp-linux -. "// Copyright (c) My Precious Company 1970-<%= new java.util.Date().getYear() + 1900 %>"` MyProgram.java
> MyFinalProgram.java
This way we could have the copyright notice inserted into the code, not bugging
developers with orders to refresh the date every Christhmas.
Parameters, say, the values of environment variables, can be passed in the command line as well, like this:
cat `jsp-linux-. "//Copyright (c) <%= request.getParameter("COMPANY_NAME")%> 1970-<%= new java.util.Date().getYear()
+ 1900 %>. <%request.getParameter("WHAT_IS_RESERVED")%> rights reserved." -COMPANY_NAME "Evil Empire" -WHAT_IS_RESERVED
"All your base"` MyEvilProgram.java.jsp > MyEvilProgram.java
As you see, the JSP contents is just a special parameter named '.'.
Above we saw a shortcut method of passing parameters. An official method to pass parameters is the following:
--param <parameter name> --value <parameter value>
It is rarely convenient to pass the whole JSP contents in a command line; the contents is usually stored in a file. Other parameters may as well reside in a file - hence the third method of passing parameters:
--param <parameter name> --file <file name>
For instance, instead of writing a three-four-line "command line", we could write the following:
cat `jsp-linux -param . -file copyright.jsp -COMPANY_NAME $COMPANY_NAME -WHAT_IS_RESERVED "All your base"` MyEvilProgram.java >MyFinalEvilProgram.java
>
And, at last, the easest way to pass a JSP to execute is via standard input, like this:
cat `cat copyright.jsp | jsp-linux -COMPANY_NAME $COMPANY_NAME -WHAT_IS_RESERVED "All your base"` MyEvilProgram.java >MyFinalEvilProgram.java
One more form of passing parameters could probably be added: --param <parameter
name> --http <url> - but I doubt whether it makes any practical sense.
Here is a real-world example of a real-world JSP being applied to the contents of another file:
jsp --param . --file sampletable.jsp --param data --file sampledata.txt > sampleresult.html
And here is one more example.
This time we show that this can be used for conditional compilation
(see Dan Savarese's "The Case for Conditional Compilation").
The sample code from that article can be rewritten, using JSP, like this:
import java.util.*;
/***
* Heap implements a binary heap stored as an array
* that can be used as a priority queue or for
* performing a heap sort.
*/
public class Heap
<% if (request.getParameter("HAS_JAVA_IO_SERIALIZABLE") != null) {%>
implements java.io.Serializable
<%}%>
{
<% if (request.getParameter("HAS_JAVA_UTIL_COMPARATOR") != null) {%>
public static interface Comparator {
public int compare(Object o1, Object o2);
public boolean equals(Object obj);
}
<%}%>
....
The Trick
Well, how does it work then? When jsp.exe starts, it retrieves a zip
file with Tomcat from its resources and installs Tomcat in a working
directory - unless it is already installed. Then it launches Tomcat on
a special port (8079). Inside Tomcat's web directory there is a very
simple but powerful JSP program - Universal JSP. Its code looks like
this:
<%
/**
* Universal JSP
*/
String value = (String)request.getParameter(".");
if (value != null) {
String filename = session.getId() + ".jsp";
java.io.File sourcefile = new java.io.File("webapps/ROOT", filename);
try {
java.io.PrintWriter pw = new java.io.PrintWriter(
new java.io.FileOutputStream(sourcefile));
pw.write(value);
pw.close();
%><jsp:include page="<%=filename%>" flush="true"/><%
} catch (Exception e) {
out.print("***** Error: problems with file permissions for this jsp<br>" +
e + "<br>");
e.printStackTrace(new java.io.PrintWriter(out));
}
} else {
%>;)<%
}%>
jsp.exe sends to Universal JSP a request that contains all the
parameters and the body of the JSP that has to be executed. The normal output from
Universal JSP is that of the JSP that we had just passed - and it is
caught by jsp.exe and redirected to the standard output.
Download
Click here to download the program, with all the source code.
|
Connect with Us