NIHVIVO-3088 On error in Freemarker servlet processing, display stack trace to authorized users.

This commit is contained in:
ryounes 2011-08-11 22:03:19 +00:00
parent 100df03127
commit 6bb9831bda
4 changed files with 56 additions and 22 deletions

View file

@ -5,8 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -14,16 +12,15 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditOwnAccount; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditOwnAccount;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.UseMiscellaneousAdminPages;
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage; import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.TemplateProcessingHelper.TemplateProcessingException; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.TemplateProcessingHelper.TemplateProcessingException;
@ -35,7 +32,6 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Red
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.User; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.User;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.MainMenu; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.MainMenu;
import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.BeansWrapper;
@ -57,6 +53,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
STANDARD_ERROR("error-standard.ftl"), STANDARD_ERROR("error-standard.ftl"),
ERROR_MESSAGE("error-message.ftl"), ERROR_MESSAGE("error-message.ftl"),
TITLED_ERROR_MESSAGE("error-titled.ftl"), TITLED_ERROR_MESSAGE("error-titled.ftl"),
ERROR_DISPLAY("error-display.ftl"),
MESSAGE("message.ftl"), MESSAGE("message.ftl"),
TITLED_MESSAGE("message-titled.ftl"), TITLED_MESSAGE("message-titled.ftl"),
PAGE_DEFAULT("page.ftl"), PAGE_DEFAULT("page.ftl"),
@ -94,7 +91,6 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
config.resetRequestSpecificSharedVariables(); config.resetRequestSpecificSharedVariables();
responseValues = processRequest(vreq); responseValues = processRequest(vreq);
doResponse(vreq, response, responseValues); doResponse(vreq, response, responseValues);
} catch (Throwable e) { } catch (Throwable e) {
@ -112,7 +108,22 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
protected void handleException(VitroRequest vreq, HttpServletResponse response, Throwable t) throws ServletException { protected void handleException(VitroRequest vreq, HttpServletResponse response, Throwable t) throws ServletException {
try { try {
doResponse(vreq, response, new ExceptionResponseValues(t, HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
ExceptionResponseValues rv;
String templateName = Template.ERROR_DISPLAY.toString();
if (PolicyHelper.isAuthorizedForActions(vreq, new UseMiscellaneousAdminPages())) {
Map<String, Object> map = new HashMap<String, Object>();
Map<String, String> errorData = new HashMap<String, String>();
errorData.put("errorMessage", t.getMessage());
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
errorData.put("stackTrace", sw.toString());
map.put("errorData", errorData);
rv = new ExceptionResponseValues(templateName, map, t, statusCode);
} else {
rv = new ExceptionResponseValues(templateName, t, statusCode);
}
doResponse(vreq, response, rv);
} catch (TemplateProcessingException e) { } catch (TemplateProcessingException e) {
throw new ServletException(); throw new ServletException();
} }
@ -206,7 +217,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
// Tell the template and any directives it uses that we're processing a page template. // Tell the template and any directives it uses that we're processing a page template.
templateDataModel.put("templateType", PAGE_TEMPLATE_TYPE); templateDataModel.put("templateType", PAGE_TEMPLATE_TYPE);
writePage(templateDataModel, config, vreq, response, values.getStatusCode()); writePage(templateDataModel, config, vreq, response, values.getStatusCode(), values);
} }
protected void doRedirect(HttpServletRequest request, HttpServletResponse response, ResponseValues values) protected void doRedirect(HttpServletRequest request, HttpServletResponse response, ResponseValues values)
@ -256,8 +267,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
ResponseValues values) throws TemplateProcessingException { ResponseValues values) throws TemplateProcessingException {
// Log the error, and display an error message on the page. // Log the error, and display an error message on the page.
log.error(values.getException(), values.getException()); log.error(values.getException(), values.getException());
TemplateResponseValues trv = TemplateResponseValues.getTemplateResponseValuesFromException((ExceptionResponseValues)values); doTemplate(vreq, response, values);
doTemplate(vreq, response, trv);
} }
public String getThemeDir(ApplicationBean appBean) { public String getThemeDir(ApplicationBean appBean) {
@ -408,9 +418,15 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
return processTemplate(values, config, request).toString(); return processTemplate(values, config, request).toString();
} }
protected void writePage(Map<String, Object> root, Configuration config, protected void writePage(Map<String, Object> root, Configuration config, HttpServletRequest request,
HttpServletRequest request, HttpServletResponse response, int statusCode) throws TemplateProcessingException { HttpServletResponse response, int statusCode, ResponseValues rv) throws TemplateProcessingException {
writeTemplate(getPageTemplateName(), root, config, request, response, statusCode);
// For an error page, use the standard page template rather than a special one, in case that is the source
// of the error. (The standard page template could also be the source of the error, but that is
// less likely.
String pageTemplateName =
rv instanceof ExceptionResponseValues ? Template.PAGE_DEFAULT.toString() : getPageTemplateName();
writeTemplate(pageTemplateName, root, config, request, response, statusCode);
} }
protected void writeTemplate(String templateName, Map<String, Object> map, Configuration config, protected void writeTemplate(String templateName, Map<String, Object> map, Configuration config,

View file

@ -48,10 +48,5 @@ public class TemplateResponseValues extends BaseResponseValues {
return this.templateName; return this.templateName;
} }
public static TemplateResponseValues getTemplateResponseValuesFromException(ExceptionResponseValues responseValues) {
return new TemplateResponseValues(responseValues.getTemplateName(),
responseValues.getMap(),
responseValues.getStatusCode());
}
} }

View file

@ -4,10 +4,10 @@
<h2>${title}</h2> <h2>${title}</h2>
<#if aboutText??> <#if aboutText?has_content>
<div class="pageGroupBody" id="aboutText">${aboutText}</div> <div class="pageGroupBody" id="aboutText">${aboutText}</div>
</#if> </#if>
<#if acknowledgeText??> <#if acknowledgeText?has_content>
<div class="pageGroupBody" id="acknowledgementText">${acknowledgeText}</div> <div class="pageGroupBody" id="acknowledgementText">${acknowledgeText}</div>
</#if> </#if>

View file

@ -0,0 +1,23 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Template for general system error. -->
<p>
There was an error in the system.
<#-- This error has been reported to the site administrator. -->
</p>
<#if errorData??> <#-- view for site administrators -->
<#if errorData.errorMessage?has_content>
<p><strong>Error message:</strong> ${errorData.errorMessage}</p>
</#if>
<#if errorData.stackTrace?has_content>
<div>
<p><strong>Stack trace</strong> (full trace available in the vivo log):</p>
${errorData.stackTrace}
</div>
</#if>
<#elseif ! urls.currentPage?ends_with("home")> <#-- view for other users -->
<p>Return to the <a href="${urls.home}">home page</a>.</p>
</#if>