TemplateServlet.java

  1. /*
  2.  * $Source$
  3.  * $Revision$
  4.  *
  5.  * Copyright (C) 2000 Tim Joyce
  6.  *
  7.  * Part of Melati (http://melati.org), a framework for the rapid
  8.  * development of clean, maintainable web applications.
  9.  *
  10.  * Melati is free software; Permission is granted to copy, distribute
  11.  * and/or modify this software under the terms either:
  12.  *
  13.  * a) the GNU General Public License as published by the Free Software
  14.  *    Foundation; either version 2 of the License, or (at your option)
  15.  *    any later version,
  16.  *
  17.  *    or
  18.  *
  19.  * b) any version of the Melati Software License, as published
  20.  *    at http://melati.org
  21.  *
  22.  * You should have received a copy of the GNU General Public License and
  23.  * the Melati Software License along with this program;
  24.  * if not, write to the Free Software Foundation, Inc.,
  25.  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
  26.  * GNU General Public License and visit http://melati.org to obtain the
  27.  * Melati Software License.
  28.  *
  29.  * Feel free to contact the Developers of Melati (http://melati.org),
  30.  * if you would like to work out a different arrangement than the options
  31.  * outlined here.  It is our intention to allow Melati to be used by as
  32.  * wide an audience as possible.
  33.  *
  34.  * This program is distributed in the hope that it will be useful,
  35.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  36.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  37.  * GNU General Public License for more details.
  38.  *
  39.  * Contact details for copyright holder:
  40.  *
  41.  *     Tim Joyce <timj At paneris.org>
  42.  *     http://paneris.org/
  43.  *     68 Sandbanks Rd, Poole, Dorset. BH14 8BY. UK
  44.  */

  45. package org.melati.servlet;

  46. import java.io.PrintWriter;
  47. import java.io.StringWriter;

  48. import javax.servlet.ServletException;
  49. import javax.servlet.ServletConfig;

  50. import org.melati.Melati;
  51. import org.melati.util.MelatiWriter;
  52. import org.melati.template.ServletTemplateEngine;
  53. import org.melati.template.ServletTemplateContext;
  54. import org.melati.template.MultipartTemplateContext;
  55. import org.melati.template.Template;

  56. /**
  57.  * Base class to use Melati with a Template Engine.
  58.  * To create your own servlet simply extend this class,
  59.  * overriding the <code>doTemplateRequest</code> method.
  60.  *
  61.  * @author Tim Joyce
  62.  * $Revision$
  63.  */
  64. public abstract class TemplateServlet extends PoemServlet {

  65.   /**
  66.    * Eclipse generated.
  67.    */
  68.   private static final long serialVersionUID = -5228388231472549208L;
  69.  
  70.   // the template engine
  71.   protected ServletTemplateEngine templateEngine;

  72.   /**
  73.    * Initialise the template engine.
  74.    *
  75.    * @param config a <code>ServletConfig</code>
  76.    * @throws ServletException if the ServletTemplateEngine has a problem
  77.    */
  78.   public void init(ServletConfig config) throws ServletException {
  79.     super.init(config);
  80.     templateEngine = melatiConfig.getServletTemplateEngine();
  81.     templateEngine.init(melatiConfig, this);
  82.   }

  83.   /**
  84.    * Set the ServletTemplateEngine and ServletTemplateContext in our Melati.
  85.    * This allows us to parse any uploaded files before we enter
  86.    * our PoemSession (so we don't hang on to transactions
  87.    * unnecessarily).
  88.    *
  89.    * @param melati the current Melati
  90.    * @throws Exception if anything goes wrong
  91.    */
  92.   protected void prePoemSession(Melati melati) throws Exception {
  93.     // for this request, set the Initialised Template Engine
  94.     melati.setTemplateEngine(templateEngine);
  95.     ServletTemplateContext templateContext =
  96.             templateEngine.getServletTemplateContext(melati);

  97.     melati.setTemplateContext(templateContext);
  98.   }

  99.   protected void doPoemRequest(Melati melati) throws Exception {
  100.     ServletTemplateContext templateContext = melati.getServletTemplateContext();
  101.     // If we have a multi-part form, we use a different template context
  102.     // which allows us to access the uploaded files as well as fields.
  103.     // This used to be in prePoemSession, but the use case was pretty thin,
  104.     // the main Adaptor is PoemFileFormDataAdaptor, which needs to be in session.
  105.     String contentType = melati.getRequest().getHeader("content-type");
  106.     if (contentType != null && contentType.length() >= 19 &&
  107.         contentType.substring(0,19).equalsIgnoreCase("multipart/form-data")) {
  108.       templateContext =
  109.         new MultipartTemplateContext(melati, templateContext);
  110.     }

  111.     templateContext.put("melati", melati);
  112.     templateContext.put("ml", melati.getMarkupLanguage());

  113.     String templateName = doTemplateRequest(melati,templateContext);

  114.     // only expand a template if we have one (it could be a redirect)
  115.     if (templateName != null) {
  116.       templateName = addExtension(templateName);
  117.       templateEngine.expandTemplate(melati.getWriter(),
  118.                                     templateName,
  119.                                     templateContext);
  120.     }
  121.   }
  122.  
  123.   /**
  124.    * The template extension is added in an overridable method
  125.    * to allow the application developer to specify their own template
  126.    * extensions.
  127.    * <p>
  128.    * To obtain nice URLs one method is to call your templates
  129.    * <code>foo.html.wm</code> for example, your urls can then look like
  130.    * <code>servlet/db/table/troid/method.html</code>.
  131.    */
  132.   protected String addExtension(String templateName) {
  133.     if (!templateName.endsWith(templateEngine.templateExtension()))  
  134.       return templateName + templateEngine.templateExtension();
  135.     else
  136.       return templateName;      
  137.   }

  138.    
  139.   /**
  140.    * Send an error message.
  141.    *
  142.    * Single call to the templet loader giving purpose (error) and
  143.    * Exception class.
  144.    *
  145.    * This will look in the purpose directory,
  146.    * the standard templet directory and the classpath, in that order,
  147.    * for a templet.
  148.    * This can no longer fail with NotFoundException,
  149.    * as the Object templet will always be found
  150.    * (or this is a broken installation).
  151.    *
  152.    * @param melati the {@link Melati}
  153.    * @param e      the {@link Exception} to report
  154.    */
  155.   public void error(Melati melati, Exception e) {
  156.     melati.getResponse().setStatus(httpStatusCode(e));
  157.     ServletTemplateContext templateContext = melati.getServletTemplateContext();
  158.     // If this a DB error which has occurred prior to
  159.     // the establishment of a template context
  160.     if (templateContext == null) {
  161.       super.error(melati, e);
  162.     } else

  163.     // has it been trapped already, if so, we don't need to relog it here
  164.     if (!(e instanceof TrappedException)) {
  165.       try {
  166.         // log it
  167.         e.printStackTrace(System.err);
  168.         // and put it on the page
  169.         MelatiWriter mw =  melati.getWriter();
  170.         // get rid of anything that has been written so far
  171.         mw.reset();
  172.         templateContext.put("melati",melati);
  173.         templateContext.put("ml", melati.getMarkupLanguage());
  174.         templateContext.put("object", e);
  175.         StringWriter sw = new StringWriter();
  176.         e.printStackTrace(new PrintWriter(sw));
  177.         templateContext.put("error",sw);
  178.         templateContext.put("sysAdminName", getSysAdminName());
  179.         templateContext.put("sysAdminEmail", getSysAdminEmail());

  180.         Template errorTemplate;
  181.         errorTemplate = melati.getConfig().getTempletLoader().
  182.               templet(melati.getTemplateEngine(), melati.getMarkupLanguage(),"error", e.getClass());
  183.         templateEngine.expandTemplate(mw, errorTemplate, templateContext);
  184.         melati.write();
  185.       } catch (Exception f) {
  186.         System.err.println("Error finding/writing error template:");
  187.         f.printStackTrace();
  188.         super.error(melati,e);
  189.       }
  190.     }
  191.   }


  192.   /**
  193.    * Prepare context and establish name of template to interpolate against it.
  194.    *
  195.    * Override this method to build up your own output.
  196.    *
  197.    * @param melati the current Melati
  198.    * @param templateContext the current <code>ServletTemplateContext</code>
  199.    * @return a Template name, possibly excluding extension.
  200.    */
  201.   protected abstract String doTemplateRequest(Melati melati,
  202.                                               ServletTemplateContext templateContext)
  203.       throws Exception;
  204. }