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 }