View Javadoc

1   /*
2    * $Source: /usr/cvsroot/melati/melati/src/main/java/org/melati/servlet/TemplateServlet.java,v $
3    * $Revision: 1.53 $
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  
46  package org.melati.servlet;
47  
48  import java.io.PrintWriter;
49  import java.io.StringWriter;
50  
51  import javax.servlet.ServletException;
52  import javax.servlet.ServletConfig;
53  
54  import org.melati.Melati;
55  import org.melati.util.MelatiWriter;
56  import org.melati.template.ServletTemplateEngine;
57  import org.melati.template.ServletTemplateContext;
58  import org.melati.template.MultipartTemplateContext;
59  import org.melati.template.TemplateEngineException;
60  import org.melati.template.Template;
61  
62  /**
63   * Base class to use Melati with a Template Engine.
64   * To create your own servlet simply extend this class, 
65   * overriding the <code>doTemplateRequest</code> method.
66   *
67   * @author Tim Joyce
68   * $Revision: 1.53 $
69   */
70  public abstract class TemplateServlet extends PoemServlet {
71  
72    /**
73     * Eclipse generated. 
74     */
75    private static final long serialVersionUID = -5228388231472549208L;
76    
77    // the template engine
78    protected ServletTemplateEngine templateEngine;
79  
80    /**
81     * Inititialise the template engine.
82     *
83     * @param config a <code>ServletConfig</code>
84     * @throws ServletException if the ServletTemplateEngine has a problem
85     */
86    public void init(ServletConfig config) throws ServletException {
87      super.init(config);
88      try {
89        templateEngine = melatiConfig.getServletTemplateEngine();
90        templateEngine.init(melatiConfig, this);
91      } catch (TemplateEngineException e) {
92        // log it to system.err as ServletExceptions go to the
93        // servlet runner log (eg jserv.log), and don't have a stack trace!
94        e.printStackTrace(System.err);
95        throw new ServletException(e.toString());
96      }
97    }
98  
99    /**
100    * Set the ServletTemplateEngine and ServletTemplateContext in our Melati.
101    * This allows us to parse any uploaded files before we enter
102    * our PoemSession (so we don't hang on to transactions
103    * unnecessarily).
104    *
105    * @param melati the current Melati
106    * @throws Exception if anything goes wrong
107    */
108   protected void prePoemSession(Melati melati) throws Exception {
109     // for this request, set the Initialised Template Engine
110     melati.setTemplateEngine(templateEngine);
111     ServletTemplateContext templateContext =
112             templateEngine.getServletTemplateContext(melati);
113 
114     melati.setTemplateContext(templateContext);
115   }
116 
117   protected void doPoemRequest(Melati melati) throws Exception {
118     ServletTemplateContext templateContext = melati.getServletTemplateContext();
119     // If we have an multipart form, we use a different template context
120     // which allows us to access the uploaded files as well as fields.
121     // This used to be in prePoemSession, but the use case was pretty thin,
122     // the main Adaptor is PoemFileFormDataAdaptor, which needs to be in session.
123     String contentType = melati.getRequest().getHeader("content-type");
124     if (contentType != null && contentType.length() >= 19 &&
125         contentType.substring(0,19).equalsIgnoreCase("multipart/form-data")) {
126       templateContext =
127         new MultipartTemplateContext(melati, templateContext);
128     }
129 
130     templateContext.put("melati", melati);
131     templateContext.put("ml", melati.getMarkupLanguage());
132 
133     String templateName = doTemplateRequest(melati,templateContext);
134 
135     // only expand a template if we have one (it could be a redirect)
136     if (templateName != null) {
137       templateName = addExtension(templateName);
138       templateEngine.expandTemplate(melati.getWriter(), 
139                                     templateName,
140                                     templateContext);
141     }
142   }
143   
144   /**
145    * The template extension is added in an overridable method
146    * to allow the application developer to specify their own template
147    * extensions.
148    * <p>
149    * To obtain nice URLs one method is to call your templates 
150    * <code>foo.html.wm</code> for example, your urls can then look like
151    * <code>servlet/db/table/troid/method.html</code>.
152    */
153   protected String addExtension(String templateName) {
154     if (!templateName.endsWith(templateEngine.templateExtension()))  
155       return templateName + templateEngine.templateExtension();
156     else
157       return templateName;      
158   }
159 
160    
161   /**
162    * Send an error message.
163    * 
164    * Single call to the templet loader giving purpose (error) and 
165    * Exception class.
166    *
167    * This will look in the purpose directory, 
168    * the standard templet directory and the classpath, in that order, 
169    * for a templet.
170    * This can no longer fail with NotFoundException, 
171    * as the Object templet will always be found 
172    * (or this is a broken installation).
173    *
174    * @param melati the {@link Melati}
175    * @param e      the {@link Exception} to report
176    */
177   public void error(Melati melati, Exception e) {
178     ServletTemplateContext templateContext = melati.getServletTemplateContext();
179     // If this a DB error which has occurred prior to 
180     // the establishment of a template context
181     if (templateContext == null) {
182       super.error(melati, e);
183     } else 
184 
185     // has it been trapped already, if so, we don't need to relog it here
186     if (!(e instanceof TrappedException)) {
187       try {
188         // log it
189         e.printStackTrace(System.err);
190         // and put it on the page
191         MelatiWriter mw =  melati.getWriter();
192         // get rid of anything that has been written so far
193         mw.reset();
194         templateContext.put("melati",melati);
195         templateContext.put("ml", melati.getMarkupLanguage());
196         templateContext.put("object", e);
197         StringWriter sw = new StringWriter();
198         e.printStackTrace(new PrintWriter(sw));
199         templateContext.put("error",sw);
200         templateContext.put("sysAdminName", getSysAdminName());
201         templateContext.put("sysAdminEmail", getSysAdminEmail());
202 
203         Template errorTemplate;
204         errorTemplate = melati.getConfig().getTempletLoader().
205               templet(melati.getTemplateEngine(), melati.getMarkupLanguage(),"error", e.getClass());
206         templateEngine.expandTemplate(mw, errorTemplate, templateContext);
207         melati.write();
208       } catch (Exception f) {
209         System.err.println("Error finding/writing error template:");
210         f.printStackTrace();
211         super.error(melati,e);
212       }
213     }
214   }
215 
216 
217   /**
218    * Override this method to build up your own output.
219    *
220    * @param melati the current Melati
221    * @param templateContext the current <code>ServletTemplateContext</code>
222    * @return a Template name, possibly excluding extension.
223    */
224   protected abstract String doTemplateRequest(Melati melati, 
225                                               ServletTemplateContext templateContext)
226       throws Exception;
227 }