1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.struts.tiles;
20
21 import java.io.IOException;
22
23 import javax.servlet.ServletException;
24 import javax.servlet.http.HttpServletRequest;
25 import javax.servlet.http.HttpServletResponse;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.struts.action.ActionServlet;
30 import org.apache.struts.action.RequestProcessor;
31 import org.apache.struts.config.ForwardConfig;
32 import org.apache.struts.config.ModuleConfig;
33
34 /***
35 * <p><strong>RequestProcessor</strong> contains the processing logic that
36 * the Struts controller servlet performs as it receives each servlet request
37 * from the container.</p>
38 * <p>This processor subclasses the Struts RequestProcessor in order to intercept calls to forward
39 * or include. When such calls are done, the Tiles processor checks if the specified URI
40 * is a definition name. If true, the definition is retrieved and included. If
41 * false, the original URI is included or a forward is performed.
42 * <p>
43 * Actually, catching is done by overloading the following methods:
44 * <ul>
45 * <li>{@link #processForwardConfig(HttpServletRequest,HttpServletResponse,ForwardConfig)}</li>
46 * <li>{@link #internalModuleRelativeForward(String, HttpServletRequest , HttpServletResponse)}</li>
47 * <li>{@link #internalModuleRelativeInclude(String, HttpServletRequest , HttpServletResponse)}</li>
48 * </ul>
49 * </p>
50 * @since Struts 1.1
51 */
52 public class TilesRequestProcessor extends RequestProcessor {
53
54 /***
55 * Definitions factory.
56 */
57 protected DefinitionsFactory definitionsFactory = null;
58
59 /***
60 * Commons Logging instance.
61 */
62 protected static Log log = LogFactory.getLog(TilesRequestProcessor.class);
63
64 /***
65 * Initialize this request processor instance.
66 *
67 * @param servlet The ActionServlet we are associated with.
68 * @param moduleConfig The ModuleConfig we are associated with.
69 * @throws ServletException If an error occurs during initialization.
70 */
71 public void init(ActionServlet servlet, ModuleConfig moduleConfig)
72 throws ServletException {
73
74 super.init(servlet, moduleConfig);
75 this.initDefinitionsMapping();
76 }
77
78 /***
79 * Read component instance mapping configuration file.
80 * This is where we read files properties.
81 */
82 protected void initDefinitionsMapping() throws ServletException {
83
84 definitionsFactory =
85 (
86 (TilesUtilStrutsImpl) TilesUtil
87 .getTilesUtil())
88 .getDefinitionsFactory(
89 getServletContext(),
90 moduleConfig);
91
92 if (definitionsFactory == null) {
93
94 log.info(
95 "Definition Factory not found for module '"
96 + moduleConfig.getPrefix()
97 + "'. "
98 + "Have you declared the appropriate plugin in struts-config.xml ?");
99
100 return;
101 }
102
103 log.info(
104 "Tiles definition factory found for request processor '"
105 + moduleConfig.getPrefix()
106 + "'.");
107
108 }
109
110 /***
111 * Process a Tile definition name.
112 * This method tries to process the parameter <code>definitionName</code>
113 * as a definition name.
114 * It returns <code>true</code> if a definition has been processed, or
115 * <code>false</code> otherwise.
116 * This method is deprecated; the method without the
117 * <code>contextRelative</code> parameter should be used instead.
118 *
119 * @param definitionName Definition name to insert.
120 * @param contextRelative Is the definition marked contextRelative ?
121 * @param request Current page request.
122 * @param response Current page response.
123 * @return <code>true</code> if the method has processed uri as a
124 * definition name, <code>false</code> otherwise.
125 * @deprecated use processTilesDefinition(definitionName, request, response)
126 * instead. This method will be removed in a version after 1.3.0.
127 */
128 protected boolean processTilesDefinition(
129 String definitionName,
130 boolean contextRelative,
131 HttpServletRequest request,
132 HttpServletResponse response)
133 throws IOException, ServletException {
134
135 return processTilesDefinition(definitionName, request, response);
136
137 }
138
139 /***
140 * Process a Tile definition name.
141 * This method tries to process the parameter <code>definitionName</code>
142 * as a definition name.
143 * It returns <code>true</code> if a definition has been processed, or
144 * <code>false</code> otherwise.
145 *
146 * @param definitionName Definition name to insert.
147 * @param request Current page request.
148 * @param response Current page response.
149 * @return <code>true</code> if the method has processed uri as a
150 * definition name, <code>false</code> otherwise.
151 */
152 protected boolean processTilesDefinition(
153 String definitionName,
154 HttpServletRequest request,
155 HttpServletResponse response)
156 throws IOException, ServletException {
157
158
159 boolean doInclude = false;
160
161
162 Controller controller = null;
163
164
165 String uri = null;
166
167 ComponentContext tileContext = null;
168
169 try {
170
171
172 tileContext = ComponentContext.getContext(request);
173 doInclude = (tileContext != null);
174 ComponentDefinition definition = null;
175
176
177
178 if (definitionsFactory != null) {
179
180 try {
181 definition =
182 definitionsFactory.getDefinition(
183 definitionName,
184 request,
185 getServletContext());
186 } catch (NoSuchDefinitionException ex) {
187
188 log.debug("NoSuchDefinitionException " + ex.getMessage());
189 }
190 if (definition != null) {
191
192
193 uri = definition.getPath();
194 controller = definition.getOrCreateController();
195
196 if (tileContext == null) {
197 tileContext =
198 new ComponentContext(definition.getAttributes());
199 ComponentContext.setContext(tileContext, request);
200
201 } else {
202 tileContext.addMissing(definition.getAttributes());
203 }
204 }
205 }
206
207
208 definition = DefinitionsUtil.getActionDefinition(request);
209 if (definition != null) {
210
211
212 if (definition.getPath() != null) {
213 uri = definition.getPath();
214 }
215
216 if (definition.getOrCreateController() != null) {
217 controller = definition.getOrCreateController();
218 }
219
220 if (tileContext == null) {
221 tileContext =
222 new ComponentContext(definition.getAttributes());
223 ComponentContext.setContext(tileContext, request);
224 } else {
225 tileContext.addMissing(definition.getAttributes());
226 }
227 }
228
229 } catch (java.lang.InstantiationException ex) {
230
231 log.error("Can't create associated controller", ex);
232
233 throw new ServletException(
234 "Can't create associated controller",
235 ex);
236 } catch (DefinitionsFactoryException ex) {
237 throw new ServletException(ex);
238 }
239
240
241 if (uri == null) {
242 return false;
243 }
244
245
246 if (controller != null) {
247 try {
248 controller.execute(
249 tileContext,
250 request,
251 response,
252 getServletContext());
253
254 } catch (Exception e) {
255 throw new ServletException(e);
256 }
257 }
258
259
260
261 if (log.isDebugEnabled()) {
262 log.debug("uri=" + uri + " doInclude=" + doInclude);
263 }
264
265 if (doInclude) {
266 doInclude(uri, request, response);
267 } else {
268 doForward(uri, request, response);
269 }
270
271 return true;
272 }
273
274 /***
275 * Do a forward using request dispatcher.
276 * Uri is a valid uri. If response has already been commited, do an include
277 * instead.
278 * @param uri Uri or Definition name to forward.
279 * @param request Current page request.
280 * @param response Current page response.
281 */
282 protected void doForward(
283 String uri,
284 HttpServletRequest request,
285 HttpServletResponse response)
286 throws IOException, ServletException {
287
288 if (response.isCommitted()) {
289 this.doInclude(uri, request, response);
290
291 } else {
292 super.doForward(uri, request, response);
293 }
294 }
295
296 /***
297 * Overloaded method from Struts' RequestProcessor.
298 * Forward or redirect to the specified destination by the specified
299 * mechanism.
300 * This method catches the Struts' actionForward call. It checks if the
301 * actionForward is done on a Tiles definition name. If true, process the
302 * definition and insert it. If false, call the original parent's method.
303 * @param request The servlet request we are processing.
304 * @param response The servlet response we are creating.
305 * @param forward The ActionForward controlling where we go next.
306 *
307 * @exception IOException if an input/output error occurs.
308 * @exception ServletException if a servlet exception occurs.
309 */
310 protected void processForwardConfig(
311 HttpServletRequest request,
312 HttpServletResponse response,
313 ForwardConfig forward)
314 throws IOException, ServletException {
315
316
317 if (forward == null) {
318 return;
319 }
320
321 if (log.isDebugEnabled()) {
322 log.debug(
323 "processForwardConfig("
324 + forward.getPath()
325 + ")");
326 }
327
328
329 if (processTilesDefinition(forward.getPath(),
330 request,
331 response)) {
332 if (log.isDebugEnabled()) {
333 log.debug(
334 " '" + forward.getPath() + "' - processed as definition");
335 }
336 return;
337 }
338
339 if (log.isDebugEnabled()) {
340 log.debug(" '" + forward.getPath() + "' - processed as uri");
341 }
342
343
344 super.processForwardConfig(request, response, forward);
345 }
346
347 /***
348 * Catch the call to a module relative forward.
349 * If the specified uri is a tiles definition name, insert it.
350 * Otherwise, parent processing is called.
351 * Do a module relative forward to specified uri using request dispatcher.
352 * Uri is relative to the current module. The real uri is computed by
353 * prefixing the module name.
354 * <strong>This method is used internally and is not part of the public
355 * API. It is advised to not use it in subclasses.</strong>
356 * @param uri Module-relative URI to forward to.
357 * @param request Current page request.
358 * @param response Current page response.
359 * @since Struts 1.1
360 */
361 protected void internalModuleRelativeForward(
362 String uri,
363 HttpServletRequest request,
364 HttpServletResponse response)
365 throws IOException, ServletException {
366
367 if (processTilesDefinition(uri, request, response)) {
368 return;
369 }
370
371 super.internalModuleRelativeForward(uri, request, response);
372 }
373
374 /***
375 * Do a module relative include to specified uri using request dispatcher.
376 * Uri is relative to the current module. The real uri is computed by
377 * prefixing the module name.
378 * <strong>This method is used internally and is not part of the public
379 * API. It is advised to not use it in subclasses.</strong>
380 * @param uri Module-relative URI to forward to.
381 * @param request Current page request.
382 * @param response Current page response.
383 * @since Struts 1.1
384 */
385 protected void internalModuleRelativeInclude(
386 String uri,
387 HttpServletRequest request,
388 HttpServletResponse response)
389 throws IOException, ServletException {
390
391 if (processTilesDefinition(uri, request, response)) {
392 return;
393 }
394
395 super.internalModuleRelativeInclude(uri, request, response);
396 }
397
398 /***
399 * Get associated definition factory.
400 */
401 public DefinitionsFactory getDefinitionsFactory() {
402 return definitionsFactory;
403 }
404
405 }