This project has retired. For details please refer to its
Attic page.
TilesDecorationFilter xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.tiles.web.util;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.tiles.Attribute;
26 import org.apache.tiles.AttributeContext;
27 import org.apache.tiles.TilesContainer;
28 import org.apache.tiles.TilesException;
29 import org.apache.tiles.Attribute.AttributeType;
30 import org.apache.tiles.access.TilesAccess;
31
32 import javax.servlet.Filter;
33 import javax.servlet.FilterChain;
34 import javax.servlet.FilterConfig;
35 import javax.servlet.ServletContext;
36 import javax.servlet.ServletException;
37 import javax.servlet.ServletRequest;
38 import javax.servlet.ServletResponse;
39 import javax.servlet.http.HttpServletRequest;
40 import java.io.IOException;
41 import java.util.Map;
42 import java.util.Enumeration;
43 import java.util.HashMap;
44
45 /***
46 * Decoration Filter. Intercepts all requests and decorates them
47 * with the configured definition.
48 * <p/>
49 * For example, given the following config:
50 * <xmp>
51 * <filter>
52 * <filter-name>Tiles Decoration Filter</filter-name>
53 * <filter-class>org.apache.tiles.web.TilesDecorationFilter</filter-class>
54 * <init-param>
55 * <param-name>definition</param-name>
56 * <param-value>test.definition</param-value>
57 * </init-param>
58 * <init-param>
59 * <param-name>attribute-name</param-name>
60 * <param-value>body</param-value>
61 * </init-param>
62 * <init-param>
63 * <param-name>prevent-token</param-name>
64 * <param-value>layout</param-value>
65 * </init-param>
66 * </filter>
67 * <p/>
68 * <filter-mapping>
69 * <filter-name>Tiles Decoration Filter</filter-name>
70 * <url-pattern>/testdecorationfilter.jsp</url-pattern>
71 * <dispatcher>REQUEST</dispatcher>
72 * </filter-mapping>
73 * </xmp>
74 * The filter will intercept all requests to the indicated url pattern
75 * store the initial request path as the "body" attribute and then render the
76 * "test.definition" definition. The filter will only redecorate those requests
77 * which do not contain the request attribute associated with the prevent token
78 * "layout".
79 */
80 public class TilesDecorationFilter implements Filter {
81
82 /***
83 * The logging object.
84 */
85 private static final Log LOG =
86 LogFactory.getLog(TilesDecorationFilter.class);
87
88 /***
89 * Filter configuration.
90 */
91 private FilterConfig filterConfig;
92
93 /***
94 * The name of the definition attribute used to
95 * pass on the request.
96 */
97 private String definitionAttributeName = "content";
98
99 /***
100 * The definition name to use.
101 */
102 private String definitionName = "layout";
103
104 /***
105 * Token used to prevent re-decoration of requests.
106 * This token is used to prevent infinate loops on
107 * filters configured to match wildcards.
108 */
109 private String preventDecorationToken;
110
111 /***
112 * Stores a map of the type "mask -> definition": when a definition name
113 * mask is identified, it is substituted with the configured definition.
114 */
115 private Map<String, String> alternateDefinitions;
116
117 /***
118 * The object that will mutate the attribute context so that it uses
119 * different attributes.
120 */
121 private AttributeContextMutator mutator = null;
122
123 /***
124 * Returns the filter configuration object.
125 *
126 * @return The filter configuration.
127 */
128 public FilterConfig getFilterConfig() {
129 return filterConfig;
130 }
131
132 /***
133 * Returns the servlet context.
134 *
135 * @return The servlet context.
136 */
137 public ServletContext getServletContext() {
138 return filterConfig.getServletContext();
139 }
140
141 /*** {@inheritDoc} */
142 public void init(FilterConfig config) throws ServletException {
143 filterConfig = config;
144 String temp = config.getInitParameter("attribute-name");
145 if (temp != null) {
146 definitionAttributeName = temp;
147 }
148
149 temp = config.getInitParameter("definition");
150 if (temp != null) {
151 definitionName = temp;
152 }
153
154 temp = config.getInitParameter("prevent-token");
155 preventDecorationToken = "org.apache.tiles.decoration.PREVENT:"+(temp == null ? definitionName : temp);
156
157 alternateDefinitions = parseAlternateDefinitions();
158
159 temp = config.getInitParameter("mutator");
160 if (temp != null) {
161 try {
162 mutator = (AttributeContextMutator) Class.forName(temp)
163 .newInstance();
164 } catch (Exception e) {
165 throw new ServletException("Unable to instantiate specified context mutator.", e);
166 }
167 } else {
168 mutator = new DefaultMutator();
169 }
170 }
171
172 /***
173 * Creates the alternate definitions map, to map a mask of definition names
174 * to a configured definition.
175 *
176 * @return The alternate definitions map.
177 */
178 @SuppressWarnings("unchecked")
179 protected Map<String, String> parseAlternateDefinitions() {
180 Map<String, String> map = new HashMap<String, String>();
181 Enumeration<String> e = filterConfig.getInitParameterNames();
182 while (e.hasMoreElements()) {
183 String parm = e.nextElement();
184 if (parm.startsWith("definition(") && parm.endsWith("*)")) {
185 String value = filterConfig.getInitParameter(parm);
186 String mask = parm.substring("definition(".length());
187 mask = mask.substring(0, mask.lastIndexOf("*)"));
188 map.put(mask, value);
189 LOG.info("Mapping all requests matching '" + mask
190 + "*' to definition '" + value + "'");
191 }
192 }
193 return map;
194 }
195
196 /*** {@inheritDoc} */
197 public void destroy() {
198 filterConfig = null;
199 }
200
201
202 /***
203 * {@inheritDoc}
204 */
205 public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
206 throws IOException, ServletException {
207
208
209
210 if (isPreventTokenPresent(req)) {
211 filterChain.doFilter(req, res);
212 return;
213 }
214
215 TilesContainer container = TilesAccess.getContainer(getServletContext());
216 mutator.mutate(container.getAttributeContext(req, res), req);
217 try {
218 if(preventDecorationToken != null) {
219 req.setAttribute(preventDecorationToken, Boolean.TRUE);
220 }
221 String definitionName = getDefinitionForRequest(req);
222 container.render(definitionName, req, res);
223 }
224 catch (TilesException e) {
225 throw new ServletException("Error wrapping jsp with tile definition. "
226 + e.getMessage(), e);
227 }
228 }
229
230 /***
231 * Returns the final definition to render for the given request.
232 *
233 * @param request The request object.
234 * @return The final definition name.
235 */
236 private String getDefinitionForRequest(ServletRequest request) {
237 if (alternateDefinitions.size() < 1) {
238 return definitionName;
239 }
240 String base = getRequestBase(request);
241 for (Map.Entry<String, String> pair : alternateDefinitions.entrySet()) {
242 if (base.startsWith(pair.getKey())) {
243 return pair.getValue();
244 }
245 }
246 return definitionName;
247 }
248
249 /***
250 * Returns the request base, i.e. the the URL to calculate all the relative
251 * paths.
252 *
253 * @param request The request object to use.
254 * @return The request base.
255 */
256 private String getRequestBase(ServletRequest request) {
257
258 String include = (String) request.getAttribute("javax.servlet.include.servlet_path");
259 if (include != null) {
260 return include;
261 }
262
263
264
265 return ((HttpServletRequest) request).getServletPath();
266 }
267
268 /***
269 * The default attribute context mutator to use.
270 */
271 class DefaultMutator implements AttributeContextMutator {
272
273 /*** {@inheritDoc} */
274 public void mutate(AttributeContext ctx, ServletRequest req) {
275 Attribute attr = new Attribute();
276 attr.setType(AttributeType.TEMPLATE);
277 attr.setValue(getRequestBase(req));
278 ctx.putAttribute(definitionAttributeName, attr);
279 }
280 }
281
282 private boolean isPreventTokenPresent(ServletRequest request) {
283 return preventDecorationToken != null && request.getAttribute(preventDecorationToken) != null;
284 }
285 }