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 java.util.Iterator;
018    
019    import org.apache.tapestry.engine.IEngineService;
020    import org.apache.tapestry.services.Infrastructure;
021    import org.apache.tapestry.services.ResponseBuilder;
022    
023    /**
024     * Controller object that manages a single request cycle. A request cycle is one 'hit' on the web
025     * server. In the case of a Tapestry application, this will involve:
026     * <ul>
027     * <li>Responding to the URL by finding an {@link IEngineService}object
028     * <li>Determining the result page
029     * <li>Renderring the result page
030     * <li>Releasing any resources
031     * </ul>
032     * <p>
033     * Mixed in with this is:
034     * <ul>
035     * <li>Exception handling
036     * <li>Loading of pages and templates from resources
037     * <li>Tracking changes to page properties, and restoring pages to prior states
038     * <li>Pooling of page objects
039     * </ul>
040     * 
041     * <p>
042     * A request cycle is broken up into two phases. The <em>rewind</em> phase is optional, as it tied
043     * to {@link org.apache.tapestry.link.ActionLink}or {@link org.apache.tapestry.form.Form}
044     * components. In the rewind phase, a previous page render is redone (discarding output) until a
045     * specific component of the page is reached. This rewinding ensures that the page is restored to
046     * the exact state it had when the URL for the request cycle was generated, taking into account the
047     * dynamic nature of the page ({@link org.apache.tapestry.components.Foreach},
048     * {@link org.apache.tapestry.components.Conditional}, etc.). Once this component is reached, it
049     * can notify its {@link IActionListener}. The listener has the ability to update the state of any
050     * pages and select a new result page.
051     * </p>
052     * 
053     * <p>
054     * Following the rewind phase is the <em>render</em> phase. During the render phase, a page is
055     * actually rendered and output sent to the client web browser.
056     * </p>
057     * @author Howard Lewis Ship
058     */
059    
060    public interface IRequestCycle
061    {
062        /**
063         * Invoked after the request cycle is no longer needed, to release any resources it may have.
064         * This includes releasing any loaded pages back to the page source.
065         */
066    
067        void cleanup();
068    
069        /**
070         * Passes the String through
071         * {@link javax.servlet.http.HttpServletResponse#encodeURL(java.lang.String)}, which ensures
072         * that the session id is encoded in the URL (if necessary).
073         */
074    
075        String encodeURL(String URL);
076    
077        /**
078         * Returns the engine which is processing this request cycle.
079         */
080    
081        IEngine getEngine();
082    
083        /**
084         * Retrieves a previously stored attribute, returning null if not found. Attributes allow
085         * components to locate each other; primarily they allow a wrapped component to locate a
086         * component which wraps it. Attributes are cleared at the end of the render (or rewind).
087         */
088    
089        Object getAttribute(String name);
090    
091        /**
092         * Identifies the active page, the page which will ultimately render the response.
093         */
094    
095        IPage getPage();
096    
097        /**
098         * Returns the page with the given name. If the page has been previously loaded in the current
099         * request cycle, that page is returned. Otherwise, the engine's page loader is used to load the
100         * page.
101         * 
102         * @throws PageNotFoundException
103         *             if the page does not exist.
104         * @see org.apache.tapestry.engine.IPageSource#getPage(IRequestCycle, String, IMonitor)
105         */
106    
107        IPage getPage(String name);
108    
109        /**
110         * Returns true if the context is being used to rewind a prior state of the page. This is only
111         * true when there is a target action id.
112         */
113    
114        boolean isRewinding();
115    
116        /**
117         * Checks to see if the current action id matches the target action id. Returns true only if
118         * they match. Returns false if there is no target action id (that is, during page rendering).
119         * <p>
120         * If theres a match on action id, then the component is compared against the target component.
121         * If there's a mismatch then a {@link StaleLinkException}is thrown.
122         */
123    
124        boolean isRewound(IComponent component);
125    
126        /**
127         * Sets the {@link ResponseBuilder} to use for this response, don't 
128         * try setting this unless you're very sure you know what you are doing as
129         * this isn't the only way that it is used. (ie replacing this builder won't 
130         * necessarily override another builder being used already)
131         * 
132         * @param builder The response builder that may be used by components
133         * to help with delegate/sub component rendering.
134         */
135        void setResponseBuilder(ResponseBuilder builder);
136        
137        /**
138         * Entry point for getting the response builder used to build
139         * this response.
140         * @return The response builder used for this response.
141         */
142        ResponseBuilder getResponseBuilder();
143        
144        /**
145         * Tests if the render component chain is empty, meaning no components have
146         * been loaded onto the stack yet.
147         * 
148         * @return True, if the current stack is empty.
149         */
150        boolean renderStackEmpty();
151        
152        /**
153         * Looks at the object at the top of the render stack without removing 
154         * the {@link IRender} from the stack.
155         * 
156         * @return The last (parent) item added to the current render stack.
157         */
158        IRender renderStackPeek();
159        
160        /**
161         * Removes the {@link IRender} at the top of the stack, if any.
162         * 
163         * @return The removed {@link IRender}, if any.
164         */
165        IRender renderStackPop();
166        
167        /**
168         * Pushes the specified render onto the current render stack.
169         * 
170         * @param render The {@link IRender} object being pushed.
171         * @return The added {@link IRender}.
172         */
173        IRender renderStackPush(IRender render);
174        
175        /**
176         * Returns the 1-based position where an object is on this stack. If the object 
177         * o occurs as an item in this stack, this method returns the distance from the 
178         * top of the stack of the occurrence nearest the top of the stack; the topmost 
179         * item on the stack is considered to be at distance 1. The equals method is used 
180         * to compare o to the items in this stack.
181         * 
182         * @param render The {@link IRender} being searched for.
183         * 
184         * @return the 1-based position from the top of the stack where the object is 
185         *          located; the return value -1  indicates that the object is not on the stack.
186         */
187        int renderStackSearch(IRender render);
188        
189        /**
190         * Creates a traversable iterator for moving through the stack.
191         * 
192         * @return An iterator over the current stack.
193         */
194        Iterator renderStackIterator();
195        
196        /**
197         * Removes a previously stored attribute, if one with the given name exists.
198         */
199    
200        void removeAttribute(String name);
201    
202        /**
203         * Renders the given page. Applications should always use this method to render the page, rather
204         * than directly invoking {@link IPage#render(IMarkupWriter, IRequestCycle)}since the request
205         * cycle must perform some setup before rendering.
206         */
207    
208        void renderPage(ResponseBuilder builder);
209    
210        /**
211         * Allows a temporary object to be stored in the request cycle, which allows otherwise unrelated
212         * objects to communicate. This is similar to <code>HttpServletRequest.setAttribute()</code>,
213         * except that values can be changed and removed as well.
214         * <p>
215         * This is used by components to locate each other. A component, such as
216         * {@link org.apache.tapestry.html.Body}, will write itself under a well-known name into the
217         * request cycle, and components it wraps can locate it by that name.
218         * <p>
219         * Attributes are cleared at the end of each render or rewind phase.
220         */
221    
222        void setAttribute(String name, Object value);
223    
224        /**
225         * Invoked just before rendering the response page to get all
226         * {@link org.apache.tapestry.engine.IPageRecorder page recorders}touched in this request cycle
227         * to commit their changes (save them to persistant storage).
228         * 
229         * @see org.apache.tapestry.engine.IPageRecorder#commit()
230         */
231    
232        void commitPageChanges();
233    
234        /**
235         * Returns the service which initiated this request cycle.
236         * 
237         * @since 1.0.1
238         */
239    
240        IEngineService getService();
241    
242        /**
243         * Used by {@link IForm forms}to perform a <em>partial</em> rewind so as to respond to the
244         * form submission (using the direct service).
245         * <p>
246         * Note: the targetActionId parameter was removed in release 4.0.
247         * 
248         * @since 1.0.2
249         */
250    
251        void rewindForm(IForm form);
252    
253        /**
254         * Invoked by a {@link IEngineService service}&nbsp;to store an array of application-specific
255         * parameters. These can later be retrieved (typically, by an application-specific listener
256         * method) by invoking {@link #getListenerParameters()}.
257         * 
258         * @see org.apache.tapestry.engine.DirectService
259         * @since 4.0
260         */
261        void setListenerParameters(Object[] parameters);
262    
263        /**
264         * Returns parameters previously stored by {@link #setListenerParameters(Object[])}.
265         * 
266         * @since 4.0
267         */
268    
269        Object[] getListenerParameters();
270    
271        /**
272         * A convienience for invoking {@link #activate(IPage)}. Invokes {@link #getPage(String)}to
273         * get an instance of the named page.
274         * 
275         * @since 3.0
276         */
277    
278        void activate(String name);
279    
280        /**
281         * Sets the active page for the request. The active page is the page which will ultimately
282         * render the response. The activate page is typically set by the {@link IEngineService service}.
283         * Frequently, the active page is changed (from a listener method) to choose an alternate page
284         * to render the response).
285         * <p>
286         * {@link IPage#validate(IRequestCycle)}is invoked on the page to be activated.
287         * {@link PageRedirectException}is caught and the page specified in the exception will be the
288         * active page instead (that is, a page may "pass the baton" to another page using the
289         * exception). The new page is also validated. This continues until a page does not throw
290         * {@link PageRedirectException}.
291         * <p>
292         * Validation loops can occur, where page A redirects to page B and then page B redirects back
293         * to page A (possibly with intermediate steps). This is detected and results in an
294         * {@link ApplicationRuntimeException}.
295         * 
296         * @since 3.0
297         */
298        void activate(IPage page);
299        
300        /**
301         * Returns a query parameter value, or null if not provided in the request. If multiple values
302         * are provided, returns the first value.
303         * 
304         * @since 4.0
305         */
306        String getParameter(String name);
307    
308        /**
309         * Returns all query parameter values for the given name. Returns null if no values were
310         * provided.
311         * 
312         * @since 4.0
313         */
314        String[] getParameters(String name);
315    
316        /**
317         * Converts a partial URL into an absolute URL. Prefixes the provided URL with servlet context
318         * path (if any), then expands it to a full URL by prepending with the scheme, server and port
319         * (determined from the current {@link org.apache.tapestry.web.WebRequest request}.
320         * 
321         * @since 4.0
322         */
323    
324        String getAbsoluteURL(String partialURL);
325    
326        /**
327         * Forgets any stored changes to the specified page. If the page has already been loaded (and
328         * rolled back) then the loaded page instance is not affected; if the page is only loaded
329         * subsequently, the page instance will not see any persisted property changes.
330         * 
331         * @since 4.0
332         */
333    
334        void forgetPage(String name);
335    
336        /**
337         * Returns the central {@link org.apache.tapestry.services.Infrastructure}&nbsp;object used to
338         * manage the processing of the request.
339         * 
340         * @since 4.0
341         */
342    
343        Infrastructure getInfrastructure();
344    
345        /**
346         * Returns the provided string, possibly modified (with an appended suffix) to make it unique.
347         * 
348         * @param baseId
349         *            the base id from which to generate the unique string.
350         * @return baseId, or baseId with a suffix appended (if the method has been previously invoked
351         *         with the same baseId).
352         */
353    
354        String getUniqueId(String baseId);
355    
356        /**
357         * Sends a redirect to the client web browser. This is currently a convinience for constructing
358         * and throwing a {@link RedirectException}, but may change in a later release.
359         * 
360         * @since 4.0
361         * @throws RedirectException
362         */
363    
364        void sendRedirect(String URL);
365    }