KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > GenericResponseWrapper


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util;
11 import java.io.*;
12
13 import javax.servlet.*;
14 import javax.servlet.http.*;
15
16 import java.util.Locale JavaDoc;
17 import java.util.regex.*;
18
19 import org.mmbase.util.logging.Logger;
20 import org.mmbase.util.logging.Logging;
21
22 /**
23  * Wrapper around the response. It collects all data that is sent to it, and makes it available
24  * through a toString() method. It is used by taglib's Include-Tag, but it might find more general
25  * use, outside taglib.
26  *
27  * @author Kees Jongenburger
28  * @author Johannes Verelst
29  * @author Michiel Meeuwissen
30  * @since MMBase-1.7
31  * @version $Id: GenericResponseWrapper.java,v 1.17.2.1 2006/09/18 11:39:48 johannes Exp $
32  */

33 public class GenericResponseWrapper extends HttpServletResponseWrapper {
34     private static final Logger log = Logging.getLoggerInstance(GenericResponseWrapper.class);
35
36     /**
37      * If this pattern matched the first line of an InputStream then it is a XML. The encoding is in
38      * matching group 1 (when using " as quote) or 2 (when using ' as quote)
39      */

40     private static final Pattern XMLHEADER = Pattern.compile("<\\?xml.*?(?:\\sencoding=(?:\"([^\"]+?)\"|'([^']+?)'))?\\s*\\?>.*", Pattern.DOTALL);
41
42
43     private static String JavaDoc UNSET_CHARSET = "iso-8859-1";
44     public static String JavaDoc TEXT_XML_DEFAULT_CHARSET = "US-ASCII";
45
46     private static String JavaDoc DEFAULT_CONTENTTYPE = "text/html";
47
48     private static String JavaDoc[] IGNORED_HEADERS = new String JavaDoc[]{"Last-Modified", "ETag"};
49
50     private PrintWriter writer;
51     private StringWriter string; // wrapped by writer
52

53     private ServletOutputStream outputStream; // wrapped by outputStream
54
private ByteArrayOutputStream bytes;
55
56     private String JavaDoc contentType = DEFAULT_CONTENTTYPE;
57     private String JavaDoc characterEncoding = UNSET_CHARSET;
58
59     private HttpServletResponse wrappedResponse;
60
61     /**
62      * Public constructor
63      */

64     public GenericResponseWrapper(HttpServletResponse resp) {
65         super(resp);
66         wrappedResponse = resp; // I don't understand why this object is not super.getResponse();
67

68     }
69     /**
70      * Sets also a value for the characterEncoding which must be supposed.
71      * Normally it would be determined automaticly right, but if for some reason it doesn't you can override it.
72      */

73     public GenericResponseWrapper(HttpServletResponse resp, String JavaDoc encoding) {
74         this(resp);
75         characterEncoding = encoding;
76         wrappedResponse = resp; //
77
}
78
79
80     /**
81      * Gets the response object which this wrapper is wrapping. You might need this when giving a
82      * redirect or so.
83      * @since MMBase-1.7.1
84      */

85     public HttpServletResponse getHttpServletResponse() {
86         //return (HttpServletResponse) getResponse(); // shoudl work, I think, but doesn't
87
HttpServletResponse response = wrappedResponse;
88         while (response instanceof GenericResponseWrapper) { // if this happens in an 'mm:included' page.
89
response = ((GenericResponseWrapper) response).wrappedResponse;
90         }
91         return response;
92     }
93
94     private boolean mayAddHeader(String JavaDoc header) {
95         for (int i=0; i<IGNORED_HEADERS.length; i++) {
96             if (IGNORED_HEADERS[i].equalsIgnoreCase(header)) {
97                 return false;
98             }
99         }
100         return true;
101     }
102
103     public void sendRedirect(String JavaDoc location) throws IOException {
104         getHttpServletResponse().sendRedirect(location);
105     }
106
107     public void setStatus(int s) {
108         getHttpServletResponse().setStatus(s);
109     }
110
111     public void addCookie(Cookie c) {
112         getHttpServletResponse().addCookie(c);
113     }
114
115     public void setHeader(String JavaDoc header, String JavaDoc value) {
116         if (mayAddHeader(header)) {
117             getHttpServletResponse().setHeader(header,value);
118         }
119     }
120     
121     /**
122      * @see javax.servlet.http.HttpServletResponse#addDateHeader(java.lang.String, long)
123      */

124     public void addDateHeader(String JavaDoc arg0, long arg1) {
125         if (mayAddHeader(arg0)) {
126             getHttpServletResponse().addDateHeader(arg0, arg1);
127         }
128     }
129
130     /**
131      * @see javax.servlet.http.HttpServletResponse#addHeader(java.lang.String, java.lang.String)
132      */

133     public void addHeader(String JavaDoc arg0, String JavaDoc arg1) {
134         if (mayAddHeader(arg0)) {
135             getHttpServletResponse().addHeader(arg0, arg1);
136         }
137     }
138     
139     /**
140      * @see javax.servlet.http.HttpServletResponse#addIntHeader(java.lang.String, int)
141      */

142     public void addIntHeader(String JavaDoc arg0, int arg1) {
143         if (mayAddHeader(arg0)) {
144             getHttpServletResponse().addIntHeader(arg0, arg1);
145         }
146     }
147     /**
148      * @see javax.servlet.http.HttpServletResponse#containsHeader(java.lang.String)
149      */

150     public boolean containsHeader(String JavaDoc arg0) {
151         return getHttpServletResponse().containsHeader(arg0);
152     }
153     /**
154      * @see javax.servlet.http.HttpServletResponse#encodeRedirectURL(java.lang.String)
155      */

156     public String JavaDoc encodeRedirectURL(String JavaDoc arg0) {
157         return getHttpServletResponse().encodeRedirectURL(arg0);
158     }
159     /**
160      * @see javax.servlet.http.HttpServletResponse#encodeURL(java.lang.String)
161      */

162     public String JavaDoc encodeURL(String JavaDoc arg0) {
163         return getHttpServletResponse().encodeURL(arg0);
164     }
165     /**
166      * @see javax.servlet.ServletResponse#getLocale()
167      */

168     public Locale JavaDoc getLocale() {
169         return getHttpServletResponse().getLocale();
170     }
171     /**
172      * @see javax.servlet.http.HttpServletResponse#sendError(int, java.lang.String)
173      */

174     public void sendError(int arg0, String JavaDoc arg1) throws IOException {
175         getHttpServletResponse().sendError(arg0, arg1);
176     }
177     /**
178      * @see javax.servlet.http.HttpServletResponse#sendError(int)
179      */

180     public void sendError(int arg0) throws IOException {
181         getHttpServletResponse().sendError(arg0);
182     }
183     /**
184      * @see javax.servlet.http.HttpServletResponse#setDateHeader(java.lang.String, long)
185      */

186     public void setDateHeader(String JavaDoc arg0, long arg1) {
187         if (mayAddHeader(arg0)) {
188             getHttpServletResponse().setDateHeader(arg0, arg1);
189         }
190     }
191     /**
192      * @see javax.servlet.http.HttpServletResponse#setIntHeader(java.lang.String, int)
193      */

194     public void setIntHeader(String JavaDoc arg0, int arg1) {
195         if (mayAddHeader(arg0)) {
196             getHttpServletResponse().setIntHeader(arg0, arg1);
197         }
198     }
199     /**
200      * @see javax.servlet.ServletResponse#setLocale(java.util.Locale)
201      */

202     public void setLocale(Locale JavaDoc arg0) {
203         getHttpServletResponse().setLocale(arg0);
204     }
205
206     /**
207      * Return the OutputStream. This is a 'MyServletOutputStream'.
208      */

209     public ServletOutputStream getOutputStream() throws IOException {
210         if (writer != null) {
211             throw new RuntimeException JavaDoc("Should use getOutputStream _or_ getWriter");
212         }
213         if (outputStream == null) {
214             bytes = new ByteArrayOutputStream();
215             outputStream = new MyServletOutputStream(bytes);
216         }
217         return outputStream;
218     }
219
220     /**
221      * Return the PrintWriter
222      */

223     public PrintWriter getWriter() throws IOException {
224         if (outputStream != null) {
225             throw new RuntimeException JavaDoc("Should use getOutputStream _or_ getWriter");
226         }
227         if (writer == null) {
228             string = new StringWriter();
229             writer = new PrintWriter(string);
230         }
231         return writer;
232     }
233
234     /**
235      * Sets the content type of the response being sent to the
236      * client. The content type may include the type of character
237      * encoding used, for example, text/html; charset=ISO-8859-4. If
238      * obtaining a PrintWriter, this method should be called first.
239      */

240     public void setContentType(String JavaDoc ct) {
241         if (ct == null) {
242             contentType = DEFAULT_CONTENTTYPE;
243         } else {
244             contentType = ct;
245             characterEncoding = getEncoding(ct); // gets char-encoding from content type
246
if (characterEncoding == null) {
247                 characterEncoding = getDefaultEncoding(contentType);
248             }
249         }
250
251         if (log.isDebugEnabled()) {
252             log.debug("set contenttype of include page to: '" + contentType + "' (and character encoding to '" + characterEncoding + "')");
253         }
254     }
255
256     /**
257      * Returns the name of the charset used for the MIME body sent in this response.
258      * If no charset has been assigned, it is implicitly set to ISO-8859-1 (Latin-1).
259      * See <a HREF="http://www.ietf.org/rfc/rfc2047.txt">RFC 2047</a> for more information about character encoding and MIME.
260      * returns the encoding
261      */

262     public String JavaDoc getCharacterEncoding() {
263         log.debug(characterEncoding);
264         /*
265         if (characterEncoding == UNSET_CHARSET && outputStream != null) {
266             determinXMLEncoding();
267         }
268         */

269         return characterEncoding;
270     }
271
272     protected byte[] determinXMLEncoding() {
273         byte[] allBytes = bytes.toByteArray();
274         characterEncoding = getXMLEncoding(allBytes);
275         if (characterEncoding == null) characterEncoding = "UTF-8"; // missing <?xml header, but we _know_ it is XML.
276
return allBytes;
277     }
278
279     /**
280      * Return all data that has been written to the PrintWriter.
281      */

282     public String JavaDoc toString() {
283         if (writer != null) {
284             return string.toString();
285         } else if (outputStream != null) {
286             try {
287                 byte[] allBytes;
288                 if (TEXT_XML_DEFAULT_CHARSET.equals(characterEncoding)) {
289                     // see comments in getDefaultEncoding
290
allBytes = determinXMLEncoding();
291                 } else {
292                     allBytes = bytes.toByteArray();
293                 }
294                 return new String JavaDoc(allBytes, getCharacterEncoding());
295             } catch (Exception JavaDoc e) {
296                 return bytes.toString();
297             }
298         } else {
299             return "";
300         }
301     }
302
303     /**
304      * Takes a String, which is considered to be (the first) part of an XML, and returns the
305      * encoding (the specified one, or the XML default)
306      * @return The XML Encoding, or <code>null</code> if the String was not recognized as XML (no &lt;?xml&gt; header found)
307      * @since MMBase-1.7.1
308      * @see #getXMLEncoding(byte[])
309      */

310     public static final String JavaDoc getXMLEncoding(String JavaDoc xmlString) {
311         Matcher m = XMLHEADER.matcher(xmlString);
312         if (! m.matches()) {
313             return null; // No <? xml header found, this file is probably not XML.
314
} else {
315             String JavaDoc encoding = m.group(1);
316             if (encoding == null) encoding = m.group(2);
317             if (encoding == null) encoding = "UTF-8"; // default encoding for XML.
318
return encoding;
319         }
320     }
321
322     /**
323      * Takes a ByteArrayInputStream, which is considered to be (the first) part of an XML, and returns the encoding.
324      * @return The XML Encoding, or <code>null</code> if the String was not recognized as XML (not &lt;?xml&gt; header found)
325      * @since MMBase-1.7.1
326      * @see #getXMLEncoding(String)
327      */

328     public static String JavaDoc getXMLEncoding(byte[] allBytes) {
329         byte[] firstBytes = allBytes;
330         if (allBytes.length > 100) {
331             firstBytes = new byte[100];
332             System.arraycopy(allBytes, 0, firstBytes, 0, 100);
333         }
334         try {
335             return getXMLEncoding(new String JavaDoc(firstBytes, "US-ASCII"));
336         } catch (java.io.UnsupportedEncodingException JavaDoc uee) {
337             // cannot happen, US-ASCII is known
338
}
339         return "UTF-8"; // cannot come here.
340
}
341
342     /**
343      * Takes the value of a Content-Type header, and tries to find the encoding from it.
344      * @since MMBase-1.7.1
345      * @return The found charset if found, otherwise 'null'
346      */

347     public static String JavaDoc getEncoding(String JavaDoc contentType) {
348         String JavaDoc contentTypeLowerCase = contentType.toLowerCase();
349         int cs = contentTypeLowerCase.indexOf("charset=");
350         if (cs > 0) {
351             return contentType.substring(cs + 8);
352         } else {
353             return null;
354         }
355     }
356
357     /**
358      * Supposes that no explicit charset is mentioned in a contentType, and returns a default. (UTF-8 or US-ASCII
359      * for XML types and ISO-8859-1 otherwise).
360      * @since MMBase-1.7.1
361      * @return A charset.
362      */

363     public static String JavaDoc getDefaultEncoding(String JavaDoc contentType) {
364         if (contentType.equals("text/xml")) {
365             return TEXT_XML_DEFAULT_CHARSET; // = us-ascii, See
366
// http://www.rfc-editor.org/rfc/rfc3023.txt. We will
367
// ignore it, because if not not ascii, it will never
368
// work, and all known charset are superset of us-ascii
369
// (so the response _is_ correct it will work).
370
} else if ( contentType.equals("application/xml") || contentType.equals("application/xhtml+xml")) {
371             return "UTF-8";
372         } else {
373             return "iso-8859-1";
374         }
375
376     }
377 }
378
379 /**
380  * Implements ServletOutputStream.
381  */

382 class MyServletOutputStream extends ServletOutputStream {
383
384     private OutputStream stream;
385
386     public MyServletOutputStream(OutputStream output) {
387         stream = output;
388     }
389
390     public void write(int b) throws IOException {
391         stream.write(b);
392     }
393
394     public void write(byte[] b) throws IOException {
395         stream.write(b);
396     }
397
398     public void write(byte[] b, int off, int len) throws IOException {
399         stream.write(b, off, len);
400     }
401 }
402
403
Popular Tags