1 package org.cateproject.view.ajax;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.Map;
22
23 import javax.servlet.ServletContext;
24 import javax.servlet.ServletException;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28 import org.apache.tiles.Attribute;
29 import org.apache.tiles.AttributeContext;
30 import org.apache.tiles.Definition;
31 import org.apache.tiles.Attribute.AttributeType;
32 import org.apache.tiles.context.ChainedTilesRequestContextFactory;
33 import org.apache.tiles.context.TilesRequestContext;
34 import org.apache.tiles.context.TilesRequestContextFactory;
35 import org.apache.tiles.definition.DefinitionsFactoryException;
36 import org.apache.tiles.impl.BasicTilesContainer;
37 import org.apache.tiles.servlet.context.ServletUtil;
38 import org.springframework.js.ajax.AjaxHandler;
39 import org.springframework.js.ajax.SpringJavascriptAjaxHandler;
40 import org.springframework.util.StringUtils;
41 import org.springframework.web.servlet.support.JstlUtils;
42 import org.springframework.web.servlet.support.RequestContext;
43 import org.springframework.web.servlet.view.tiles2.TilesView;
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class AjaxTiles21View extends TilesView {
58
59 private static final String FRAGMENTS_PARAM = "fragments";
60
61 private TilesRequestContextFactory tilesRequestContextFactory;
62
63 private AjaxHandler ajaxHandler = new SpringJavascriptAjaxHandler();
64
65 @Override
66 public void afterPropertiesSet() throws Exception {
67 super.afterPropertiesSet();
68 if (tilesRequestContextFactory == null) {
69 tilesRequestContextFactory = new ChainedTilesRequestContextFactory();
70 tilesRequestContextFactory.init(new HashMap<String, String>());
71 }
72 }
73
74 public AjaxHandler getAjaxHandler() {
75 return ajaxHandler;
76 }
77
78 public void setAjaxHandler(AjaxHandler ajaxHandler) {
79 this.ajaxHandler = ajaxHandler;
80 }
81
82 protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response)
83 throws Exception {
84
85 ServletContext servletContext = getServletContext();
86 if (ajaxHandler.isAjaxRequest(request, response)) {
87
88 String[] attrNames = getRenderFragments(model, request, response);
89 if (attrNames.length == 0) {
90 logger.warn("An Ajax request was detected, but no fragments were specified to be re-rendered. "
91 + "Falling back to full page render. This can cause unpredictable results when processing "
92 + "the ajax response on the client.");
93 super.renderMergedOutputModel(model, request, response);
94 return;
95 }
96
97 BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getCurrentContainer(request,
98 servletContext);
99 if (container == null) {
100 throw new ServletException("Tiles container is not initialized. "
101 + "Have you added a TilesConfigurer to your web application context?");
102 }
103
104 exposeModelAsRequestAttributes(model, request);
105 JstlUtils.exposeLocalizationContext(new RequestContext(request, servletContext));
106
107 TilesRequestContext tilesRequestContext = tilesRequestContextFactory.createRequestContext(container
108 .getApplicationContext(), new Object[] { request, response });
109 Definition compositeDefinition = container.getDefinitionsFactory().getDefinition(getUrl(),
110 tilesRequestContext);
111 Map flattenedAttributeMap = new HashMap();
112 flattenAttributeMap(container, tilesRequestContext, flattenedAttributeMap, compositeDefinition, request,
113 response);
114
115
116
117 request.getSession();
118
119
120
121
122 response.setContentType(getContentType());
123
124
125
126
127
128
129 if(logger.isInfoEnabled()) {
130 logger.info("Composite Definition " + compositeDefinition.getName() + " has " + compositeDefinition.getCascadedAttributeNames().size());
131 }
132 if(compositeDefinition.getCascadedAttributeNames() != null) {
133 for(String cascadedAttributeName : compositeDefinition.getCascadedAttributeNames()) {
134 if(logger.isInfoEnabled()) {
135 logger.info("Adding " + cascadedAttributeName + " to request");
136 }
137 request.setAttribute(cascadedAttributeName, compositeDefinition.getAttribute(cascadedAttributeName));
138 }
139 }
140
141 for (int i = 0; i < attrNames.length; i++) {
142 Attribute attributeToRender = (Attribute) flattenedAttributeMap.get(attrNames[i]);
143
144 if (attributeToRender == null) {
145 throw new ServletException("No tiles attribute with a name of '" + attrNames[i] + "' could be found for the current view: " + this);
146 } else {
147 container.render(attributeToRender, response.getWriter(), new Object[] { request, response });
148 }
149 }
150 } else {
151 super.renderMergedOutputModel(model, request, response);
152 }
153 }
154
155 protected String[] getRenderFragments(Map model, HttpServletRequest request, HttpServletResponse response) {
156 String attrName = request.getParameter(FRAGMENTS_PARAM);
157 String[] renderFragments = StringUtils.commaDelimitedListToStringArray(attrName);
158 return StringUtils.trimArrayElements(renderFragments);
159 }
160
161 protected void flattenAttributeMap(BasicTilesContainer container, TilesRequestContext requestContext,
162 Map resultMap, Definition compositeDefinition, HttpServletRequest request, HttpServletResponse response)
163 throws Exception {
164 if (compositeDefinition.getAttributes() != null && compositeDefinition.getAttributes().size() > 0) {
165 Iterator i = compositeDefinition.getAttributes().keySet().iterator();
166 while (i.hasNext()) {
167 Object key = i.next();
168 Attribute attr = (Attribute) compositeDefinition.getAttributes().get(key);
169 AttributeType attrType = attr.getType() != null ? attr.getType() : detectType(container,
170 requestContext, attr);
171 if (AttributeType.DEFINITION.equals(attrType) || AttributeType.TEMPLATE.equals(attrType)) {
172 resultMap.put(key, attr);
173 if (AttributeType.DEFINITION.equals(attrType)) {
174 Definition nestedDefinition = container.getDefinitionsFactory().getDefinition(
175 attr.getValue().toString(), requestContext);
176 if (nestedDefinition != null && nestedDefinition != compositeDefinition) {
177 flattenAttributeMap(container, requestContext, resultMap, nestedDefinition, request,
178 response);
179 }
180 }
181 }
182 }
183 }
184
185
186 AttributeContext attributeContext = container.getAttributeContext(new Object[] { request, response });
187
188 for (Iterator i = attributeContext.getAttributeNames(); i.hasNext();) {
189 String key = (String) i.next();
190 Attribute attr = attributeContext.getAttribute(key);
191 resultMap.put(key, attr);
192 }
193 }
194
195 private AttributeType detectType(BasicTilesContainer container, TilesRequestContext requestContext, Attribute attr)
196 throws DefinitionsFactoryException {
197 if (attr.getValue() instanceof String) {
198 if (container.getDefinitionsFactory().getDefinition(attr.getValue().toString(), requestContext) != null) {
199 return AttributeType.DEFINITION;
200 } else if (attr.getValue().toString().startsWith("/")) {
201 return AttributeType.TEMPLATE;
202 } else {
203 return AttributeType.STRING;
204 }
205 }
206 return AttributeType.OBJECT;
207 }
208 }