View Javadoc

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 }