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