KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > velocity > tools > view > servlet > VelocityViewServlet


1 /*
2  * Copyright 2003 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.velocity.tools.view.servlet;
18
19
20 import java.io.IOException JavaDoc;
21 import java.io.OutputStreamWriter JavaDoc;
22 import java.io.PrintWriter JavaDoc;
23 import java.io.StringWriter JavaDoc;
24 import java.io.UnsupportedEncodingException JavaDoc;
25 import java.io.Writer JavaDoc;
26
27 import javax.servlet.ServletConfig JavaDoc;
28 import javax.servlet.ServletContext JavaDoc;
29 import javax.servlet.ServletException JavaDoc;
30 import javax.servlet.http.HttpServlet JavaDoc;
31 import javax.servlet.http.HttpServletRequest JavaDoc;
32 import javax.servlet.http.HttpServletResponse JavaDoc;
33
34 import org.apache.commons.collections.ExtendedProperties;
35
36 import org.apache.velocity.Template;
37 import org.apache.velocity.app.Velocity;
38 import org.apache.velocity.context.Context;
39 import org.apache.velocity.exception.ResourceNotFoundException;
40 import org.apache.velocity.exception.ParseErrorException;
41 import org.apache.velocity.exception.MethodInvocationException;
42 import org.apache.velocity.io.VelocityWriter;
43 import org.apache.velocity.runtime.RuntimeConstants;
44 import org.apache.velocity.runtime.RuntimeSingleton;
45 import org.apache.velocity.util.SimplePool;
46
47 import org.apache.velocity.tools.view.ToolboxManager;
48 import org.apache.velocity.tools.view.context.ToolboxContext;
49 import org.apache.velocity.tools.view.context.ChainedContext;
50 import org.apache.velocity.tools.view.servlet.ServletToolboxManager;
51 import org.apache.velocity.tools.view.servlet.WebappLoader;
52
53
54 /**
55  * <p>A servlet to process Velocity templates. This is comparable to the
56  * the JspServlet for JSP-based applications.</p>
57  *
58  * <p>The servlet provides the following features:</p>
59  * <ul>
60  * <li>renders Velocity templates</li>
61  * <li>provides support for an auto-loaded, configurable toolbox</li>
62  * <li>provides transparent access to the servlet request attributes,
63  * servlet session attributes and servlet context attributes by
64  * auto-searching them</li>
65  * <li>logs to the logging facility of the servlet API</li>
66  * </ul>
67  *
68  * <p>VelocityViewServlet supports the following configuration parameters
69  * in web.xml:</p>
70  * <dl>
71  * <dt>org.apache.velocity.toolbox</dt>
72  * <dd>Path and name of the toolbox configuration file. The path must be
73  * relative to the web application root directory. If this parameter is
74  * not found, no toolbox is instantiated.</dd>
75  * <dt>org.apache.velocity.properties</dt>
76  * <dd>Path and name of the Velocity configuration file. The path must be
77  * relative to the web application root directory. If this parameter
78  * is not present, Velocity is initialized with default settings.</dd>
79  * </dl>
80  *
81  * <p>There are methods you may wish to override to access, alter or control
82  * any part of the request processing chain. Please see the javadocs for
83  * more information on :
84  * <ul>
85  * <li> {@link #loadConfiguration} : <br>for loading Velocity properties and
86  * configuring the Velocity runtime
87  * <li> {@link #setContentType} : <br>for changing the content type on a request
88  * by request basis
89  * <li> {@link #requestCleanup} : <br>post rendering resource or other cleanup
90  * <li> {@link #error} : <br>error handling
91  * </ul>
92  * </p>
93  *
94  * @author Dave Bryson
95  * @author <a HREF="mailto:jon@latchkey.com">Jon S. Stevens</a>
96  * @author <a HREF="mailto:sidler@teamup.com">Gabe Sidler</a>
97  * @author <a HREF="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
98  * @author <a HREF="mailto:kjohnson@transparent.com">Kent Johnson</a>
99  * @author <a HREF="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
100  * @author <a HREF="mailto:nathan@esha.com">Nathan Bubna</a>
101  *
102  * @version $Id: VelocityViewServlet.java,v 1.20.2.1 2004/03/12 20:16:28 nbubna Exp $
103  */

