1 /*
2 * $Id$
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 package org.apache.struts.tiles2;
23
24 import java.io.IOException;
25
26 import org.apache.struts.action.ActionServlet;
27 import org.apache.struts.action.RequestProcessor;
28 import org.apache.struts.config.ForwardConfig;
29 import org.apache.struts.config.ModuleConfig;
30 import org.apache.tiles.TilesContainer;
31 import org.apache.tiles.TilesException;
32 import org.apache.tiles.access.TilesAccess;
33 import org.apache.tiles.request.ApplicationContext;
34 import org.apache.tiles.request.Request;
35 import org.apache.tiles.request.jakarta.servlet.ServletRequest;
36 import org.apache.tiles.request.jakarta.servlet.ServletUtil;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import jakarta.servlet.ServletContext;
41 import jakarta.servlet.ServletException;
42 import jakarta.servlet.http.HttpServletRequest;
43 import jakarta.servlet.http.HttpServletResponse;
44
45 /**
46 * <p><strong>RequestProcessor</strong> contains the processing logic that
47 * the Struts controller servlet performs as it receives each servlet request
48 * from the container.</p>
49 * <p>This processor subclasses the Struts RequestProcessor in order to intercept calls to forward
50 * or include. When such calls are done, the Tiles processor checks if the specified URI
51 * is a definition name. If true, the definition is retrieved and included. If
52 * false, the original URI is included or a forward is performed.
53 * <p>
54 * Actually, catching is done by overloading the following methods:
55 * <ul>
56 * <li>{@link #processForwardConfig(HttpServletRequest,HttpServletResponse,ForwardConfig)}</li>
57 * <li>{@link #internalModuleRelativeForward(String, HttpServletRequest , HttpServletResponse)}</li>
58 * <li>{@link #internalModuleRelativeInclude(String, HttpServletRequest , HttpServletResponse)}</li>
59 * </ul>
60 * </p>
61 * @since Struts 1.1
62 */
63 public class TilesRequestProcessor extends RequestProcessor {
64 private static final long serialVersionUID = 6212184689866961850L;
65
66 /**
67 * The {@code Log} instance for this class.
68 */
69 private transient final Logger log =
70 LoggerFactory.getLogger(TilesRequestProcessor.class);
71
72 /**
73 * The used servlet context.
74 */
75 protected ServletContext servletContext;
76
77 /**
78 * Initialize this request processor instance.
79 *
80 * @param servlet The ActionServlet we are associated with.
81 * @param moduleConfig The ModuleConfig we are associated with.
82 * @throws ServletException If an error occurs during initialization.
83 */
84 public void init(ActionServlet servlet, ModuleConfig moduleConfig)
85 throws ServletException {
86
87 super.init(servlet, moduleConfig);
88 }
89
90 /**
91 * Process a Tile definition name.
92 * This method tries to process the parameter <code>definitionName</code>
93 * as a definition name.
94 * It returns <code>true</code> if a definition has been processed, or
95 * <code>false</code> otherwise.
96 *
97 * @param definitionName Definition name to insert.
98 * @param req Current page request.
99 * @param res Current page response.
100 * @throws IOException If something goes wrong during writing the
101 * definition.
102 * @throws ServletException If something goes wrong during the evaluation
103 * of the definition
104 * @return <code>true</code> if the method has processed uri as a
105 * definition name, <code>false</code> otherwise.
106 */
107 protected boolean processTilesDefinition(
108 String definitionName,
109 HttpServletRequest req,
110 HttpServletResponse res)
111 throws IOException, ServletException {
112
113 ApplicationContext applicationContext = ServletUtil
114 .getApplicationContext(getServletContext());
115 Request request = new ServletRequest(applicationContext,
116 req, res);
117 TilesContainer container = TilesAccess.getContainer(applicationContext);
118 if (container == null) {
119 log.debug("Tiles container not found, so pass to next command.");
120 return false;
121 }
122
123 boolean retValue = false;
124
125 if (container.isValidDefinition(definitionName, request)) {
126 retValue = true;
127 try {
128 container.render(definitionName, request);
129 } catch (TilesException e) {
130 throw new ServletException("Cannot render definition '"
131 + definitionName + "'");
132 }
133 } else {
134 // ignore not found
135 log.debug("Cannot find definition '{}'", definitionName);
136 }
137
138 return retValue;
139 }
140
141 /**
142 * Do a forward using request dispatcher.
143 * Uri is a valid uri. If response has already been commited, do an include
144 * instead.
145 * @param uri Uri or Definition name to forward.
146 * @param request Current page request.
147 * @param response Current page response.
148 * @throws IOException If something goes wrong during writing the
149 * definition.
150 * @throws ServletException If something goes wrong during the evaluation
151 * of the definition
152 */
153 protected void doForward(
154 String uri,
155 HttpServletRequest request,
156 HttpServletResponse response)
157 throws IOException, ServletException {
158
159 if (response.isCommitted()) {
160 this.doInclude(uri, request, response);
161
162 } else {
163 super.doForward(uri, request, response);
164 }
165 }
166
167 /**
168 * Overloaded method from Struts' RequestProcessor.
169 * Forward or redirect to the specified destination by the specified
170 * mechanism.
171 * This method catches the Struts' actionForward call. It checks if the
172 * actionForward is done on a Tiles definition name. If true, process the
173 * definition and insert it. If false, call the original parent's method.
174 * @param request The servlet request we are processing.
175 * @param response The servlet response we are creating.
176 * @param forward The ActionForward controlling where we go next.
177 *
178 * @exception IOException if an input/output error occurs.
179 * @exception ServletException if a servlet exception occurs.
180 */
181 protected void processForwardConfig(
182 HttpServletRequest request,
183 HttpServletResponse response,
184 ForwardConfig forward)
185 throws IOException, ServletException {
186
187 // Required by struts contract
188 if (forward == null) {
189 return;
190 }
191
192 log.debug("processForwardConfig({})", forward.getPath());
193
194 // Try to process the definition.
195 if (processTilesDefinition(forward.getPath(),
196 request, response)) {
197 log.debug(" '{}' - processed as definition", forward.getPath());
198 return;
199 }
200
201 log.debug(" '{}' - processed as uri", forward.getPath());
202
203 // forward doesn't contain a definition, let parent do processing
204 super.processForwardConfig(request, response, forward);
205 }
206
207 /**
208 * Catch the call to a module relative forward.
209 * If the specified uri is a tiles definition name, insert it.
210 * Otherwise, parent processing is called.
211 * Do a module relative forward to specified uri using request dispatcher.
212 * Uri is relative to the current module. The real uri is computed by
213 * prefixing the module name.
214 * <strong>This method is used internally and is not part of the public
215 * API. It is advised to not use it in subclasses.</strong>
216 * @param uri Module-relative URI to forward to.
217 * @param request Current page request.
218 * @param response Current page response.
219 * @throws IOException If something goes wrong during writing the
220 * definition.
221 * @throws ServletException If something goes wrong during the evaluation
222 * of the definition
223 * @since Struts 1.1
224 */
225 protected void internalModuleRelativeForward(
226 String uri,
227 HttpServletRequest request,
228 HttpServletResponse response)
229 throws IOException, ServletException {
230
231 if (processTilesDefinition(uri, request, response)) {
232 return;
233 }
234
235 super.internalModuleRelativeForward(uri, request, response);
236 }
237
238 /**
239 * Do a module relative include to specified uri using request dispatcher.
240 * Uri is relative to the current module. The real uri is computed by
241 * prefixing the module name.
242 * <strong>This method is used internally and is not part of the public
243 * API. It is advised to not use it in subclasses.</strong>
244 * @param uri Module-relative URI to forward to.
245 * @param request Current page request.
246 * @param response Current page response.
247 * @throws IOException If something goes wrong during writing the
248 * definition.
249 * @throws ServletException If something goes wrong during the evaluation
250 * of the definition
251 * @since Struts 1.1
252 */
253 protected void internalModuleRelativeInclude(
254 String uri,
255 HttpServletRequest request,
256 HttpServletResponse response)
257 throws IOException, ServletException {
258
259 if (processTilesDefinition(uri, request, response)) {
260 return;
261 }
262
263 super.internalModuleRelativeInclude(uri, request, response);
264 }
265 }