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 }