Mult in Java
The Java implementation is rather different than the previous implementations. This is understandablePHP, Perl, and Javascript are often considered scripting languages, which can be more flexible and loose than more formal languages like Java.
In this application, the Java version is implemented as a JSP combined with a supporting class. The supporting class, called
Mult, contains the multiplication routine:
public class Mult
{
static public String mult( int a, int b ) {
int prod = a * b;
return "<center><h1>"+a+" x "+b+" = "+prod+"</h1></center>";
}
}
The generation of the multiplication table lives in
index.jsp, and is straightforward:
<center>
<table border="1">
<tr>
<td>X</td>
<%
for (int c=0; c<10; ++c) {
out.println( "<td>"+c+"</td>" );
}
%>
</tr>
<%
for (int r=0; r<10; ++r) {
out.println( "<tr><td>"+r+"</td>" );
for (int c=0; c<10; ++c) {
ActiveLink link = new ActiveLink( "mult.Mult", "mult" );
link.addParam( r );
link.addParam( c );
out.println( "<td> <a href=\""+link+"\">"+r+" x "+c+"</a> </td>" );
}
out.println( "</tr>" );
}
%>
</table>
</center>
Note that the creation of the link is different than in the previous applications. This is because Java is a strongly-typed language, and one that does not have functions that take a variable number of arguments. Thus, the link must be constructed in steps.
This line creates the link object:
ActiveLink link = new ActiveLink( "mult.Mult", "mult" );
The first argument to the ActiveLink constructor is the class name
Mult lives in a package called
mult. The second argument is the name of a static method in that class.
Next, add the parameters, i.e. the two numbers to be multiplied:
link.addParam( r );
link.addParam( c );
alinvoke.jsp is also a bit different. It contains a single line of active code:
<% out.println( ActiveLink.call( request.getParameter( "_alinfo" ) ) ); %>
This gets the
_alinfo parameter and passes it to
ActiveLink.call() for invocation.
Freezing and Thawing in Java
To create the link, write a list containing the function name and arguments to an ObjectOutputStream which is writing to a byte array:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream( baos );
oos.writeObject( info );
byte bs[] = baos.toByteArray();
Encode this array as string (using the ISO-8859-1 character encoding), and further encode it for inclusion in a link:
String s = new String( bs, "ISO-8859-1" );
return URLEncoder.encode( s, "ISO-8859-1" );
To thaw the function call, call the static method
ActiveLink.call(), passing in the encoded string. This in turns calls
ActiveLink.createFromEncoded(), which reads the function call information and returns an ActiveLink object.
static public Object call( String info )
throws ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException, IOException {
ActiveLink al = createFromEncoded( info );
return al.call();
}
Calling the
call() method of this object calls the method. It does this by using a helper class,
ExecuteCall, which loads the specified class using
Class.forName(), and then calls the specified method using the
java.lang.reflect package.
Towards a Strcutured CGI
As you can see, it's possible to radically alter the way you program an application simply by building the proper plumbing behind the scenes. This can be done in a variety of languages, using techniques that work similarly in each of those languages.
The only exception to this is the Java version. The techniques used in PHP, Perl, and JavaScript don't readily apply to Java. I mentioned above that this has to do with the fact that Java is strongly-typed, but this isn't the real reason. The real reason is that Java doesn't provide any kind of introspection at the call-siteit's not possible to write code that iterates through the list of parameters to a function. This is really a problem with lacking a hygenic macro facility more than it is a problem with being typed.