001    // Copyright Mar 18, 2006 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.impl;
015    
016    import org.apache.hivemind.Resource;
017    import org.apache.hivemind.util.Defense;
018    import org.apache.tapestry.*;
019    import org.apache.tapestry.asset.AssetFactory;
020    import org.apache.tapestry.engine.NullWriter;
021    import org.apache.tapestry.markup.MarkupWriterSource;
022    import org.apache.tapestry.services.RequestLocaleManager;
023    import org.apache.tapestry.services.ResponseBuilder;
024    import org.apache.tapestry.util.ContentType;
025    import org.apache.tapestry.util.PageRenderSupportImpl;
026    import org.apache.tapestry.web.WebResponse;
027    
028    import java.io.IOException;
029    import java.io.PrintWriter;
030    
031    
032    /**
033     * Manages normal html responses for tapestry request/response cycles.
034     *
035     * @author jkuhnert
036     */
037    public class DefaultResponseBuilder implements ResponseBuilder
038    {
039        private final AssetFactory _assetFactory;
040    
041        private final String _namespace;
042    
043        private PageRenderSupportImpl _prs;
044    
045        private RequestLocaleManager _localeManager;
046    
047        private MarkupWriterSource _markupWriterSource;
048    
049        private WebResponse _webResponse;
050    
051        /** Default writer for rendering html output. */
052        private IMarkupWriter _writer;
053    
054        private boolean _closeWriter = true;
055    
056        /**
057         * Portlet constructor.
058         *
059         * @param writer
060         */
061        public DefaultResponseBuilder(IRequestCycle cycle, IMarkupWriter writer,
062                                      AssetFactory assetFactory, String namespace, boolean closeWriter)
063        {
064            _writer = writer;
065            _assetFactory = assetFactory;
066            _namespace = namespace;
067            _closeWriter = closeWriter;
068    
069            _prs = new PageRenderSupportImpl(_assetFactory, _namespace, this, cycle);
070        }
071    
072        /**
073         * Used in testing only.
074         * @param writer
075         */
076        public DefaultResponseBuilder(IMarkupWriter writer)
077        {
078            _writer = writer;
079            _assetFactory = null;
080            _namespace = null;
081        }
082    
083        /**
084         * Creates a new response builder with the required services it needs
085         * to render the response when {@link #renderResponse(IRequestCycle)} is called.
086         *
087         * @param cycle
088         *          The current request.
089         * @param localeManager
090         *          Used to set the locale on the response.
091         * @param markupWriterSource
092         *          Creates IMarkupWriter instance to be used.
093         * @param webResponse
094         *          Web response for output stream.
095         * @param assetFactory
096         *          Used to generate asset urls.
097         * @param namespace
098         *          Used for portal / javascript namespacing support.
099         */
100        public DefaultResponseBuilder(IRequestCycle cycle, RequestLocaleManager localeManager,
101                                      MarkupWriterSource markupWriterSource, WebResponse webResponse,
102                                      AssetFactory assetFactory, String namespace)
103        {
104            Defense.notNull(assetFactory, "assetService");
105    
106            _localeManager = localeManager;
107            _markupWriterSource = markupWriterSource;
108            _webResponse = webResponse;
109    
110            // Used by PageRenderSupport
111    
112            _assetFactory = assetFactory;
113            _namespace = namespace;
114    
115            _prs = new PageRenderSupportImpl(_assetFactory, _namespace, this, cycle);
116        }
117    
118        /**
119         *
120         * {@inheritDoc}
121         */
122        public boolean isDynamic()
123        {
124            return false;
125        }
126    
127        /**
128         *
129         * {@inheritDoc}
130         */
131        public void renderResponse(IRequestCycle cycle)
132          throws IOException
133        {
134            if (_writer == null)
135            {
136                _localeManager.persistLocale();
137    
138                IPage page = cycle.getPage();
139    
140                ContentType contentType = page.getResponseContentType();
141                String encoding = contentType.getParameter(ENCODING_KEY);
142    
143                if (encoding == null)
144                {
145                    encoding = cycle.getEngine().getOutputEncoding();
146    
147                    contentType.setParameter(ENCODING_KEY, encoding);
148                }
149    
150                PrintWriter printWriter = _webResponse.getPrintWriter(contentType);
151    
152                _writer = _markupWriterSource.newMarkupWriter(printWriter, contentType);
153            }
154    
155            // render response
156    
157            TapestryUtils.storePageRenderSupport(cycle, _prs);
158    
159            cycle.renderPage(this);
160    
161            TapestryUtils.removePageRenderSupport(cycle);
162    
163            flush();
164    
165            if (_closeWriter)
166                _writer.close();
167        }
168    
169        public void flush()
170          throws IOException
171        {
172            // Important - causes any cookies stored to properly be written out before the
173            // rest of the response starts being written - see TAPESTRY-825
174    
175            _writer.flush();
176        }
177    
178        /**
179         *
180         * {@inheritDoc}
181         */
182        public void render(IMarkupWriter writer, IRender render, IRequestCycle cycle)
183        {
184            if (writer == null)
185                render.render(_writer, cycle);
186            else
187                render.render(writer, cycle);
188        }
189    
190        /**
191         * {@inheritDoc}
192         */
193        public void updateComponent(String id)
194        {
195        }
196    
197        /**
198         * {@inheritDoc}
199         */
200        public boolean contains(IComponent target)
201        {
202            return false;
203        }
204    
205        /**
206         * {@inheritDoc}
207         */
208        public boolean explicitlyContains(IComponent target)
209        {
210            return false;
211        }
212    
213        /**
214         * {@inheritDoc}
215         */
216        public IMarkupWriter getWriter()
217        {
218            if (_writer == null)
219                return NullWriter.getSharedInstance();
220    
221            return _writer;
222        }
223    
224        /**
225         * {@inheritDoc}
226         */
227        public IMarkupWriter getWriter(String id, String type)
228        {
229            if (_writer == null)
230                return NullWriter.getSharedInstance();
231    
232            return _writer;
233        }
234    
235        /**
236         * {@inheritDoc}
237         */
238        public boolean isBodyScriptAllowed(IComponent target)
239        {
240            return true;
241        }
242    
243        /**
244         * {@inheritDoc}
245         */
246        public boolean isExternalScriptAllowed(IComponent target)
247        {
248            return true;
249        }
250    
251        /**
252         * {@inheritDoc}
253         */
254        public boolean isInitializationScriptAllowed(IComponent target)
255        {
256            return true;
257        }
258    
259        /**
260         * {@inheritDoc}
261         */
262        public boolean isImageInitializationAllowed(IComponent target)
263        {
264            return true;
265        }
266    
267        /**
268         * {@inheritDoc}
269         */
270        public String getPreloadedImageReference(IComponent target, IAsset source)
271        {
272            return _prs.getPreloadedImageReference(target, source);
273        }
274    
275        /**
276         * {@inheritDoc}
277         */
278        public String getPreloadedImageReference(IComponent target, String url)
279        {
280            return _prs.getPreloadedImageReference(target, url);
281        }
282    
283        /**
284         * {@inheritDoc}
285         */
286        public String getPreloadedImageReference(String url)
287        {
288            return _prs.getPreloadedImageReference(url);
289        }
290    
291        /**
292         * {@inheritDoc}
293         */
294        public void addBodyScript(IComponent target, String script)
295        {
296            _prs.addBodyScript(target, script);
297        }
298    
299        /**
300         * {@inheritDoc}
301         */
302        public void addBodyScript(String script)
303        {
304            _prs.addBodyScript(script);
305        }
306    
307        /**
308         * {@inheritDoc}
309         */
310        public void addExternalScript(IComponent target, Resource resource)
311        {
312            _prs.addExternalScript(target, resource);
313        }
314    
315        /**
316         * {@inheritDoc}
317         */
318        public void addExternalScript(Resource resource)
319        {
320            _prs.addExternalScript(resource);
321        }
322    
323        /**
324         * {@inheritDoc}
325         */
326        public void addInitializationScript(IComponent target, String script)
327        {
328            _prs.addInitializationScript(target, script);
329        }
330    
331        /**
332         * {@inheritDoc}
333         */
334        public void addInitializationScript(String script)
335        {
336            _prs.addInitializationScript(script);
337        }
338    
339        public void addScriptAfterInitialization(IComponent target, String script)
340        {
341            _prs.addScriptAfterInitialization(target, script);
342        }
343    
344        /**
345         * {@inheritDoc}
346         */
347        public String getUniqueString(String baseValue)
348        {
349            return _prs.getUniqueString(baseValue);
350        }
351    
352        /**
353         * {@inheritDoc}
354         */
355        public void writeBodyScript(IMarkupWriter writer, IRequestCycle cycle)
356        {
357            _prs.writeBodyScript(writer, cycle);
358        }
359    
360        /**
361         * {@inheritDoc}
362         */
363        public void writeInitializationScript(IMarkupWriter writer)
364        {
365            _prs.writeInitializationScript(writer);
366        }
367    
368        /**
369         * {@inheritDoc}
370         */
371        public void beginBodyScript(IMarkupWriter writer, IRequestCycle cycle)
372        {
373            writer.begin("script");
374            writer.attribute("type", "text/javascript");
375            writer.printRaw("<!--");
376            writer.println();
377        }
378    
379        /**
380         * {@inheritDoc}
381         */
382        public void endBodyScript(IMarkupWriter writer, IRequestCycle cycle)
383        {
384            writer.println();
385            writer.printRaw("// -->");
386            writer.end();
387        }
388    
389        /**
390         * {@inheritDoc}
391         */
392        public void writeBodyScript(IMarkupWriter writer, String script, IRequestCycle cycle)
393        {
394            writer.printRaw(script);
395        }
396    
397        /**
398         * {@inheritDoc}
399         */
400        public void writeExternalScript(IMarkupWriter writer, String url, IRequestCycle cycle)
401        {
402            writer.begin("script");
403            writer.attribute("type", "text/javascript");
404            writer.attribute("src", url);
405            writer.end();
406            writer.println();
407        }
408    
409        /**
410         * {@inheritDoc}
411         */
412        public void writeImageInitializations(IMarkupWriter writer, String script, String preloadName, IRequestCycle cycle)
413        {
414    
415            writer.println();
416            writer.printRaw("tapestry.addOnLoad(function(e) {\n");
417    
418            writer.printRaw(preloadName + " = [];\n");
419            writer.printRaw("if (document.images)\n");
420            writer.printRaw("{\n");
421            writer.printRaw(script);
422            writer.printRaw("}\n");
423    
424            writer.printRaw("});");
425        }
426    
427        /**
428         * {@inheritDoc}
429         */
430        public void writeInitializationScript(IMarkupWriter writer, String script)
431        {
432            writer.begin("script");
433            writer.attribute("type", "text/javascript");
434            writer.printRaw("<!--\n");
435    
436            writer.printRaw("tapestry.addOnLoad(function(e) {\n");
437    
438            writer.printRaw(script);
439    
440            writer.printRaw("});");
441    
442            writer.printRaw("\n// -->");
443            writer.end();
444        }
445    
446        /**
447         * This implementation does nothing.
448         * {@inheritDoc}
449         */
450        public void addStatusMessage(IMarkupWriter normalWriter, String category, String text)
451        {
452        }
453    }