Source code: lutris/jolt/joltsim/SimComms.java
1 /*
2 * Enhydra Java Application Server Project
3 *
4 * The contents of this file are subject to the Enhydra Public License
5 * Version 1.1 (the "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy of the License on
7 * the Enhydra web site ( http://www.enhydra.org/ ).
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11 * the License for the specific terms governing rights and limitations
12 * under the License.
13 *
14 * The Initial Developer of the Enhydra Application Server is Lutris
15 * Technologies, Inc. The Enhydra Application Server and portions created
16 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17 * All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * $Id: SimComms.java,v 1.14.4.1 2000/10/19 17:59:08 jasona Exp $
22 */
23
24
25
26
27
28 package lutris.jolt.joltsim;
29 import lutris.jolt.presentation.*;
30 import lutris.keywordValue.*;
31 import lutris.http.*;
32 import java.io.*;
33 import java.util.*;
34
35 /**
36 * Simulation comms objects. Reads HTTP headers from a file and
37 * can print out response. Currently does not handle streaming output.
38 */
39 public class SimComms extends Comms {
40 private HttpPageArgs httpPageArgs;
41 private String scriptName;
42 private int responseStatusCode = 0;
43 private String responseStatusReason = "";
44 private boolean outputIsStreaming = false;
45 private DataOutputStream headerOutputStream;
46 private DataOutputStream bodyOutputStream;
47
48
49 /**
50 * Public Constructor
51 *
52 * @param httpPageArgs Pre-formatted table of HTTP request arguments,
53 * exactly as they will be passed to the presentation.
54 * @param headerOutputStream Stream that the HTTP response header is
55 * written to.
56 * @param bodyOutputStream Stream that the HTTP response body is
57 * written to.
58 */
59 public SimComms (HttpPageArgs httpPageArgs,
60 DataOutputStream headerOutputStream,
61 DataOutputStream bodyOutputStream) {
62 this.httpPageArgs = httpPageArgs;
63 this.headerOutputStream = headerOutputStream;
64 this.bodyOutputStream = bodyOutputStream;
65 }
66
67 /**
68 * Generate an error if data is already streaming
69 *
70 * @exception IOException
71 */
72 private void streamingCheck()
73 throws IOException
74 {
75 if (outputIsStreaming) {
76 throw new IOException("Unable to set header;" +
77 " Response body data is already streaming.");
78 }
79 }
80
81
82 /**
83 * This method sets an output header.
84 *
85 * @exception IOException If an occurs setting the header.
86 */
87 public void setHeader(String name,
88 String value)
89 throws IOException {
90 streamingCheck();
91 try {
92 httpPageArgs.setHeader(name, value);
93 } catch (KeywordValueException e) {
94 throw new IOException (e.getMessage());
95 }
96 }
97
98 /**
99 * This method sets the response status header.
100 *
101 * @exception IOException If an occurs setting the status.
102 */
103 public void setStatus(int status,
104 String reason)
105 throws IOException {
106 streamingCheck();
107 responseStatusCode = status;
108 responseStatusReason = reason;
109 }
110
111 /**
112 * This method maps a set of cookies into a single "Set-Cookie"
113 * header. Repeated calls to this method will replace the
114 * previous "Set-Cookie" settings.
115 *
116 * @param cookies Table with leaf keys that contain
117 * arrays of Cookie. All cookies are compined into
118 * a single "Set-Cookie" request.
119 */
120 public void setCookie(KeywordValueTable cookies)
121 throws IOException, KeywordValueException {
122 streamingCheck();
123 String [] keys = cookies.leafKeys();
124 for (int idx1=0; idx1<keys.length; idx1++) {
125 Cookie [] c = (Cookie [])cookies.get(keys[idx1]);
126 for (int idx2=0; idx2<c.length; idx2++) {
127 httpPageArgs.setHttpResponseCookie (c [idx2]);
128 }
129 }
130 }
131
132 /**
133 * This method sets a cookie header.
134 *
135 * @exception IOException If an occurs setting the cookie.
136 */
137 public void setCookie(String name,
138 String value,
139 String expires,
140 String domain,
141 String path,
142 boolean secure)
143 throws IOException {
144 streamingCheck();
145 try {
146 String stag = "";
147 if (secure)
148 stag = "secure";
149 String cookie = name + "=" + value + "; expires=" + expires +
150 "; path=" + path + "; domain=" + domain + "; " + stag;
151 httpPageArgs.setHeader("Set-Cookie", cookie);
152 } catch (KeywordValueException e) {
153 throw new IOException (e.getMessage());
154 }
155 }
156
157
158 /**
159 * This method sets a cookie header localized to
160 * the root of the application tree.
161 *
162 * @exception IOException If an occurs setting the cookie.
163 */
164 public void setCookie(String name,
165 String value)
166 throws IOException {
167 streamingCheck();
168 setCookie(name, value, "", "", this.scriptName, false);
169 }
170
171
172
173 /**
174 * This method expires a cookie.
175 *
176 * @exception IOException If an occurs expiring the cookie.
177 */
178 public void expireCookie(String name, String path)
179 throws IOException {
180 streamingCheck();
181 setCookie(name, "expired",
182 "Saturday, 07-Dec-1996 12:00:00 GMT",
183 "",
184 path, false);
185 }
186
187
188 /**
189 * This method expires a cookie at the root of
190 * the application tree.
191 *
192 * @exception IOException If an occurs expiring the cookie.
193 */
194 public void expireCookie(String name)
195 throws IOException {
196 streamingCheck();
197 setCookie(name, "expired",
198 "Saturday, 07-Dec-1996 12:00:00 GMT",
199 "",
200 this.scriptName, false);
201 }
202
203
204 /**
205 * This method sets the content length http header.
206 *
207 * @exception IOException If an occurs setting the header.
208 */
209 public void setContentLength(int length)
210 throws IOException {
211 streamingCheck();
212 try {
213 httpPageArgs.setHttpResponseHeader("ContentLength", Integer.toString (length));
214 } catch (KeywordValueException e) {
215 throw new IOException (e.getMessage());
216 }
217 }
218
219 /**
220 * This method sets the Contenttype http header.
221 *
222 * @exception IOException If an occurs setting the header.
223 */
224 public void setContentType(String contentType)
225 throws IOException {
226 streamingCheck();
227 try {
228 httpPageArgs.setHttpResponseHeader("ContentType", contentType);
229 } catch (KeywordValueException e) {
230 throw new IOException (e.getMessage());
231 }
232 }
233
234 /**
235 * This method returns an array containing all of the values
236 * set for the named HTTP request header.
237 *
238 * @param name The header name.
239 * @return An array of strings containing the values set for the
240 * header. The array length is zero if no values were set.
241 * @exception InvalidKeywordException if the header name is invalid.
242 */
243 public String [] getHttpRequestHeader(String name)
244 throws Exception {
245 return httpPageArgs.getHttpRequestHeader(name);
246 }
247
248 /**
249 * This method returns all HTTP request cookies that have the
250 * specified name.
251 *
252 * @param name The cookie name.
253 * @return Array containing all the matched cookie names. If
254 * none are matched the array legth is zero.
255 */
256 public Cookie [] getHttpRequestCookie(String name)
257 throws Exception {
258 return httpPageArgs.getHttpRequestCookies(name);
259 }
260
261
262
263 /**
264 * This method returns values associated with a HTTP (CGI)
265 * request arguments.
266 *
267 * @return Array containing all the values set for that argument.
268 * The array length is zero if the argument was not set.
269 */
270 public String [] getHttpRequestArg(String name)
271 throws Exception {
272 return httpPageArgs.getHttpRequestArg(name);
273 }
274
275
276 /**
277 * This method returns values associated with a HTTP (CGI)
278 * request arguments. If no value is set then the default
279 * is returned.
280 *
281 * @param name The name of the HTTP request argument desired.
282 * @param defValue The default value to use if no value exists.
283 * @return Array containing all the values set for that argument.
284 * The array length is zero if the argument was not set.
285 */
286 public String [] getHttpRequestArg(String name, String defValue)
287 throws Exception {
288 return httpPageArgs.getHttpRequestArg(name, defValue);
289 }
290
291
292
293 /**
294 * This method sets an HTTP response header.
295 *
296 * @param name The header name.
297 * @param value The header value.
298 */
299 public void setHttpResponseHeader(String name, String value)
300 throws Exception {
301 streamingCheck();
302 httpPageArgs.setHttpResponseHeader(name, value);
303 }
304
305
306
307 /**
308 * This method returns an array containing all of the values
309 * set for the named HTTP response header.
310 *
311 * @param name The header name.
312 * @return An array of strings containing the values set for the
313 * header. The array length is zero if no values were set.
314 * @exception InvalidKeywordException if the header name is invalid.
315 */
316 public String [] getHttpResponseHeader(String name)
317 throws Exception {
318 return httpPageArgs.getHttpResponseHeader(name);
319 }
320
321 /**
322 * This method sets an HTTP response cookie.
323 *
324 * @param name The cookie name.
325 */
326 public void setHttpResponseCookie(Cookie cookie)
327 throws Exception {
328 httpPageArgs.setHttpResponseCookie(cookie);
329 }
330
331 /**
332 * This method returns all HTTP response cookies that have the
333 * specified name.
334 *
335 * @param name The cookie name.
336 * @return Array containing all the matched cookie names. If
337 * none are matched the array legth is zero.
338 */
339 public Cookie [] getHttpResponseCookies(String name)
340 throws Exception {
341 return httpPageArgs.getHttpResponseCookies(name);
342 }
343
344 /**
345 * This method sets an HTTP redirect header.
346 *
347 * @param name The header name.
348 */
349 public void setHttpRedirectHeader(String name, String value)
350 throws Exception {
351 streamingCheck();
352 httpPageArgs.setHttpRedirectHeader(name, value);
353 }
354
355 /**
356 * This method returns an array containing all of the values
357 * set for the named HTTP redirect header.
358 *
359 * @param name The header name.
360 * @return An array of strings containing the values set for the
361 * header. The array length is zero if no values were set.
362 * @exception InvalidKeywordException if the header name is invalid.
363 */
364 public String [] getHttpRedirectHeader(String name)
365 throws Exception {
366 return httpPageArgs.getHttpRedirectHeader(name);
367 }
368
369 /**
370 * This method sets an HTTP redirect cookie.
371 *
372 * @param name The cookie name.
373 */
374 public void setHttpRedirectCookie(Cookie cookie)
375 throws Exception {
376 streamingCheck();
377 httpPageArgs.setHttpRedirectCookie(cookie);
378 }
379
380 /**
381 * This method returns all HTTP redirect cookies that have the
382 * specified name.
383 *
384 * @param name The cookie name.
385 * @return Array containing all the matched cookie names. If
386 * none are matched the array legth is zero.
387 */
388 public Cookie [] getHttpRedirectCookie(String name)
389 throws Exception {
390 return httpPageArgs.getHttpRedirectCookie(name);
391 }
392
393 /**
394 * This method sets a HTTP (CGI) arguments to use when redirecting
395 * the page.
396 *
397 * @param name The argument name.
398 * @param value The argument value.
399 */
400 public void setHttpRedirectArg(String name, String value)
401 throws Exception {
402 streamingCheck();
403 httpPageArgs.setHttpRedirectArg(name, value);
404 }
405
406 /**
407 * This method returns all values associated with a HTTP (CGI)
408 * redirect arguments.
409 *
410 * @return Array containing all the values set for that argument.
411 * The array length is zero if the argument was not set.
412 */
413 public String [] getHttpRedirectArg(String name)
414 throws Exception {
415 return httpPageArgs.getHttpRedirectArg(name);
416 }
417
418
419 //FIX: trying to grab entry zero of the returned arrays is really
420 // a quick hack. Not sure what the right answer here is.
421
422 /**
423 * Return the query string of this request.
424 */
425 public String getHttpQueryString() {
426 String result;
427 try {
428 result = httpPageArgs.getHttpRequestHeader(HttpPageArgs.QUERY_STRING)[0];
429 } catch (Exception e) {
430 result = "";
431 }
432 return result;
433 }
434
435 /**
436 * Return the url of this request.
437 */
438 public String getHttpUrl() {
439 String result;
440 try {
441 result = httpPageArgs.getHttpRequestHeader(HttpPageArgs.URL)[0];
442 } catch (Exception e) {
443 result = "";
444 }
445 return result;
446 }
447
448 /**
449 * Returns the remote host name.
450 */
451 public String getHttpRemoteHost() {
452 String result;
453 try {
454 result = httpPageArgs.getHttpRequestHeader(HttpPageArgs.REMOTE_HOST)[0];
455 } catch (Exception e) {
456 result = "";
457 }
458 return result;
459 }
460
461 /**
462 * Return the document root.
463 */
464 public String getHttpDocumentRoot() {
465 String result;
466 try {
467 result = httpPageArgs.getHttpRequestHeader(HttpPageArgs.DOCUMENT_ROOT)[0];
468 } catch (Exception e) {
469 result = "";
470 }
471 return result;
472 }
473
474 /**
475 * Returns the document root.
476 */
477 public String getHttpPathInfo() {
478 String result;
479 try {
480 // FIX: This is probably wrong.
481 result = httpPageArgs.getHttpRequestHeader(HttpPageArgs.DOCUMENT_URI)[0];
482 } catch (Exception e) {
483 result = "";
484 }
485 return result;
486 }
487
488
489 /**
490 * This method causes the current request to be redirected
491 * to another location. The redirection is performed on
492 * the client side via the "Location:" header. Any redirect
493 * arguments set in this page are appended to the url. Likewise,
494 * any redirect cookies are set.
495 *
496 * @param url The url which should handle the request.
497 * @exception lutris.jolt.presentation.PageRedirectException This
498 * exception should not be caught as it is handeled by the
499 * presentation manager.
500 */
501 public Exception clientSideRedirectException(String url) {
502 PageRedirectException p = new PageRedirectException(url);
503 p.setRedirectionViaClient(true);
504 try {
505 if (requestArgs.containsKey(requestArgs.REDIRECT_ARGS)) {
506 p.setHttpRedirectArgs(requestArgs.
507 getSection(requestArgs.REDIRECT_ARGS));
508 }
509 if (requestArgs.containsKey(requestArgs.REDIRECT_COOKIE)) {
510 p.setHttpRedirectCookie(requestArgs.
511 getSection(requestArgs.
512 REDIRECT_COOKIE));
513 }
514 }
515 catch (Exception e) {
516 System.err.println(e); //FIX:
517 }
518 return p;
519 }
520
521 /**
522 * This method causes the current request to be redirected
523 * to another location. The redirection is performed locally
524 * on the server side. Any redirect
525 * arguments set in this page are appended to the url. Likewise,
526 * any redirect cookies are passed on to the new url.
527 *
528 * <UL>Notes:
529 * <LI>cookies are not set on the browser.
530 * <LI>internal (server side) redirection should be handeled carefully.
531 * The new url should not contain any relative references to
532 * images and objects since the browser has no way of knowing
533 * that the page was redirected. If this confuses you then
534 * you are better off using client-side redirection.
535 * </UL>
536 *
537 * @param url The url which should handle the request.
538 * @exception lutris.jolt.presentation.PageRedirectException This
539 * exception should not be caught as it is handeled by the
540 * presentation manager.
541 */
542 public Exception serverSideRedirectException(String url) {
543 PageRedirectException p = new PageRedirectException(url);
544 p.setRedirectionViaClient(false);
545 try {
546 if (requestArgs.containsKey(requestArgs.REDIRECT_ARGS)) {
547 p.setHttpRedirectArgs(requestArgs.
548 getSection(requestArgs.REDIRECT_ARGS));
549 }
550 if (requestArgs.containsKey(requestArgs.REDIRECT_COOKIE)) {
551 p.setHttpRedirectCookie(requestArgs.
552 getSection(requestArgs.
553 REDIRECT_COOKIE));
554 }
555 }
556 catch (Exception e) {
557 System.err.println(e); //FIX:
558 }
559 return p;
560 }
561
562 /**
563 * Start writing output if it hasn't already begun.
564 *
565 * @exception IOException If an HTTP error occurs.
566 */
567 private void startWrite ()
568 throws IOException {
569 if (!outputIsStreaming) {
570 headerOutputStream.writeBytes ("HTTP/1.0 " + responseStatusCode + " " +
571 responseStatusReason + "\n");
572 try {
573 if (httpPageArgs.containsKey (HttpPageArgs.RESPONSE_HEADER)) {
574 KeywordValueTable headers = httpPageArgs.getSection (HttpPageArgs.RESPONSE_HEADER);
575 String [] headerNames = headers.leafKeys();
576 for (int i = 0; i < headerNames.length; i++) {
577 String [] values = httpPageArgs.getHttpResponseHeader(headerNames[i]);
578 for (int j = 0; j < values.length; j++) {
579 headerOutputStream.writeBytes (headerNames[i] + ": " + values[j] + "\n");
580 }
581 }
582 }
583 } catch (KeywordValueException e) {
584 // Hopefully due to no headers being set.
585 }
586
587 Cookie [] cookies = requestArgs.getAllHttpResponseCookies();
588 for (int idx = 0; idx < cookies.length; idx++) {
589 headerOutputStream.writeBytes (cookies[idx].toString());
590 }
591 headerOutputStream.writeBytes ("\n");
592 headerOutputStream.flush();
593 outputIsStreaming = true;
594 }
595 }
596
597 //------------------------------------------
598 // Implementation of DataOutput interface
599 //------------------------------------------
600
601 public void write(int b)
602 throws IOException
603 {
604 startWrite ();
605 bodyOutputStream.write(b);
606 }
607
608 public void write(byte[] b)
609 throws IOException
610 {
611 startWrite ();
612 bodyOutputStream.write(b);
613 }
614
615 public void write(byte[] b, int off, int len)
616 throws IOException
617 {
618 startWrite ();
619 bodyOutputStream.write(b, off, len);
620 }
621
622 public void writeBoolean(boolean v)
623 throws IOException
624 {
625 startWrite ();
626 bodyOutputStream.writeBoolean(v);
627 }
628
629 public void writeByte(int v)
630 throws IOException
631 {
632 startWrite ();
633 bodyOutputStream.writeByte(v);
634 }
635
636 public void writeBytes(String s)
637 throws IOException
638 {
639 startWrite ();
640 bodyOutputStream.writeBytes(s);
641 }
642
643 public void writeChar(int v)
644 throws IOException
645 {
646 startWrite ();
647 bodyOutputStream.writeChar(v);
648 }
649
650 public void writeChars(String s)
651 throws IOException
652 {
653 startWrite ();
654 bodyOutputStream.writeChars(s);
655 }
656
657 public void writeDouble(double v)
658 throws IOException
659 {
660 startWrite ();
661 bodyOutputStream.writeDouble(v);
662 }
663
664 public void writeFloat(float v)
665 throws IOException
666 {
667 startWrite ();
668 bodyOutputStream.writeFloat(v);
669 }
670
671 public void writeInt(int v)
672 throws IOException
673 {
674 startWrite ();
675 bodyOutputStream.writeInt(v);
676 }
677
678 public void writeLong(long v)
679 throws IOException
680 {
681 startWrite ();
682 bodyOutputStream.writeLong(v);
683 }
684
685 public void writeShort(int v)
686 throws IOException
687 {
688 startWrite ();
689 bodyOutputStream.writeShort(v);
690 }
691
692 public void writeUTF(String str)
693 throws IOException
694 {
695 startWrite ();
696 bodyOutputStream.writeUTF(str);
697 }
698
699 }
700