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