Skip to content

Commit

Permalink
Grails would sometimes attempt to render the wrong view, particularly
Browse files Browse the repository at this point in the history
during error dispatch. This was because certain information about the
view to render was stored in the request, and that was affecting whatever
was forwarded to. So while Grails would try to render the view associated
with an error action, suddenly it would end up rendering the original
one.

This fix clears certain request attributes before that request is
forwarded. This was already being done for includes, so I refactored
to share the code with the forwarding methods.

Conflicts:

	src/java/org/codehaus/groovy/grails/web/servlet/mvc/SimpleGrailsControllerHelper.java
	src/java/org/codehaus/groovy/grails/web/util/WebUtils.java
  • Loading branch information
pledbrook committed Jul 30, 2010
1 parent 3a1539d commit 3a0e57a
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 32 deletions.
Expand Up @@ -338,7 +338,7 @@ public Locale getLocale() {

mv = super.processHandlerException(processedRequest, response, mappedHandler, e);
handlerException = e;
render(mv, processedRequest, response);
if (mv != null) render(mv, processedRequest, response);
}
else {
request.removeAttribute(GrailsApplicationAttributes.RENDERING_ERROR_ATTRIBUTE);
Expand Down
Expand Up @@ -384,14 +384,14 @@ public Object handleAction(GroovyObject controller,Closure action, HttpServletRe
public ModelAndView handleActionResponse( GroovyObject controller,Object returnValue,String closurePropertyName, String viewName) {
boolean viewNameBlank = (viewName == null || viewName.length() == 0);
// reset the metaclass
ModelAndView explicityModelAndView = (ModelAndView)controller.getProperty(ControllerDynamicMethods.MODEL_AND_VIEW_PROPERTY);
ModelAndView explicitModelAndView = (ModelAndView)controller.getProperty(ControllerDynamicMethods.MODEL_AND_VIEW_PROPERTY);

if (!webRequest.isRenderView()) {
return null;
}

if (explicityModelAndView != null) {
return explicityModelAndView;
if (explicitModelAndView != null) {
return explicitModelAndView;
}

if (returnValue == null) {
Expand Down
102 changes: 74 additions & 28 deletions src/java/org/codehaus/groovy/grails/web/util/WebUtils.java
Expand Up @@ -281,6 +281,12 @@ public static String forwardRequestForUrlMappingInfo(HttpServletRequest request,
//populateParamsForMapping(info);
RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);

// Clear the request attributes that affect view rendering. Otherwise
// whatever we forward to may render the wrong thing! Note that we
// don't care about the return value because we're delegating
// responsibility for rendering the response.
saveAndResetWebRequest(request, info);

exposeForwardRequestAttributes(request);
exposeRequestAttributes(request, model);
dispatcher.forward(request, response);
Expand All @@ -303,42 +309,82 @@ public static IncludedContent includeForUrlMappingInfo(HttpServletRequest reques
String includeUrl = buildDispatchUrlForMapping(info, true);

final GrailsWebRequest webRequest = GrailsWebRequest.lookup(request);

String currentController = null;
String currentAction = null;
String currentId = null;
ModelAndView currentMv = null;
Map currentParams = null;
if (webRequest != null) {
currentController = webRequest.getControllerName();
currentAction = webRequest.getActionName();
currentId = webRequest.getId();
currentParams = new HashMap();
currentParams.putAll(webRequest.getParameterMap());
currentMv = (ModelAndView)webRequest.getAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, 0);
}
InternalSavedRequest savedRequest = null;

try {
if (webRequest!=null) {
webRequest.getParameterMap().clear();
info.configure(webRequest);
webRequest.getParameterMap().putAll(info.getParameters());
webRequest.removeAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, 0);
}
savedRequest = saveAndResetWebRequest(request, info);
return includeForUrl(includeUrl, request, response, model);
}
finally {
if (webRequest!=null) {
webRequest.getParameterMap().clear();
webRequest.getParameterMap().putAll(currentParams);
webRequest.setId(currentId);
webRequest.setControllerName(currentController);
webRequest.setActionName(currentAction);
if (currentMv != null) {
webRequest.setAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, currentMv, 0);
if (savedRequest != null) {
webRequest.getParameterMap().clear();
webRequest.getParameterMap().putAll(savedRequest.getParameterMap());
webRequest.setId(savedRequest.getId());
webRequest.setControllerName(savedRequest.getController());
webRequest.setActionName(savedRequest.getAction());
if (savedRequest.getModelAndView() != null) {
webRequest.setAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, savedRequest.getModelAndView(), 0);
}
}
}
}

/**
* Saves the details of the current web request in an {@link InternalSavedRequest}
* instance, clears information related to view rendering from the request
* attributes, and returns the saved request.
* @param request The underlying HTTP request to process.
* @param info The URL mapping that should be applied to the request after
* the attributes have been cleared.
* @return The saved web request details.
*/
public static InternalSavedRequest saveAndResetWebRequest(HttpServletRequest request, UrlMappingInfo info) {
final GrailsWebRequest webRequest = GrailsWebRequest.lookup(request);
InternalSavedRequest savedRequest = null;
if (webRequest != null) {
savedRequest = new InternalSavedRequest(
webRequest.getControllerName(),
webRequest.getActionName(),
webRequest.getId(),
webRequest.getParameterMap(),
(ModelAndView) webRequest.getAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, 0));
webRequest.getParameterMap().clear();
info.configure(webRequest);
webRequest.getParameterMap().putAll(info.getParameters());
webRequest.removeAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, 0);
}

return savedRequest;
}

/**
* Simple class that stores a subset of information about a request, including
* the target controller and action, and the request parameters. Also stores
* information about any current ModelAndView that will be used to render the
* response.
*/
private static class InternalSavedRequest {
private String controller;
private String action;
private String id;
private HashMap parameters;
private ModelAndView modelAndView;

public InternalSavedRequest(String controllerName, String actionName, String id, Map parameterMap, ModelAndView mv) {
this.controller = controllerName;
this.action = actionName;
this.id = id;
this.parameters = new HashMap(parameterMap);
this.modelAndView = mv;
}

public String getController() { return controller; }
public String getAction() { return action; }
public String getId() { return id; }
public Map getParameterMap() { return parameters; }
public ModelAndView getModelAndView() { return modelAndView; }
}


/**
* Includes the given URL returning the resulting content as a String
Expand Down

0 comments on commit 3a0e57a

Please sign in to comment.