Initial revision
[catagits/fcgi2.git] / doc / fcgi-java.gut
1 Integrating FastCGI with Java
2 /fastcgi/words
3 fcgi-hd.gif
4 [FastCGI]
5 <center>Integrating FastCGI with Java</center>
6
7 <!--Copyright (c) 1996 Open Market, Inc.                                    -->
8 <!--See the file "LICENSE.TERMS" for information on usage and redistribution-->
9 <!--of this file, and for a DISCLAIMER OF ALL WARRANTIES.                   -->
10 <!-- $Id: fcgi-java.gut,v 1.1 1997/09/16 15:36:26 stanleyg Exp $ -->
11
12 <P ALIGN=CENTER>
13 Steve Harris
14 <BR>
15 Open Market, Inc.
16 <BR>
17 <EM>7 May 1996</EM>
18 </P>
19
20 <h5 align=center>
21 Copyright &copy; 1996 Open Market, Inc.  245 First Street, Cambridge,
22   MA 02142 U.S.A.<br>
23 Tel: 617-621-9500 Fax: 617-621-1703 URL:
24   <a href="http://www.openmarket.com/">http://www.openmarket.com/</a><br>
25 </h5>
26 <hr>
27
28 <H3><A NAME = "S1"> 1. Introduction</A></H3>
29 Java is an object-oriented programming language developed by Sun
30 Microsystems.  The Java Depvelopers Kit (JDK), which contains the basic
31 Java class packages, is available from Sun in both source and binary
32 forms at Sun's
33 <a href="http://java.sun.com/java.sun.com/JDK-1.0/index.html">JavaSoft</a>
34 site.  This document assumes that you have some familiarity with the
35 basics of compiling and running Java programs. 
36 <p>
37 There are two kinds of applications built using Java.
38 <ul>
39   <li> <i>Java Applets</i> are graphical components which are run off
40        HTML pages via the <tt>&lt;APPLET&gt;</tt> HTML extention tag.<br><br>
41        
42   <li> <i>Java Applications (Apps) </i> are stand-alone programs
43        that are run by invoking the Java interpreter directly. Like
44        C programs, they have a <tt>main()</tt> method which the interpreter
45        uses as an entry point.
46 </ul>
47 The initial emphasis on using Java for client side applets should not
48 obscure the fact that Java is a full strength programming language
49 which can be used to develop server side stand alone applications,
50 including CGI and now FastCGI applications.
51 <p>
52 The remainder of this document explains how to write and run FastCGI Java
53 applications. It also illustrates the conversion of a sample Java CGI program
54 to a FastCGI program.
55
56
57
58 <H3><A NAME = "S2"> 2. Writing FastCGI applications in Java</A></H3>
59
60 Writing a FastCGI application in Java is as simple as writing one in C.
61
62 <ol>
63   <li> Import the <tt>FCGIInterface</tt> class.
64   <li> Perform one-time initialization at the top of the
65        <tt>main()</tt> method.
66   <li> Create a new <tt>FCGIInterface</tt> object and send it an
67        <tt>FCGIaccept()</tt> message in a loop.
68   <li> Put the per-request application code inside that loop.
69 </ol>
70
71 On return from <tt>FCGIaccept()</tt> you can access the request's environment
72 variables using <tt>System.getProperty</tt> and perform request-related
73 I/O through the standard variables <tt>System.in</tt>,
74 <tt>System.out</tt>, and <tt>System.err</tt>.<p>
75
76 To illustrate these points, the kit includes <tt>examples/TinyCGI</tt>,
77 a CGI Java application, and <tt>examples/TinyFCGI</tt>, the FastCGI
78 version of TinyCGI.  These programs perform the same
79 functions as the C programs <tt>examples/tiny-cgi.c</tt> and
80 <tt>examples/tiny-fcgi.c</tt> that are used as examples in the
81 <A HREF="fcgi-devel-kit.htm#S3.1.1">FastCGI Developer's Kit document</A>.
82
83
84 <h4>A. TinyCGI</h4>
85 <PRE> 
86 class TinyCGI { 
87         public static void main (String args[]) {               
88                 int count = 0;
89                 ++count;
90                 System.out.println("Content-type: text/html\n\n");
91                 System.out.println("&lt;html&gt;");
92                 System.out.println(
93                         "&lt;head&gt;&lt;TITLE&gt;CGI-Hello&lt;/TITLE&gt;&lt;/head&gt;");
94                 System.out.println("&lt;body&gt;");
95                 System.out.println("&lt;H3&gt;CGI Hello&lt;/H3&gt;");
96                 System.out.println("request number " + count + 
97                                         " running on host " 
98                                 + System.getProperty&lt;"SERVER_NAME"));
99                 System.out.println("&lt;/body&gt;");
100                 System.out.println("&lt;/html&gt;"); 
101                 }
102         }
103
104 </PRE>
105 <h4>B. TinyFCGI</h4>
106 <PRE> 
107 import FCGIInterface;
108
109 class TinyFCGI {        
110         public static void main (String args[]) {               
111                 int count = 0;
112                 while(new FCGIInterface().FCGIaccept()>= 0) {
113                         count ++;
114                         System.out.println("Content-type: text/html\n\n");
115                         System.out.println("&lt;html&gt;");
116                         System.out.println(
117                           "&lt;head&gt;&lt;TITLE&gt;FastCGI-Hello Java stdio&lt;/TITLE&gt;&lt;/head&gt;");
118                         System.out.println("&lt;body&gt;");
119                         System.out.println("&lt;H3&gt;FastCGI-Hello Java stdio&lt;/H3&gt;");
120                         System.out.println("request number " + count + 
121                                         " running on host " 
122                                 + System.getProperty&lt;"SERVER_NAME"));
123                         System.out.println("&lt;/body&gt;");
124                         System.out.println("&lt;/html&gt;"); 
125                         }
126                 }
127         }
128
129 </PRE>
130 <h4>C. Running these Examples</h4>
131
132 We assume that you have downloaded the JDK and the FastCGI Developer's
133 Kit, and that you have a Web server running that can access the
134 <tt>fcgi-devel-kit/examples</tt> directory. In all cases where we
135 specify paths, we are using relative paths within
136 <tt>fcgi-devel-kit</tt> or the JDK which will need to be enlarged to a
137 full path by the user.
138
139 <h5>Configuring</h5>
140 <ol>
141   <li> Add your JDK's <tt>java/bin</tt> directory to your Unix <tt>PATH</tt>
142        if it isn't there already.<br><br>
143        
144   <li> Add the directories <tt>fcgi-devel-kit/examples</tt> and
145        <tt>fcgi-devel-kit/java/classes</tt> to your Java
146        <tt>CLASSPATH</tt>.<br><br>
147         
148   <li>In your Open Market Secure WebServer configuration file,
149       <tt>httpd.config</tt>, add the following two lines:<br><br>
150        
151        <tt>ExternalAppClass TinyFCGI -host </tt><i>hostName:portNum</i><br>
152        <tt>Responder TinyFCGI fcgi-devel-kit/examples/TinyFCGI</tt><br><br>
153               
154        <ul>
155        <li><i>hostName</i> is the name of your host machine.<br>
156        <li><i>portNum</i> is the port that you've selected for
157             communication between the Web server and the Java application.<br>
158        </ul><br>
159
160        On other servers you can use <tt>cgi-fcgi</tt> to get a
161        similar effect.
162        
163   <li> Create a soft link <tt>examples/javexe</tt> to the
164        <tt>java/bin</tt> directory in your JDK.
165        This link is required only to run the
166        CGI scripts <tt>examples/TinyCGI.cgi</tt> and
167        <tt>examples/TinyFCGI.cgi</tt>, which use it to
168        invoke the Java interpreter <tt>java/bin/java</tt>.
169        It is not used by FastCGI applications.
170
171    <li> You might have to modify <tt>examples/TinyFCGI.cgi</tt> to use a
172         Unix shell for which your CLASSPATH is defined.
173 </ol>
174
175 <h5> Running </h5>
176
177 <ul>
178   <li> To run TinyFCGI as FastCGI, you invoke the Java interpreter
179        with the -D option, giving it the <tt>FCGI_PORT</tt> environment
180        variable
181        and the same <i>portNum</i> that was used in the Web server
182        configuration. The command is:
183        <br><br>
184        <tt>java -DFCGI_PORT=portNum TinyFCGI</tt>
185        <br><br>
186        Then point your browser at <tt>fcgi-devel-kit/examples/TinyFCGI</tt>.
187        Notice that each time you reload, the count increments.<br><br>
188        
189   <li> To run TinyCGI, point your browser at
190        <tt>fcgi-devel-kit/examples/TinyCGI.cgi</tt> on your host machine.
191        Notice that the count does not increment.<br><br>
192
193   <li> Finally, you can run TinyFCGI as a straight CGI program by pointing
194        your browser at <tt>fcgi-devel-kit/examples/TinyFCGI.cgi.</tt> The results
195        are exactly the same as when you ran TinyCGI. Invoking a FastCGI
196        program without an <tt>FCGI_PORT</tt> parameter tells the
197        FastCGI interface
198        to leave the normal CGI environment in place.
199 </ul>
200 <p>
201 Due to gaps in the Java interpreter's support for listening
202 sockets, Java FastCGI applications are currently limited to
203 being started as external applications.  They can't be started and
204 managed by the Web server because they are incapable of using
205 a listening socket that the Web server creates.
206
207
208
209 <H3><A NAME = "S3"> 3. Standard I/O and Application Libraries</A></H3>
210
211 As we have seen above, FastCGI for Java offers a redefinition
212 of standard I/O corresponding to the the <i>fcgi_stdio</i> functionality.
213 It also offers a set of directly callable I/O methods corresponding to
214 the <i>fcgiapp</i> C library. To understand where these methods occur
215 we need to look briefly at the FastCGI redefinition of standard I/O.<p>
216
217 Java defines standard I/O in the <i>java.System</i> class as follows:<p>
218
219 public static InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in), 128);<br>
220 public static PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out), 128), true);<br>
221 public static PrintStream err = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.err), 128), true);<p>
222
223 The File Descriptors <i>in</i>, <i>out</i>, <i>err</i> are constants set to 0, 1 and 2 respectively.<p>
224
225 The FastCGI interface redefines <i>java.System in, out</i>, and <i>err</i>
226 by replacing the File streams with Socket streams and inserting streams
227 which know how to manage the FastCGI protocol between the Socket streams
228 and the Buffered streams in the above definitions.
229 <p>
230 For those cases where the FCGI application needs to bypass the standard I/O
231 streams, it can directly access the methods of the FCGI input and output
232 streams which roughly correspond to the functions in the C <i>fcgiapp</i>
233 library. These streams can be accessed via the <i>request</i> class variable
234 in FCGIInterface. Each Request object has instance variables that refer to an
235 FCGIInputStream, and to two FCGIOutputStreams associated with that request.
236
237 <H3><A NAME = "S4"> 4. Environment Variables</A></H3>
238
239 Java does not use the  C <i/>environ<i/> list. Nor is there a <i>getenv</i>
240 command that reads system environment variables. This is intentional for
241 reasons of portability and security. Java has an internal dictionary of
242 properties which belongs to the System class. These System properties
243 are <i>name/value</i> associations that constitute the Java environment.
244 When a Java application starts up, it reads in a file with default properties.
245 As we have seen, additional System properties may be inserted by using
246 the -D <i>Java</i> command argument.<p>
247
248 For CGI, where the Java application is invoked from a .cgi script that,
249 in turn, invokes the Java interpreter, this script could read the environment
250 and pass the variables to the Java application either by writing a file
251 or by creating -D options on the fly. Both of these methods are somewhat
252 awkward.<p>
253
254 For FastCGI Java applications, the environment variables are obtained from
255 the FastCGI web server via <tt>FCGI_PARAMS</tt> records that are sent to the
256 application at the start of each request. The FastCGI interface stores the
257 original startup properties, combines these with the properties obtained
258 from the server, and puts the new set of properties in the System properties
259 dictionary. The only parameter that has to be specifically added at startup
260 time is the FCGI_PORT parameter for the Socket creation.  In the future, we
261 expect that even this parameter won't be needed, since its use is due to an
262 acknowledged rigidity in the JDK's implementation of sockets.<p>
263
264 <H3><A NAME = "S4"> 5. Further examples: EchoFCGI and Echo2FCGI</A></H3>
265
266 The next two examples illustrate the points made in the last two sections.
267 EchoFCGI and Echo2FCGI both echo user input and display the application's
268 environment variables. EchoFCGI reads the user input from System.in, while
269 Echo2FCGI reads the user input directly from the intermediate FastCGI input
270 stream.
271
272 <h4>A. EchoFCGI</h4>
273 <pre>
274 import FCGIInterface;
275 import FCGIGlobalDefs;
276 import java.io.*;
277
278 class EchoFCGI {
279         
280         public static void main (String args[]) {
281                 int status = 0;
282                 while(new FCGIInterface().FCGIaccept()>= 0) {
283                 System.out.println("Content-type: text/html\n\n");
284                         System.out.println("&lt;html&gt;");
285                         System.out.println(
286                                 "&lt;head%gt;&lt;TITLE&gt;FastCGI echo
287                                       &lt;/TITLE&gt;&lt;/head&gt;");
288                         System.out.println("&lt;body&gt;");     
289                         System.out.println(
290                                          "&lt;H2&gt;FastCGI echo&lt;/H2&gt;");
291                         System.out.println("&lt;H3&gt;STDIN&lt;/H3&gt;");
292                         for ( int c = 0; c != -1; ) {
293                                 try {
294                                         c = System.in.read();
295                                 } catch(IOException e) {
296                                         System.out.println(
297                                         "&lt;br&gt;&lt;b&gt;SYSTEM EXCEPTION");
298                                         Runtime rt = Runtime.getRuntime();
299                                         rt.exit(status);
300                                         }
301                                 if (c != -1) {  
302                                         System.out.print((char)c);
303                                         }
304                                 }
305                         System.out.println(
306                                 "&lt;H3&gt;Environment Variables:&lt;/H3&gt;");
307         
308                         System.getProperties().list(System.out);
309                         System.out.println("&lt;/body&gt;");
310                         System.out.println("&lt;/html&gt;");
311                         }
312                 }
313         }
314 </pre>
315 <h4>B. Echo2FCGI</h4>
316 <pre>
317 import FCGIInterface;
318 import FCGIGlobalDefs;
319 import FCGIInputStream;
320 import FCGIOutputStream;
321 import FCGIMessage;
322 import FCGIRequest;
323 import java.io.*;
324
325 class Echo2FCGI {
326
327         public static void main (String args[]) {
328                 int status = 0;
329                 FCGIInterface intf = new FCGIInterface();
330                 while(intf.FCGIaccept()>= 0) {
331                 System.out.println("Content-type: text/html\n\n");
332                         System.out.println("&lt;html&gt;");
333                         System.out.println(
334                                 "&lt;head&gt;&lt;TITLE&gt;FastCGI echo
335                                     &lt;/TITLE&gt;&lt;/head&gt;");
336                         System.out.println("&lt;body&gt;");                     
337                         System.out.println("&lt;H2&gt;FastCGI echo&lt;/H2&gt;");
338                         System.out.println("&lt;H3&gt;STDIN:&lt;/H3"&gt;);
339                         for ( int c = 0; c != -1; ) {
340                                 try {
341                                         c = intf.request.inStream.read();
342                                 } catch(IOException e) {
343                                         System.out.println(
344                                         "&lt;br&gt;&lt;b&gt;SYSTEM EXCEPTION");
345                                         Runtime rt = Runtime.getRuntime();
346                                         rt.exit(status);
347                                         }
348                                 if (c != -1) {  
349                                         System.out.print((char)c);
350                                         }
351                                 }
352                         System.out.println(
353                                 "&lt;H3&gt;Environment Variables:&lt;/H3&gt;");
354         
355                         System.getProperties().list(System.out);
356                         System.out.println(&lt;"/body&gt;");
357                         System.out.println("&lt;/html&gt;");
358                         }
359                 }
360         }
361 </pre>
362 <h4>C. Running these Examples</h4>
363
364 <h5>Configuring</h5>
365
366 As with TinyFCGI, you need to configure the web server to recognize these
367 two FastCGI applications. Your configuration now looks like this:<p> 
368 <pre>
369 ExternalAppClass java1 -host hostname:portNum
370 Responder java1 fcgi-devel-kit/examples/TinyFCGI
371 ExternalAppClass java2 -host hostname:portNumA
372 Responder java2 fcgi-devel-kit/examples/EchoFCGI
373 ExternalAppClass java3 -host hostname:porNumB
374 Responder java3 fcgi-devel-kit/examples/Echo2FCGI
375 </pre>
376 <p>
377 Note that the application classes and port numbers are different for each
378 application.
379
380 <h5>Running</h5>
381
382 As with TinyFCGI, you need to run these programs with the -D option
383 using FCGI_PORT and the appropriate port number.
384
385 To get some data for standard input we have created two html pages with
386 forms that use a POST method. These are echo.html and echo2.html. You must
387 edit these .html files to expand the path to <i>fcgi-devel-kit/examples</i>
388 to a full path. Once the appropriate Java program is running, point your browser at the corresponding HTML page, enter some data and select the <i>go_find</i> button.
389
390
391 <H3><A NAME = "S6"> 6. FastCGI Java Classes</A></H3>
392
393 The Java FastCGI classes are included in both source and byte code format in
394 <i>fcgi-devel-kit/java/src</i> and :<i>fcgi-devel-kit/java/classes</i>
395 respectively. The following is a brief description of these classes:<p>
396
397 <dl>
398 <dt><i>FCGIInterface</i><dd> This class contains the FCGIaccept method called
399      by the FastCGI user application. This method sets up the appropriate
400      FastCGI environment for communication with the web server and manages
401      FastCGI requests.<br>
402      
403  <dt><i>FCGIInputStream</i><dd> This input stream manages FastCGI
404       internal buffers to ensure that the user gets all of the FastCGI
405       messages associated with a request. It uses FCGIMessage objects
406       to interpret these incoming messages.<br>
407       
408   <dt><i>FCGIOutputStream</i><dd> This output stream manages FastCGI
409        internal buffers to send user data back to the web server
410        and to notify the server of various FCGI protocol conditions.
411        It uses FCGIMessage objects to format outgoing FastCGI messages.<br>
412       
413 <dt><i>FCGIMessage</i><dd> This is the only class that understands the
414      actual structure of the FastCGI messages. It interprets incoming
415      FastCGI records and constructs outgoing ones..<br>
416      
417 <dt><i>FCGIRequest</i><dd>This class currently contains data fields
418      used by FastCGI to manage user requests.  In a multi-threaded
419      version of FastCGI, the role of this class will be expanded.<br>
420
421 <dt><i>FCGIGlobalDefs</i><dd>This class contains definitions of FastCGI
422      constants.
423 </dl>
424 <HR>
425 <ADDRESS><A HREF="mailto:harris@openmarket.com">Steve Harris // harris@openmarket.com</A></ADDRESS>