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