Steve Harris
Open Market, Inc.
7 May 1996
There are two kinds of applications built using Java.
The remainder of this document explains how to write and run FastCGI Java applications. It also illustrates the conversion of a sample Java CGI program to a FastCGI program.
To illustrate these points, the kit includes examples/TinyCGI, a CGI Java application, and examples/TinyFCGI, the FastCGI version of TinyCGI. These programs perform the same functions as the C programs examples/tiny-cgi.c and examples/tiny-fcgi.c that are used as examples in the FastCGI Developer's Kit document.
class TinyCGI {
public static void main (String args[]) {
int count = 0;
++count;
System.out.println("Content-type: text/html\n\n");
System.out.println("<html>");
System.out.println(
"<head><TITLE>CGI Hello</TITLE></head>");
System.out.println("<body>");
System.out.println("<H3>CGI-Hello</H3>");
System.out.println("request number " + count +
" running on host "
+ System.getProperty<"SERVER_NAME"));
System.out.println("</body>");
System.out.println("</html>");
}
}
import FCGIInterface;
class TinyFCGI {
public static void main (String args[]) {
int count = 0;
while(new FCGIInterface().FCGIaccept()>= 0) {
count ++;
System.out.println("Content-type: text/html\n\n");
System.out.println("<html>");
System.out.println(
"<head><TITLE>FastCGI-Hello Java stdio</TITLE></head>");
System.out.println("<body>");
System.out.println("<H3>FastCGI-HelloJava stdio</H3>");
System.out.println("request number " + count +
" running on host "
+ System.getProperty<"SERVER_NAME"));
System.out.println("</body>");
System.out.println("</html>");
}
}
}
Due to gaps in the Java interpreter's support for listening sockets, Java FastCGI applications are currently limited to being started as external applications. They can't be started and managed by the Web server because they are incapable of using a listening socket that the Web server creates.
Java defines standard I/O in the java.System class as follows:
public static InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in), 128);
public static PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out), 128), true);
public static PrintStream err = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.err), 128), true);
The File Descriptors in, out, err are constants set to 0, 1 and 2 respectively.
The FastCGI interface redefines java.System in, out, and err by replacing the File streams with Socket streams and inserting streams which know how to manage the FastCGI protocol between the Socket streams and the Buffered streams in the above definitions.
For those cases where the FCGI application needs to bypass the standard I/O streams, it can directly access the methods of the FCGI input and output streams which roughly correspond to the functions in the C fcgiapp library. These streams can be accessed via the request class variable in FCGIInterface. Each Request object has instance variables that refer to an FCGIInputStream, and to two FCGIOutputStreams associated with that request.
For CGI, where the Java application is invoked from a .cgi script that, in turn, invokes the Java interpreter, this script could read the environment and pass the variables to the Java application either by writing a file or by creating -D options on the fly. Both of these methods are somewhat awkward.
For FastCGI Java applications, the environment variables are obtained from the FastCGI web server via FCGI_PARAMS records that are sent to the application at the start of each request. The FastCGI interface stores the original startup properties, combines these with the properties obtained from the server, and puts the new set of properties in the System properties dictionary. The only parameter that has to be specifically added at startup time is the FCGI_PORT parameter for the Socket creation. In the future, we expect that even this parameter won't be needed, since its use is due to an acknowledged rigidity in the JDK's implementation of sockets.
import FCGIInterface;
import FCGIGlobalDefs;
import java.io.*;
class EchoFCGI {
public static void main (String args[]) {
int status = 0;
while(new FCGIInterface().FCGIaccept()>= 0) {
System.out.println("Content-type: text/html\n\n");
System.out.println("<html>");
System.out.println(
"<head%gt;<TITLE>FastCGI echo
</TITLE></head>");
System.out.println("<body>");
System.out.println(
"<H2>FastCGI echo</H2>");
System.out.println("<H3>STDIN</H3>");
for ( int c = 0; c != -1; ) {
try {
c = System.in.read();
} catch(IOException e) {
System.out.println(
"<br><b>SYSTEM EXCEPTION");
Runtime rt = Runtime.getRuntime();
rt.exit(status);
}
if (c != -1) {
System.out.print((char)c);
}
}
System.out.println(
"<H3>Environment Variables:</H3>");
System.getProperties().list(System.out);
System.out.println("</body>");
System.out.println("</html>");
}
}
}
import FCGIInterface;
import FCGIGlobalDefs;
import FCGIInputStream;
import FCGIOutputStream;
import FCGIMessage;
import FCGIRequest;
import java.io.*;
class Echo2FCGI {
public static void main (String args[]) {
int status = 0;
FCGIInterface intf = new FCGIInterface();
while(intf.FCGIaccept()>= 0) {
System.out.println("Content-type: text/html\n\n");
System.out.println("<html>");
System.out.println(
"<head><TITLE>FastCGI echo
</TITLE></head>");
System.out.println("<body>");
System.out.println("<H2>FastCGI echo</H2>");
System.out.println("<H3>STDIN:</H3">);
for ( int c = 0; c != -1; ) {
try {
c = intf.request.inStream.read();
} catch(IOException e) {
System.out.println(
"<br><b>SYSTEM EXCEPTION");
Runtime rt = Runtime.getRuntime();
rt.exit(status);
}
if (c != -1) {
System.out.print((char)c);
}
}
System.out.println(
"<H3>Environment Variables:</H3>");
System.getProperties().list(System.out);
System.out.println(<"/body>");
System.out.println("</html>");
}
}
}
ExternalAppClass java1 -host hostname:portNum Responder java1 fcgi-devel-kit/examples/TinyFCGI ExternalAppClass java2 -host hostname:portNumA Responder java2 fcgi-devel-kit/examples/EchoFCGI ExternalAppClass java3 -host hostname:porNumB Responder java3 fcgi-devel-kit/examples/Echo2FCGI
Note that the application classes and port numbers are different for each application.