TemplateServlet.java
/*
* $Source$
* $Revision$
*
* Copyright (C) 2000 Tim Joyce
*
* Part of Melati (http://melati.org), a framework for the rapid
* development of clean, maintainable web applications.
*
* Melati is free software; Permission is granted to copy, distribute
* and/or modify this software under the terms either:
*
* a) the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version,
*
* or
*
* b) any version of the Melati Software License, as published
* at http://melati.org
*
* You should have received a copy of the GNU General Public License and
* the Melati Software License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
* GNU General Public License and visit http://melati.org to obtain the
* Melati Software License.
*
* Feel free to contact the Developers of Melati (http://melati.org),
* if you would like to work out a different arrangement than the options
* outlined here. It is our intention to allow Melati to be used by as
* wide an audience as possible.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contact details for copyright holder:
*
* Tim Joyce <timj At paneris.org>
* http://paneris.org/
* 68 Sandbanks Rd, Poole, Dorset. BH14 8BY. UK
*/
package org.melati.servlet;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import org.melati.Melati;
import org.melati.util.MelatiWriter;
import org.melati.template.ServletTemplateEngine;
import org.melati.template.ServletTemplateContext;
import org.melati.template.MultipartTemplateContext;
import org.melati.template.Template;
/**
* Base class to use Melati with a Template Engine.
* To create your own servlet simply extend this class,
* overriding the <code>doTemplateRequest</code> method.
*
* @author Tim Joyce
* $Revision$
*/
public abstract class TemplateServlet extends PoemServlet {
/**
* Eclipse generated.
*/
private static final long serialVersionUID = -5228388231472549208L;
// the template engine
protected ServletTemplateEngine templateEngine;
/**
* Initialise the template engine.
*
* @param config a <code>ServletConfig</code>
* @throws ServletException if the ServletTemplateEngine has a problem
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
templateEngine = melatiConfig.getServletTemplateEngine();
templateEngine.init(melatiConfig, this);
}
/**
* Set the ServletTemplateEngine and ServletTemplateContext in our Melati.
* This allows us to parse any uploaded files before we enter
* our PoemSession (so we don't hang on to transactions
* unnecessarily).
*
* @param melati the current Melati
* @throws Exception if anything goes wrong
*/
protected void prePoemSession(Melati melati) throws Exception {
// for this request, set the Initialised Template Engine
melati.setTemplateEngine(templateEngine);
ServletTemplateContext templateContext =
templateEngine.getServletTemplateContext(melati);
melati.setTemplateContext(templateContext);
}
protected void doPoemRequest(Melati melati) throws Exception {
ServletTemplateContext templateContext = melati.getServletTemplateContext();
// If we have a multi-part form, we use a different template context
// which allows us to access the uploaded files as well as fields.
// This used to be in prePoemSession, but the use case was pretty thin,
// the main Adaptor is PoemFileFormDataAdaptor, which needs to be in session.
String contentType = melati.getRequest().getHeader("content-type");
if (contentType != null && contentType.length() >= 19 &&
contentType.substring(0,19).equalsIgnoreCase("multipart/form-data")) {
templateContext =
new MultipartTemplateContext(melati, templateContext);
}
templateContext.put("melati", melati);
templateContext.put("ml", melati.getMarkupLanguage());
String templateName = doTemplateRequest(melati,templateContext);
// only expand a template if we have one (it could be a redirect)
if (templateName != null) {
templateName = addExtension(templateName);
templateEngine.expandTemplate(melati.getWriter(),
templateName,
templateContext);
}
}
/**
* The template extension is added in an overridable method
* to allow the application developer to specify their own template
* extensions.
* <p>
* To obtain nice URLs one method is to call your templates
* <code>foo.html.wm</code> for example, your urls can then look like
* <code>servlet/db/table/troid/method.html</code>.
*/
protected String addExtension(String templateName) {
if (!templateName.endsWith(templateEngine.templateExtension()))
return templateName + templateEngine.templateExtension();
else
return templateName;
}
/**
* Send an error message.
*
* Single call to the templet loader giving purpose (error) and
* Exception class.
*
* This will look in the purpose directory,
* the standard templet directory and the classpath, in that order,
* for a templet.
* This can no longer fail with NotFoundException,
* as the Object templet will always be found
* (or this is a broken installation).
*
* @param melati the {@link Melati}
* @param e the {@link Exception} to report
*/
public void error(Melati melati, Exception e) {
melati.getResponse().setStatus(httpStatusCode(e));
ServletTemplateContext templateContext = melati.getServletTemplateContext();
// If this a DB error which has occurred prior to
// the establishment of a template context
if (templateContext == null) {
super.error(melati, e);
} else
// has it been trapped already, if so, we don't need to relog it here
if (!(e instanceof TrappedException)) {
try {
// log it
e.printStackTrace(System.err);
// and put it on the page
MelatiWriter mw = melati.getWriter();
// get rid of anything that has been written so far
mw.reset();
templateContext.put("melati",melati);
templateContext.put("ml", melati.getMarkupLanguage());
templateContext.put("object", e);
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
templateContext.put("error",sw);
templateContext.put("sysAdminName", getSysAdminName());
templateContext.put("sysAdminEmail", getSysAdminEmail());
Template errorTemplate;
errorTemplate = melati.getConfig().getTempletLoader().
templet(melati.getTemplateEngine(), melati.getMarkupLanguage(),"error", e.getClass());
templateEngine.expandTemplate(mw, errorTemplate, templateContext);
melati.write();
} catch (Exception f) {
System.err.println("Error finding/writing error template:");
f.printStackTrace();
super.error(melati,e);
}
}
}
/**
* Prepare context and establish name of template to interpolate against it.
*
* Override this method to build up your own output.
*
* @param melati the current Melati
* @param templateContext the current <code>ServletTemplateContext</code>
* @return a Template name, possibly excluding extension.
*/
protected abstract String doTemplateRequest(Melati melati,
ServletTemplateContext templateContext)
throws Exception;
}