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 }