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 }