SWF-1226 Upgrade dependencies to Spring 3.0.2.RELEASE, Portlet API 2.0, and Tiles 2.1.2. Change AjaxTilesView to be compatible with and take advantage of Tiles 2.1.2 features.
This commit is contained in:
@@ -16,8 +16,10 @@
|
||||
package org.springframework.js.ajax.tiles2;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -27,13 +29,14 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.tiles.Attribute;
|
||||
import org.apache.tiles.AttributeContext;
|
||||
import org.apache.tiles.Definition;
|
||||
import org.apache.tiles.Attribute.AttributeType;
|
||||
import org.apache.tiles.access.TilesAccess;
|
||||
import org.apache.tiles.context.TilesRequestContext;
|
||||
import org.apache.tiles.definition.DefinitionsFactoryException;
|
||||
import org.apache.tiles.context.TilesRequestContextFactory;
|
||||
import org.apache.tiles.impl.BasicTilesContainer;
|
||||
import org.apache.tiles.servlet.context.ServletTilesRequestContextFactory;
|
||||
import org.apache.tiles.servlet.context.ServletUtil;
|
||||
import org.springframework.js.ajax.AjaxHandler;
|
||||
import org.springframework.js.ajax.SpringJavascriptAjaxHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.support.JstlUtils;
|
||||
import org.springframework.web.servlet.support.RequestContext;
|
||||
@@ -55,8 +58,16 @@ public class AjaxTilesView extends TilesView {
|
||||
|
||||
private static final String FRAGMENTS_PARAM = "fragments";
|
||||
|
||||
private TilesRequestContextFactory tilesRequestContextFactory;
|
||||
|
||||
private AjaxHandler ajaxHandler = new SpringJavascriptAjaxHandler();
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
super.afterPropertiesSet();
|
||||
tilesRequestContextFactory = new ServletTilesRequestContextFactory();
|
||||
tilesRequestContextFactory.init(new HashMap());
|
||||
}
|
||||
|
||||
public AjaxHandler getAjaxHandler() {
|
||||
return ajaxHandler;
|
||||
}
|
||||
@@ -71,8 +82,8 @@ public class AjaxTilesView extends TilesView {
|
||||
ServletContext servletContext = getServletContext();
|
||||
if (ajaxHandler.isAjaxRequest(request, response)) {
|
||||
|
||||
String[] attrNames = getRenderFragments(model, request, response);
|
||||
if (attrNames.length == 0) {
|
||||
String[] fragmentsToRender = getRenderFragments(model, request, response);
|
||||
if (fragmentsToRender.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.");
|
||||
@@ -80,7 +91,8 @@ public class AjaxTilesView extends TilesView {
|
||||
return;
|
||||
}
|
||||
|
||||
BasicTilesContainer container = (BasicTilesContainer) TilesAccess.getContainer(servletContext);
|
||||
BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getCurrentContainer(request,
|
||||
servletContext);
|
||||
if (container == null) {
|
||||
throw new ServletException("Tiles container is not initialized. "
|
||||
+ "Have you added a TilesConfigurer to your web application context?");
|
||||
@@ -89,26 +101,29 @@ public class AjaxTilesView extends TilesView {
|
||||
exposeModelAsRequestAttributes(model, request);
|
||||
JstlUtils.exposeLocalizationContext(new RequestContext(request, servletContext));
|
||||
|
||||
TilesRequestContext tilesRequestContext = container.getContextFactory().createRequestContext(
|
||||
container.getApplicationContext(), new Object[] { request, response });
|
||||
TilesRequestContext tilesRequestContext = tilesRequestContextFactory.createRequestContext(container
|
||||
.getApplicationContext(), new Object[] { request, response });
|
||||
Definition compositeDefinition = container.getDefinitionsFactory().getDefinition(getUrl(),
|
||||
tilesRequestContext);
|
||||
|
||||
Map flattenedAttributeMap = new HashMap();
|
||||
flattenAttributeMap(container, tilesRequestContext, flattenedAttributeMap, compositeDefinition, request,
|
||||
response);
|
||||
addRuntimeAttributes(container, flattenedAttributeMap, 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 (int i = 0; i < attrNames.length; i++) {
|
||||
Attribute attributeToRender = (Attribute) flattenedAttributeMap.get(attrNames[i]);
|
||||
|
||||
for (int i = 0; i < fragmentsToRender.length; i++) {
|
||||
Attribute attributeToRender = (Attribute) flattenedAttributeMap.get(fragmentsToRender[i]);
|
||||
|
||||
if (attributeToRender == null) {
|
||||
throw new ServletException("No tiles attribute with a name of '" + attrNames[i]
|
||||
throw new ServletException("No tiles attribute with a name of '" + fragmentsToRender[i]
|
||||
+ "' could be found for the current view: " + this);
|
||||
} else {
|
||||
container.render(attributeToRender, response.getWriter(), new Object[] { request, response });
|
||||
container.render(attributeToRender, new Object[] { request, response });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -122,51 +137,67 @@ public class AjaxTilesView extends TilesView {
|
||||
return StringUtils.trimArrayElements(renderFragments);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Iterate over all attributes in the given Tiles definition. Every attribute value that represents a template (i.e.
|
||||
* start with "/") or is a nested definition is added to a Map. The method class itself recursively to traverse
|
||||
* nested definitions.
|
||||
* </p>
|
||||
*
|
||||
* @param container the TilesContainer
|
||||
* @param requestContext the TilesRequestContext
|
||||
* @param resultMap the output Map where attributes of interest are added to.
|
||||
* @param compositeDefinition the definition to search for attributes of interest.
|
||||
* @param request the servlet request
|
||||
* @param response the servlet response
|
||||
*/
|
||||
protected void flattenAttributeMap(BasicTilesContainer container, TilesRequestContext requestContext,
|
||||
Map resultMap, Definition compositeDefinition, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
if (compositeDefinition.getAttributes() != null && compositeDefinition.getAttributes().size() > 0) {
|
||||
Iterator i = compositeDefinition.getAttributes().keySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Object key = i.next();
|
||||
Attribute attr = (Attribute) compositeDefinition.getAttributes().get(key);
|
||||
AttributeType attrType = attr.getType() != null ? attr.getType() : detectType(container,
|
||||
requestContext, attr);
|
||||
if (AttributeType.DEFINITION.equals(attrType) || AttributeType.TEMPLATE.equals(attrType)) {
|
||||
resultMap.put(key, attr);
|
||||
if (AttributeType.DEFINITION.equals(attrType)) {
|
||||
Definition nestedDefinition = container.getDefinitionsFactory().getDefinition(
|
||||
attr.getValue().toString(), requestContext);
|
||||
if (nestedDefinition != null && nestedDefinition != compositeDefinition) {
|
||||
flattenAttributeMap(container, requestContext, resultMap, nestedDefinition, request,
|
||||
response);
|
||||
}
|
||||
}
|
||||
}
|
||||
Map resultMap, Definition compositeDefinition, HttpServletRequest request, HttpServletResponse response) {
|
||||
Iterator iterator = compositeDefinition.getAttributeNames();
|
||||
while (iterator.hasNext()) {
|
||||
String attributeName = (String) iterator.next();
|
||||
Attribute attribute = compositeDefinition.getAttribute(attributeName);
|
||||
if (attribute.getValue() == null || !(attribute.getValue() instanceof String)) {
|
||||
continue;
|
||||
}
|
||||
String value = attribute.getValue().toString();
|
||||
if (value.startsWith("/")) {
|
||||
resultMap.put(attributeName, attribute);
|
||||
} else if (container.isValidDefinition(value, new Object[] { request, response })) {
|
||||
resultMap.put(attributeName, attribute);
|
||||
Definition nestedDefinition = container.getDefinitionsFactory().getDefinition(value, requestContext);
|
||||
Assert.isTrue(nestedDefinition != compositeDefinition, "Circular nested definition: " + value);
|
||||
flattenAttributeMap(container, requestContext, resultMap, nestedDefinition, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
// Process dynamic attributes
|
||||
AttributeContext attributeContext = container.getAttributeContext(new Object[] { request, response });
|
||||
|
||||
for (Iterator i = attributeContext.getAttributeNames(); i.hasNext();) {
|
||||
String key = (String) i.next();
|
||||
Attribute attr = attributeContext.getAttribute(key);
|
||||
resultMap.put(key, attr);
|
||||
}
|
||||
}
|
||||
|
||||
private AttributeType detectType(BasicTilesContainer container, TilesRequestContext requestContext, Attribute attr)
|
||||
throws DefinitionsFactoryException {
|
||||
if (attr.getValue() instanceof String) {
|
||||
if (container.getDefinitionsFactory().getDefinition(attr.getValue().toString(), requestContext) != null) {
|
||||
return AttributeType.DEFINITION;
|
||||
} else if (attr.getValue().toString().startsWith("/")) {
|
||||
return AttributeType.TEMPLATE;
|
||||
} else {
|
||||
return AttributeType.STRING;
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* Iterate over dynamically added Tiles attributes (see "Runtime Composition" in the Tiles documentation) and add
|
||||
* them to the output Map passed as input.
|
||||
* </p>
|
||||
*
|
||||
* @param container the Tiles container
|
||||
* @param resultMap the output Map where attributes of interest are added to.
|
||||
* @param request the Servlet request
|
||||
* @param response the Servlet response
|
||||
*/
|
||||
protected void addRuntimeAttributes(BasicTilesContainer container, Map resultMap, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
AttributeContext attributeContext = container.getAttributeContext(new Object[] { request, response });
|
||||
Set attributeNames = new HashSet();
|
||||
if (attributeContext.getLocalAttributeNames() != null) {
|
||||
attributeNames.addAll(attributeContext.getLocalAttributeNames());
|
||||
}
|
||||
if (attributeContext.getCascadedAttributeNames() != null) {
|
||||
attributeNames.addAll(attributeContext.getCascadedAttributeNames());
|
||||
}
|
||||
Iterator iterator = attributeNames.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String name = (String) iterator.next();
|
||||
Attribute attr = attributeContext.getAttribute(name);
|
||||
resultMap.put(name, attr);
|
||||
}
|
||||
return AttributeType.OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,13 @@ import java.util.Map;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.tiles.Attribute;
|
||||
import org.apache.tiles.AttributeContext;
|
||||
import org.apache.tiles.Definition;
|
||||
import org.apache.tiles.access.TilesAccess;
|
||||
import org.apache.tiles.context.TilesRequestContext;
|
||||
import org.apache.tiles.context.TilesRequestContextFactory;
|
||||
import org.apache.tiles.impl.BasicTilesContainer;
|
||||
import org.apache.tiles.servlet.context.ServletTilesRequestContextFactory;
|
||||
import org.apache.tiles.servlet.context.ServletUtil;
|
||||
import org.springframework.js.ajax.SpringJavascriptAjaxHandler;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -36,6 +39,7 @@ public class AjaxTilesViewTests extends TestCase {
|
||||
tc.setDefinitions(new String[] { "tiles-definitions.xml" });
|
||||
tc.setValidateDefinitions(true);
|
||||
tc.setServletContext(servletContext);
|
||||
tc.setUseMutableTilesContainer(true);
|
||||
tc.afterPropertiesSet();
|
||||
|
||||
ajaxTilesView = new AjaxTilesView();
|
||||
@@ -52,6 +56,7 @@ public class AjaxTilesViewTests extends TestCase {
|
||||
public void testFullPageRendering() throws Exception {
|
||||
setupStaticWebApplicationContext();
|
||||
ajaxTilesView.setUrl("search");
|
||||
ajaxTilesView.afterPropertiesSet();
|
||||
ajaxTilesView.renderMergedOutputModel(new HashMap(), request, response);
|
||||
assertEquals("/WEB-INF/layout.jsp", response.getForwardedUrl());
|
||||
}
|
||||
@@ -60,6 +65,7 @@ public class AjaxTilesViewTests extends TestCase {
|
||||
setupStaticWebApplicationContext();
|
||||
request.addHeader("Accept", SpringJavascriptAjaxHandler.AJAX_ACCEPT_CONTENT_TYPE);
|
||||
ajaxTilesView.setUrl("search");
|
||||
ajaxTilesView.afterPropertiesSet();
|
||||
ajaxTilesView.renderMergedOutputModel(new HashMap(), request, response);
|
||||
assertEquals("/WEB-INF/layout.jsp", response.getForwardedUrl());
|
||||
}
|
||||
@@ -69,6 +75,7 @@ public class AjaxTilesViewTests extends TestCase {
|
||||
request.addHeader("Accept", SpringJavascriptAjaxHandler.AJAX_ACCEPT_CONTENT_TYPE);
|
||||
request.addParameter("fragments", "searchResults");
|
||||
ajaxTilesView.setUrl("search");
|
||||
ajaxTilesView.afterPropertiesSet();
|
||||
ajaxTilesView.renderMergedOutputModel(new HashMap(), request, response);
|
||||
assertEquals("/WEB-INF/searchResults.jsp", response.getIncludedUrl());
|
||||
}
|
||||
@@ -78,21 +85,46 @@ public class AjaxTilesViewTests extends TestCase {
|
||||
request.addHeader("Accept", SpringJavascriptAjaxHandler.AJAX_ACCEPT_CONTENT_TYPE);
|
||||
request.addParameter("fragments", "body");
|
||||
ajaxTilesView.setUrl("search");
|
||||
ajaxTilesView.afterPropertiesSet();
|
||||
ajaxTilesView.renderMergedOutputModel(new HashMap(), request, response);
|
||||
assertEquals("/WEB-INF/search.jsp", response.getIncludedUrl());
|
||||
}
|
||||
|
||||
public void testRenderFragment_CascadedAttribute() throws Exception {
|
||||
setupStaticWebApplicationContext();
|
||||
request.addHeader("Accept", SpringJavascriptAjaxHandler.AJAX_ACCEPT_CONTENT_TYPE);
|
||||
request.addParameter("fragments", "searchNavigation");
|
||||
ajaxTilesView.setUrl("search");
|
||||
ajaxTilesView.afterPropertiesSet();
|
||||
ajaxTilesView.renderMergedOutputModel(new HashMap(), request, response);
|
||||
assertEquals("/WEB-INF/searchNavigation.jsp", response.getIncludedUrl());
|
||||
}
|
||||
|
||||
public void testRenderFragment_DynamicAttribute() throws Exception {
|
||||
BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getCurrentContainer(request, servletContext);
|
||||
Object[] requestItems = new Object[] { request, response };
|
||||
AttributeContext attributeContext = container.startContext(requestItems);
|
||||
attributeContext.putAttribute("body", new Attribute("/WEB-INF/dynamicTemplate.jsp"));
|
||||
Map resultMap = new HashMap();
|
||||
ajaxTilesView.addRuntimeAttributes(container, resultMap, request, response);
|
||||
assertNotNull(resultMap.get("body"));
|
||||
assertEquals("/WEB-INF/dynamicTemplate.jsp", resultMap.get("body").toString());
|
||||
container.endContext(requestItems);
|
||||
}
|
||||
|
||||
public void testFlattenAttributeMap() throws Exception {
|
||||
BasicTilesContainer container = (BasicTilesContainer) TilesAccess.getContainer(servletContext);
|
||||
TilesRequestContext tilesRequestContext = container.getContextFactory().createRequestContext(
|
||||
container.getApplicationContext(), new Object[] { request, response });
|
||||
TilesRequestContextFactory tilesRequestContextFactory = new ServletTilesRequestContextFactory();
|
||||
tilesRequestContextFactory.init(new HashMap());
|
||||
BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getCurrentContainer(request, servletContext);
|
||||
TilesRequestContext tilesRequestContext = tilesRequestContextFactory.createRequestContext(container
|
||||
.getApplicationContext(), new Object[] { request, response });
|
||||
Definition compositeDefinition = container.getDefinitionsFactory().getDefinition("search", tilesRequestContext);
|
||||
Map resultMap = new HashMap();
|
||||
ajaxTilesView.flattenAttributeMap(container, tilesRequestContext, resultMap, compositeDefinition, request,
|
||||
response);
|
||||
assertNotNull(resultMap.get("body"));
|
||||
assertNotNull(resultMap.get("searchForm"));
|
||||
assertEquals("/WEB-INF/searchForm.jsp", ((Attribute) resultMap.get("searchForm")).getValue());
|
||||
assertEquals("/WEB-INF/searchForm.jsp", resultMap.get("searchForm").toString());
|
||||
assertNotNull(resultMap.get("searchResults"));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE tiles-definitions PUBLIC
|
||||
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
|
||||
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
|
||||
"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
|
||||
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
|
||||
|
||||
<tiles-definitions>
|
||||
|
||||
<definition name="layout" template="/WEB-INF/layout.jsp"/>
|
||||
|
||||
<definition name="search" extends="layout">
|
||||
<put-attribute name="searchForm" value="Substituted Value" type="string"/>
|
||||
<put-attribute name="searchForm" value="Substituted Value" type="string" />
|
||||
<put-attribute name="body" value="search.body" />
|
||||
<put-attribute name="searchNavigation" value="/WEB-INF/searchNavigation.jsp" cascade="true" />
|
||||
</definition>
|
||||
|
||||
<definition name="search.body" template="/WEB-INF/search.jsp">
|
||||
|
||||
Reference in New Issue
Block a user