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