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 }