/*
* Copyright 2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.agila.impl.servlet;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Enumeration;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.Template;
/**
* Standard riff ont he actionservlet idea
*
* @author <a href="mailto:geir@gluecode.com">Geir Magnusson Jr.</a>
*/
public abstract class VelocityActionServlet extends ActionServlet
{
private final Class[] args = {HttpServletRequest.class,
HttpServletResponse.class,
VelocityContext.class};
public static final String TEMPLATE_PATH_KEY = "templatePath";
public static final String SERVLET_KEY = "servlet";
public static final String DEFAULT_PROPS = "org/apache/agila/impl/servlet/velocity.properties";
public static final String HTTP_ACTION_VERB = "action";
private VelocityEngine velEngine = new VelocityEngine();
public void init()
throws ServletException {
/*
* get the default properties from the classloader
*/
Properties p = new Properties();
try {
InputStream is = getClass().getClassLoader().getResourceAsStream(DEFAULT_PROPS);
p.load(is);
}
catch(Exception e)
{
fatal("default " + DEFAULT_PROPS + " not found.", e);
throw new ServletException(e);
}
/*
* run through them and use them
*/
for (Enumeration en=p.propertyNames(); en.hasMoreElements(); ) {
String key = (String) en.nextElement();
String value = p.getProperty(key);
/*
* if it's the file.resource.loader.path then 'stick it'
*/
info("Property " + key + " = " + value);
if (key.equals(Velocity.FILE_RESOURCE_LOADER_PATH)) {
String root = getServletContext().getRealPath(value);
velEngine.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, root);
}
else {
velEngine.setProperty(key, value);
}
}
/*
* for now, log to the servlet log
*/
ServletLogger sl = new ServletLogger(getServletContext());
velEngine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, sl);
/*
* set an app context for the webapploader if we are using it
*/
ServletAppContext vssac = new ServletAppContext(getServletContext());
velEngine.setApplicationAttribute(WebappLoader.KEY, vssac);
try {
velEngine.init();
}
catch(Exception e) {
fatal("VelocityActionServlet",e);
throw new ServletException(e);
}
}
/**
* Return the root of template path. Note that this should not include
* the bit returned by getTemplatePathPrefix().
*/
public abstract String getTemplateRoot();
/**
* Service routine to dispatch via action verb.
*
* @param req
* @param res
* @throws ServletException
* @throws java.io.IOException
*/
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, java.io.IOException {
String actionVerb = getActionVerb();
String what = req.getParameter(actionVerb);
if (what == null) {
what = "defaultAction";
}
try {
Method method = this.getClass().getMethod(what, args);
Object[] objs = { req, res, getVelocityContext(req) };
method.invoke(this, objs);
}
catch(NoSuchMethodException nsme) {
unknownAction(req, res, getVelocityContext(req));
}
catch(IllegalAccessException iae) {
error("service():", iae);
}
catch(InvocationTargetException ite) {
warn("service() : exception invoking action = " + what, ite);
/*
* this is the old way. 'getCause()' is the new way, but 1.4
* specific
*/
Throwable t = ite.getTargetException();
if (t instanceof ServletException) {
throw (ServletException) t;
}
if ( t instanceof IOException) {
throw (IOException) t;
}
}
}
/**
* Abstract method to be implemented by children, called when
* there is no action specified
*
* @param req
* @param res
* @throws ServletException
* @throws java.io.IOException
*/
public abstract void defaultAction(HttpServletRequest req,
HttpServletResponse res,
VelocityContext ctx)
throws ServletException, java.io.IOException;
/**
* Abstract method to be implemented by children, calle when
* the action specified is not found
*
* @param req
* @param res
* @throws ServletException
* @throws java.io.IOException
*/
public abstract void unknownAction(HttpServletRequest req,
HttpServletResponse res,
VelocityContext ctx)
throws ServletException, java.io.IOException;
/**
* Implement this to make our parent happy
* @param req
* @param res
* @throws ServletException
*/
public final void defaultAction(HttpServletRequest req, HttpServletResponse res)
throws ServletException {
throw new ServletException("Shouldn't be here");
}
/**
* Implement this to make our parent happy
* @param req
* @param res
* @throws ServletException
*/
public final void unknownAction(HttpServletRequest req, HttpServletResponse res)
throws ServletException {
throw new ServletException("Shouldn't be here");
}
protected String getActionVerb() {
return HTTP_ACTION_VERB;
}
protected VelocityEngine getVelocityEngine() {
return velEngine;
}
protected String getInitParameter(String key, String defaultValue) {
String val = getServletConfig().getInitParameter(key);
if (val == null) {
val = defaultValue;
}
return val;
}
public void info(String msg) {
super.log("INFO : " + msg);
}
public void info(String msg, Throwable e) {
super.log("INFO : " + msg, e);
}
/**
* warning message
*/
public void warn(String msg) {
super.log("WARN : " + msg);
}
public void warn(String msg, Throwable e) {
super.log("WARN : " + msg, e);
}
/**
* error message
*/
public void error(String msg) {
super.log("ERROR : " + msg);
}
public void error(String msg, Throwable e) {
super.log("ERROR : " + msg, e);
}
/**
* fatal message
*/
public void fatal(String msg) {
super.log("FATAL : " + msg);
}
public void fatal(String msg, Throwable e) {
super.log("FATAL : " + msg, e);
}
/**
* debug messages
*/
public void debug(String msg) {
super.log("DEBUG : " + msg);
}
public void debug(String msg, Throwable e) {
super.log("DEBUG : " + msg, e);
}
/**
* trace messages
*/
public void trace(String msg) {
super.log("TRACE : " + msg);
}
public void trace(String msg, Throwable e) {
super.log("TRACE : " + msg, e);
}
/**
* little wrapper class to safely pass the ServletContext to the loader
*/
public class ServletAppContext implements WebappLoaderAppContext {
ServletContext servletContext = null;
ServletAppContext(ServletContext sc) {
servletContext = sc;
}
public ServletContext getServletContext() {
return servletContext;
}
}
protected VelocityContext getVelocityContext(HttpServletRequest req) {
VelocityContext vc = new VelocityContext();
vc.put(TEMPLATE_PATH_KEY, getTemplatePathPrefix() + getTemplateRoot());
return vc;
}
protected void errorPage(HttpServletRequest req, HttpServletResponse res)
throws ServletException, java.io.IOException {
PrintWriter pw = res.getWriter();
pw.println("<html><body>");
pw.println("Error");
pw.println("</body></html>");
pw.flush();
}
protected String getTemplatePathPrefix() {
return "/";
}
protected boolean renderTemplate(HttpServletRequest req,
HttpServletResponse res, String template) {
try {
VelocityContext vc = getVelocityContext(req);
return renderTemplate(req, res, vc, template);
}
catch (Exception e) {
e.printStackTrace();
}
return false;
}
protected boolean renderTemplate(HttpServletRequest req,
HttpServletResponse res, VelocityContext vc,
String template) {
boolean result = false;
try {
Template t = getVelocityEngine().getTemplate(getTemplatePathPrefix()
+ getTemplateRoot() + template);
t.merge(vc, res.getWriter());
result = true;
}
catch (Exception e) {
e.printStackTrace();
}
return result;
}
}