Commit | Line | Data |
0198fd3c |
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 © 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><APPLET></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("<html>"); |
92 | System.out.println( |
93 | "<head><TITLE>CGI-Hello</TITLE></head>"); |
94 | System.out.println("<body>"); |
95 | System.out.println("<H3>CGI Hello</H3>"); |
96 | System.out.println("request number " + count + |
97 | " running on host " |
98 | + System.getProperty<"SERVER_NAME")); |
99 | System.out.println("</body>"); |
100 | System.out.println("</html>"); |
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("<html>"); |
116 | System.out.println( |
117 | "<head><TITLE>FastCGI-Hello Java stdio</TITLE></head>"); |
118 | System.out.println("<body>"); |
119 | System.out.println("<H3>FastCGI-Hello Java stdio</H3>"); |
120 | System.out.println("request number " + count + |
121 | " running on host " |
122 | + System.getProperty<"SERVER_NAME")); |
123 | System.out.println("</body>"); |
124 | System.out.println("</html>"); |
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("<html>"); |
285 | System.out.println( |
286 | "<head%gt;<TITLE>FastCGI echo |
287 | </TITLE></head>"); |
288 | System.out.println("<body>"); |
289 | System.out.println( |
290 | "<H2>FastCGI echo</H2>"); |
291 | System.out.println("<H3>STDIN</H3>"); |
292 | for ( int c = 0; c != -1; ) { |
293 | try { |
294 | c = System.in.read(); |
295 | } catch(IOException e) { |
296 | System.out.println( |
297 | "<br><b>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 | "<H3>Environment Variables:</H3>"); |
307 | |
308 | System.getProperties().list(System.out); |
309 | System.out.println("</body>"); |
310 | System.out.println("</html>"); |
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("<html>"); |
333 | System.out.println( |
334 | "<head><TITLE>FastCGI echo |
335 | </TITLE></head>"); |
336 | System.out.println("<body>"); |
337 | System.out.println("<H2>FastCGI echo</H2>"); |
338 | System.out.println("<H3>STDIN:</H3">); |
339 | for ( int c = 0; c != -1; ) { |
340 | try { |
341 | c = intf.request.inStream.read(); |
342 | } catch(IOException e) { |
343 | System.out.println( |
344 | "<br><b>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 | "<H3>Environment Variables:</H3>"); |
354 | |
355 | System.getProperties().list(System.out); |
356 | System.out.println(<"/body>"); |
357 | System.out.println("</html>"); |
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> |