Coverage Report

##### Coverage Report - org.webmacro.servlet.WMServlet

Classes in this File | Line Coverage | Branch Coverage | Complexity
WMServlet |
0% | 0/164
0% | 0/26
| 2.064516129032258;2.065

1 |  |
     /*
2 |  |
      * Copyright (C) 1998-2000 Semiotek Inc.  All Rights Reserved.
3 |  |
      *
4 |  |
      * Redistribution and use in source and binary forms, with or without
5 |  |
      * modification, are permitted under the terms of either of the following
6 |  |
      * Open Source licenses:
7 |  |
      *
8 |  |
      * The GNU General Public License, version 2, or any later version, as
9 |  |
      * published by the Free Software Foundation
10 |  |
      * (http://www.fsf.org/copyleft/gpl.html);
11 |  |
      *
12 |  |
      *  or
13 |  |
      *
14 |  |
      * The Semiotek Public License (http://webmacro.org/LICENSE.)
15 |  |
      *
16 |  |
      * This software is provided "as is", with NO WARRANTY, not even the
17 |  |
      * implied warranties of fitness to purpose, or merchantability. You
18 |  |
      * assume all risks and liabilities associated with its use.
19 |  |
      *
20 |  |
      * See www.webmacro.org for more information on the WebMacro project.
21 |  |
      */
22 |  |
23 |  |
24 |  |
     package org.webmacro.servlet;
25 |  |
26 |  |
     import java.io.IOException;
27 |  |
     import java.io.OutputStream;
28 |  |
     import java.io.UnsupportedEncodingException;
29 |  |
     import java.io.Writer;
30 |  |
     import java.lang.reflect.Method;
31 |  |
     import java.util.Locale;
32 |  |
33 |  |
     import javax.servlet.ServletConfig;
34 |  |
     import javax.servlet.ServletException;
35 |  |
     import javax.servlet.http.HttpServlet;
36 |  |
     import javax.servlet.http.HttpServletRequest;
37 |  |
     import javax.servlet.http.HttpServletResponse;
38 |  |
39 |  |
     import org.slf4j.Logger;
40 |  |
     import org.slf4j.LoggerFactory;
41 |  |
42 |  |
     import org.webmacro.Broker;
43 |  |
     import org.webmacro.Context;
44 |  |
     import org.webmacro.FastWriter;
45 |  |
     import org.webmacro.InitException;
46 |  |
     import org.webmacro.NotFoundException;
47 |  |
     import org.webmacro.PropertyException;
48 |  |
     import org.webmacro.ResourceException;
49 |  |
     import org.webmacro.Template;
50 |  |
     import org.webmacro.WM;
51 |  |
     import org.webmacro.WMConstants;
52 |  |
     import org.webmacro.WebMacro;
53 |  |
54 |  |
     /**
55 |  |
      * This is an abstract base class which can be used
56 |  |
      * to implement a kind of WebMacro servlet.
57 |  |
      *
58 |  |
      * You can either subclass from it directly, or make use of one of the
59 |  |
      * generic subclasses provided.
60 |  |
      * <p>
61 |  |
      * It's primary function is to create a WebContext and manage a
62 |  |
      * Broker. It also provides a couple of convenience functions
63 |  |
      * that access the Broker and/or WebContext to make some commonly
64 |  |
      * accessed services more readily available.
65 |  |
      * <p>
66 |  |
      * @see org.webmacro.Broker
67 |  |
      */
68 | 0 |
     abstract public class WMServlet extends HttpServlet implements WebMacro
