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 }