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