package dark.web.frame.velocity.form;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.velocity.Template;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
/**
* Title:
* Description: 根据org.apache.velocity.servlet.VelocityLayoutServlet修改
* 以使dwf中的Form支持Velocity的Layout管理
* Copyright: Copyright (c) 2005
* Company: DIS
* Create Time: 2005-3-4 3:02:46
* @author darkhe
* @version 1.0
*/
public abstract class VelocityLayoutForm extends VelocityForm
{
/**
* The context/parameter key used to specify an alternate
* layout to be used for a request instead of the default layout.
*/
public static String KEY_LAYOUT = "layout";
/**
* The context key that will hold the content of the screen.
*
* This key ($screen_content) must be present in the layout
* template for the current screen to be rendered.
*/
public static String KEY_SCREEN_CONTENT = "screen_content";
/**
* The context key that holds the {@link Throwable} that
* broke the rendering of the requested screen.
*/
public static String KEY_ERROR_CAUSE = "error_cause";
/**
* The context key that holds the stack trace of the error that
* broke the rendering of the requested screen.
*/
public static String KEY_ERROR_STACKTRACE = "stack_trace";
/**
* The context key that holds the {@link MethodInvocationException}
* that broke the rendering of the requested screen.
*
* If this value is placed in the context, then $error_cause
* will hold the error that this invocation exception is wrapping.
*/
public static String KEY_ERROR_INVOCATION_EXCEPTION = "invocation_exception";
private String errorTemplate;
private String layoutDir;
private String defaultLayout;
/**
* Overrides VelocityViewServlet to check the request for
* an alternate layout
*
* @param request client request
* @param response client response
* @return the Context to fill
*/
protected Context createContext(
HttpServletRequest request,
HttpServletResponse response)
{
Context ctx = super.createContext(request, response);
// check if an alternate layout has been specified
// by way of the request parameters
String layout = request.getParameter(KEY_LAYOUT);
if (layout != null)
{
// let the template know what its new layout is
ctx.put(KEY_LAYOUT, layout);
}
return ctx;
}
/**
* Overrides VelocityViewServlet.mergeTemplate to do a two-pass
* render for handling layouts
*/
protected void mergeTemplate(
Template template,
Context context,
HttpServletResponse response)
throws
ResourceNotFoundException,
ParseErrorException,
MethodInvocationException,
IOException,
UnsupportedEncodingException,
Exception
{
//
// this section is based on Tim Colson's "two pass render"
//
// Render the screen content
StringWriter sw = new StringWriter();
template.merge(context, sw);
// Add the resulting content to the context
context.put(KEY_SCREEN_CONTENT, sw.toString());
// Check for an alternate layout
//
// we check after merging the screen template so the screen
// can overrule any layout set in the request parameters
// by doing #set( $layout = "MyLayout.vm" )
Object obj = context.get(KEY_LAYOUT);
String layout = (obj == null) ? null : obj.toString();
if (layout == null)
{
// no alternate, use default
layout = defaultLayout;
}
else
{
// make it a full(er) path
layout = layoutDir + layout;
}
try
{
//load the layout template
template = getTemplate(layout);
}
catch (Exception e)
{
Velocity.error(
"VelocityLayoutCommand: Can't load layout \""
+ layout
+ "\": "
+ e);
// if it was an alternate layout we couldn't get...
if (!layout.equals(defaultLayout))
{
// try to get the default layout
// if this also fails, let the exception go
template = getTemplate(defaultLayout);
}
}
// Render the layout template into the response
super.mergeTemplate(template, context, response);
}
/**
* Overrides VelocityViewServlet to display user's custom error template
*/
protected void error(
HttpServletRequest request,
HttpServletResponse response,
Exception e)
throws ServletException
{
try
{
// get a velocity context
Context ctx = createContext(request, response);
Throwable cause = e;
// if it's an MIE, i want the real cause and stack trace!
if (cause instanceof MethodInvocationException)
{
// put the invocation exception in the context
ctx.put(KEY_ERROR_INVOCATION_EXCEPTION, e);
// get the real cause
cause = ((MethodInvocationException) e).getWrappedThrowable();
}
// add the cause to the context
ctx.put(KEY_ERROR_CAUSE, cause);
// grab the cause's stack trace and put it in the context
StringWriter sw = new StringWriter();
cause.printStackTrace(new java.io.PrintWriter(sw));
ctx.put(KEY_ERROR_STACKTRACE, sw.toString());
// retrieve and render the error template
Template et = getTemplate(errorTemplate);
mergeTemplate(et, ctx, response);
}
catch (Exception e2)
{
// d'oh! log this
Velocity.error(
"VelocityLayoutCommand: "
+ " Error during error template rendering - "
+ e2);
// then punt the original to a higher authority
super.error(request, response, e);
}
}
/**
* @return
*/
public String getDefaultLayout()
{
return defaultLayout;
}
/**
* @param string
*/
public void setDefaultLayout(String string)
{
defaultLayout = string;
}
/**
* @return
*/
public String getErrorTemplate()
{
return errorTemplate;
}
/**
* @return
*/
public String getLayoutDir()
{
return layoutDir;
}
/**
* @param string
*/
public void setErrorTemplate(String string)
{
errorTemplate = string;
}
/**
* @param string
*/
public void setLayoutDir(String string)
{
layoutDir = string;
}
}