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    
132                String encoding = contentType.getParameter(ENCODING_KEY);
133    
134                if (encoding == null)
135                {
136                    encoding = cycle.getEngine().getOutputEncoding();
137    
138                    contentType.setParameter(ENCODING_KEY, encoding);
139                }
140                
141                PrintWriter printWriter = _webResponse.getPrintWriter(contentType);
142                
143                _writer = _markupWriterSource.newMarkupWriter(printWriter, contentType);
144            }
145            
146            // render response
147            
148            _prs = new PageRenderSupportImpl(_assetFactory, _namespace, cycle.getPage().getLocation(), this);
149            
150            TapestryUtils.storePageRenderSupport(cycle, _prs);
151            
152            cycle.renderPage(this);
153            
154            TapestryUtils.removePageRenderSupport(cycle);
155            
156            flush();
157    
158            if (_closeWriter)
159                _writer.close();
160        }
161        
162        public void flush()
163        throws IOException
164        {
165            // Important - causes any cookies stored to properly be written out before the
166            // rest of the response starts being written - see TAPESTRY-825
167    
168            _writer.flush();
169        }
170        
171        /**
172         * 
173         * {@inheritDoc}
174         */
175        public void render(IMarkupWriter writer, IRender render, IRequestCycle cycle)
176        {
177            if (writer == null)
178                render.render(_writer, cycle);
179            else
180                render.render(writer, cycle);
181        }
182        
183        /** 
184         * {@inheritDoc}
185         */
186        public void updateComponent(String id)
187        {
188        }
189        
190        /** 
191         * {@inheritDoc}
192         */
193        public boolean contains(IComponent target)
194        {
195            return false;
196        }
197        
198        /**
199         * {@inheritDoc}
200         */
201        public boolean explicitlyContains(IComponent target)
202        {
203            return false;
204        }
205    
206        /** 
207         * {@inheritDoc}
208         */
209        public IMarkupWriter getWriter()
210        {
211            if (_writer == null)
212                return NullWriter.getSharedInstance();
213            
214            return _writer;
215        }
216        
217        /** 
218         * {@inheritDoc}
219         */
220        public IMarkupWriter getWriter(String id, String type)
221        {
222            if (_writer == null)
223                return NullWriter.getSharedInstance();
224            
225            return _writer;
226        }
227        
228        /** 
229         * {@inheritDoc}
230         */
231        public boolean isBodyScriptAllowed(IComponent target)
232        {
233            return true;
234        }
235    
236        /** 
237         * {@inheritDoc}
238         */
239        public boolean isExternalScriptAllowed(IComponent target)
240        {
241            return true;
242        }
243    
244        /** 
245         * {@inheritDoc}
246         */
247        public boolean isInitializationScriptAllowed(IComponent target)
248        {
249            return true;
250        }
251        
252        /**
253         * {@inheritDoc}
254         */
255        public boolean isImageInitializationAllowed(IComponent target)
256        {
257            return true;
258        }
259        
260        /**
261         * {@inheritDoc}
262         */
263        public String getPreloadedImageReference(IComponent target, IAsset source)
264        {
265            return _prs.getPreloadedImageReference(target, source);
266        }
267        
268        /**
269         * {@inheritDoc}
270         */
271        public String getPreloadedImageReference(IComponent target, String url)
272        {
273            return _prs.getPreloadedImageReference(target, url);
274        }
275    
276        /**
277         * {@inheritDoc}
278         */
279        public String getPreloadedImageReference(String url)
280        {
281            return _prs.getPreloadedImageReference(url);
282        }
283    
284        /**
285         * {@inheritDoc}
286         */
287        public void addBodyScript(IComponent target, String script)
288        {
289            _prs.addBodyScript(target, script);
290        }
291    
292        /**
293         * {@inheritDoc}
294         */
295        public void addBodyScript(String script)
296        {
297            _prs.addBodyScript(script);
298        }
299        
300        /**
301         * {@inheritDoc}
302         */
303        public void addExternalScript(IComponent target, Resource resource)
304        {
305            _prs.addExternalScript(target, resource);
306        }
307    
308        /**
309         * {@inheritDoc}
310         */
311        public void addExternalScript(Resource resource)
312        {
313            _prs.addExternalScript(resource);
314        }
315    
316        /**
317         * {@inheritDoc}
318         */
319        public void addInitializationScript(IComponent target, String script)
320        {
321            _prs.addInitializationScript(target, script);
322        }
323    
324        /**
325         * {@inheritDoc}
326         */
327        public void addInitializationScript(String script)
328        {
329            _prs.addInitializationScript(script);
330        }
331    
332        /**
333         * {@inheritDoc}
334         */
335        public String getUniqueString(String baseValue)
336        {
337            return _prs.getUniqueString(baseValue);
338        }
339        
340        /**
341         * {@inheritDoc}
342         */
343        public void writeBodyScript(IMarkupWriter writer, IRequestCycle cycle)
344        {
345            _prs.writeBodyScript(writer, cycle);
346        }
347        
348        /**
349         * {@inheritDoc}
350         */
351        public void writeInitializationScript(IMarkupWriter writer)
352        {
353            _prs.writeInitializationScript(writer);
354        }
355        
356        /** 
357         * {@inheritDoc}
358         */
359        public void beginBodyScript(IMarkupWriter writer, IRequestCycle cycle)
360        {
361            writer.begin("script");
362            writer.attribute("type", "text/javascript");
363            writer.printRaw("<!--");
364            writer.println();
365        }
366        
367        /** 
368         * {@inheritDoc}
369         */
370        public void endBodyScript(IMarkupWriter writer, IRequestCycle cycle)
371        {
372            writer.println();
373            writer.printRaw("// -->");
374            writer.end();
375        }
376    
377        /** 
378         * {@inheritDoc}
379         */
380        public void writeBodyScript(IMarkupWriter writer, String script, IRequestCycle cycle)
381        {
382            writer.printRaw(script);
383        }
384    
385        /** 
386         * {@inheritDoc}
387         */
388        public void writeExternalScript(IMarkupWriter writer, String url, IRequestCycle cycle)
389        {        
390            writer.begin("script");
391            writer.attribute("type", "text/javascript");
392            writer.attribute("src", url);
393            writer.end();
394            writer.println();
395        }
396        
397        /** 
398         * {@inheritDoc}
399         */
400        public void writeImageInitializations(IMarkupWriter writer, String script, String preloadName, IRequestCycle cycle)
401        {
402            
403            writer.println();
404            writer.printRaw("dojo.addOnLoad(function(e) {\n");
405            
406            writer.printRaw(preloadName + " = [];\n");
407            writer.printRaw("if (document.images)\n");
408            writer.printRaw("{\n");
409            writer.printRaw(script);
410            writer.printRaw("}\n");
411            
412            writer.printRaw("});");
413        }
414        
415        /** 
416         * {@inheritDoc}
417         */
418        public void writeInitializationScript(IMarkupWriter writer, String script)
419        {
420            writer.begin("script");
421            writer.attribute("type", "text/javascript");
422            writer.printRaw("<!--\n");
423            
424            writer.printRaw("dojo.addOnLoad(function(e) {\n");
425            
426            writer.printRaw(script);
427            
428            writer.printRaw("});");
429            
430            writer.printRaw("\n// -->");
431            writer.end();
432        }
433    
434        /**
435         * This implementation does nothing.
436         * {@inheritDoc}
437         */
438        public void addStatusMessage(IMarkupWriter normalWriter, String category, String text)
439        {
440        }
441    }