mirror of
https://github.com/apache/struts.git
synced 2026-08-07 07:37:20 +00:00
WW-3887 Extracts dedicated interface (with default implementation) to handle errors
This commit is contained in:
@@ -279,4 +279,6 @@ public final class StrutsConstants {
|
||||
|
||||
public static final String DEFAULT_TEMPLATE_TYPE_CONFIG_KEY = "struts.ui.templateSuffix";
|
||||
|
||||
/** Allows override default DispatcherErrorHandler **/
|
||||
public static final String STRUTS_DISPATCHER_ERROR_HANDLER = "struts.dispatcher.errorHandler";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.location.Location;
|
||||
import com.opensymphony.xwork2.util.location.LocationUtils;
|
||||
import com.opensymphony.xwork2.util.logging.Logger;
|
||||
import com.opensymphony.xwork2.util.logging.LoggerFactory;
|
||||
import freemarker.template.Template;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.views.freemarker.FreemarkerManager;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class DefaultDispatcherErrorHandler implements DispatcherErrorHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DefaultDispatcherErrorHandler.class);
|
||||
|
||||
private FreemarkerManager freemarkerManager;
|
||||
private boolean devMode;
|
||||
private Template template;
|
||||
|
||||
@Inject
|
||||
public void setFreemarkerManager(FreemarkerManager freemarkerManager) {
|
||||
this.freemarkerManager = freemarkerManager;
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
public void setDevMode(String devMode) {
|
||||
this.devMode = "true".equalsIgnoreCase(devMode);
|
||||
}
|
||||
|
||||
public void init(ServletContext ctx) {
|
||||
try {
|
||||
freemarker.template.Configuration config = freemarkerManager.getConfiguration(ctx);
|
||||
template = config.getTemplate("/org/apache/struts2/dispatcher/error.ftl");
|
||||
} catch (IOException e) {
|
||||
throw new StrutsException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleError(HttpServletRequest request, HttpServletResponse response, int code, Exception e) {
|
||||
Boolean devModeOverride = FilterDispatcher.getDevModeOverride();
|
||||
if (devModeOverride != null ? devModeOverride : devMode) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Exception occurred during processing request: #0", e, e.getMessage());
|
||||
}
|
||||
try {
|
||||
|
||||
List<Throwable> chain = new ArrayList<Throwable>();
|
||||
Throwable cur = e;
|
||||
chain.add(cur);
|
||||
while ((cur = cur.getCause()) != null) {
|
||||
chain.add(cur);
|
||||
}
|
||||
|
||||
HashMap<String,Object> data = new HashMap<String,Object>();
|
||||
data.put("exception", e);
|
||||
data.put("unknown", Location.UNKNOWN);
|
||||
data.put("chain", chain);
|
||||
data.put("locator", new Dispatcher.Locator());
|
||||
|
||||
Writer writer = new StringWriter();
|
||||
template.process(data, writer);
|
||||
|
||||
response.setContentType("text/html");
|
||||
response.getWriter().write(writer.toString());
|
||||
response.getWriter().close();
|
||||
} catch (Exception exp) {
|
||||
try {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Cannot show problem report!", exp);
|
||||
}
|
||||
response.sendError(code, "Unable to show problem report:\n" + exp + "\n\n" + LocationUtils.getLocation(exp));
|
||||
} catch (IOException ex) {
|
||||
// we're already sending an error, not much else we can do if more stuff breaks
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// WW-1977: Only put errors in the request when code is a 500 error
|
||||
if (code == HttpServletResponse.SC_INTERNAL_SERVER_ERROR) {
|
||||
// WW-4103: Only logs error when application error occurred, not Struts error
|
||||
if (LOG.isErrorEnabled()) {
|
||||
LOG.error("Exception occurred during processing request: #0", e, e.getMessage());
|
||||
}
|
||||
// send a http error response to use the servlet defined error handler
|
||||
// make the exception availible to the web.xml defined error page
|
||||
request.setAttribute("javax.servlet.error.exception", e);
|
||||
|
||||
// for compatibility
|
||||
request.setAttribute("javax.servlet.jsp.jspException", e);
|
||||
}
|
||||
|
||||
// send the error response
|
||||
response.sendError(code, e.getMessage());
|
||||
} catch (IOException e1) {
|
||||
// we're already sending an error, not much else we can do if more stuff breaks
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,20 +21,8 @@
|
||||
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.ActionProxyFactory;
|
||||
import com.opensymphony.xwork2.FileManager;
|
||||
import com.opensymphony.xwork2.FileManagerFactory;
|
||||
import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.FileManagerFactoryProvider;
|
||||
import com.opensymphony.xwork2.config.FileManagerProvider;
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.config.*;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
@@ -53,7 +41,6 @@ import com.opensymphony.xwork2.util.location.LocationUtils;
|
||||
import com.opensymphony.xwork2.util.logging.Logger;
|
||||
import com.opensymphony.xwork2.util.logging.LoggerFactory;
|
||||
import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
|
||||
import freemarker.template.Template;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.StrutsException;
|
||||
@@ -68,7 +55,6 @@ import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
|
||||
import org.apache.struts2.util.AttributeMap;
|
||||
import org.apache.struts2.util.ObjectFactoryDestroyable;
|
||||
import org.apache.struts2.util.fs.JBossFileManager;
|
||||
import org.apache.struts2.views.freemarker.FreemarkerManager;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -76,16 +62,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
@@ -168,6 +145,11 @@ public class Dispatcher {
|
||||
*/
|
||||
private boolean handleException;
|
||||
|
||||
/**
|
||||
* Interface used to handle internal errors or missing resources
|
||||
*/
|
||||
private DispatcherErrorHandler errorHandler;
|
||||
|
||||
/**
|
||||
* Provide the dispatcher instance for the current thread.
|
||||
*
|
||||
@@ -280,6 +262,11 @@ public class Dispatcher {
|
||||
this.handleException = Boolean.parseBoolean(handleException);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setDispatcherErrorHandler(DispatcherErrorHandler errorHandler) {
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all instances bound to this dispatcher instance.
|
||||
*/
|
||||
@@ -492,6 +479,10 @@ public class Dispatcher {
|
||||
l.dispatcherInitialized(this);
|
||||
}
|
||||
}
|
||||
//if (servletContext != null) {
|
||||
errorHandler.init(servletContext);
|
||||
//}
|
||||
|
||||
} catch (Exception ex) {
|
||||
if (LOG.isErrorEnabled())
|
||||
LOG.error("Dispatcher initialization failed", ex);
|
||||
@@ -847,70 +838,26 @@ public class Dispatcher {
|
||||
* @param code the HttpServletResponse error code (see {@link javax.servlet.http.HttpServletResponse} for possible error codes).
|
||||
* @param e the Exception that is reported.
|
||||
* @param ctx the ServletContext object.
|
||||
*
|
||||
* @deprecated remove in version 3.0 - use version without ServletContext parameter
|
||||
*/
|
||||
@Deprecated
|
||||
public void sendError(HttpServletRequest request, HttpServletResponse response, ServletContext ctx, int code, Exception e) {
|
||||
Boolean devModeOverride = FilterDispatcher.getDevModeOverride();
|
||||
if (devModeOverride != null ? devModeOverride : devMode) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Exception occurred during processing request: #0", e, e.getMessage());
|
||||
}
|
||||
try {
|
||||
FreemarkerManager mgr = getContainer().getInstance(FreemarkerManager.class);
|
||||
sendError(request, response, code, e);
|
||||
}
|
||||
|
||||
freemarker.template.Configuration config = mgr.getConfiguration(ctx);
|
||||
Template template = config.getTemplate("/org/apache/struts2/dispatcher/error.ftl");
|
||||
|
||||
List<Throwable> chain = new ArrayList<Throwable>();
|
||||
Throwable cur = e;
|
||||
chain.add(cur);
|
||||
while ((cur = cur.getCause()) != null) {
|
||||
chain.add(cur);
|
||||
}
|
||||
|
||||
HashMap<String,Object> data = new HashMap<String,Object>();
|
||||
data.put("exception", e);
|
||||
data.put("unknown", Location.UNKNOWN);
|
||||
data.put("chain", chain);
|
||||
data.put("locator", new Locator());
|
||||
|
||||
Writer writer = new StringWriter();
|
||||
template.process(data, writer);
|
||||
|
||||
response.setContentType("text/html");
|
||||
response.getWriter().write(writer.toString());
|
||||
response.getWriter().close();
|
||||
} catch (Exception exp) {
|
||||
try {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Cannot show problem report!", exp);
|
||||
}
|
||||
response.sendError(code, "Unable to show problem report:\n" + exp + "\n\n" + LocationUtils.getLocation(exp));
|
||||
} catch (IOException ex) {
|
||||
// we're already sending an error, not much else we can do if more stuff breaks
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// WW-1977: Only put errors in the request when code is a 500 error
|
||||
if (code == HttpServletResponse.SC_INTERNAL_SERVER_ERROR) {
|
||||
// WW-4103: Only logs error when application error occurred, not Struts error
|
||||
if (LOG.isErrorEnabled()) {
|
||||
LOG.error("Exception occurred during processing request: #0", e, e.getMessage());
|
||||
}
|
||||
// send a http error response to use the servlet defined error handler
|
||||
// make the exception availible to the web.xml defined error page
|
||||
request.setAttribute("javax.servlet.error.exception", e);
|
||||
|
||||
// for compatibility
|
||||
request.setAttribute("javax.servlet.jsp.jspException", e);
|
||||
}
|
||||
|
||||
// send the error response
|
||||
response.sendError(code, e.getMessage());
|
||||
} catch (IOException e1) {
|
||||
// we're already sending an error, not much else we can do if more stuff breaks
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Send an HTTP error response code.
|
||||
*
|
||||
* @param request the HttpServletRequest object.
|
||||
* @param response the HttpServletResponse object.
|
||||
* @param code the HttpServletResponse error code (see {@link javax.servlet.http.HttpServletResponse} for possible error codes).
|
||||
* @param e the Exception that is reported.
|
||||
*
|
||||
* @since 2.3.17
|
||||
*/
|
||||
public void sendError(HttpServletRequest request, HttpServletResponse response, int code, Exception e) {
|
||||
errorHandler.handleError(request, response, code, e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Implementation of this interface is used to handle internal errors or missing resources.
|
||||
* Basically it sends back HTTP error codes or error page depends on requirements.
|
||||
*/
|
||||
public interface DispatcherErrorHandler {
|
||||
|
||||
/**
|
||||
* Init instance after creating {@link org.apache.struts2.dispatcher.Dispatcher}
|
||||
* @param ctx current {@link javax.servlet.ServletContext}
|
||||
*/
|
||||
public void init(ServletContext ctx);
|
||||
|
||||
/**
|
||||
* Handle passed error code or exception
|
||||
*
|
||||
* @param request current {@link javax.servlet.http.HttpServletRequest}
|
||||
* @param response current {@link javax.servlet.http.HttpServletResponse}
|
||||
* @param code HTTP Error Code, see {@link javax.servlet.http.HttpServletResponse} for possible error codes
|
||||
* @param e Exception to report
|
||||
*/
|
||||
public void handleError(HttpServletRequest request, HttpServletResponse response, int code, Exception e);
|
||||
|
||||
}
|
||||
@@ -132,6 +132,10 @@
|
||||
<bean type="org.apache.struts2.dispatcher.StaticContentLoader" class="org.apache.struts2.dispatcher.DefaultStaticContentLoader" name="struts" />
|
||||
<bean type="com.opensymphony.xwork2.UnknownHandlerManager" class="com.opensymphony.xwork2.DefaultUnknownHandlerManager" name="struts" />
|
||||
|
||||
<bean type="org.apache.struts2.dispatcher.DispatcherErrorHandler" name="struts" class="org.apache.struts2.dispatcher.DefaultDispatcherErrorHandler" />
|
||||
|
||||
<constant name="struts.dispatcher.errorHandler" value="struts" />
|
||||
|
||||
<!-- Silly workarounds for OGNL since there is currently no way to flush its internal caches -->
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
|
||||
Reference in New Issue
Block a user