104
105 public class VelocityViewServlet extends HttpServlet JavaDoc
106 {
107
108     /** The HTTP content type context key. */
109     public static final String JavaDoc CONTENT_TYPE = "default.contentType";
110
111     /** The default content type for the response */
112     public static final String JavaDoc DEFAULT_CONTENT_TYPE = "text/html";
113   
114     /** Default encoding for the output stream */
115     public static final String JavaDoc DEFAULT_OUTPUT_ENCODING = "ISO-8859-1";
116
117     /**
118      * Key used to access the ServletContext in
119      * the Velocity application attributes.
120      */

121     public static final String JavaDoc SERVLET_CONTEXT_KEY =
122         ServletContext JavaDoc.class.getName();
123
124
125     /**
126      * Key used to access the toolbox configuration file path from the
127      * Servlet or webapp init parameters ("org.apache.velocity.toolbox").
128      */

129     protected static final String JavaDoc TOOLBOX_KEY =
130         "org.apache.velocity.toolbox";
131
132     /**
133      * This is the string that is looked for when getInitParameter is
134      * called ("org.apache.velocity.properties").
135      */

136     protected static final String JavaDoc INIT_PROPS_KEY =
137         "org.apache.velocity.properties";
138
139     /** A reference to the toolbox manager. */
140     protected ToolboxManager toolboxManager = null;
141
142
143     /** Cache of writers */
144     private static SimplePool writerPool = new SimplePool(40);
145
146     /**
147      * The default content type. When necessary, includes the
148      * character set to use when encoding textual output.
149      */

150     private String JavaDoc defaultContentType;
151
152     /**
153      * Whether we've logged a deprecation warning for
154      * ServletResponse's <code>getOutputStream()</code>.
155      * @since VelocityTools 1.1
156      */

157     private boolean warnOfOutputStreamDeprecation = true;
158
159
160     /**
161      * <p>Initializes servlet, toolbox and Velocity template engine.
162      * Called by the servlet container on loading.</p>
163      *
164      * @param config servlet configuation
165      */

166     public void init(ServletConfig JavaDoc config) throws ServletException JavaDoc
167     {
168         super.init(config);
169
170         // do whatever we have to do to init Velocity
171
initVelocity(config);
172
173         // init this servlet's toolbox (if any)
174
initToolbox(config);
175
176         // we can get these now that velocity is initialized
177
defaultContentType =
178             RuntimeSingleton.getString(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
179
180         String JavaDoc encoding =
181             RuntimeSingleton.getString(RuntimeSingleton.OUTPUT_ENCODING,
182                                        DEFAULT_OUTPUT_ENCODING);
183
184         // For non Latin-1 encodings, ensure that the charset is
185
// included in the Content-Type header.
186
if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding))
187         {
188             int index = defaultContentType.lastIndexOf("charset");
189             if (index < 0)
190             {
191                 // the charset specifier is not yet present in header.
192
// append character encoding to default content-type
193
defaultContentType += "; charset=" + encoding;
194             }
195             else
196             {
197                 // The user may have configuration issues.
198
Velocity.warn("VelocityViewServlet: Charset was already " +
199                               "specified in the Content-Type property. " +
200                               "Output encoding property will be ignored.");
201             }
202         }
203
204         Velocity.info("VelocityViewServlet: Default content-type is: " +
205                       defaultContentType);
206     }
207
208
209     /**
210      * Initializes the ServletToolboxManager for this servlet's
211      * toolbox (if any).
212      *
213      * @param config servlet configuation
214      */

