KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > module > sitemesh > filter > PageResponseWrapper


1 /* This software is published under the terms of the OpenSymphony Software
2  * License version 1.1, of which a copy has been included with this
3  * distribution in the LICENSE.txt file. */

4 package com.opensymphony.module.sitemesh.filter;
5
6 import com.opensymphony.module.sitemesh.Factory;
7 import com.opensymphony.module.sitemesh.Page;
8
9 import javax.servlet.ServletOutputStream JavaDoc;
10 import javax.servlet.http.HttpServletResponse JavaDoc;
11 import javax.servlet.http.HttpServletResponseWrapper JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.io.PrintWriter JavaDoc;
14
15 /**
16  * Implementation of HttpServletResponseWrapper that captures page data instead of
17  * sending to the writer.
18  *
19  * <p>Should be used in filter-chains or when forwarding/including pages
20  * using a RequestDispatcher.</p>
21  *
22  * @author <a HREF="mailto:joe@truemesh.com">Joe Walnes</a>
23  * @author <a HREF="mailto:scott@atlassian.com">Scott Farquhar</a>
24  * @version $Revision: 1.11 $
25  */

26 public final class PageResponseWrapper extends HttpServletResponseWrapper JavaDoc {
27
28     private final RoutablePrintWriter routablePrintWriter;
29     private final RoutableServletOutputStream routableServletOutputStream;
30     private final Factory factory;
31
32     private Buffer buffer;
33     private boolean aborted = false;
34     private boolean parseablePage = false;
35
36     public PageResponseWrapper(final HttpServletResponse JavaDoc response, Factory factory) {
37         super(response);
38         this.factory = factory;
39
40         routablePrintWriter = new RoutablePrintWriter(new RoutablePrintWriter.DestinationFactory() {
41             public PrintWriter JavaDoc activateDestination() throws IOException JavaDoc {
42                 return response.getWriter();
43             }
44         });
45         routableServletOutputStream = new RoutableServletOutputStream(new RoutableServletOutputStream.DestinationFactory() {
46             public ServletOutputStream JavaDoc create() throws IOException JavaDoc {
47                 return response.getOutputStream();
48             }
49         });
50     }
51
52     /**
53      * Set the content-type of the request and store it so it can
54      * be passed to the {@link com.opensymphony.module.sitemesh.PageParser}.
55      */

56     public void setContentType(String JavaDoc type) {
57         super.setContentType(type);
58
59         if (type != null) {
60             // this is the content type + charset. eg: text/html;charset=UTF-8
61
int offset = type.lastIndexOf("charset=");
62             String JavaDoc encoding = null;
63             if (offset != -1)
64                encoding = extractContentTypeValue(type, offset + 8);
65             String JavaDoc contentType = extractContentTypeValue(type, 0);
66
67             if (factory.shouldParsePage(contentType)) {
68                 activateSiteMesh(contentType, encoding);
69             }
70         }
71
72     }
73
74     private void activateSiteMesh(String JavaDoc contentType, String JavaDoc encoding) {
75         if (parseablePage) {
76             return; // already activated
77
}
78         parseablePage = true;
79         buffer = new Buffer(factory, contentType, encoding);
80         routablePrintWriter.updateDestination(new RoutablePrintWriter.DestinationFactory() {
81             public PrintWriter JavaDoc activateDestination() {
82                 return buffer.getWriter();
83             }
84         });
85         routableServletOutputStream.updateDestination(new RoutableServletOutputStream.DestinationFactory() {
86             public ServletOutputStream JavaDoc create() {
87                 return buffer.getOutputStream();
88             }
89         });
90     }
91
92     private String JavaDoc extractContentTypeValue(String JavaDoc type, int startIndex) {
93         if (startIndex < 0)
94             return null;
95
96         // Skip over any leading spaces
97
while (startIndex < type.length() && type.charAt(startIndex) == ' ')
98             startIndex++;
99
100         if (startIndex >= type.length())
101             return null;
102
103         int endIndex = startIndex;
104
105         if (type.charAt(startIndex) == '"') {
106             startIndex++;
107             endIndex = type.indexOf('"', startIndex);
108             if (endIndex == -1)
109                 endIndex = type.length();
110         } else {
111             // Scan through until we hit either the end of the string or a
112
// special character (as defined in RFC-2045). Note that we ignore '/'
113
// since we want to capture it as part of the value.
114
char ch;
115             while (endIndex < type.length() && (ch = type.charAt(endIndex)) != ' ' && ch != ';'
116                   && ch != '(' && ch != ')' && ch != '[' && ch != ']' && ch != '<' && ch != '>'
117                   && ch != ':' && ch != ',' && ch != '=' && ch != '?' && ch != '@' && ch!= '"'
118                   && ch !='\\')
119                endIndex++;
120         }
121         return type.substring(startIndex, endIndex);
122     }
123
124     /** Prevent content-length being set if page is parseable. */
125     public void setContentLength(int contentLength) {
126         if (!parseablePage) super.setContentLength(contentLength);
127     }
128
129     /** Prevent content-length being set if page is parseable. */
130     public void setHeader(String JavaDoc name, String JavaDoc value) {
131         if (name.toLowerCase().equals("content-type")) { // ensure ContentType is always set through setContentType()
132
setContentType(value);
133         } else if (!parseablePage || !name.toLowerCase().equals("content-length")) {
134             super.setHeader(name, value);
135         }
136     }
137
138     /** Prevent content-length being set if page is parseable. */
139     public void addHeader(String JavaDoc name, String JavaDoc value) {
140         if (name.toLowerCase().equals("content-type")) { // ensure ContentType is always set through setContentType()
141
setContentType(value);
142         } else if (!parseablePage || !name.toLowerCase().equals("content-length")) {
143             super.addHeader(name, value);
144         }
145     }
146
147     /**
148      * Prevent 'not modified' (304) HTTP status from being sent if page is parseable
149      * (so web-server/browser doesn't cache contents).
150      */

151     public void setStatus(int sc) {
152         if (!parseablePage || sc != HttpServletResponse.SC_NOT_MODIFIED) {
153             super.setStatus(sc);
154         }
155     }
156
157     public ServletOutputStream JavaDoc getOutputStream() {
158         return routableServletOutputStream;
159     }
160
161     public PrintWriter JavaDoc getWriter() {
162         return routablePrintWriter;
163     }
164
165     public Page getPage() throws IOException JavaDoc {
166         if (aborted || !parseablePage) {
167             return null;
168         } else {
169             return buffer.parse();
170         }
171     }
172
173     public void sendError(int sc) throws IOException JavaDoc {
174         aborted = true;
175         super.sendError(sc);
176     }
177
178     public void sendError(int sc, String JavaDoc msg) throws IOException JavaDoc {
179         aborted = true;
180         super.sendError(sc, msg);
181     }
182
183     public void sendRedirect(String JavaDoc location) throws IOException JavaDoc {
184         aborted = true;
185         super.sendRedirect(location);
186     }
187
188     public boolean isUsingStream() {
189         return buffer != null && buffer.isUsingStream();
190     }
191 }
Popular Tags