1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts.tiles.commands;
19
20 import java.io.IOException;
21
22 import javax.servlet.RequestDispatcher;
23 import javax.servlet.ServletException;
24 import javax.servlet.http.HttpServletRequest;
25 import javax.servlet.http.HttpServletResponse;
26
27 import org.apache.commons.chain.Command;
28 import org.apache.commons.chain.Context;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.struts.chain.contexts.ServletActionContext;
32 import org.apache.struts.config.ForwardConfig;
33 import org.apache.struts.tiles.ComponentContext;
34 import org.apache.struts.tiles.ComponentDefinition;
35 import org.apache.struts.tiles.Controller;
36 import org.apache.struts.tiles.DefinitionsUtil;
37 import org.apache.struts.tiles.FactoryNotFoundException;
38 import org.apache.struts.tiles.NoSuchDefinitionException;
39 import org.apache.struts.tiles.TilesUtil;
40 import org.apache.struts.upload.MultipartRequestWrapper;
41
42
43 /***
44 * <p>Command class intended to perform responsibilities of the
45 * TilesRequestProcessor in Struts 1.1. Does not actually dispatch requests,
46 * but simply prepares the chain context for a later forward as
47 * appropriate. Should be added to a chain before something which
48 * would handle a conventional ForwardConfig.</p>
49 *
50 * <p>This class will never have any effect on the chain unless a
51 * <code>TilesDefinitionFactory</code> can be found; however it does not
52 * consider the absence of a definition factory to be a fatal error; the
53 * command simply returns false and lets the chain continue.</p>
54 *
55 * <p>To initialize the <code>TilesDefinitionFactory</code>, use
56 * <code>org.apache.struts.chain.commands.legacy.TilesPlugin</code>. This class
57 * is a simple extension to <code>org.apache.struts.tiles.TilesPlugin</code>
58 * which simply does not interfere with your choice of <code>RequestProcessor</code>
59 * implementation.
60 * </p>
61 *
62 *
63 */
64 public class TilesPreProcessor implements Command
65 {
66
67
68
69
70
71 private static final Log log = LogFactory.getLog(TilesPreProcessor.class);
72
73
74
75
76 /***
77 * <p>If the current <code>ForwardConfig</code> is using "tiles",
78 * perform necessary pre-processing to set up the <code>TilesContext</code>
79 * and substitute a new <code>ForwardConfig</code> which is understandable
80 * to a <code>RequestDispatcher</code>.</p>
81 *
82 * <p>Note that if the command finds a previously existing
83 * <code>ComponentContext</code> in the request, then it
84 * infers that it has been called from within another tile,
85 * so instead of changing the <code>ForwardConfig</code> in the chain
86 * <code>Context</code>, the command uses <code>RequestDispatcher</code>
87 * to <em>include</em> the tile, and returns true, indicating that the processing
88 * chain is complete.</p>
89 *
90 * @param context The <code>Context</code> for the current request
91 *
92 * @return <code>false</code> in most cases, but true if we determine
93 * that we're processing in "include" mode.
94 */
95 public boolean execute(Context context) throws Exception {
96
97
98 ServletActionContext sacontext = (ServletActionContext) context;
99 ForwardConfig forwardConfig = sacontext.getForwardConfig();
100 if (forwardConfig == null || forwardConfig.getPath() == null)
101 {
102 log.debug("No forwardConfig or no path, so pass to next command.");
103 return (false);
104 }
105
106
107 ComponentDefinition definition = null;
108 try
109 {
110 definition = TilesUtil.getDefinition(forwardConfig.getPath(),
111 sacontext.getRequest(),
112 sacontext.getContext());
113 }
114 catch (FactoryNotFoundException ex)
115 {
116
117 log.debug("Tiles DefinitionFactory not found, so pass to next command.");
118 return false;
119 }
120 catch (NoSuchDefinitionException ex)
121 {
122
123 log.debug("NoSuchDefinitionException " + ex.getMessage());
124 }
125
126
127 boolean doInclude = false;
128 ComponentContext tileContext = null;
129
130
131
132 tileContext = ComponentContext.getContext(sacontext.getRequest());
133 doInclude = (tileContext != null || sacontext.getResponse().isCommitted());
134
135
136 Controller controller = null;
137
138
139 String uri = null;
140
141 if (definition != null)
142 {
143
144
145
146 uri = definition.getPath();
147 controller = definition.getOrCreateController();
148
149 if (tileContext == null) {
150 tileContext =
151 new ComponentContext(definition.getAttributes());
152 ComponentContext.setContext(tileContext, sacontext.getRequest());
153
154 } else {
155 tileContext.addMissing(definition.getAttributes());
156 }
157 }
158
159
160
161
162
163
164 definition = DefinitionsUtil.getActionDefinition(sacontext.getRequest());
165 if (definition != null) {
166
167
168 if (definition.getPath() != null) {
169 log.debug("Override forward uri "
170 + uri
171 + " with action uri "
172 + definition.getPath());
173 uri = definition.getPath();
174 }
175
176 if (definition.getOrCreateController() != null) {
177 log.debug("Override forward controller with action controller");
178 controller = definition.getOrCreateController();
179 }
180
181 if (tileContext == null) {
182 tileContext =
183 new ComponentContext(definition.getAttributes());
184 ComponentContext.setContext(tileContext, sacontext.getRequest());
185 } else {
186 tileContext.addMissing(definition.getAttributes());
187 }
188 }
189
190
191 if (uri == null) {
192 log.debug("no uri computed, so pass to next command");
193 return false;
194 }
195
196
197 if (controller != null) {
198 log.trace("Execute controller: " + controller);
199 controller.execute(
200 tileContext,
201 sacontext.getRequest(),
202 sacontext.getResponse(),
203 sacontext.getContext());
204 }
205
206
207
208
209 if (doInclude) {
210 log.info("Tiles process complete; doInclude with " + uri);
211 doInclude(sacontext, uri);
212 } else {
213 log.info("Tiles process complete; forward to " + uri);
214 doForward(sacontext, uri);
215 }
216
217 log.debug("Tiles processed, so clearing forward config from context.");
218 sacontext.setForwardConfig( null );
219 return (false);
220 }
221
222
223
224
225 /***
226 * <p>Do an include of specified URI using a <code>RequestDispatcher</code>.</p>
227 *
228 * @param context a chain servlet/web context
229 * @param uri Context-relative URI to include
230 */
231 protected void doInclude(
232 ServletActionContext context,
233 String uri)
234 throws IOException, ServletException {
235
236 RequestDispatcher rd = getRequiredDispatcher(context, uri);
237
238 if (rd != null) {
239 rd.include(context.getRequest(), context.getResponse());
240 }
241 }
242
243 /***
244 * <p>Do an include of specified URI using a <code>RequestDispatcher</code>.</p>
245 *
246 * @param context a chain servlet/web context
247 * @param uri Context-relative URI to include
248 */
249 protected void doForward(
250 ServletActionContext context,
251 String uri)
252 throws IOException, ServletException {
253
254 RequestDispatcher rd = getRequiredDispatcher(context, uri);
255
256 if (rd != null) {
257 rd.forward(context.getRequest(), context.getResponse());
258 }
259 }
260
261 /***
262 * <p>Get the <code>RequestDispatcher</code> for the specified <code>uri</code>. If it is not found,
263 * send a 500 error as a response and return null;
264 *
265 * @param context the current <code>ServletActionContext</code>
266 * @param uri the ServletContext-relative URI of the request dispatcher to find.
267 * @return the <code>RequestDispatcher</code>, or null if none is returned from the <code>ServletContext</code>.
268 * @throws IOException if <code>getRequestDispatcher(uri)</code> has an error.
269 */
270 private RequestDispatcher getRequiredDispatcher(ServletActionContext context, String uri) throws IOException {
271 RequestDispatcher rd = context.getContext().getRequestDispatcher(uri);
272 if (rd == null) {
273 log.debug("No request dispatcher found for " + uri);
274 HttpServletResponse response = context.getResponse();
275 response.sendError(
276 HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
277 "Error getting RequestDispatcher for " + uri);
278 }
279 return rd;
280 }
281
282 }