215     protected void initToolbox(ServletConfig JavaDoc config) throws ServletException JavaDoc
216     {
217         ServletContext JavaDoc servletContext = config.getServletContext();
218
219         /* check the servlet config for a toolbox */
220         String JavaDoc file = config.getInitParameter(TOOLBOX_KEY);
221
222         /* check the servlet context for a toolbox */
223         if (file == null || file.length() == 0)
224         {
225             file = servletContext.getInitParameter(TOOLBOX_KEY);
226         }
227
228         /* if we have a toolbox, get a manager for it */
229         if (file != null)
230         {
231             toolboxManager =
232                 ServletToolboxManager.getInstance(servletContext, file);
233         }
234         else
235         {
236             Velocity.info("VelocityViewServlet: No toolbox entry in configuration.");
237         }
238     }
239
240
241     /**
242      * Initializes the Velocity runtime, first calling
243      * loadConfiguration(ServletConfig) to get a
244      * org.apache.commons.collections.ExtendedProperties
245      * of configuration information
246      * and then calling Velocity.init(). Override this
247      * to do anything to the environment before the
248      * initialization of the singleton takes place, or to
249      * initialize the singleton in other ways.
250      *
251      * @param config servlet configuration parameters
252      */

253     protected void initVelocity(ServletConfig JavaDoc config) throws ServletException JavaDoc
254     {
255         Velocity.setApplicationAttribute(SERVLET_CONTEXT_KEY, getServletContext());
256
257         // default to servletlogger, which logs to the servlet engines log
258
Velocity.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
259                              ServletLogger.class.getName());
260
261         // by default, load resources with webapp resource loader
262
Velocity.setProperty(RuntimeConstants.RESOURCE_LOADER, "webapp");
263         Velocity.setProperty("webapp.resource.loader.class",
264                              WebappLoader.class.getName());
265
266         // Try reading an overriding Velocity configuration
267
try
268         {
269             ExtendedProperties p = loadConfiguration(config);
270             Velocity.setExtendedProperties(p);
271         }
272         catch(Exception JavaDoc e)
273         {
274             getServletContext().log("VelocityViewServlet: Unable to read Velocity configuration file: "+e);
275             getServletContext().log("VelocityViewServlet: Using default Velocity configuration.");
276         }
277
278         // now all is ready - init Velocity
279
try
280         {
281             Velocity.init();
282         }
283         catch(Exception JavaDoc e)
284         {
285             getServletContext().log("VelocityViewServlet: PANIC! unable to init() - "+e);
286             throw new ServletException JavaDoc(e);
287         }
288     }
289
290      
291     /**
292      * Loads the configuration information and returns that
293      * information as an ExtendedProperties, which will be used to
294      * initialize the Velocity runtime.
295      * <br><br>
296      * Currently, this method gets the initialization parameter
297      * VelocityServlet.INIT_PROPS_KEY, which should be a file containing
298      * the configuration information.
299      * <br><br>
300      * To configure your Servlet Spec 2.2 compliant servlet runner to pass
301      * this to you, put the following in your WEB-INF/web.xml file
302      * <br>
303      * <pre>
304      * &lt;servlet&gt;
305      * &lt;servlet-name&gt; YourServlet &lt/servlet-name&gt;
306      * &lt;servlet-class&gt; your.package.YourServlet &lt;/servlet-class&gt;
307      * &lt;init-param&gt;
308      * &lt;param-name&gt; org.apache.velocity.properties &lt;/param-name&gt;
309      * &lt;param-value&gt; velocity.properties &lt;/param-value&gt;
310      * &lt;/init-param&gt;
311      * &lt;/servlet&gt;
312      * </pre>
313      *
314      * Alternately, if you wish to configure an entire context in this
315      * fashion, you may use the following:
316      * <br>
317      * <pre>
318      * &lt;context-param&gt;
319      * &lt;param-name&gt; org.apache.velocity.properties &lt;/param-name&gt;
320      * &lt;param-value&gt; velocity.properties &lt;/param-value&gt;
321      * &lt;description&gt; Path to Velocity configuration &lt;/description&gt;
322      * &lt;/context-param&gt;
323      * </pre>
324      *
325      * Derived classes may do the same, or take advantage of this code to do the loading for them via :
326      * <pre>
327      * ExtendedProperties p = super.loadConfiguration(config);
328      * </pre>
329      * and then add or modify the configuration values from the file.
330      * <br>
331      *
332      * @param config ServletConfig passed to the servlets init() function
333      * Can be used to access the real path via ServletContext (hint)
334      * @return ExtendedProperties loaded with configuration values to be used
335      * to initialize the Velocity runtime.
336      * @throws IOException I/O problem accessing the specified file, if specified.
337      */

