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