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    package org.apache.tapestry.services;
015    
016    import org.apache.tapestry.*;
017    import org.apache.tapestry.services.impl.DojoAjaxResponseBuilder;
018    
019    import java.io.IOException;
020    
021    /**
022     * Represents the service responsible for managing all content output that is sent
023     * to the client. In the case of normal http responses this management would inlude 
024     * handing out {@link IMarkupWriter} instances to render components with, as well as 
025     * managing any javascript written to the output using Script templates.
026     *
027     * <p>
028     *  This is a major internal change in terms of the way tapestry renders pages/components.
029     *  Traditionally a response has been rendered via:
030     *  <em>
031     *  IPage.render(writer, cycle);
032     *  </em>
033     *  The logic has now changed somewhat, while the IPage.render(writer, cycle) does still happen, this
034     *  service is the primary invoker of all renders, even nested component bodies. That means that in the majority
035     *  of cases the ResponseBuilder service is used to invoke IComponent.render() throught the entire render
036     *  cycle, creating a great deal of flexibility in terms of what can be done to control the output of a given
037     *  response.
038     * </p>
039     *
040     * <p>
041     * This service was primarily created to help bolster support for more dynamic content responses, such 
042     * as XHR/JSON/etc - where controlling individual component output (and javascript) becomes very important
043     * when managaing client side browser state. 
044     * </p>
045     *
046     * @since 4.1
047     */
048    public interface ResponseBuilder extends PageRenderSupport {
049    
050        /**
051         * Inside a {@link org.apache.tapestry.util.ContentType}, the output encoding is called
052         * "charset".
053         */
054        String ENCODING_KEY = "charset";
055    
056        /**
057         * The content type of the response that will be returned.
058         */
059        String CONTENT_TYPE = "text/xml";
060    
061        /**
062         * The response element type.
063         */
064        String ELEMENT_TYPE = "element";
065    
066        /**
067         * The response exception type.
068         */
069        String EXCEPTION_TYPE = "exception";
070    
071        /**
072         * The response element type denoting a brand new page render.
073         */
074        String PAGE_TYPE = "page";
075    
076        String SCRIPT_TYPE = "script";
077    
078        String BODY_SCRIPT = "bodyscript";
079    
080        String INCLUDE_SCRIPT = "includescript";
081    
082        String INITIALIZATION_SCRIPT = "initializationscript";
083    
084        /**
085         * Implementors that manage content writes dynamically (ie {@link DojoAjaxResponseBuilder}) should
086         * return true to denote that dynamic behaviour is on for a particular response.
087         *
088         * @return Whether or not request is dynamic.
089         */
090        boolean isDynamic();
091    
092        /**
093         * Causes the output stream to be flushed, used primarily in concert with {@link IRequestCycle} to sync
094         * up flushing of headers to the browser once any page changes have been committed.
095         *
096         * @throws IOException During io error.
097         */
098        void flush()
099          throws IOException;
100    
101        /**
102         * Renders the response to a client. Handles transitioning logic
103         * for setting up page and associated components for response.
104         *
105         * @param cycle
106         *          The main request cycle object for this request.
107         *
108         * @throws IOException During io error.
109         */
110    
111        void renderResponse(IRequestCycle cycle)
112          throws IOException;
113    
114        /**
115         * Invoked to render a renderable object. Performs any necessary
116         * under the hood type logic involving ajax/json/normal responses, where
117         * needed.
118         *
119         * @param writer
120         *          The markup writer to use, this may be ignored or swapped
121         *          out for a different writer depending on the implementation being used.
122         * @param render The renderable object to render
123         * @param cycle Render request cycle
124         */
125    
126        void render(IMarkupWriter writer, IRender render, IRequestCycle cycle);
127    
128        /**
129         * If the component identified by the specified id isn't already set to
130         * be updated, will add it to the response for updating. (Only applicable
131         * in dynamic responses such as XHR/JSON ).
132         *
133         * @param id
134         *          The {@link IComponent} id to update.
135         */
136        void updateComponent(String id);
137    
138        /**
139         * Checks if the rendered response contains a particular component. Contains
140         * can mean many things. In the instance of a dynamic response it could potentially
141         * mean a component explicitly set to be updated - or a component that has a containing
142         * component explicitly set to be updated.
143         *
144         * @param target The component to check containment of.
145         * @return True if response contains the specified component, false otherwise.
146         */
147        boolean contains(IComponent target);
148    
149        /**
150         * Similar to {@link #contains(IComponent)}, but only returns true if the component
151         * has been marked for update directly via an <code>updateComponents</code> property 
152         * or by calling {@link ResponseBuilder#updateComponent(String)} directly. 
153         *
154         * <p>
155         * <b>IMPORTANT!:</b> This will not return true for components contained by a component
156         *  marked for update. If you want that kind of behaviour use {@link #contains(IComponent)}. 
157         * </p>
158         *
159         * @param target The component to check.
160         * @return True if the component as listed as one to be updated, false otherwise.
161         */
162        boolean explicitlyContains(IComponent target);
163    
164        /**
165         * Invoked by components that know "when" the method should be called. Causes all queued up
166         * body related javascript data to be written out to the response.
167         *
168         * @param writer
169         *          The writer to use . (may / may not be ignored depending on the response type)
170         * @param cycle
171         *          Associated request.
172         */
173        void writeBodyScript(IMarkupWriter writer, IRequestCycle cycle);
174    
175        /**
176         * Invoked by components that know "when" the method should be called. Causes all queued up
177         * initialization related javascript data to be written out to the response.
178         *
179         * @param writer
180         *          The writer to use . (may / may not be ignored depending on the response type)
181         */
182        void writeInitializationScript(IMarkupWriter writer);
183    
184        /**
185         * Invoked by {@link PageRenderSupport} to write external js package
186         * includes. This method will be invoked for each external script requesting
187         * inclusion in the response.
188         *
189         * These will typically be written out as 
190         * <code>
191         * <script type="text/javascript" src="url"></script>
192         * </code>.
193         *
194         * @param writer
195         *          The markup writer to use, this may be ignored or swapped
196         *          out for a different writer depending on the implementation being used.
197         * @param url
198         *          The absolute url to the .js package to be included.
199         * @param cycle
200         *          The associated request.
201         */
202        void writeExternalScript(IMarkupWriter writer, String url, IRequestCycle cycle);
203    
204        /**
205         * Marks the beginning of the core body script.
206         *
207         * @param writer
208         *          The markup writer to use, this may be ignored or swapped
209         *          out for a different writer depending on the implementation being used.
210         * @param cycle
211         *          The associated request.
212         */
213        void beginBodyScript(IMarkupWriter writer, IRequestCycle cycle);
214    
215        /**
216         * Intended to be written within the confines of the body script, should
217         * be invoked once just after {@link #beginBodyScript(IMarkupWriter, IRequestCycle)} is called
218         * to include any image initializations. This method should only be called if
219         * there are actually images that need pre-initialization. Ie in many instances 
220         * it will not be called at all.
221         *
222         * @param writer
223         *          The markup writer to use, this may be ignored or swapped
224         *          out for a different writer depending on the implementation being used.
225         * @param script
226         *          The non null value of the script images to include. 
227         * @param preloadName
228         *          The global variable name to give to the preloaded images array.
229         * @param cycle
230         *          The associated request.
231         */
232        void writeImageInitializations(IMarkupWriter writer, String script, String preloadName, IRequestCycle cycle);
233    
234        /**
235         * Called after {@link #beginBodyScript(IMarkupWriter, IRequestCycle)} to write the containing
236         * body script. This method may not be called at all if there is no js body 
237         * to write into the response.
238         *
239         * @param writer
240         *          The markup writer to use, this may be ignored or swapped
241         *          out for a different writer depending on the implementation being used.
242         * @param script
243         *          The script to write into the body response.
244         * @param cycle
245         *          The associated request.
246         */
247        void writeBodyScript(IMarkupWriter writer, String script, IRequestCycle cycle);
248    
249        /**
250         * Marks the end of the body block being called. This method will 
251         * always be called if {@link #beginBodyScript(IMarkupWriter, IRequestCycle)} was previously
252         * called. 
253         *
254         * @param writer
255         *          The markup writer to use, this may be ignored or swapped
256         *          out for a different writer depending on the implementation being used.
257         * @param cycle
258         *          The associated request.
259         */
260        void endBodyScript(IMarkupWriter writer, IRequestCycle cycle);
261    
262        /**
263         * Writes any javascript that should only execute after all other items
264         * on a page have completed rendering. This is typically implemented via
265         * wrapping the executing of the code to some sort of <code>window.onload</code> 
266         * event, but will vary depending on the implementation of the builder being used.
267         *
268         * This method will ~only~ be called if there is any queued intialization script 
269         * to write.
270         *
271         * @param writer
272         *          The markup writer to use, this may be ignored or swapped
273         *          out for a different writer depending on the implementation being used.
274         * @param script
275         *          The initialzation script to write.
276         */
277        void writeInitializationScript(IMarkupWriter writer, String script);
278    
279        /**
280         * Returns the IMarkupWriter associated with this response, it may or may
281         * not be a NullWriter instance depending on the response type or stage 
282         * of the render cycle. (specifically during rewind)
283         *
284         * @return A validly writable markup writer, even if the content is sometimes
285         * ignored.
286         */
287    
288        IMarkupWriter getWriter();
289    
290        /**
291         * Gets a write that will output its content in a <code>response</code>
292         * element with the given id and type. 
293         *
294         * @param id
295         *          The response element id to give writer.
296         * @param type
297         *          Optional - If specified will give the response element a type
298         *          attribute.
299         * @return A valid {@link IMarkupWriter} instance to write content to.
300         */
301        IMarkupWriter getWriter(String id, String type);
302    
303        /**
304         * Determines if the specified component should have any asset image URL
305         * references embedded in the response.
306         *
307         * @param target
308         *          The component to allow/disallow image initialization script content from.
309         * @return True if the component script should be allowed.
310         */
311        boolean isImageInitializationAllowed(IComponent target);
312    
313        /**
314         * Adds a status message to the current response.
315         *
316         * @param writer
317         *          The markup writer to use, this may be ignored or swapped
318         *          out for a different writer depending on the implementation being used.
319         * @param category
320         *          Allows setting a category that best describes the type of the status message,
321         *          i.e. info, error, e.t.c.
322         * @param text
323         *          The status message. 
324         */
325        void addStatusMessage(IMarkupWriter writer, String category, String text);
326    }