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
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        
109        void renderResponse(IRequestCycle cycle)
110        throws IOException;
111        
112        /**
113         * Invoked to render a renderable object. Performs any necessary
114         * under the hood type logic involving ajax/json/normal responses, where
115         * needed.
116         * 
117         * @param writer 
118         *          The markup writer to use, this may be ignored or swapped
119         *          out for a different writer depending on the implementation being used.
120         * @param render The renderable object to render
121         * @param cycle Render request cycle
122         */
123        
124        void render(IMarkupWriter writer, IRender render, IRequestCycle cycle);
125        
126        /**
127         * If the component identified by the specified id isn't already set to
128         * be updated, will add it to the response for updating. (Only applicable
129         * in dynamic responses such as XHR/JSON ).
130         * 
131         * @param id
132         *          The {@link IComponent} id to update.
133         */
134        void updateComponent(String id);
135        
136        /**
137         * Checks if the rendered response contains a particular component. Contains
138         * can mean many things. In the instance of a dynamic response it could potentially
139         * mean a component explicitly set to be updated - or a component that has a containing
140         * component explicitly set to be updated.
141         * 
142         * @param target The component to check containment of.
143         * @return True if response contains the specified component, false otherwise.
144         */
145        boolean contains(IComponent target);
146        
147        /**
148         * Similar to {@link #contains(IComponent)}, but only returns true if the component
149         * has been marked for update directly via an <code>updateComponents</code> property 
150         * or by calling {@link ResponseBuilder#updateComponent(String)} directly. 
151         * 
152         * <p>
153         * <b>IMPORTANT!:</b> This will not return true for components contained by a component
154         *  marked for update. If you want that kind of behaviour use {@link #contains(IComponent)}. 
155         * </p>
156         * 
157         * @param target The component to check.
158         * @return True if the component as listed as one to be updated, false otherwise.
159         */
160        boolean explicitlyContains(IComponent target);
161        
162        /**
163         * Invoked by components that know "when" the method should be called. Causes all queued up
164         * body related javascript data to be written out to the response.
165         * 
166         * @param writer
167         *          The writer to use . (may / may not be ignored depending on the response type)
168         * @param cycle
169         *          Associated request.
170         */
171        void writeBodyScript(IMarkupWriter writer, IRequestCycle cycle);
172        
173        /**
174         * Invoked by components that know "when" the method should be called. Causes all queued up
175         * initialization related javascript data to be written out to the response.
176         * 
177         * @param writer
178         *          The writer to use . (may / may not be ignored depending on the response type)
179         */
180        void writeInitializationScript(IMarkupWriter writer);
181        
182        /**
183         * Invoked by {@link PageRenderSupport} to write external js package
184         * includes. This method will be invoked for each external script requesting
185         * inclusion in the response.
186         * 
187         * These will typically be written out as 
188         * <code>
189         * <script type="text/javascript" src="url"></script>
190         * </code>.
191         *
192         * @param writer
193         *          The markup writer to use, this may be ignored or swapped
194         *          out for a different writer depending on the implementation being used.
195         * @param url
196         *          The absolute url to the .js package to be included.
197         * @param cycle
198         *          The associated request.
199         */    
200        void writeExternalScript(IMarkupWriter writer, String url, IRequestCycle cycle);
201        
202        /**
203         * Marks the beginning of the core body script.
204         *
205         * @param writer
206         *          The markup writer to use, this may be ignored or swapped
207         *          out for a different writer depending on the implementation being used.
208         * @param cycle
209         *          The associated request.
210         */
211        void beginBodyScript(IMarkupWriter writer, IRequestCycle cycle);
212        
213        /**
214         * Intended to be written within the confines of the body script, should
215         * be invoked once just after {@link #beginBodyScript(IMarkupWriter, IRequestCycle)} is called
216         * to include any image initializations. This method should only be called if
217         * there are actually images that need pre-initialization. Ie in many instances 
218         * it will not be called at all.
219         *
220         * @param writer
221         *          The markup writer to use, this may be ignored or swapped
222         *          out for a different writer depending on the implementation being used.
223         * @param script
224         *          The non null value of the script images to include. 
225         * @param preloadName 
226         *          The global variable name to give to the preloaded images array.
227         * @param cycle
228         *          The associated request.
229         */
230        void writeImageInitializations(IMarkupWriter writer, String script, String preloadName, IRequestCycle cycle);
231        
232        /**
233         * Called after {@link #beginBodyScript(IMarkupWriter, IRequestCycle)} to write the containing
234         * body script. This method may not be called at all if there is no js body 
235         * to write into the response.
236         *
237         * @param writer
238         *          The markup writer to use, this may be ignored or swapped
239         *          out for a different writer depending on the implementation being used.
240         * @param script
241         *          The script to write into the body response.
242         * @param cycle
243         *          The associated request.
244         */
245        void writeBodyScript(IMarkupWriter writer, String script, IRequestCycle cycle);
246        
247        /**
248         * Marks the end of the body block being called. This method will 
249         * always be called if {@link #beginBodyScript(IMarkupWriter, IRequestCycle)} was previously
250         * called. 
251         *
252         * @param writer
253         *          The markup writer to use, this may be ignored or swapped
254         *          out for a different writer depending on the implementation being used.
255         * @param cycle
256         *          The associated request.
257         */
258        void endBodyScript(IMarkupWriter writer, IRequestCycle cycle);
259        
260        /**
261         * Writes any javascript that should only execute after all other items
262         * on a page have completed rendering. This is typically implemented via
263         * wrapping the executing of the code to some sort of <code>window.onload</code> 
264         * event, but will vary depending on the implementation of the builder being used.
265         * 
266         * This method will ~only~ be called if there is any queued intialization script 
267         * to write.
268         *
269         * @param writer
270         *          The markup writer to use, this may be ignored or swapped
271         *          out for a different writer depending on the implementation being used.
272         * @param script
273         *          The initialzation script to write.
274         */
275        void writeInitializationScript(IMarkupWriter writer, String script);
276        
277        /**
278         * Returns the IMarkupWriter associated with this response, it may or may
279         * not be a NullWriter instance depending on the response type or stage 
280         * of the render cycle. (specifically during rewind)
281         * 
282         * @return A validly writable markup writer, even if the content is sometimes
283         * ignored.
284         */
285        
286        IMarkupWriter getWriter();
287        
288        /**
289         * Gets a write that will output its content in a <code>response</code>
290         * element with the given id and type. 
291         * 
292         * @param id 
293         *          The response element id to give writer.
294         * @param type
295         *          Optional - If specified will give the response element a type
296         *          attribute.
297         * @return A valid {@link IMarkupWriter} instance to write content to.
298         */
299        IMarkupWriter getWriter(String id, String type);
300        
301        /**
302         * Determines if the specified component should have any asset image URL
303         * references embedded in the response.
304         * 
305         * @param target
306         *          The component to allow/disallow image initialization script content from.
307         * @return True if the component script should be allowed.
308         */
309        boolean isImageInitializationAllowed(IComponent target);
310        
311        /**
312         * Adds a status message to the current response.
313         *
314         * @param writer
315         *          The markup writer to use, this may be ignored or swapped
316         *          out for a different writer depending on the implementation being used.
317         * @param category
318         *          Allows setting a category that best describes the type of the status message,
319         *          i.e. info, error, e.t.c.
320         * @param text
321         *          The status message. 
322         */
323        void addStatusMessage(IMarkupWriter writer, String category, String text);
324    }