KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lutris > appserver > server > httpPresentation > servlet > ServletHttpPresentationResponse


1
2 /*
3  * Enhydra Java Application Server Project
4  *
5  * The contents of this file are subject to the Enhydra Public License
6  * Version 1.1 (the "License"); you may not use this file except in
7  * compliance with the License. You may obtain a copy of the License on
8  * the Enhydra web site ( http://www.enhydra.org/ ).
9  *
10  * Software distributed under the License is distributed on an "AS IS"
11  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
12  * the License for the specific terms governing rights and limitations
13  * under the License.
14  *
15  * The Initial Developer of the Enhydra Application Server is Lutris
16  * Technologies, Inc. The Enhydra Application Server and portions created
17  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
18  * All Rights Reserved.
19  *
20  * Contributor(s):
21  *
22  * $Id: ServletHttpPresentationResponse.java,v 1.4 2005/03/24 10:51:16 slobodan Exp $
23  */

24
25 package com.lutris.appserver.server.httpPresentation.servlet;
26
27 import java.io.IOException JavaDoc;
28 import java.io.PrintWriter JavaDoc;
29 import java.io.StringWriter JavaDoc;
30 import java.util.Enumeration JavaDoc;
31
32 import javax.servlet.http.Cookie JavaDoc;
33 import javax.servlet.http.HttpServletResponse JavaDoc;
34
35 import org.enhydra.util.jivan.JivanSimpleXMLObjectImpl;
36 import org.enhydra.xml.dom.DOMStats;
37 import org.enhydra.xml.io.DOMFormatter;
38 import org.enhydra.xml.io.Encodings;
39 import org.enhydra.xml.io.OutputOptions;
40 import org.enhydra.xml.io.URLRewriter;
41 import org.enhydra.xml.xmlc.XMLObject;
42 import org.w3c.dom.html.HTMLDocument;
43
44 import com.lutris.appserver.server.StandardAppUtil;
45 import com.lutris.appserver.server.httpPresentation.HttpPresentationException;
46 import com.lutris.appserver.server.httpPresentation.HttpPresentationIOException;
47 import com.lutris.appserver.server.httpPresentation.HttpPresentationOutputStream;
48 import com.lutris.appserver.server.httpPresentation.HttpPresentationResponse;
49 import com.lutris.appserver.server.session.SessionException;
50 import com.lutris.appserver.server.session.SessionManager;
51 import com.lutris.util.StringEnum;
52
53 /**
54  * Object passed to presentation objects that is used to generate HTTP
55  * responses.
56  */