338     protected ExtendedProperties loadConfiguration(ServletConfig JavaDoc config)
339         throws IOException JavaDoc
340     {
341         ServletContext JavaDoc servletContext = config.getServletContext();
342
343         // grab the path to the custom props file (if any)
344
String JavaDoc propsFile = config.getInitParameter(INIT_PROPS_KEY);
345         if (propsFile == null || propsFile.length() == 0)
346         {
347             propsFile = servletContext.getInitParameter(INIT_PROPS_KEY);
348         }
349         
350         ExtendedProperties p = new ExtendedProperties();
351         if (propsFile != null)
352         {
353             p.load(servletContext.getResourceAsStream(propsFile));
354
355             Velocity.info("VelocityViewServlet: Custom Properties File: "+propsFile);
356         }
357         else
358         {
359             Velocity.info("VelocityViewServlet: No custom properties found. " +
360                           "Using default Velocity configuration.");
361         }
362
363         return p;
364     }
365
366           
367     /**
368      * Handles GET - calls doRequest()
369      */

370     public void doGet(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
371         throws ServletException JavaDoc, IOException JavaDoc
372     {
373         doRequest(request, response);
374     }
375
376
377     /**
378      * Handle a POST request - calls doRequest()
379      */

380     public void doPost(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
381         throws ServletException JavaDoc, IOException JavaDoc
382     {
383         doRequest(request, response);
384     }
385
386
387     /**
388      * Handles with both GET and POST requests
389      *
390      * @param request HttpServletRequest object containing client request
391      * @param response HttpServletResponse object for the response
392      */

393     protected void doRequest(HttpServletRequest JavaDoc request,
394                              HttpServletResponse JavaDoc response)
395          throws ServletException JavaDoc, IOException JavaDoc
396     {
397         Context JavaDoc context = null;
398         try
399         {
400             // first, get a context
401
context = createContext(request, response);
402             
403             // set the content type
404
setContentType(request, response);
405
406             // get the template
407
Template template = handleRequest(request, response, context);
408
409             // bail if we can't find the template
410
if (template == null)
411             {
412                 Velocity.warn("VelocityViewServlet: couldn't find template to match request.");
413                 return;
414             }
415
416             // merge the template and context
417
mergeTemplate(template, context, response);
418         }
419         catch (Exception JavaDoc e)
420         {
421             // log the exception
422
Velocity.error("VelocityViewServlet: Exception processing the template: "+e);
423
424             // call the error handler to let the derived class
425
// do something useful with this failure.
426
error(request, response, e);
427         }
428         finally
429         {
430             // call cleanup routine to let a derived class do some cleanup
431
requestCleanup(request, response, context);
432         }
433     }
434
435
436     /**
437      * Cleanup routine called at the end of the request processing sequence
438      * allows a derived class to do resource cleanup or other end of
439      * process cycle tasks. This default implementation does nothing.
440      *
441      * @param request servlet request from client
442      * @param response servlet reponse
443      * @param context Context created by the {@link #createContext}
444      */

445     protected void requestCleanup(HttpServletRequest JavaDoc request,
446                                   HttpServletResponse JavaDoc response,
447                                   Context JavaDoc context)
448     {
449     }
450
451
452     /**
453      * <p>Handle the template processing request.</p>
454      *
455      * @param request client request
456      * @param response client response
457      * @param ctx VelocityContext to fill
458      *
459      * @return Velocity Template object or null
460      */

461     protected Template handleRequest(HttpServletRequest JavaDoc request,
462                                      HttpServletResponse JavaDoc response,
463                                      Context JavaDoc ctx)
464         throws Exception JavaDoc
465     {
466         // If we get here from RequestDispatcher.include(), getServletPath()
467
// will return the original (wrong) URI requested. The following special
468
// attribute holds the correct path. See section 8.3 of the Servlet
469
// 2.3 specification.
470
String JavaDoc path = (String JavaDoc)request.getAttribute("javax.servlet.include.servlet_path");
471         if (path == null)
472         {
473             path = request.getServletPath();
474         }
475         return getTemplate(path);
476     }
477
478
479     /**
480      * Sets the content type of the response. This is available to be overriden
481      * by a derived class.
482      *
483      * <p>The default implementation is :
484      * <pre>
485      *
486      * response.setContentType(defaultContentType);
487      *
488      * </pre>
489      * where defaultContentType is set to the value of the default.contentType
490      * property, or "text/html" if that is not set.</p>
491      *
492      * @param request servlet request from client
493      * @param response servlet reponse to client
494      */

495     protected void setContentType(HttpServletRequest JavaDoc request,
496                                   HttpServletResponse JavaDoc response)
497     {
498         response.setContentType(defaultContentType);
499     }
500
501
502     /**
503      * <p>Creates and returns an initialized Velocity context.</p>
504      *
505      * A new context of class {@link ChainedContext} is created and
506      * initialized.
507      *
508      * @param request servlet request from client
509      * @param response servlet reponse to client
510      */

511     protected Context JavaDoc createContext(HttpServletRequest JavaDoc request,
512                                     HttpServletResponse JavaDoc response)
513     {
514         ChainedContext ctx = new ChainedContext(null, request, response, getServletContext());
515
516         /* if we have a toolbox manager, get a toolbox from it */
517         if (toolboxManager != null)
518         {
519             ctx.setToolbox(toolboxManager.getToolboxContext(ctx));
520         }
521         return ctx;
522     }
523
524
525     /**
526      * Retrieves the requested template.
527      *
528      * @param name The file name of the template to retrieve relative to the
529      * template root.
530      * @return The requested template.
531      * @throws ResourceNotFoundException if template not found
532      * from any available source.
533      * @throws ParseErrorException if template cannot be parsed due
534      * to syntax (or other) error.
535      * @throws Exception if an error occurs in template initialization
536      */

537     public Template getTemplate(String JavaDoc name)
538         throws ResourceNotFoundException, ParseErrorException, Exception JavaDoc
539     {
540         return RuntimeSingleton.getTemplate(name);
541     }
542
543     
544     /**
545      * Retrieves the requested template with the specified character encoding.
546      *
547      * @param name The file name of the template to retrieve relative to the
548      * template root.
549      * @param encoding the character encoding of the template
550      * @return The requested template.
551      * @throws ResourceNotFoundException if template not found
552      * from any available source.
553      * @throws ParseErrorException if template cannot be parsed due
554      * to syntax (or other) error.
555      * @throws Exception if an error occurs in template initialization
556      */

557     public Template getTemplate(String JavaDoc name, String JavaDoc encoding)
558         throws ResourceNotFoundException, ParseErrorException, Exception JavaDoc
559     {
560         return RuntimeSingleton.getTemplate(name, encoding);
561     }
562
563
564     /**
565      * Merges the template with the context. Only override this if you really, really
566      * really need to. (And don't call us with questions if it breaks :)
567      *
568      * @param template template object returned by the handleRequest() method
569      * @param context Context created by the {@link #createContext}
570      * @param response servlet reponse (used to get a Writer)
571      */

572     protected void mergeTemplate(Template template,
573                                  Context JavaDoc context,
574                                  HttpServletResponse JavaDoc response)
575         throws ResourceNotFoundException, ParseErrorException,
576                MethodInvocationException, IOException JavaDoc,
577                UnsupportedEncodingException JavaDoc, Exception JavaDoc
578     {
579         VelocityWriter vw = null;
580         Writer JavaDoc writer = getResponseWriter(response);
581         try
582         {
583             vw = (VelocityWriter)writerPool.get();
584             if (vw == null)
585             {
586                 vw = new VelocityWriter(writer, 4 * 1024, true);
587             }
588             else
589             {
590                 vw.recycle(writer);
591             }
592             template.merge(context, vw);
593         }
594         finally
595         {
596             if (vw != null)
597             {
598                 try
599                 {
600                     // flush and put back into the pool
601
// don't close to allow us to play
602
// nicely with others.
603
vw.flush();
604                     /* This hack sets the VelocityWriter's internal ref to the
605                      * PrintWriter to null to keep memory free while
606                      * the writer is pooled. See bug report #18951 */

607                     vw.recycle(null);
608                     writerPool.put(vw);
609                 }
610                 catch (Exception JavaDoc e)
611                 {
612                     Velocity.debug("VelocityViewServlet: " +
613                                    "Trouble releasing VelocityWriter: " +
614                                    e.getMessage());
615                 }
616             }
617         }
618     }
619
620  
621     /**
622      * Invoked when there is an error thrown in any part of doRequest() processing.
623      * <br><br>
624      * Default will send a simple HTML response indicating there was a problem.
625      *
626      * @param request original HttpServletRequest from servlet container.
627      * @param response HttpServletResponse object from servlet container.
628      * @param e Exception that was thrown by some other part of process.
629      */

630     protected void error(HttpServletRequest JavaDoc request,
631                          HttpServletResponse JavaDoc response,
632                          Exception JavaDoc e)
633         throws ServletException JavaDoc
634     {
635         try
636         {
637             StringBuffer JavaDoc html = new StringBuffer JavaDoc();
638             html.append("<html>\n");
639             html.append("<head><title>Error</title></head>\n");
640             html.append("<body>\n");
641             html.append("<h2>VelocityViewServlet : Error processing the template</h2>\n");
642
643             Throwable JavaDoc cause = e;
644
645             String JavaDoc why = cause.getMessage();
646             if (why != null && why.trim().length() > 0)
647             {
648                 html.append(why);
649                 html.append("\n<br>\n");
650             }
651
652             // if it's an MIE, i want the real stack trace!
653
if (cause instanceof MethodInvocationException)
654             {
655                 // get the real cause
656
cause = ((MethodInvocationException)cause).getWrappedThrowable();
657             }
658
659             StringWriter JavaDoc sw = new StringWriter JavaDoc();
660             cause.printStackTrace(new PrintWriter JavaDoc(sw));
661
662             html.append("<pre>\n");
663             html.append(sw.toString());
664             html.append("</pre>\n");
665             html.append("</body>\n");
666             html.append("</html>");
667             getResponseWriter(response).write(html.toString());
668         }
669         catch (Exception JavaDoc e2)
670         {
671             // clearly something is quite wrong.
672
// let's log the new exception then give up and
673
// throw a servlet exception that wraps the first one
674
Velocity.error("VelocityViewServlet: Exception while printing error screen: "+e2);
675             throw new ServletException JavaDoc(e);
676         }
677     }
678
679     /**
680      * <p>Procure a Writer with correct encoding which can be used
681      * even if HttpServletResponse's <code>getOutputStream()</code> method
682      * has already been called.</p>
683      *
684      * <p>This is a transitional method which will be removed in a
685      * future version of Velocity. It is not recommended that you
686      * override this method.</p>
687      *
688      * @param response The response.
689      * @return A <code>Writer</code>, possibly created using the
690      * <code>getOutputStream()</code>.
691      */

692     protected Writer JavaDoc getResponseWriter(HttpServletResponse JavaDoc response)
693         throws UnsupportedEncodingException JavaDoc, IOException JavaDoc
694     {
695         Writer JavaDoc writer = null;
696         try
697         {
698             writer = response.getWriter();
699         }
700         catch (IllegalStateException JavaDoc e)
701         {
702             // ASSUMPTION: We already called getOutputStream(), so
703
// calls to getWriter() fail. Use of OutputStreamWriter
704
// assures our desired character set
705
if (this.warnOfOutputStreamDeprecation)
706             {
707                 this.warnOfOutputStreamDeprecation = false;
708                 Velocity.warn("VelocityViewServlet: " +
709                               "Use of ServletResponse's getOutputStream() " +
710                               "method with VelocityViewServlet is " +
711                               "deprecated -- support will be removed in " +
712                               "an upcoming release");
713             }
714             // Assume the encoding has been set via setContentType().
715
String JavaDoc encoding = response.getCharacterEncoding();
716             if (encoding == null)
717             {
718                 encoding = DEFAULT_OUTPUT_ENCODING;
719             }
720             writer = new OutputStreamWriter JavaDoc(response.getOutputStream(),
721                                             encoding);
722         }
723         return writer;
724     }
725
726 }
727
Popular Tags