001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry;
016
017 import org.apache.hivemind.ApplicationRuntimeException;
018 import org.apache.tapestry.engine.IEngineService;
019 import org.apache.tapestry.services.Infrastructure;
020 import org.apache.tapestry.services.ResponseBuilder;
021
022 import java.util.Iterator;
023
024 /**
025 * Controller object that manages a single request cycle. A request cycle is one 'hit' on the web
026 * server. In the case of a Tapestry application, this will involve:
027 * <ul>
028 * <li>Responding to the URL by finding an {@link IEngineService}object
029 * <li>Determining the result page
030 * <li>Renderring the result page
031 * <li>Releasing any resources
032 * </ul>
033 * <p>
034 * Mixed in with this is:
035 * <ul>
036 * <li>Exception handling
037 * <li>Loading of pages and templates from resources
038 * <li>Tracking changes to page properties, and restoring pages to prior states
039 * <li>Pooling of page objects
040 * </ul>
041 *
042 * <p>
043 * A request cycle is broken up into two phases. The <em>rewind</em> phase is optional, as it tied
044 * to {@link org.apache.tapestry.form.Form}
045 * components. In the rewind phase, a previous page render is redone (discarding output) until a
046 * specific component of the page is reached. This rewinding ensures that the page is restored to
047 * the exact state it had when the URL for the request cycle was generated, taking into account the
048 * dynamic nature of the page ({@link org.apache.tapestry.components.ForBean},
049 * {@link org.apache.tapestry.components.Conditional}, etc.). Once this component is reached, it
050 * can notify its {@link IActionListener}. The listener has the ability to update the state of any
051 * pages and select a new result page.
052 * </p>
053 *
054 * <p>
055 * Following the rewind phase is the <em>render</em> phase. During the render phase, a page is
056 * actually rendered and output sent to the client web browser.
057 * </p>
058 * @author Howard Lewis Ship
059 */
060
061 public interface IRequestCycle
062 {
063 /**
064 * Invoked after the request cycle is no longer needed, to release any resources it may have.
065 * This includes releasing any loaded pages back to the page source.
066 */
067
068 void cleanup();
069
070 /**
071 * Passes the String through
072 * {@link javax.servlet.http.HttpServletResponse#encodeURL(java.lang.String)}, which ensures
073 * that the session id is encoded in the URL (if necessary).
074 *
075 * @param URL The url to encode.
076 * @return The encoded form of the url.
077 */
078
079 String encodeURL(String URL);
080
081 /**
082 * Returns the engine which is processing this request cycle.
083 *
084 * @return The engine.
085 */
086
087 IEngine getEngine();
088
089 /**
090 * Retrieves a previously stored attribute, returning null if not found. Attributes allow
091 * components to locate each other; primarily they allow a wrapped component to locate a
092 * component which wraps it. Attributes are cleared at the end of the render (or rewind).
093 *
094 * @param name The name of the attribute to retrieve.
095 * @return The matching attribute with the specified name, or null if none found.
096 */
097
098 Object getAttribute(String name);
099
100 /**
101 * Identifies the active page, the page which will ultimately render the response.
102 *
103 * @return The active page.
104 */
105
106 IPage getPage();
107
108 /**
109 * Returns the page with the given name. If the page has been previously loaded in the current
110 * request cycle, that page is returned. Otherwise, the engine's page loader is used to load the
111 * page.
112 *
113 * @param name The page to get a reference to.
114 * @return The page instance.
115 *
116 * @throws PageNotFoundException
117 * if the page does not exist.
118 *
119 * @see org.apache.tapestry.engine.IPageSource#getPage(IRequestCycle, String)
120 */
121
122 IPage getPage(String name);
123
124 /**
125 * Returns true if the context is being used to rewind a prior state of the page. This is only
126 * true when there is a target action id.
127 *
128 * @return True if rewinding a form, false otherwise.
129 */
130
131 boolean isRewinding();
132
133 /**
134 * Checks to see if the current action id matches the target action id. Returns true only if
135 * they match. Returns false if there is no target action id (that is, during page rendering).
136 * <p>
137 * If theres a match on action id, then the component is compared against the target component.
138 * If there's a mismatch then a {@link StaleLinkException}is thrown.
139 *
140 * @param component The component to check.
141 * @return True if the specified component has been rewound.
142 */
143
144 boolean isRewound(IComponent component);
145
146 /**
147 * Sets the {@link ResponseBuilder} to use for this response, don't
148 * try setting this unless you're very sure you know what you are doing as
149 * this isn't the only way that it is used. (ie replacing this builder won't
150 * necessarily override another builder being used already)
151 *
152 * @param builder The response builder that may be used by components
153 * to help with delegate/sub component rendering.
154 */
155 void setResponseBuilder(ResponseBuilder builder);
156
157 /**
158 * Entry point for getting the response builder used to build
159 * this response.
160 * @return The response builder used for this response.
161 */
162 ResponseBuilder getResponseBuilder();
163
164 /**
165 * Tests if the render component chain is empty, meaning no components have
166 * been loaded onto the stack yet.
167 *
168 * @return True, if the current stack is empty.
169 */
170 boolean renderStackEmpty();
171
172 /**
173 * Looks at the object at the top of the render stack without removing
174 * the {@link IRender} from the stack.
175 *
176 * @return The last (parent) item added to the current render stack.
177 */
178 IRender renderStackPeek();
179
180 /**
181 * Removes the {@link IRender} at the top of the stack, if any.
182 *
183 * @return The removed {@link IRender}, if any.
184 */
185 IRender renderStackPop();
186
187 /**
188 * Pushes the specified render onto the current render stack.
189 *
190 * @param render The {@link IRender} object being pushed.
191 * @return The added {@link IRender}.
192 */
193 IRender renderStackPush(IRender render);
194
195 /**
196 * Returns the 1-based position where an object is on this stack. If the object
197 * o occurs as an item in this stack, this method returns the distance from the
198 * top of the stack of the occurrence nearest the top of the stack; the topmost
199 * item on the stack is considered to be at distance 1. The equals method is used
200 * to compare o to the items in this stack.
201 *
202 * @param render The {@link IRender} being searched for.
203 *
204 * @return the 1-based position from the top of the stack where the object is
205 * located; the return value -1 indicates that the object is not on the stack.
206 */
207 int renderStackSearch(IRender render);
208
209 /**
210 * Creates a traversable iterator for moving through the stack.
211 *
212 * @return An iterator over the current stack.
213 */
214 Iterator renderStackIterator();
215
216 /**
217 * Removes a previously stored attribute, if one with the given name exists.
218 *
219 * @param name The key name of the attribute to remove.
220 */
221
222 void removeAttribute(String name);
223
224 /**
225 * Renders the given page. Applications should always use this method to render the page, rather
226 * than directly invoking {@link IPage#render(IMarkupWriter, IRequestCycle)}since the request
227 * cycle must perform some setup before rendering.
228 *
229 * @param builder Renders the currently active page using the specified builder.
230 */
231
232 void renderPage(ResponseBuilder builder);
233
234 /**
235 * Allows a temporary object to be stored in the request cycle, which allows otherwise unrelated
236 * objects to communicate. This is similar to <code>HttpServletRequest.setAttribute()</code>,
237 * except that values can be changed and removed as well.
238 * <p>
239 * This is used by components to locate each other. A component, such as
240 * {@link org.apache.tapestry.html.Body}, will write itself under a well-known name into the
241 * request cycle, and components it wraps can locate it by that name.
242 * <p>
243 * Attributes are cleared at the end of each render or rewind phase.
244 *
245 * @param name Key name of the attribute to store.
246 * @param value Value of the attribute.
247 */
248
249 void setAttribute(String name, Object value);
250
251 /**
252 * Invoked just before rendering the response page to get all
253 * {@link org.apache.tapestry.engine.IPageRecorder page recorders}touched in this request cycle
254 * to commit their changes (save them to persistant storage).
255 *
256 * @see org.apache.tapestry.engine.IPageRecorder#commit()
257 */
258
259 void commitPageChanges();
260
261 /**
262 * Returns the service which initiated this request cycle.
263 *
264 * @return The service associated with current request.
265 * @since 1.0.1
266 */
267
268 IEngineService getService();
269
270 /**
271 * Used by {@link IForm forms}to perform a <em>partial</em> rewind so as to respond to the
272 * form submission (using the direct service).
273 *
274 * @param form The form to rewind.
275 *
276 * @since 1.0.2
277 */
278
279 void rewindForm(IForm form);
280
281 /**
282 * Sets client side form focus off globally for all forms in this request cycle.
283 */
284 void disableFocus();
285
286 /**
287 * Check for global focus being disabled.
288 * @return True if focus is disabled, false otherwise.
289 */
290 boolean isFocusDisabled();
291
292 /**
293 * Invoked by a {@link IEngineService service} to store an array of application-specific
294 * parameters. These can later be retrieved (typically, by an application-specific listener
295 * method) by invoking {@link #getListenerParameters()}.
296 *
297 * @param parameters The parameters to set which will be available as method parameters
298 * to any listeners invoked in this request.
299 * @see org.apache.tapestry.engine.DirectService
300 * @since 4.0
301 */
302 void setListenerParameters(Object[] parameters);
303
304 /**
305 * Returns parameters previously stored by {@link #setListenerParameters(Object[])}.
306 *
307 * @return The current set of bound listener parameters for the current service.
308 * @since 4.0
309 */
310
311 Object[] getListenerParameters();
312
313 /**
314 * A convienience for invoking {@link #activate(IPage)}. Invokes {@link #getPage(String)}to
315 * get an instance of the named page.
316 *
317 * @param name The name of the page to activate.
318 * @since 3.0
319 */
320
321 void activate(String name);
322
323 /**
324 * Sets the active page for the request. The active page is the page which will ultimately
325 * render the response. The activate page is typically set by the {@link IEngineService service}.
326 * Frequently, the active page is changed (from a listener method) to choose an alternate page
327 * to render the response).
328 * <p>
329 * {@link IPage#validate(IRequestCycle)}is invoked on the page to be activated.
330 * {@link PageRedirectException}is caught and the page specified in the exception will be the
331 * active page instead (that is, a page may "pass the baton" to another page using the
332 * exception). The new page is also validated. This continues until a page does not throw
333 * {@link PageRedirectException}.
334 * <p>
335 * Validation loops can occur, where page A redirects to page B and then page B redirects back
336 * to page A (possibly with intermediate steps). This is detected and results in an
337 * {@link ApplicationRuntimeException}.
338 *
339 * @param page The page to activate.
340 *
341 * @since 3.0
342 */
343 void activate(IPage page);
344
345 /**
346 * Returns a query parameter value, or null if not provided in the request. If multiple values
347 * are provided, returns the first value.
348 *
349 * @param name The name of the request parameter to retrieve.
350 * @return The value matching the specified parameter name, or null if none found.
351 * @since 4.0
352 */
353 String getParameter(String name);
354
355 /**
356 * Returns all query parameter values for the given name. Returns null if no values were
357 * provided.
358 *
359 * @param name The name of the parameters to retrieve.
360 * @return The matching multi value array for the specified name, or null if none found.
361 * @since 4.0
362 */
363 String[] getParameters(String name);
364
365 /**
366 * Converts a partial URL into an absolute URL. Prefixes the provided URL with servlet context
367 * path (if any), then expands it to a full URL by prepending with the scheme, server and port
368 * (determined from the current {@link org.apache.tapestry.web.WebRequest request}.
369 *
370 * @param partialURL The url to modify into an absolute url.
371 * @return The converted absolute url representation of the specified partialURL.
372 * @since 4.0
373 */
374
375 String getAbsoluteURL(String partialURL);
376
377 /**
378 * Forgets any stored changes to the specified page. If the page has already been loaded (and
379 * rolled back) then the loaded page instance is not affected; if the page is only loaded
380 * subsequently, the page instance will not see any persisted property changes.
381 *
382 * @param name The name of the page instance to throw all persistent properties away for.
383 * @since 4.0
384 */
385
386 void forgetPage(String name);
387
388 /**
389 * Returns the central {@link org.apache.tapestry.services.Infrastructure} object used to
390 * manage the processing of the request.
391 *
392 * @return The {@link Infrastructure} object associated with this request.
393 * @since 4.0
394 */
395
396 Infrastructure getInfrastructure();
397
398 /**
399 * Returns the provided string, possibly modified (with an appended suffix) to make it unique.
400 *
401 * @param baseId
402 * the base id from which to generate the unique string.
403 * @return baseId, or baseId with a suffix appended (if the method has been previously invoked
404 * with the same baseId).
405 */
406
407 String getUniqueId(String baseId);
408
409 /**
410 * Returns what <i>will</i> be the next unique id generated based on the given input, but doesn't
411 * store the result.
412 *
413 * @param baseId
414 * the base id from which to generate the unique string.
415 * @return baseId, or baseId with a suffix appended (if the method has been previously invoked
416 * with the same baseId).
417 */
418
419 String peekUniqueId(String baseId);
420
421 /**
422 * Sends a redirect to the client web browser. This is currently a convinience for constructing
423 * and throwing a {@link RedirectException}, but may change in a later release.
424 *
425 * @param URL The url to send a client redirect for.
426 * @since 4.0
427 * @throws RedirectException
428 */
429
430 void sendRedirect(String URL);
431
432 /**
433 * Encodes the current state of all allocated component ids (using {@link org.apache.tapestry.util.IdAllocator})
434 * to a String value that can be embedded in URLs or forms.
435 *
436 * <p>
437 * This method is used primarily by the {@link org.apache.tapestry.form.Form} component to encode the state
438 * of the current ids allocated so as to maintain consistent state during rewind - especially in cases where
439 * multiple form components are rendered in a page.
440 * </p>
441 *
442 * @return The encoded state, which can be used to re-initialize a request to the same ID state
443 * by invoking {@link #initializeIdState(String)}.
444 */
445 String encodeIdState();
446
447 /**
448 * Used in conjunction with {@link #encodeIdState()} to re-initialize the internal id allocation state
449 * of a request during a form rewind.
450 *
451 * @param encodedSeed The value returned from a previous invocation of {@link #encodeIdState()} .
452 */
453 void initializeIdState(String encodedSeed);
454 }