57 public class ServletHttpPresentationResponse
58     implements HttpPresentationResponse { //SV , DebugResponse
59

60     /*
61      * Servlet objects.
62      */

63     private HttpServletResponse JavaDoc response;
64     private HttpPresentationOutputStream outputStream = null; // Lazy allocation
65

66     /*
67      * Default encoding of the VM
68      */

69     private static final String JavaDoc defaultEncoding = System.getProperty("file.encoding");
70
71     /*
72      * Encoding for output
73      */

74     private String JavaDoc encoding = null;
75
76     /*
77      * The current session key
78      */

79     private String JavaDoc sessionKey = null;
80
81     /*
82      * The current session manager
83      */

84     private SessionManager sessionManager = null;
85
86     /*
87      * Boolean flag indicating if response requires a sessionId cookie
88      */

89     private boolean sessionIdCookie = true;
90
91     /*
92      * Boolean flag indicating if response requires url encoding for sessionId
93      */

94     private boolean sessionIdUrl = true;
95
96     /**
97      * If not null, log DOM statistics here after each DOM write.
98      */

99     private PrintWriter JavaDoc domStatsLogWriter;
100
101     /**
102      * Construct an object associated with a servlet response.
103      *
104      * @param response Servlet response object that this object will front-end.
105      */

106     protected ServletHttpPresentationResponse(HttpServletResponse JavaDoc response,
107                           PrintWriter JavaDoc domStatsLogWriter) {
108         this.response = response;
109         this.domStatsLogWriter = domStatsLogWriter;
110     }
111
112     /**
113      * Returns the original HttpServletResponse.
114      */

115     public HttpServletResponse JavaDoc getHttpServletResponse() {
116     return this.response;
117     }
118
119     /**
120      * Sets the content length for this response.
121      *
122      * @param len the content length
123      */

124     public void setContentLength(int len)
125     throws HttpPresentationException {
126
127         response.setContentLength(len);
128     }
129
130
131     /**
132      * Sets the content type for this response.
133      *
134      * @param type the content's MIME type
135      */

136     public void setContentType(String JavaDoc type)
137     throws HttpPresentationException {
138
139         response.setContentType(type);
140     }
141
142
143     /**
144      * Returns an output stream for writing response data.
145      */

146     public HttpPresentationOutputStream getOutputStream()
147     throws HttpPresentationException {
148
149         if (outputStream == null) {
150             try {
151                 outputStream = new ServletHttpPresentationOutputStream
152             (this, response.getOutputStream());
153             } catch (IOException JavaDoc except) {
154                 // Want to throw a HttpPresentationIOException to record the fact that
155
// the client disconnected, but want to maintain the HttpPresentationException
156
// API.
157
throw new HttpPresentationException(new HttpPresentationIOException(except));
158             }
159         }
160         return outputStream;
161     }
162
163
164     /**
165      * Adds the specified cookie to the response. It can be called multiple
166      * times to set more than one cookie.
167      *
168      * @param cookie - The Cookie to return to the client.
169      */

170     public void addCookie(Cookie JavaDoc cookie)
171     throws HttpPresentationException {
172         response.addCookie(cookie);
173     }
174
175
176     /**
177      * Returns true if the response message header has a field with
178      * the specified name.
179      * @param name the header field name
180      */

181     public boolean containsHeader(String JavaDoc name)
182     throws HttpPresentationException {
183
184         return response.containsHeader(name);
185     }
186
187
188     /**
189      * Sets the status code and message for this response.
190      *
191      * @param sc the status code
192      * @param sm the status message
193      */

194     public void setStatus(int sc, String JavaDoc sm)
195     throws HttpPresentationException {
196
197         response.setStatus(sc, sm);
198     }
199
200
201     /**
202      * Sets the status code and a default message for this response.
203      *
204      * @param sc the status code
205      */

206     public void setStatus(int sc)
207     throws HttpPresentationException {
208
209         response.setStatus(sc);
210     }
211
212
213     /**
214      * Adds a field to the response header with a given name and
215      * value. If the field had already been set, the new value
216      * overwrites the previous one. The containsHeader method can be
217      * used to test for the presence of a header before setting its
218      * value.
219      *
220      * @param name the header field name
221      * @param value the header field value
222      */

223     public void setHeader(String JavaDoc name, String JavaDoc value)
224     throws HttpPresentationException {
225
226         response.setHeader(name, value);
227     }
228
229
230     /**
231      * Adds a field to the response header with a given name and
232      * integer value. If the field had already been set, the new
233      * value overwrites the previous one. The containsHeader method
234      * can be used to test for the presence of a header before setting
235      * its value.
236      *
237      * @param name the header field name
238      * @param value the header field integer value
239      */

240     public void setIntHeader(String JavaDoc name, int value)
241     throws HttpPresentationException {
242
243         response.setIntHeader(name, value);
244     }
245
246
247     /**
248      * Adds a field to the response header with a given name and
249      * date-valued field. The date is specified in terms of
250      * milliseconds since the epoch. If the date field had already
251      * been set, the new value overwrites the previous one. The
252      * containsHeader method can be used to test for the presence of a
253      * header before setting its value.
254      *
255      * @param name the header field name
256      * @param value the header field date value
257      */

258     public void setDateHeader(String JavaDoc name, long date)
259     throws HttpPresentationException {
260
261         response.setDateHeader(name, date);
262     }
263
264
265     /**
266      * Sends an error response to the client using the specified status
267      * code and descriptive message.
268      *
269      * @param sc the status code
270      * @param msg the detail message
271      */

272     public void sendError(int sc, String JavaDoc msg)
273     throws HttpPresentationException {
274
275     try {
276         response.sendError(sc, msg);
277     } catch (IOException JavaDoc except) {
278             // Want to throw a HttpPresentationIOException to record the fact that
279
// the client disconnected, but want to maintain the HttpPresentationException
280
// API.
281
throw new HttpPresentationException(new HttpPresentationIOException(except));
282     }
283     }
284
285     /**
286      * Sends an error response to the client using the specified
287      * status code and a default message.
288      *
289      * @param sc the status code
290      */

291     public void sendError(int sc)
292     throws HttpPresentationException {
293
294     try {
295             response.sendError(sc);
296     } catch (IOException JavaDoc except) {
297             // Want to throw a HttpPresentationIOException to record the fact that
298
// the client disconnected, but want to maintain the HttpPresentationException
299
// API.
300
throw new HttpPresentationException(new HttpPresentationIOException(except));
301     }
302     }
303
304     /**
305      * Called at the end of processing a response to force any cached
306      * headers to be written and buffers flushed.
307      */

308     public void flush() throws HttpPresentationException {
309
310     try {
311             // Before version 3.0 of enhydra this was getOutputStream().flush()
312
// the getOutStream() can throw an exception if the writer was used
313
// instead of the outputstream.
314
response.flushBuffer();
315         } catch (IOException JavaDoc except) {
316             // Want to throw a HttpPresentationIOException to record the fact that
317
// the client disconnected, but want to maintain the HttpPresentationException
318
// API.
319
throw new HttpPresentationException(new HttpPresentationIOException(except));
320         }
321     }
322
323     /**
324      * Encodes a url with session id for use with cookieless browsers.
325      *
326      * @param url the url to be encoded.
327      * @return the encoded URL if encoding is needed; the unchanged URL
328      * otherwise.
329      */

330     public String JavaDoc encodeUrl(String JavaDoc url) {
331     return response.encodeUrl(url);
332     }
333
334     /**
335      * Encodes a url with session id for sendRedirect for use with
336      * cookieless browsers.
337      *
338      * @param url the url to be encoded.
339      * @return the encoded URL if encoding is needed; the unchanged URL
340      * otherwise.
341      *
342      * @see #sendRedirect
343      * @see #encodeUrl
344      */

345     public String JavaDoc encodeRedirectUrl(String JavaDoc url) {
346     return response.encodeUrl(url);
347     }
348
349
350
351
352     /*
353      * The following methods are for the debugging interface...
354      */

355
356     /**
357      * Returns the size of the request entity data, or -1 if not available.
358      * This is necessary to support the DebugResponse interface.
359      *
360      * @see com.lutris.http.debug.DebugResponse
361      * @return the content length.
362      */

363     public int getContentLength() {
364     // FIX: When we have our own servlet implementation, we can
365
// FIX: support this.
366
return -1;
367     }
368
369
370     /**
371      * Returns the Internet Media Type of the response, or null if not known
372      * This is necessary to support the DebugResponse interface.
373      *
374      * @see com.lutris.http.debug.DebugResponse
375      * @return the content type.
376      */

377     public String JavaDoc getContentType() {
378     // FIX: When we have our own servlet implementation, we can
379
// FIX: support this.
380
return null;
381     }
382
383
384     /**
385      * Returns the status code for the response, or -1 if not available.
386      * This is necessary to support the DebugResponse interface.
387      *
388      * @see com.lutris.http.debug.DebugResponse
389      * @return the status code.
390      */

391     public int getStatusCode() {
392     // FIX: When we have our own servlet implementation, we can
393
// FIX: support this.
394
return -1;
395     }
396
397
398     /**
399      * Returns the status message for the response, or null if not available.
400      * This is necessary to support the DebugResponse interface.
401      *
402      * @see com.lutris.http.debug.DebugResponse
403      * @return the status message.
404      */

405     public String JavaDoc getStatusMessage() {
406     // FIX: When we have our own servlet implementation, we can
407
// FIX: support this.
408
return null;
409     }
410
411
412     /**
413      * Returns an array of cookies to be set by this response, or
414      * a 0 length array if the information is not available.
415      * This is necessary to support the DebugResponse interface.
416      *
417      * @see com.lutris.http.debug.DebugResponse
418      * @return The array of cookies found in this response.
419      */

420     public Cookie JavaDoc[] getCookies() {
421     // FIX: Not supported - our servlet response implementation
422
// FIX: should implement this debug interface directly to save
423
// FIX: storing this stuff here.
424
return new Cookie JavaDoc[0];
425     }
426
427
428     /**
429      * Returns the values of the specified header for the response as
430      * an array of strings, or a 0 length array if the named header does
431      * not exist.
432      * This is necessary to support the DebugResponse interface.
433      *
434      * @see com.lutris.http.debug.DebugResponse
435      * @param name the case-insensitive header field name
436      * @return the value of the supplied header.
437      */

438     public String JavaDoc getHeader(String JavaDoc name) {
439     // FIX: Not supported - our servlet response implementation
440
// FIX: should implement this debug interface directly to save
441
// FIX: storing this stuff here.
442
return "";
443     }
444
445
446     /**
447      * Returns an array of strings representing the header names
448      * for this response. This does not have return cookies - use
449      * getCookies().
450      *
451      * @see com.lutris.http.debug.DebugResponse
452      * @return name the case-insensitive header field name
453      */

454     public Enumeration JavaDoc getHeaderNames() {
455     // FIX: Not supported - our servlet response implementation
456
// FIX: should implement this debug interface directly to save
457
// FIX: storing this stuff here.
458
return new StringEnum(new String JavaDoc[0]);
459     }
460
461
462     /**
463      * Returns the total number of bytes that make up this response.
464      * This is not supported for Jolt Presentations and is necessary
465      * to support the DebugResponse interface.
466      *
467      * @see com.lutris.http.debug.DebugResponse
468      * @return the total number of bytes in the response.
469      */

470     public int getTotalBytes() {
471     // FIX: Not supported - our servlet response implementation
472
// FIX: should implement this debug interface directly to save
473
// FIX: storing this stuff here.
474
return -1;
475     }
476
477     /**
478      * Returns null.
479      * Normally this function returns the data written to the output
480      * stream associated with this request.
481      */

482     public String JavaDoc getResponseData() {
483         return null;
484     }
485
486     /**
487      * Set the output character encoding.
488      *
489      * @param enc character encoding
490      */

491     public void setEncoding(String JavaDoc enc) {
492         encoding = enc;
493     }
494
495     /**
496      * Get the output character encoding.
497      */

498     public String JavaDoc getEncoding() {
499         return encoding;
500     }
501
502     /**
503      * Sets the current session key for this response
504      *
505      * @param sessionKey
506      * The current sessionKey
507      **/

508     public void setSessionKey(String JavaDoc sessionKey) {
509     this.sessionKey = sessionKey;
510     }
511
512     /**
513      * Sets the session manager.
514      **/

515     public void setSessionManager(SessionManager sessionManager) {
516     this.sessionManager = sessionManager;
517     }
518
519     /**
520      * Indicates whether client response requires a sessionId cookie
521      * @return true if client response requires a sessionId cookie
522      * false otherwise
523      */

524     public boolean isSessionIdCookieRequired()
525     throws HttpPresentationException {
526     return sessionIdCookie;
527     }
528
529     /*
530      * set boolean flag for sessionId response cookie. Indicates whether
531      * client response requires a sessionId cookie
532      * @param isFromCookie boolean flag
533      */

534     public void setSessionIdCookieRequired(boolean sessionIdCookie)
535     throws HttpPresentationException {
536     this.sessionIdCookie = sessionIdCookie;
537     }
538
539     /**
540      * Indicates whether client response requires url encoding for
541      * sessionId
542      * @return true if client response requires url encoding for
543      * sessionId; false otherwise
544      */

545     public boolean isSessionIdEncodeUrlRequired()
546     throws HttpPresentationException {
547     return sessionIdUrl;
548     }
549     /*
550      * Set boolean flag url encoding for sessionId. Indicates whether
551      * client response requires url encoding for sessionId
552      * @param sessionIdUrl boolean flag
553      */

554     public void setSessionIdEncodeUrlRequired(boolean sessionIdUrl)
555     throws HttpPresentationException {
556     this.sessionIdUrl = sessionIdUrl;
557     }
558
559     /**
560      * Determine if a session key should be encoded in URLs, based on
561      * what is requested and session being valid.
562      */

563     private boolean shouldEncodeSessionKey() throws HttpPresentationException {
564         try {
565             return (sessionIdUrl && (sessionManager != null) && (sessionKey != null)
566                     && sessionManager.sessionExists(sessionKey)
567                     && !(sessionManager).getEncodeUrlState().equalsIgnoreCase(SessionManager.ENCODE_URL_NEVER));
568             /*
569             return (sessionIdUrl && (sessionManager != null) && (sessionKey != null)
570                     && sessionManager.sessionExists(sessionKey)
571                     && (sessionManager instanceof StandardSessionManager)
572                     && !((StandardSessionManager)sessionManager).getEncodeUrlState().equalsIgnoreCase(StandardSessionManager.ENCODE_URL_NEVER));
573                     */

574         } catch (SessionException except) {
575             throw new HttpPresentationException(except);
576         }
577     }
578     
579     /**
580      * Set up the encoding using either the encoding specified with
581      * setEncoding(), OutputOptions, or the XMLC default encoding.
582      * Either a Java or MIME encoding name is recognized.
583      * Generates an error if the conding is invalid.
584      */

585     private void setupEncoding(XMLObject document,
586                                OutputOptions options)
587         throws HttpPresentationException {
588
589         // If encoding is already specified, we don't override.
590
if (options.getEncoding() == null) {
591             String JavaDoc outputEncoding = encoding; // User specified.
592
if (outputEncoding == null) {
593                 // Use document default encoding.
594
outputEncoding = document.getEncoding();
595             }
596             if (outputEncoding == null) {
597                 outputEncoding = defaultEncoding;
598             }
599             options.setEncoding(outputEncoding);
600         }
601     }
602
603     /**
604      * Create an OutputOptions object for a document. Options are default for
605      * the specified document. The object maybe then modified as needed to
606      * override the default values.
607      * <P>
608      * The following attributes are set in the object:
609      * <UL>
610      * <LI> encoding
611      * <LI> MIME type - Defaults for document.
612      * <LI> URLRewriter - Set if URL encoding of sessions is enabled.
613      * </UL>
614      */

615     public OutputOptions createOutputOptions(XMLObject document)
616         throws HttpPresentationException {
617
618         OutputOptions options = DOMFormatter.getDefaultOutputOptions(document);
619
620         setupEncoding(document, options);
621
622         // Get the default MIME type from object
623
options.setMIMEType(document.getMIMEType());
624
625         // Enable encoding of session id in URL, if needed.
626
boolean encodeSessionKey = shouldEncodeSessionKey();
627         if (encodeSessionKey) {
628             options.setURLRewriter(new URLRewriter() {
629                     public String JavaDoc rewriteURL(String JavaDoc urlAttrValue) {
630                         if (StandardAppUtil.pointsToPO(urlAttrValue)) {
631                             return StandardAppUtil.encodeUrl(urlAttrValue, sessionKey);
632                         } else {
633                             return urlAttrValue;
634                         }
635                     }
636                 });
637         }
638         return options;
639     }
640
641     /**
642      * Write a string document represented as a byte array.
643      */

644     private void outputDocumentBytes(byte[] docBytes,
645                                      String JavaDoc mimeEncoding,
646                                      String JavaDoc mimeType)
647         throws HttpPresentationException, IOException JavaDoc {
648
649         // Set headers
650
setContentLength(docBytes.length);
651         if (mimeType != null) {
652             if (mimeEncoding != null) {
653                 setContentType(mimeType + "; charset=" + mimeEncoding);
654             } else {
655                 setContentType(mimeType);
656             }
657         }
658
659         // Disable caching of page unless otherwise specified.
660
if (getHeader("Cache-Control") == null) {
661             setHeader("Cache-Control", "no-cache");
662         }
663         if (getHeader("Expires") == null) {
664             setHeader("Expires", "0");
665         }
666
667         // Output
668
getOutputStream().write(docBytes);
669         getOutputStream().flush();
670     }
671
672     /**
673      * Do common operations for writing DOM document. Sets approriate HTTP
674      * header, including setting of cache-control headers, if not already set.
675      * Handles encoding conversion and output.
676      */

677     private void outputDocument(XMLObject document,
678                                 OutputOptions outputOptions)
679         throws HttpPresentationException, IOException JavaDoc {
680
681         // Convert to bytes and output
682
if(document instanceof JivanSimpleXMLObjectImpl) { // vr 16.05.2004
683
// Jivan specific conversion XMLObject to byte array
684
outputDocumentBytes(((JivanSimpleXMLObjectImpl)document).toByteDocument(),
685                             outputOptions.getMIMEEncoding(),
686                             outputOptions.getMIMEType());
687       }
688       else {
689           DOMFormatter formatter = new DOMFormatter(outputOptions);
690           outputDocumentBytes(formatter.toBytes(document),
691                               outputOptions.getMIMEEncoding(),
692                               outputOptions.getMIMEType());
693       }
694         // Log if requested
695
if (domStatsLogWriter != null) {
696         // Buffer results so it gets logged as a single entry
697
StringWriter JavaDoc buf = new StringWriter JavaDoc(2048);
698             PrintWriter JavaDoc writer = new PrintWriter JavaDoc(buf);
699             DOMStats.printStats("Write " + document.getClass().getName(),
700                                 document, 0, writer);
701             writer.flush();
702         domStatsLogWriter.println(buf.toString());
703         }
704     }
705
706     /**
707      * Output an an XMLC document object (DOM). The document is formatted
708      * according to it's type. The MIME type of the response is automatically
709      * set.
710      *
711      * @param outputFormat Object use to specify options controling formatting
712      * of the document.
713      * @param doc The DOM object to be returned as response.
714      */

715     public void writeDOM(OutputOptions outputOptions,
716                          XMLObject document) throws HttpPresentationException {
717         try {
718             // Copy options so as to not modify when changing encoding.
719
OutputOptions options = new OutputOptions(outputOptions);
720             setupEncoding(document, options);
721             outputDocument(document, options);
722         } catch (IOException JavaDoc except) {
723             throw new HttpPresentationException(except);
724         }
725     }
726
727     /**
728      * Output an an XMLC document object (DOM). The document is formatted
729      * according to it's type. The MIME type of the response is automatically
730      * set.
731      *
732      * @param doc The DOM object to be returned as response.
733      */

734     public void writeDOM(XMLObject document) throws HttpPresentationException {
735
736         OutputOptions outputOptions = createOutputOptions(document);
737         // this ugly IE hack disabled by Petr Stehlik 2003/01/07
738
// since it's been causing problems in CSS pages.
739
// The hack was required for IE4 only, anyway..
740
/*
741          if (document instanceof HTMLDocument) {
742              // special, ugly hack for IE
743              outputOptions.setDropHtmlSpanIds(true);
744          }
745         */

746         outputOptions.setEnableXHTMLCompatibility(true);
747         try {
748             outputDocument(document, outputOptions);
749         } catch (IOException JavaDoc except) {
750             throw new HttpPresentationException(except);
751         }
752     }
753
754     /**
755      * Utility method to output an HTML page. The appropriate headers are
756      * set for MIME type and to disable caching of the HTML by the broswer.
757      */

758     public void writeHTML(String JavaDoc html) throws HttpPresentationException {
759         byte bytes[];
760
761         // Determine encoding to use.
762
String JavaDoc mimeEncoding = null;
763         if (encoding != null) {
764             mimeEncoding = Encodings.getEncodings().getMIMEPreferred(encoding);
765             if (mimeEncoding == null) {
766                 mimeEncoding = encoding;
767             }
768         }
769
770         try {
771             if (encoding != null) {
772                 bytes = html.getBytes(encoding);
773             } else {
774                 bytes = html.getBytes();
775             }
776             outputDocumentBytes(bytes, mimeEncoding, "text/html");
777         } catch (IOException JavaDoc except) {
778             throw new HttpPresentationException(except);
779         }
780     }
781
782     /**
783      * Utility method to output an HTML page from a DOM object. The
784      * appropriate headers are set for MIME type and to disable caching
785      * of the HTML by the broswer.
786      *
787      * @param doc The DOM object to be returned as response
788      * @deprecated use writeDOM
789      */

790     public void writeHTML(HTMLDocument doc) throws HttpPresentationException {
791         writeDOM((XMLObject)doc);
792     }
793 }
794
Popular Tags