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}&nbsp;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}&nbsp;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    }