69 |  |
     {
70 |  |
71 |  |
             private static final long serialVersionUID = -4903102471116106113L;
72 | 0 |
         static Logger _log =  LoggerFactory.getLogger(WMServlet.class);
73 |  |
74 | 0 |
             private WebMacro _wm = null;
75 | 0 |
         private Broker _broker = null;
76 | 0 |
         private boolean _started = false;
77 |  |
         /**
78 |  |
          * The name of the config entry we look for to find out what to
79 |  |
          * call the variable used in the ERROR_TEMPLATE.
80 |  |
          */
81 |  |
         final static String ERROR_VARIABLE = "ErrorVariable";
82 |  |
83 |  |
         /**
84 |  |
          * The name of the error template we will use if something
85 |  |
          * goes wrong.
86 |  |
          */
87 |  |
         final static String ERROR_TEMPLATE = "ErrorTemplate";
88 |  |
89 |  |
         /**
90 |  |
          * Defaults for error variable and error template.
91 |  |
          */
92 |  |
         final static String ERROR_TEMPLATE_DEFAULT = "error.wm";
93 |  |
         final static String ERROR_VARIABLE_DEFAULT = "error";
94 |  |
95 |  |
         /**
96 |  |
          * Null means all OK.
97 |  |
          */
98 | 0 |
         private String _problem = "Not yet initialized: " +
99 |  |
             "Your servlet API tried to access WebMacro without first calling init()!!!";
100 |  |
101 |  |
         /**
102 |  |
          * This is the old-style init method, it just calls init(), after
103 |  |
          * handing the ServletConfig object to the superclass.
104 |  |
          * @exception ServletException if it failed to initialize
105 |  |
          */
106 |  |
         public synchronized void init (ServletConfig sc)
107 |  |
                 throws ServletException
108 |  |
         {
109 | 0 |
             super.init(sc);
110 | 0 |
             init();
111 | 0 |
         }
112 |  |
113 |  |
         /**
114 |  |
          * This method is called by the servlet runner--do not call it. It
115 |  |
          * must not be overidden because it manages a shared instance
116 |  |
          * of the broker--you can overide the start() method instead, which
117 |  |
          * is called just after the broker is initialized.
118 |  |
          */
119 |  |
         public synchronized void init ()
120 |  |
         {
121 |  |
122 | 0 |
             if (_started)
123 |  |
             {
124 | 0 |
                 return;
125 |  |
             }
126 |  |
127 |  |
             // locate a Broker
128 |  |
129 | 0 |
             if (_wm == null)
130 |  |
             {
131 |  |
                 try
132 |  |
                 {
133 | 0 |
                     _wm = initWebMacro();
134 | 0 |
                     _broker = _wm.getBroker();
135 |  |
                 }
136 | 0 |
                 catch (InitException e)
137 |  |
                 {
138 | 0 |
                     _problem = "Could not initialize the broker!\n\n"
139 |  |
                             + "*** Check that WebMacro.properties was in your servlet\n"
140 |  |
                             + "*** classpath, in a similar place to webmacro.jar \n"
141 |  |
                             + "*** and that all values were set correctly.\n\n"
142 |  |
                             + e.getMessage();
143 | 0 |
                     _log.error(_problem, e);
144 | 0 |
                     return;
145 | 0 |
                 }
146 |  |
             }
147 |  |
148 |  |
             try
149 |  |
             {
150 | 0 |
                 if (_log.isDebugEnabled())
151 |  |
                 {
152 | 0 |
                     java.net.URL url = getBroker().getResource(Broker.WEBMACRO_PROPERTIES);
153 | 0 |
                     if (url != null)
154 | 0 |
                         _log.debug("Using properties from " + url.toExternalForm());
155 |  |
                     else
156 | 0 |
                         _log.debug("No WebMacro.properties file was found.");
157 |  |
                 }
158 | 0 |
                 start();
159 | 0 |
                 _problem = null;
160 |  |
             }
161 | 0 |
             catch (ServletException e)
162 |  |
             {
163 | 0 |
                 _problem = "WebMacro application code failed to initialize: \n"
164 |  |
                         + e + "\n" + "This error is the result of a failure in the\n"
165 |  |
                         + "code supplied by the application programmer.\n";
166 | 0 |
                 _log.error(_problem, e);
167 | 0 |
             }
168 | 0 |
             _log.info("started: " + this);
169 | 0 |
             _started = true;
170 |  |
171 | 0 |
         }
172 |  |
173 |  |
         /**
174 |  |
          * This method is called by the servlet runner--do not call it. It
175 |  |
          * must not be overidden because it manages a shared instance of
176 |  |
          * the broker--you can overide the stop() method instead, which
177 |  |
          * will be called just before the broker is shut down.  Once the
178 |  |
          * stop() method has been called, the nested WM will be destroyed
179 |  |
          * and then the parent destroy() method will be invoked.
180 |  |
          * @see WM#destroy()
181 |  |
          */
182 |  |
         public synchronized void destroy ()
183 |  |
         {
184 | 0 |
             stop();
185 | 0 |
             _wm.destroy();
186 | 0 |
             _log.info("stopped: " + this);
187 | 0 |
             _wm = null;
188 | 0 |
             _started = false;
189 | 0 |
             super.destroy();
190 | 0 |
         }
191 |  |
192 |  |
193 |  |
         // SERVLET API METHODS
194 |  |
195 |  |
         /**
196 |  |
          * Process an incoming GET request: Builds a WebContext up and then
197 |  |
          * passes it to the handle() method. You can overide this if you want,
198 |  |
          * though for most purposes you are expected to overide handle()
199 |  |
          * instead.
200 |  |
          * <p>
201 |  |
          * @param req the request we got
202 |  |
          * @param resp the response we are generating
203 |  |
          * @exception ServletException if we can't get our configuration
204 |  |
          * @exception IOException if we can't write to the output stream
205 |  |
          */
206 |  |
         protected void doGet (HttpServletRequest req, HttpServletResponse resp)
207 |  |
                 throws ServletException, IOException
208 |  |
         {
209 | 0 |
             doRequest(req, resp);
210 | 0 |
         }
211 |  |
212 |  |
         /**
213 |  |
          * Behaves exactly like doGet() except that it reads data from POST
214 |  |
          * before doing exactly the same thing. This means that you can use
215 |  |
          * GET and POST interchangeably with WebMacro. You can overide this if
216 |  |
          * you want, though for most purposes you are expected to overide
217 |  |
          * handle() instead.
218 |  |
          * <p>
219 |  |
          * @param req the request we got
220 |  |
          * @param resp the response we are generating
221 |  |
          * @exception ServletException if we can't get our configuration
222 |  |
          * @exception IOException if we can't read/write to the streams we got
223 |  |
          */
224 |  |
         protected void doPost (HttpServletRequest req, HttpServletResponse resp)
225 |  |
                 throws ServletException, IOException
226 |  |
         {
227 | 0 |
             doRequest(req, resp);
228 | 0 |
         }
229 |  |
230 |  |
         final private void doRequest (
231 |  |
                 HttpServletRequest req, HttpServletResponse resp)
232 |  |
                 throws IOException
233 |  |
         {
234 |  |
235 | 0 |
             WebContext context = null;
236 |  |
237 | 0 |
             if (_problem != null)
238 |  |
             {
239 | 0 |
                 init();
240 | 0 |
                 if (_problem != null)
241 |  |
                 {
242 |  |
                     try
243 |  |
                     {
244 | 0 |
                         resp.setContentType("text/html");
245 | 0 |
                         Writer out = resp.getWriter();
246 |  |
247 | 0 |
                         out.write("<html><head><title>WebMacro Error</title></head>");
248 | 0 |
                         out.write("<body><h1><font color=\"red\">WebMacro Error: ");
249 | 0 |
                         out.write("</font></h1><pre>");
250 | 0 |
                         out.write(_problem);
251 | 0 |
                         out.write("</pre>");
252 | 0 |
                         out.write("Please contact the server administrator");
253 | 0 |
                         out.flush();
254 | 0 |
                         out.close();
255 |  |
                     }
256 | 0 |
                     catch (Exception e)
257 |  |
                     {
258 | 0 |
                         _log.error(_problem, e);
259 | 0 |
                     }
260 | 0 |
                     return;
261 |  |
                 }
262 |  |
             }
263 |  |
264 |  |
265 | 0 |
             context = newWebContext(req, resp);
266 |  |
             try
267 |  |
             {
268 |  |
                 Template t;
269 | 0 |
                 t = handle(context);
270 |  |
271 | 0 |
                 if (t != null)
272 |  |
                 {
273 | 0 |
                     execute(t, context);
274 |  |
                 }
275 | 0 |
                 destroyContext(context);
276 |  |
             }
277 | 0 |
             catch (HandlerException e)
278 |  |
             {
279 | 0 |
                 _log.error("Your handler failed to handle the request:" + this, e);
280 | 0 |
                 Template tmpl = error(context,
281 |  |
                         "Your handler was unable to process the request successfully " +
282 |  |
                         "for some reason. Here are the details:<p>" +
283 |  |
                         "<pre>" + e + "</pre>");
284 | 0 |
                 execute(tmpl, context);
285 |  |
             }
286 | 0 |
             catch (Exception e)
287 |  |
             {
288 | 0 |
                 _log.error("Your handler failed to handle the request:" + this, e);
289 | 0 |
                 Template tmpl = error(context,
290 |  |
                         "The handler WebMacro used to handle this request failed for " +
291 |  |
                         "some reason. This is likely a bug in the handler written " +
292 |  |
                         "for this application. Here are the details:<p>" +
293 |  |
                         "<pre>" + e + "</pre>");
294 | 0 |
                 execute(tmpl, context);
295 | 0 |
             }
296 | 0 |
         }
297 |  |
298 |  |
299 |  |
         // CONVENIENCE METHODS & ACCESS TO THE BROKER
300 |  |
301 |  |
         /**
302 |  |
          * Create an error template using the built in error handler.
303 |  |
          * This is useful for returning error messages on failure;
304 |  |
          * it is used by WMServlet to display errors resulting from
305 |  |
          * any exception that you may throw from the handle() method.
306 |  |
          * @param context will add error variable to context (see Config)
307 |  |
          * @param error a string explaining what went wrong
308 |  |
          */
309 |  |
         protected Template error (WebContext context, String error)
310 |  |
         {
311 | 0 |
             Template tmpl = null;
312 |  |
             //Handler hand = new ErrorHandler();
313 |  |
             try
314 |  |
             {
315 | 0 |
                 context.put(getErrorVariableName(),
316 |  |
                         error);
317 |  |
                 //tmpl = hand.accept(context);
318 | 0 |
                 tmpl = getErrorTemplate();
319 |  |
             }
320 | 0 |
             catch (Exception e2)
321 |  |
             {
322 | 0 |
                 _log.error("Unable to use ErrorHandler", e2);
323 | 0 |
             }
324 | 0 |
             return tmpl;
325 |  |
         }
326 |  |
327 |  |
         /**
328 |  |
          * Returns the name of the error variable, as per the config.
329 |  |
          * @return Name to use for the error variable in templates
330 |  |
          */
331 |  |
         protected String getErrorVariableName ()
332 |  |
         {
333 | 0 |
             return getConfig(ERROR_VARIABLE, ERROR_VARIABLE_DEFAULT);
334 |  |
         }
335 |  |
336 |  |
         /**
337 |  |
          * This object is used to access components that have been plugged
338 |  |
          * into WebMacro; it is shared between all instances of this class and
339 |  |
          * its subclasses. It is created when the first instance is initialized,
340 |  |
          * and deleted when the last instance is shut down. If you attempt to
341 |  |
          * access it after the last servlet has been shutdown, it will either
342 |  |
          * be in a shutdown state or else null.
343 |  |
          */
344 |  |
         public Broker getBroker ()
345 |  |
         {
346 |  |
             // this method can be unsynch. because the broker manages its own
347 |  |
             // state, plus the only time the _broker will be shutdown or null
348 |  |
             // is after the last servlet has shutdown--so why would anyone be
349 |  |
             // accessing us then? if they do the _broker will throw exceptions
350 |  |
             // complaining that it has been shut down, or they'll get a null here.
351 | 0 |
             return _broker;
352 |  |
         }
353 |  |
354 |  |
         /**
355 |  |
          * Retrieve a template from the "template" provider. Equivalent to
356 |  |
          * getBroker().get(TemplateProvider.TYPE,key)
357 |  |
          * @exception NotFoundException if the template was not found
358 |  |
          * @exception ResourceException if the template coult not be loaded
359 |  |
          */
360 |  |
         public Template getTemplate (String key)
361 |  |
                 throws ResourceException
362 |  |
         {
363 | 0 |
             return _wm.getTemplate(key);
364 |  |
         }
365 |  |
366 |  |
         /**
367 |  |
          * Retrieve a URL. This is largely equivalent to creating a URL
368 |  |
          * object and requesting its content, though it will sit in
369 |  |
          * WebMacro's cache rather than re-requesting each time.
370 |  |
          * The content will be returned as an Object.
371 |  |
          */
372 |  |
         public String getURL (String url)
373 |  |
                 throws ResourceException
374 |  |
         {
375 | 0 |
             return _wm.getURL(url);
376 |  |
         }
377 |  |
378 |  |
379 |  |
         /**
380 |  |
          * Retrieve configuration information from the "config" provider.
381 |  |
          * Equivalent to getBroker().get(Config.TYPE,key)
382 |  |
          * @exception NotFoundException could not locate requested information
383 |  |
          */
384 |  |
         public String getConfig (String key)
385 |  |
                 throws NotFoundException
386 |  |
         {
387 | 0 |
             return _wm.getConfig(key);
388 |  |
         }
389 |  |
390 |  |
         /**
391 |  |
          * Retrieve configuration information from the "config" provider.
392 |  |
          * Return specified default if key could not be found
393 |  |
          */
394 |  |
         public String getConfig (String key, String defaultValue)
395 |  |
         {
396 |  |
             try
397 |  |
             {
398 | 0 |
                 return _wm.getConfig(key);
399 |  |
             }
400 | 0 |
             catch (NotFoundException e)
401 |  |
             {
402 | 0 |
                 return defaultValue;
403 |  |
             }
404 |  |
         }
405 |  |
406 |  |
         /**
407 |  |
          * Create a new Context object.
408 |  |
          */
409 |  |
         public Context getContext ()
410 |  |
         {
411 | 0 |
             return _wm.getContext();
412 |  |
         }
413 |  |
414 |  |
         /**
415 |  |
          * Create a new WebContext object; can be overridden.
416 |  |
          */
417 |  |
         public WebContext getWebContext (HttpServletRequest req, HttpServletResponse res)
418 |  |
         {
419 | 0 |
             return _wm.getWebContext(req, res);
420 |  |
         }
421 |  |
422 |  |
         /**
423 |  |
          * Convenience method for writing a template to an OutputStream.
424 |  |
          * This method takes care of all the typical work involved
425 |  |
          * in writing a template.<p>
426 |  |
          *
427 |  |
          * This method uses the default <code>TemplateOutputEncoding</code> specified in
428 |  |
          * WebMacro.defaults or your custom WebMacro.properties.
429 |  |
          *
430 |  |
          * @param templateName name of Template to write.  Must be accessible
431 |  |
          *                     via TemplatePath
432 |  |
          * @param out          where the output of the template should go
433 |  |
          * @param context      The Context (can be a WebContext too) used
434 |  |
          *                     during the template evaluation phase
435 |  |
          * @throws java.io.IOException if the template cannot be written to the
436 |  |
          *                             specified output stream
437 |  |
          * @throws ResourceException if the template name specified cannot be found
438 |  |
          * @throws PropertyException if a fatal error occured during the Template
439 |  |
          *                           evaluation phase
440 |  |
          */
441 |  |
         public void writeTemplate (String templateName, java.io.OutputStream out,
442 |  |
                                    Context context)
443 |  |
                 throws java.io.IOException, ResourceException, PropertyException
444 |  |
         {
445 |  |
446 | 0 |
             writeTemplate(templateName, out,
447 |  |
                     getConfig(WMConstants.TEMPLATE_OUTPUT_ENCODING),
448 |  |
                     context);
449 | 0 |
         }
450 |  |
451 |  |
         /**
452 |  |
          * Convienence method for writing a template to an OutputStream.
453 |  |
          * This method takes care of all the typical work involved
454 |  |
          * in writing a template.
455 |  |
          *
456 |  |
          * @param templateName name of Template to write.  Must be accessible
457 |  |
          *                     via TemplatePath
458 |  |
          * @param out          where the output of the template should go
459 |  |
          * @param encoding     character encoding to use when writing the template
460 |  |
          *                     if the encoding is <code>null</code>, the default
461 |  |
          *                     <code>TemplateOutputEncoding</code> is used
462 |  |
          * @param context      The Context (can be a WebContext too) used
463 |  |
          *                     during the template evaluation phase
464 |  |
          * @throws java.io.IOException if the template cannot be written to the
465 |  |
          *                             specified output stream
466 |  |
          * @throws ResourceException if the template name specified cannot be found
467 |  |
          * @throws PropertyException if a fatal error occured during the Template
468 |  |
          *                           evaluation phase
469 |  |
          */
470 |  |
         public void writeTemplate (String templateName, java.io.OutputStream out,
471 |  |
                                    String encoding, Context context)
472 |  |
                 throws java.io.IOException, ResourceException, PropertyException
473 |  |
         {
474 |  |
475 | 0 |
             if (encoding == null)
476 | 0 |
                 encoding = getConfig(WMConstants.TEMPLATE_OUTPUT_ENCODING);
477 |  |
478 | 0 |
             Template tmpl = getTemplate(templateName);
479 | 0 |
             tmpl.write(out, encoding, context);
480 | 0 |
         }
481 |  |
482 |  |
483 |  |
         // DELEGATE-TO METHODS -- COMMON THINGS MADE EASIER
484 |  |
485 |  |
         /**
486 |  |
          * This method takes a populated context and a template and
487 |  |
          * writes out the interpreted template to the context's output
488 |  |
          * stream.
489 |  |
          */
490 |  |
         protected void execute (Template tmpl, WebContext c)
491 |  |
                 throws IOException
492 |  |
         {
493 |  |
             try
494 |  |
             {
495 | 0 |
                 HttpServletResponse resp = c.getResponse();
496 |  |
497 | 0 |
                 Locale locale = (Locale) tmpl.getParam(
498 |  |
                         WMConstants.TEMPLATE_LOCALE);
499 | 0 |
                 _log.debug("TemplateLocale=" + locale);
500 | 0 |
                 if (locale != null)
501 |  |
                 {
502 | 0 |
                     setLocale(resp, locale);
503 |  |
                 }
504 |  |
505 | 0 |
                 String encoding = (String) tmpl.getParam(
506 |  |
                         WMConstants.TEMPLATE_OUTPUT_ENCODING);
507 | 0 |
                 if (encoding == null)
508 |  |
                 {
509 | 0 |
                     encoding = resp.getCharacterEncoding();
510 |  |
                 }
511 |  |
512 | 0 |
                 _log.debug("Using output encoding " + encoding);
513 |  |
514 |  |
                 // get the bytes before calling getOutputStream
515 |  |
                 // this is necessary to be compatible with JSDK 2.3
516 |  |
                 // where you can't call setContentType() after getOutputStream(),
517 |  |
                 // which could be happening during the template evaluation
518 | 0 |
                 byte[] bytes = tmpl.evaluateAsBytes(encoding, c);
519 |  |
520 |  |
521 |  |
                 // now write the FW buffer to the response output stream
522 | 0 |
                 writeResponseBytes(resp, bytes, encoding);
523 |  |
             }
524 | 0 |
             catch (UnsupportedEncodingException e)
525 |  |
             {
526 |  |
                 // can be thrown by FastWriter.getInstance
527 |  |
                 // rethrow it, because otherwise it would be ignored
528 |  |
                 // as an IOException
529 | 0 |
                 _log.error("tried to use an unsupported encoding", e);
530 | 0 |
                 throw e;
531 |  |
             }
532 | 0 |
             catch (IOException e)
533 |  |
             {
534 |  |
                 // ignore disconnect
535 |  |
             }
536 | 0 |
             catch (Exception e)
537 |  |
             {
538 | 0 |
                 String error =
539 |  |
                         "WebMacro encountered an error while executing a template:\n"
540 |  |
                         + ((tmpl != null) ? (tmpl + ": " + e + "\n") :
541 |  |
                         ("The template failed to load; double check the "
542 |  |
                         + "TemplatePath in your webmacro.properties file."));
543 | 0 |
                 _log.error(error, e);
544 |  |
                 try
545 |  |
                 {
546 | 0 |
                     Template errorTemplate = error(c,
547 |  |
                             "WebMacro encountered an error while executing a template:\n"
548 |  |
                             + ((tmpl != null) ? (tmpl + ": ")
549 |  |
                             : ("The template failed to load; double check the "
550 |  |
                             + "TemplatePath in your webmacro.properties file."))
551 |  |
                             + "\n<pre>" + e + "</pre>\n");
552 |  |
553 | 0 |
                     String err = errorTemplate.evaluateAsString(c);
554 | 0 |
                     c.getResponse().getWriter().write(err);
555 |  |
                 }
556 | 0 |
                 catch (Exception errExcept)
557 |  |
                 {
558 | 0 |
                     _log.error("Error writing error template!", errExcept);
559 | 0 |
                 }
560 | 0 |
             }
561 | 0 |
         }
562 |  |
563 |  |
         /**
564 |  |
          * Helper method to write out a FastWriter (that has bufferd
565 |  |
          * the response) to a ServletResponse. This method will try to use
566 |  |
          * the response's OutputStream first and if this fails, fall back
567 |  |
          * to its Writer.
568 |  |
          * @param response where to write fast writer to
569 |  |
          * @param bytes the bytes to write
570 |  |
          */
571 |  |
         private void writeResponseBytes (HttpServletResponse response, byte[] bytes, String encoding)
572 |  |
                 throws IOException
573 |  |
         {
574 |  |
             OutputStream out;
575 |  |
             // We'll check, if the OutputStream is available
576 |  |
             try
577 |  |
             {
578 | 0 |
                 out = response.getOutputStream();
579 |  |
             }
580 | 0 |
             catch (IllegalStateException e)
581 |  |
             {
582 |  |
                 // Here comes a quick hack, we need a cleaner
583 |  |
                 // solution in a future release. (skanthak)
584 |  |
585 |  |
                 // this means, that the ServletOutputStream is
586 |  |
                 // not available, because the Writer has already
587 |  |
                 // be used. We have to use it, although its
588 |  |
                 // much slower, especially, because we need to
589 |  |
                 // revert the encoding process now
590 | 0 |
                 out = null;
591 | 0 |
                 _log.debug("Using Writer instead of OutputStream");
592 | 0 |
             }
593 | 0 |
             response.setContentLength(bytes.length);
594 | 0 |
             if (out != null)
595 |  |
             {
596 | 0 |
                 out.write(bytes);
597 |  |
             }
598 |  |
             else
599 |  |
             {
600 | 0 |
                 response.getWriter().write(new String(bytes, encoding));
601 |  |
             }
602 | 0 |
         }
603 |  |
604 |  |
605 |  |
         // FRAMEWORK TEMPLATE METHODS--PLUG YOUR CODE IN HERE
606 |  |
607 |  |
608 |  |
         /**
609 |  |
          * This method is called at the beginning of a request and is
610 |  |
          * responsible for providing a Context for the request. The
611 |  |
          * default implementation calls WebContext.newInstance(req,resp)
612 |  |
          * on the WebContext prototype returned by the initWebContext() method.
613 |  |
          * This is probably suitable for most servlets, though you can override
614 |  |
          * it and do something different if you like. You can throw a
615 |  |
          * HandlerException if something goes wrong.
616 |  |
          */
617 |  |
         public WebContext newContext (
618 |  |
                 HttpServletRequest req, HttpServletResponse resp)
619 |  |
                 throws HandlerException
620 |  |
         {
621 | 0 |
             return _wm.getWebContext(req, resp);
622 |  |
             //return _wcPrototype.newInstance(req, resp);
623 |  |
         }
624 |  |
625 |  |
         /**
626 |  |
          * This method is called to handle the processing of a request. It
627 |  |
          * should analyze the data in the request, put whatever values are
628 |  |
          * required into the context, and return the appropriate view.
629 |  |
          * @param context contains all relevant data structures, incl builtins.
630 |  |
          * @return the template to be rendered by the WebMacro engine
631 |  |
          * @throws HandlerException throw this to produce vanilla error messages
632 |  |
          */
633 |  |
         public abstract Template handle (WebContext context)
634 |  |
                 throws HandlerException;
635 |  |
636 |  |
637 |  |
         /**
638 |  |
          * This method is called at the end of a request and is responsible
639 |  |
          * for cleaning up the Context at the end of the request. You may
640 |  |
          * not need to do anything here, but it is sometimes important if
641 |  |
          * you have an open database connection in your context that you
642 |  |
          * need to close. The default implementation calls wc.clear().
643 |  |
          */
644 |  |
         public void destroyContext (WebContext wc)
645 |  |
                 throws HandlerException
646 |  |
         {
647 | 0 |
         }
648 |  |
649 |  |
650 |  |
         /**
651 |  |
          * Override this method to implement any startup/init code
652 |  |
          * you require. The broker will have been created before this
653 |  |
          * method is called; the default implementation does nothing.
654 |  |
          * This is called when the servlet environment initializes
655 |  |
          * the servlet for use via the init() method.
656 |  |
          * @exception ServletException to indicate initialization failed
657 |  |
          */
658 |  |
         protected void start () throws ServletException
659 |  |
         {
660 | 0 |
         }
661 |  |
662 |  |
         /**
663 |  |
          * Override this method to implement any shutdown code you require.
664 |  |
          * The broker may be destroyed just after this method exits. This
665 |  |
          * is called when the servlet environment shuts down the servlet
666 |  |
          * via the shutdown() method. The default implementation does nothing.
667 |  |
          */
668 |  |
         protected void stop ()
669 |  |
         {
670 | 0 |
         }
671 |  |
672 |  |
673 |  |
         /**
674 |  |
          * This method returns the WebMacro object which will be used to load,
675 |  |
          * access, and manage the Broker. The default implementation is to
676 |  |
          * return a new WM() object. You could override it and return a WM
677 |  |
          * object constructed with a particular configuration file, or some
678 |  |
          * other implementation of the WebMacro interface.
679 |  |
          */
680 |  |
         public WebMacro initWebMacro () throws InitException
681 |  |
         {
682 | 0 |
             return new WM(this);
683 |  |
         }
684 |  |
685 |  |
         /**
686 |  |
          * NO LONGER USED
687 |  |
          * Exists only to catch implementations that use it.
688 |  |
          * Use newWebContext instead.
689 |  |
          * @deprecated
690 |  |
          */
691 |  |
         public final WebContext initWebContext () throws InitException
692 |  |
         {
693 | 0 |
             return null;
694 |  |
         }
695 |  |
696 |  |
         public WebContext newWebContext(HttpServletRequest req, HttpServletResponse resp) {
697 | 0 |
             return new WebContext(_broker, req, resp);
698 |  |
         }
699 |  |
700 |  |
         /**
701 |  |
          * Set the locale on the response.  The reflection trickery is because
702 |  |
          * this is only defined for JSDK 2.2+
703 |  |
          */
704 |  |
         protected void setLocale (HttpServletResponse resp, Locale locale)
705 |  |
         {
706 |  |
             try
707 |  |
             {
708 | 0 |
                 Method m = HttpServletResponse.class.getMethod(
709 |  |
                         "setLocale",
710 |  |
                         new Class[]
711 |  |
                         {Locale.class});
712 | 0 |
                 m.invoke(resp, (Object[])new Locale[]{locale});
713 | 0 |
                 _log.debug("Successfully set locale to " + locale);
714 |  |
             }
715 | 0 |
             catch (Exception e)
716 |  |
             {
717 | 0 |
                _log.debug("Error set locale to " + locale + ": " + e.getClass());
718 | 0 |
             }
719 | 0 |
         }
720 |  |
721 |  |
         /**
722 |  |
          * Get a new FastWriter.
723 |  |
          * A FastWriter is used when writing templates to an output stream
724 |  |
          *
725 |  |
          * @param out The output stream the FastWriter should write to.  Typically
726 |  |
          *           this will be your ServletOutputStream
727 |  |
          * @param enctype the Encoding type to use
728 |  |
          * @deprecated
729 |  |
          */
730 |  |
         public FastWriter getFastWriter (OutputStream out, String enctype)
731 |  |
                 throws UnsupportedEncodingException
732 |  |
         {
733 | 0 |
             return _wm.getFastWriter(out, enctype);
734 |  |
         }
735 |  |
736 |  |
737 |  |
         private static final String DEFAULT_ERROR_TEXT =
738 |  |
                 "<HTML><HEAD><TITLE>Error</TITLE></HEAD>\n"
739 |  |
                 + "#set $Response.ContentType = \"text/html\"\n"
740 |  |
                 + "<BODY><H1>Error</H1>"
741 |  |
                 + "<HR>$error</BODY></HTML>";
742 |  |
743 | 0 |
         private Template _errorTemplate = null;
744 |  |
745 |  |
         /**
746 |  |
          * Gets a template for displaying an error message.
747 |  |
          * Tries to get configured template, then default template
748 |  |
          * and lastly constructs a string template.
749 |  |
          * @return A Template which can be used to format an error message
750 |  |
          */
751 |  |
         public Template getErrorTemplate ()
752 |  |
         {
753 | 0 |
             String templateName = getErrorTemplateName();
754 |  |
755 |  |
             try
756 |  |
             {
757 | 0 |
                 _errorTemplate = (Template) _broker.get("template", templateName);
758 |  |
             }
759 | 0 |
             catch (ResourceException e)
760 |  |
             {
761 | 0 |
                 _errorTemplate = new org.webmacro.engine.StringTemplate(_broker, DEFAULT_ERROR_TEXT,
762 |  |
                         "WebMacro default error template");
763 | 0 |
             }
764 | 0 |
             return _errorTemplate;
765 |  |
         }
766 |  |
767 |  |
         protected String getErrorTemplateName ()
768 |  |
         {
769 |  |
             String templateName;
770 |  |
771 |  |
             try
772 |  |
             {
773 | 0 |
                 templateName = (String) _broker.get("config", ERROR_TEMPLATE);
774 |  |
             }
775 | 0 |
             catch (ResourceException e)
776 |  |
             {
777 | 0 |
                 templateName = ERROR_TEMPLATE_DEFAULT;
778 | 0 |
             }
779 | 0 |
             return templateName;
780 |  |
         }
781 |  |
782 |  |
783 |  |
     }
784 |  |