Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AjaxTilesView does not work with Spring 3 and Tiles 2.1.2 [SWF-1220] #429

Closed
spring-operator opened this issue Jul 9, 2009 · 8 comments
Closed
Assignees
Milestone

Comments

@spring-operator
Copy link
Contributor

Scott Andrews opened SWF-1220 and commented

The AjaxTilesView is incompatible with the Tiles support in Spring 3. The Tiles version in Spring 3 was upgraded to 2.1.2 which has a significantly different API then 2.0.x.

The relevant stack trace for the 2.0.7 AjaxTilesView with Spring 3 and Tiles 2.1.2 is:
java.lang.NullPointerException
at org.springframework.js.ajax.tiles2.AjaxTilesView.renderMergedOutputModel(AjaxTilesView.java:92)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1062)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:709)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:617)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:526)
...


Attachments:

8 votes, 9 watchers

@spring-operator
Copy link
Contributor Author

Dave Syer commented

Spring 3 is now depending on Tiles 2.1.3. The problem is the same. The Javadocs say the BasicTilesContainer.getContextFactory() is deprecated and always returns null (duh!), but there is a replacement method called getRequestContextFactory().

@spring-operator
Copy link
Contributor Author

Dave Syer commented

On a closer look this is more complicated. TilesContainer has changed its interface significantly (and in some pretty brain dead ways). I think we might have to provide our own TilesContainer implementation to get this working now. I suppose at least that way there might be a chance to support Tiles 2.0 and 2.1?

@spring-operator
Copy link
Contributor Author

Derek OKeeffe commented

Hello,
Did you find a work around for this problem.
I'm in the process of writing a custom FlowAjaxTilesView to plug into the tilesViewResolver but its a pain in the ....

@spring-operator
Copy link
Contributor Author

Derek OKeeffe commented

Here is a fix that seems to work....

1: Configure the tilesViewResolver to take a new viewClass.
<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
<property name="viewClass" value="com.your.companys.project..FlowAjaxTiles21View"/>
<property name="requestContextAttribute" value="requestContext" />
</bean>

2: Here is the code for the new viewClass.
package com.your.companys.project;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tiles.Attribute;
import org.apache.tiles.Definition;
import org.apache.tiles.impl.BasicTilesContainer;
import org.apache.tiles.servlet.context.ServletTilesRequestContext;
import org.apache.tiles.servlet.context.ServletUtil;
import org.springframework.js.ajax.AjaxHandler;
import org.springframework.js.ajax.SpringJavascriptAjaxHandler;
import org.springframework.web.servlet.support.JstlUtils;
import org.springframework.web.servlet.support.RequestContext;
import org.springframework.web.servlet.view.tiles2.TilesView;
import org.springframework.webflow.mvc.view.FlowAjaxTilesView;

public class FlowAjaxTiles21View extends FlowAjaxTilesView {

private AjaxHandler ajaxHandler = new SpringJavascriptAjaxHandler();

/**
 * Render the tiles. If its an ajax request then handle that using the custom code for tiles 2.1. Otherwise just do the default rendering.
 */
@SuppressWarnings("unchecked")
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response)
    throws Exception {

ServletContext servletContext = getServletContext();
if (ajaxHandler.isAjaxRequest(request, response)) {
    handleAjaxRequest(model, request, response, servletContext);
} else {
    super.renderMergedOutputModel(model, request, response);
}
}

/**
 * Handle the Ajax request this is the custom code for the Tiles 2.1 interface.
 * @param model
 * @param request
 * @param response
 * @param servletContext
 * @throws Exception
 * @throws ServletException
 * @throws IOException
 */
@SuppressWarnings("unchecked")
private void handleAjaxRequest(Map model, HttpServletRequest request, HttpServletResponse response,
    ServletContext servletContext) throws Exception, ServletException, IOException {
String[] attrNames = getRenderFragments(model, request, response);
if (attrNames.length == 0) {
    logger.warn("An Ajax request was detected, but no fragments were specified to be re-rendered.  "
	    + "Falling back to full page render.  This can cause unpredictable results when processing "
	    + "the ajax response on the client.");
    super.renderMergedOutputModel(model, request, response);
    return;
}

BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getContainer(servletContext);
if (container == null) {
    throw new ServletException("Tiles container is not initialized. "
	    + "Have you added a TilesConfigurer to your web application context?");
}

exposeModelAsRequestAttributes(model, request);
JstlUtils.exposeLocalizationContext(new RequestContext(request, servletContext));

ServletTilesRequestContext tilesRequestContext = new ServletTilesRequestContext(container
	.getApplicationContext(), request, response);
Definition compositeDefinition = container.getDefinitionsFactory().getDefinition(getUrl(), tilesRequestContext);

Map flattenedAttributeMap = new HashMap();
flattenAttributeMap(container, tilesRequestContext, flattenedAttributeMap, compositeDefinition, request,
	response);
// initialize the session before rendering any fragments. Otherwise views that require the session which has
// not otherwise been initialized will fail to render
request.getSession();
response.flushBuffer();
for (String attr : attrNames) {
    Attribute attrib = compositeDefinition.getAttribute(attr);
    container.render(attrib, new Object[] { request, response });
}
}

}

@spring-operator
Copy link
Contributor Author

Jeremy Grelle commented

I have attached a version of AjaxTilesView that has been updated to use the Tiles 2.1 APIs. This is meant as a stop-gap for anyone who needs Tiles 2.1 support prior to the release of a proper Spring JS 3.0 milestone. I expect to do some significant refactoring and cleanup before actually committing a solution to the Spring JS trunk.

@spring-operator
Copy link
Contributor Author

Eros Sy commented

I am also receiving this error message..

WARN o.s.w.mvc.view.FlowAjaxTilesView - An Ajax request was detected, but no fragments were specified to be re-rendered. Falling back to full page render. This can cause unpredictable results when processing the ajax response on the client.

My environment is kinda different:
Spring 2.5.6.SEC01
SWF 2.0.8.RELEASE
Tiles 2.0.5

could you give me some ideas on how to resolve this issue?

thanks

@spring-operator
Copy link
Contributor Author

Eros Sy commented

by the way...

while I receiving the above error... the spring renders the popup view but its renders the main view so the result... two main view, one is the original main view and the other one is popup main view..

please give me hints thanks..

@spring-operator
Copy link
Contributor Author

Rossen Stoyanchev commented

AjaxTilesView has been upgraded to Tiles 2.1.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants