001: /*
002: * Enhydra Java Application Server Project
003: *
004: * The contents of this file are subject to the Enhydra Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License on
007: * the Enhydra web site ( http://www.enhydra.org/ ).
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
011: * the License for the specific terms governing rights and limitations
012: * under the License.
013: *
014: * The Initial Developer of the Enhydra Application Server is Lutris
015: * Technologies, Inc. The Enhydra Application Server and portions created
016: * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
017: * All Rights Reserved.
018: *
019: * Contributor(s):
020: *
021: * $Id: ServletHttpPresentationResponse.java,v 1.6 2007-12-27 16:18:48 sinisa Exp $
022: */
023:
024: package com.lutris.appserver.server.httpPresentation.servlet;
025:
026: import java.io.IOException;
027: import java.io.PrintWriter;
028: import java.io.StringWriter;
029: import java.util.Enumeration;
030:
031: import javax.servlet.http.Cookie;
032: import javax.servlet.http.HttpServletResponse;
033:
034: import org.enhydra.util.jivan.JivanSimpleXMLObjectImpl;
035: import org.enhydra.xml.dom.DOMStats;
036: import org.enhydra.xml.io.DOMFormatter;
037: import org.enhydra.xml.io.Encodings;
038: import org.enhydra.xml.io.ExtHTMLFormatter;
039: import org.enhydra.xml.io.ExtXMLFormatter;
040: import org.enhydra.xml.io.OutputOptions;
041: import org.enhydra.xml.io.URLRewriter;
042: import org.enhydra.xml.xmlc.XMLObject;
043: import org.w3c.dom.Node;
044: import org.w3c.dom.html.HTMLDocument;
045:
046: import com.lutris.appserver.server.ResponsePostProcessingManager;
047: import com.lutris.appserver.server.StandardAppUtil;
048: import com.lutris.appserver.server.httpPresentation.HttpPresentationException;
049: import com.lutris.appserver.server.httpPresentation.HttpPresentationIOException;
050: import com.lutris.appserver.server.httpPresentation.HttpPresentationOutputStream;
051: import com.lutris.appserver.server.httpPresentation.HttpPresentationResponse;
052: import com.lutris.appserver.server.session.SessionException;
053: import com.lutris.appserver.server.session.SessionManager;
054: import com.lutris.util.StringEnum;
055:
056: /**
057: * Object passed to presentation objects that is used to generate HTTP
058: * responses.
059: */
060: public class ServletHttpPresentationResponse implements
061: HttpPresentationResponse { //SV , DebugResponse
062:
063: /*
064: * Servlet objects.
065: */
066: private HttpServletResponse response;
067: private HttpPresentationOutputStream outputStream = null; // Lazy allocation
068:
069: /*
070: * Default encoding of the VM
071: */
072: //4.6.2007. Aleksandar Stojsavljevic
073: //private static final String defaultEncoding = System.getProperty("file.encoding");
074: private static final String defaultEncoding = "UTF-8";
075:
076: /*
077: * Encoding for output
078: */
079: private String encoding = null;
080:
081: /*
082: * The current session key
083: */
084: private String sessionKey = null;
085:
086: /*
087: * The current session manager
088: */
089: private SessionManager sessionManager = null;
090:
091: /*
092: * Response Post Processing Manager
093: */
094: private ResponsePostProcessingManager processingManager = null;
095:
096: /*
097: * Boolean flag indicating if response requires a sessionId cookie
098: */
099: private boolean sessionIdCookie = true;
100:
101: /*
102: * Boolean flag indicating if response requires url encoding for sessionId
103: */
104: private boolean sessionIdUrl = true;
105:
106: /**
107: * If not null, log DOM statistics here after each DOM write.
108: */
109: private PrintWriter domStatsLogWriter;
110:
111: /**
112: * Construct an object associated with a servlet response.
113: *
114: * @param response Servlet response object that this object will front-end.
115: */
116: protected ServletHttpPresentationResponse(
117: HttpServletResponse response, PrintWriter domStatsLogWriter) {
118: this .response = response;
119: this .domStatsLogWriter = domStatsLogWriter;
120: }
121:
122: /**
123: * Returns the original HttpServletResponse.
124: */
125: public HttpServletResponse getHttpServletResponse() {
126: return this .response;
127: }
128:
129: /**
130: * Sets the content length for this response.
131: *
132: * @param len the content length
133: */
134: public void setContentLength(int len)
135: throws HttpPresentationException {
136:
137: response.setContentLength(len);
138: }
139:
140: /**
141: * Sets the content type for this response.
142: *
143: * @param type the content's MIME type
144: */
145: public void setContentType(String type)
146: throws HttpPresentationException {
147:
148: response.setContentType(type);
149: }
150:
151: /**
152: * Returns an output stream for writing response data.
153: */
154: public HttpPresentationOutputStream getOutputStream()
155: throws HttpPresentationException {
156:
157: if (outputStream == null) {
158: try {
159: outputStream = new ServletHttpPresentationOutputStream(
160: this , response.getOutputStream());
161: } catch (IOException except) {
162: // Want to throw a HttpPresentationIOException to record the fact that
163: // the client disconnected, but want to maintain the HttpPresentationException
164: // API.
165: throw new HttpPresentationException(
166: new HttpPresentationIOException(except));
167: }
168: }
169: return outputStream;
170: }
171:
172: /**
173: * Adds the specified cookie to the response. It can be called multiple
174: * times to set more than one cookie.
175: *
176: * @param cookie - The Cookie to return to the client.
177: */
178: public void addCookie(Cookie cookie)
179: throws HttpPresentationException {
180: response.addCookie(cookie);
181: }
182:
183: /**
184: * Returns true if the response message header has a field with
185: * the specified name.
186: * @param name the header field name
187: */
188: public boolean containsHeader(String name)
189: throws HttpPresentationException {
190:
191: return response.containsHeader(name);
192: }
193:
194: /**
195: * Sets the status code and message for this response.
196: *
197: * @param sc the status code
198: * @param sm the status message
199: */
200: public void setStatus(int sc, String sm)
201: throws HttpPresentationException {
202:
203: response.setStatus(sc, sm);
204: }
205:
206: /**
207: * Sets the status code and a default message for this response.
208: *
209: * @param sc the status code
210: */
211: public void setStatus(int sc) throws HttpPresentationException {
212:
213: response.setStatus(sc);
214: }
215:
216: /**
217: * Adds a field to the response header with a given name and
218: * value. If the field had already been set, the new value
219: * overwrites the previous one. The containsHeader method can be
220: * used to test for the presence of a header before setting its
221: * value.
222: *
223: * @param name the header field name
224: * @param value the header field value
225: */
226: public void setHeader(String name, String value)
227: throws HttpPresentationException {
228:
229: response.setHeader(name, value);
230: }
231:
232: /**
233: * Adds a field to the response header with a given name and
234: * integer value. If the field had already been set, the new
235: * value overwrites the previous one. The containsHeader method
236: * can be used to test for the presence of a header before setting
237: * its value.
238: *
239: * @param name the header field name
240: * @param value the header field integer value
241: */
242: public void setIntHeader(String name, int value)
243: throws HttpPresentationException {
244:
245: response.setIntHeader(name, value);
246: }
247:
248: /**
249: * Adds a field to the response header with a given name and
250: * date-valued field. The date is specified in terms of
251: * milliseconds since the epoch. If the date field had already
252: * been set, the new value overwrites the previous one. The
253: * containsHeader method can be used to test for the presence of a
254: * header before setting its value.
255: *
256: * @param name the header field name
257: * @param value the header field date value
258: */
259: public void setDateHeader(String name, long date)
260: throws HttpPresentationException {
261:
262: response.setDateHeader(name, date);
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 msg)
273: throws HttpPresentationException {
274:
275: try {
276: response.sendError(sc, msg);
277: } catch (IOException 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(
282: new HttpPresentationIOException(except));
283: }
284: }
285:
286: /**
287: * Sends an error response to the client using the specified
288: * status code and a default message.
289: *
290: * @param sc the status code
291: */
292: public void sendError(int sc) throws HttpPresentationException {
293:
294: try {
295: response.sendError(sc);
296: } catch (IOException 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(
301: new HttpPresentationIOException(except));
302: }
303: }
304:
305: /**
306: * Called at the end of processing a response to force any cached
307: * headers to be written and buffers flushed.
308: */
309: public void flush() throws HttpPresentationException {
310:
311: try {
312: // Before version 3.0 of enhydra this was getOutputStream().flush()
313: // the getOutStream() can throw an exception if the writer was used
314: // instead of the output stream.
315: response.flushBuffer();
316: } catch (IOException except) {
317: // Want to throw a HttpPresentationIOException to record the fact that
318: // the client disconnected, but want to maintain the HttpPresentationException
319: // API.
320: throw new HttpPresentationException(
321: new HttpPresentationIOException(except));
322: }
323: }
324:
325: /**
326: * Encodes a url with session id for use with cookieless browsers.
327: *
328: * @param url the url to be encoded.
329: * @return the encoded URL if encoding is needed; the unchanged URL
330: * otherwise.
331: */
332: public String encodeUrl(String url) {
333: return response.encodeUrl(url);
334: }
335:
336: /**
337: * Encodes a url with session id for sendRedirect for use with
338: * cookieless browsers.
339: *
340: * @param url the url to be encoded.
341: * @return the encoded URL if encoding is needed; the unchanged URL
342: * otherwise.
343: *
344: * @see #sendRedirect
345: * @see #encodeUrl
346: */
347: public String encodeRedirectUrl(String url) {
348: return response.encodeUrl(url);
349: }
350:
351: /*
352: * The following methods are for the debugging interface...
353: */
354:
355: /**
356: * Returns the size of the request entity data, or -1 if not available.
357: * This is necessary to support the DebugResponse interface.
358: *
359: * @see com.lutris.http.debug.DebugResponse
360: * @return the content length.
361: */
362: public int getContentLength() {
363: // FIX: When we have our own servlet implementation, we can
364: // FIX: support this.
365: return -1;
366: }
367:
368: /**
369: * Returns the Internet Media Type of the response, or null if not known
370: * This is necessary to support the DebugResponse interface.
371: *
372: * @see com.lutris.http.debug.DebugResponse
373: * @return the content type.
374: */
375: public String getContentType() {
376: // FIX: When we have our own servlet implementation, we can
377: // FIX: support this.
378: return null;
379: }
380:
381: /**
382: * Returns the status code for the response, or -1 if not available.
383: * This is necessary to support the DebugResponse interface.
384: *
385: * @see com.lutris.http.debug.DebugResponse
386: * @return the status code.
387: */
388: public int getStatusCode() {
389: // FIX: When we have our own servlet implementation, we can
390: // FIX: support this.
391: return -1;
392: }
393:
394: /**
395: * Returns the status message for the response, or null if not available.
396: * This is necessary to support the DebugResponse interface.
397: *
398: * @see com.lutris.http.debug.DebugResponse
399: * @return the status message.
400: */
401: public String getStatusMessage() {
402: // FIX: When we have our own servlet implementation, we can
403: // FIX: support this.
404: return null;
405: }
406:
407: /**
408: * Returns an array of cookies to be set by this response, or
409: * a 0 length array if the information is not available.
410: * This is necessary to support the DebugResponse interface.
411: *
412: * @see com.lutris.http.debug.DebugResponse
413: * @return The array of cookies found in this response.
414: */
415: public Cookie[] getCookies() {
416: // FIX: Not supported - our servlet response implementation
417: // FIX: should implement this debug interface directly to save
418: // FIX: storing this stuff here.
419: return new Cookie[0];
420: }
421:
422: /**
423: * Returns the values of the specified header for the response as
424: * an array of strings, or a 0 length array if the named header does
425: * not exist.
426: * This is necessary to support the DebugResponse interface.
427: *
428: * @see com.lutris.http.debug.DebugResponse
429: * @param name the case-insensitive header field name
430: * @return the value of the supplied header.
431: */
432: public String getHeader(String name) {
433: // FIX: Not supported - our servlet response implementation
434: // FIX: should implement this debug interface directly to save
435: // FIX: storing this stuff here.
436: return "";
437: }
438:
439: /**
440: * Returns an array of strings representing the header names
441: * for this response. This does not have return cookies - use
442: * getCookies().
443: *
444: * @see com.lutris.http.debug.DebugResponse
445: * @return name the case-insensitive header field name
446: */
447: public Enumeration getHeaderNames() {
448: // FIX: Not supported - our servlet response implementation
449: // FIX: should implement this debug interface directly to save
450: // FIX: storing this stuff here.
451: return new StringEnum(new String[0]);
452: }
453:
454: /**
455: * Returns the total number of bytes that make up this response.
456: * This is not supported for Jolt Presentations and is necessary
457: * to support the DebugResponse interface.
458: *
459: * @see com.lutris.http.debug.DebugResponse
460: * @return the total number of bytes in the response.
461: */
462: public int getTotalBytes() {
463: // FIX: Not supported - our servlet response implementation
464: // FIX: should implement this debug interface directly to save
465: // FIX: storing this stuff here.
466: return -1;
467: }
468:
469: /**
470: * Returns null.
471: * Normally this function returns the data written to the output
472: * stream associated with this request.
473: */
474: public String getResponseData() {
475: return null;
476: }
477:
478: /**
479: * Set the output character encoding.
480: *
481: * @param enc character encoding
482: */
483: public void setEncoding(String enc) {
484: encoding = enc;
485: }
486:
487: /**
488: * Get the output character encoding.
489: */
490: public String getEncoding() {
491: return encoding;
492: }
493:
494: /**
495: * Sets the current session key for this response
496: *
497: * @param sessionKey
498: * The current sessionKey
499: **/
500: public void setSessionKey(String sessionKey) {
501: this .sessionKey = sessionKey;
502: }
503:
504: /**
505: * Sets the session manager.
506: **/
507: public void setSessionManager(SessionManager sessionManager) {
508: this .sessionManager = sessionManager;
509: }
510:
511: /**
512: * Sets the response post processing manager.
513: *
514: * @param processingManager
515: */
516: public void setPostProcessingManager(
517: ResponsePostProcessingManager processingManager) {
518: this .processingManager = processingManager;
519: }
520:
521: /**
522: * Returns the response post processing manager.
523: */
524: public ResponsePostProcessingManager getPostProcessingManager() {
525: return this .processingManager;
526: }
527:
528: /**
529: * Indicates whether client response requires a sessionId cookie
530: * @return true if client response requires a sessionId cookie
531: * false otherwise
532: */
533: public boolean isSessionIdCookieRequired()
534: throws HttpPresentationException {
535: return sessionIdCookie;
536: }
537:
538: /*
539: * set boolean flag for sessionId response cookie. Indicates whether
540: * client response requires a sessionId cookie
541: * @param isFromCookie boolean flag
542: */
543: public void setSessionIdCookieRequired(boolean sessionIdCookie)
544: throws HttpPresentationException {
545: this .sessionIdCookie = sessionIdCookie;
546: }
547:
548: /**
549: * Indicates whether client response requires url encoding for
550: * sessionId
551: * @return true if client response requires url encoding for
552: * sessionId; false otherwise
553: */
554: public boolean isSessionIdEncodeUrlRequired()
555: throws HttpPresentationException {
556: return sessionIdUrl;
557: }
558:
559: /*
560: * Set boolean flag url encoding for sessionId. Indicates whether
561: * client response requires url encoding for sessionId
562: * @param sessionIdUrl boolean flag
563: */
564: public void setSessionIdEncodeUrlRequired(boolean sessionIdUrl)
565: throws HttpPresentationException {
566: this .sessionIdUrl = sessionIdUrl;
567: }
568:
569: /**
570: * Determine if a session key should be encoded in URLs, based on
571: * what is requested and session being valid.
572: */
573: private boolean shouldEncodeSessionKey()
574: throws HttpPresentationException {
575: try {
576: return (sessionIdUrl && (sessionManager != null)
577: && (sessionKey != null)
578: && sessionManager.sessionExists(sessionKey) && !(sessionManager)
579: .getEncodeUrlState().equalsIgnoreCase(
580: SessionManager.ENCODE_URL_NEVER));
581: /*
582: return (sessionIdUrl && (sessionManager != null) && (sessionKey != null)
583: && sessionManager.sessionExists(sessionKey)
584: && (sessionManager instanceof StandardSessionManager)
585: && !((StandardSessionManager)sessionManager).getEncodeUrlState().equalsIgnoreCase(StandardSessionManager.ENCODE_URL_NEVER));
586: */
587: } catch (SessionException except) {
588: throw new HttpPresentationException(except);
589: }
590: }
591:
592: /**
593: * Set up the encoding using either the encoding specified with
594: * setEncoding(), OutputOptions, or the XMLC default encoding.
595: * Either a Java or MIME encoding name is recognized.
596: * Generates an error if the encoding is invalid.
597: */
598: private void setupEncoding(XMLObject document, OutputOptions options)
599: throws HttpPresentationException {
600:
601: // If encoding is already specified, we don't override.
602: if (options.getEncoding() == null) {
603: String outputEncoding = encoding; // User specified.
604: if (outputEncoding == null) {
605: // Use document default encoding.
606: outputEncoding = document.getEncoding();
607: }
608: if (outputEncoding == null) {
609: outputEncoding = defaultEncoding;
610: }
611: options.setEncoding(outputEncoding);
612: }
613: }
614:
615: /**
616: * Set up the encoding using either the encoding specified with
617: * setEncoding(), OutputOptions, or the XMLC default encoding.
618: * Either a Java or MIME encoding name is recognized.
619: * Generates an error if the encoding is invalid.
620: */
621: private void setupEncoding(Node document, OutputOptions options)
622: throws HttpPresentationException {
623:
624: // If encoding is already specified, we don't override.
625: if (options.getEncoding() == null) {
626: options.setEncoding(defaultEncoding);
627: }
628: }
629:
630: /**
631: * Create an OutputOptions object for a document. Options are default for
632: * the specified document. The object maybe then modified as needed to
633: * override the default values.
634: * <P>
635: * The following attributes are set in the object:
636: * <UL>
637: * <LI> encoding
638: * <LI> MIME type - Defaults for document.
639: * <LI> URLRewriter - Set if URL encoding of sessions is enabled.
640: * </UL>
641: */
642: public OutputOptions createOutputOptions(XMLObject document)
643: throws HttpPresentationException {
644:
645: OutputOptions options = DOMFormatter
646: .getDefaultOutputOptions(document);
647:
648: setupEncoding(document, options);
649:
650: // Get the default MIME type from object
651: options.setMIMEType(document.getMIMEType());
652:
653: // Enable encoding of session id in URL, if needed.
654: boolean encodeSessionKey = shouldEncodeSessionKey();
655:
656: if (encodeSessionKey) {
657: options.setURLRewriter(new URLRewriter() {
658: public String rewriteURL(String urlAttrValue) {
659: if (StandardAppUtil.pointsToPO(urlAttrValue)) {
660: return StandardAppUtil.encodeUrl(urlAttrValue,
661: sessionKey);
662: } else {
663: return urlAttrValue;
664: }
665: }
666: });
667: }
668: return options;
669: }
670:
671: /**
672: * Write a string document represented as a byte array.
673: */
674: private void outputDocumentBytes(byte[] docBytes,
675: String mimeEncoding, String mimeType)
676: throws HttpPresentationException, IOException {
677:
678: if (processingManager != null) {
679: docBytes = processingManager.manage(docBytes, mimeEncoding,
680: mimeType);
681: mimeType = processingManager.getOutputMimeType();
682: }
683:
684: // Set headers
685: setContentLength(docBytes.length);
686: if (mimeType != null) {
687: if (mimeEncoding != null) {
688: setContentType(mimeType + "; charset=" + mimeEncoding);
689: } else {
690: setContentType(mimeType);
691: }
692: }
693:
694: // Disable caching of page unless otherwise specified.
695: if (getHeader("Cache-Control") == null) {
696: setHeader("Cache-Control", "no-cache");
697: }
698: if (getHeader("Expires") == null) {
699: setHeader("Expires", "0");
700: }
701:
702: // Output
703: getOutputStream().write(docBytes);
704: getOutputStream().flush();
705: }
706:
707: /**
708: * Do common operations for writing DOM document. Sets appropriate HTTP
709: * header, including setting of cache-control headers, if not already set.
710: * Handles encoding conversion and output.
711: */
712: private void outputDocument(Node document,
713: OutputOptions outputOptions)
714: throws HttpPresentationException, IOException {
715:
716: if (processingManager != null) {
717: document = processingManager
718: .manage(outputOptions, document);
719: }
720:
721: // Convert to bytes and output
722: if (document instanceof JivanSimpleXMLObjectImpl) { // vr 16.05.2004
723: // Jivan specific conversion XMLObject to byte array
724: outputDocumentBytes(((JivanSimpleXMLObjectImpl) document)
725: .toByteDocument(), outputOptions.getMIMEEncoding(),
726: outputOptions.getMIMEType());
727: } else if (null != outputOptions
728: .getFreeformOption(org.enhydra.util.DOMFormatter.FORMATTER_NAME)) {
729: // Specific conversion of Documet to array of bytes
730: org.enhydra.util.DOMFormatter formatter = (org.enhydra.util.DOMFormatter) outputOptions
731: .getFreeformOption(org.enhydra.util.DOMFormatter.FORMATTER_NAME);
732: outputDocumentBytes(formatter.toBytes(document),
733: outputOptions.getMIMEEncoding(), outputOptions
734: .getMIMEType());
735: } else {
736: DOMFormatter formatter = new DOMFormatter(outputOptions);
737: outputDocumentBytes(formatter.toBytes(document),
738: outputOptions.getMIMEEncoding(), outputOptions
739: .getMIMEType());
740: }
741: // Log if requested
742: if (domStatsLogWriter != null) {
743: // Buffer results so it gets logged as a single entry
744: StringWriter buf = new StringWriter(2048);
745: PrintWriter writer = new PrintWriter(buf);
746: DOMStats.printStats("Write "
747: + document.getClass().getName(), document, 0,
748: writer);
749: writer.flush();
750: domStatsLogWriter.println(buf.toString());
751: }
752: }
753:
754: /**
755: * Output an an XMLC document object (DOM). The document is formatted
756: * according to it's type. The MIME type of the response is automatically
757: * set.
758: *
759: * @param outputFormat Object use to specify options controlling formatting
760: * of the document.
761: * @param doc The DOM object to be returned as response.
762: */
763: /*public void writeDOM(Map outputOptions,
764: Node document) throws HttpPresentationException {
765: try {
766:
767: if (!outputOptions.containsKey("inMimeType")){
768: outputOptions.put("inMimeType", "text/html");
769: }
770:
771: if (!outputOptions.containsKey("encoding")){
772: outputOptions.put("encoding", "UTF-8");
773: }
774:
775: if (processingManager!=null){
776: document = processingManager.manage(outputOptions,document);
777: }
778:
779: OutputOptions outOptions = new OutputOptions();// createOutputOptions(document);
780: outOptions.setEnableXHTMLCompatibility(true);
781: outOptions.setUseAposEntity(false);
782: outOptions.setEncoding((String)outputOptions.get("encoding"));
783: outOptions.setMIMEType((String)outputOptions.get("inMimeType"));
784: outputDocument(document,outOptions);
785:
786: } catch (IOException ioex){
787: ioex.printStackTrace();
788: }
789: }*/
790:
791: /**
792: * Output an an XMLC document object (DOM). The document is formatted
793: * according to it's type. The MIME type of the response is automatically
794: * set.
795: *
796: * @param outputFormat
797: * Object use to specify options controlling formatting of the
798: * document.
799: * @param doc
800: * The DOM object to be returned as response.
801: */
802: public void writeDOM(OutputOptions outputOptions, Node document)
803: throws HttpPresentationException {
804: try {
805: // Copy options so as to not modify when changing encoding.
806: OutputOptions options = new OutputOptions(outputOptions);
807:
808: setupEncoding(document, options);
809:
810: if (options.getMIMEType() != null
811: && options.getMIMEType().equals("text/html"))
812: options.addFreeformOption(
813: org.enhydra.util.DOMFormatter.FORMATTER_NAME,
814: new ExtHTMLFormatter(document, options, true));
815: else
816: options.addFreeformOption(
817: org.enhydra.util.DOMFormatter.FORMATTER_NAME,
818: new ExtXMLFormatter(document, options, true));
819:
820: // Enable encoding of session id in URL, if needed.
821: boolean encodeSessionKey = shouldEncodeSessionKey();
822: if (encodeSessionKey && options.getURLRewriter() == null) {
823: options.setURLRewriter(new URLRewriter() {
824: public String rewriteURL(String urlAttrValue) {
825: if (StandardAppUtil.pointsToPO(urlAttrValue)) {
826: return StandardAppUtil.encodeUrl(
827: urlAttrValue, sessionKey);
828: } else {
829: return urlAttrValue;
830: }
831: }
832: });
833: }
834:
835: // this ugly IE hack disabled by Petr Stehlik 2003/01/07
836: // since it's been causing problems in CSS pages.
837: // The hack was required for IE4 only, anyway..
838: /*
839: * if (document instanceof HTMLDocument) { // special, ugly hack for IE
840: * outputOptions.setDropHtmlSpanIds(true); }
841: */
842:
843: options.setEnableXHTMLCompatibility(true);
844:
845: outputDocument(document, options);
846: } catch (IOException except) {
847: throw new HttpPresentationException(except);
848: }
849: }
850:
851: /**
852: * Output an an XMLC document object (DOM). The document is formatted
853: * according to it's type. The MIME type of the response is automatically
854: * set.
855: *
856: * @param doc
857: * The DOM object to be returned as response.
858: */
859: public void writeDOM(Node document)
860: throws HttpPresentationException {
861:
862: OutputOptions outputOptions = null;
863:
864: if (document instanceof XMLObject)
865: outputOptions = createOutputOptions((XMLObject) document);
866: else
867: outputOptions = new OutputOptions();
868:
869: // this ugly IE hack disabled by Petr Stehlik 2003/01/07
870: // since it's been causing problems in CSS pages.
871: // The hack was required for IE4 only, anyway..
872: /*
873: if (document instanceof HTMLDocument) {
874: // special, ugly hack for IE
875: outputOptions.setDropHtmlSpanIds(true);
876: }
877: */
878:
879: outputOptions.setEnableXHTMLCompatibility(true);
880:
881: try {
882: outputDocument(document, outputOptions);
883: } catch (IOException except) {
884: throw new HttpPresentationException(except);
885: }
886: }
887:
888: /**
889: * Utility method to output an HTML page. The appropriate headers are
890: * set for MIME type and to disable caching of the HTML by the broswer.
891: */
892: public void writeHTML(String html) throws HttpPresentationException {
893: byte bytes[];
894:
895: // Determine encoding to use.
896: String mimeEncoding = null;
897: if (encoding != null) {
898: mimeEncoding = Encodings.getEncodings().getMIMEPreferred(
899: encoding);
900: if (mimeEncoding == null) {
901: mimeEncoding = encoding;
902: }
903: }
904:
905: try {
906: if (encoding != null) {
907: bytes = html.getBytes(encoding);
908: } else {
909: bytes = html.getBytes();
910: }
911: outputDocumentBytes(bytes, mimeEncoding, "text/html");
912: } catch (IOException except) {
913: throw new HttpPresentationException(except);
914: }
915: }
916:
917: /**
918: * Utility method to output an HTML page from a DOM object. The
919: * appropriate headers are set for MIME type and to disable caching
920: * of the HTML by the broswer.
921: *
922: * @param doc The DOM object to be returned as response
923: * @deprecated use writeDOM
924: */
925: public void writeHTML(HTMLDocument doc)
926: throws HttpPresentationException {
927: writeDOM((XMLObject) doc);
928: }
929: }
|