1 /*
2 * $Source: /usr/cvsroot/melati/melati/src/main/java/org/melati/servlet/TemplateServlet.java,v $
3 * $Revision: 1.55 $
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: 1.55 $
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 * Inititialise 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 an multipart 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 * Override this method to build up your own output.
212 *
213 * @param melati the current Melati
214 * @param templateContext the current <code>ServletTemplateContext</code>
215 * @return a Template name, possibly excluding extension.
216 */
217 protected abstract String doTemplateRequest(Melati melati,
218 ServletTemplateContext templateContext)
219 throws Exception;
220 }