001// Copyright 2007, 2008, 2009, 2013 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 015package org.apache.tapestry5.internal.services; 016 017import java.util.List; 018 019import org.apache.tapestry5.MarkupWriter; 020import org.apache.tapestry5.dom.DefaultMarkupModel; 021import org.apache.tapestry5.dom.Html5MarkupModel; 022import org.apache.tapestry5.dom.MarkupModel; 023import org.apache.tapestry5.dom.XMLMarkupModel; 024import org.apache.tapestry5.http.ContentType; 025import org.apache.tapestry5.internal.parser.DTDToken; 026import org.apache.tapestry5.internal.parser.TemplateToken; 027import org.apache.tapestry5.internal.parser.TokenType; 028import org.apache.tapestry5.internal.structure.Page; 029import org.apache.tapestry5.model.ComponentModel; 030import org.apache.tapestry5.services.MarkupWriterFactory; 031import org.apache.tapestry5.services.pageload.ComponentRequestSelectorAnalyzer; 032import org.apache.tapestry5.services.pageload.ComponentResourceSelector; 033 034public class MarkupWriterFactoryImpl implements MarkupWriterFactory 035{ 036 private final PageContentTypeAnalyzer pageContentTypeAnalyzer; 037 038 private final RequestPageCache cache; 039 040 private final ComponentTemplateSource templateSource; 041 042 private final ComponentRequestSelectorAnalyzer componentRequestSelectorAnalyzer; 043 044 private final MarkupModel htmlModel = new DefaultMarkupModel(); 045 046 private final MarkupModel xmlModel = new XMLMarkupModel(); 047 048 private final MarkupModel htmlPartialModel = new DefaultMarkupModel(true); 049 050 private final MarkupModel xmlPartialModel = new XMLMarkupModel(true); 051 052 private final MarkupModel html5Model = new Html5MarkupModel(); 053 054 private final MarkupModel html5PartialModel = new Html5MarkupModel(true); 055 056 public MarkupWriterFactoryImpl(PageContentTypeAnalyzer pageContentTypeAnalyzer, 057 RequestPageCache cache, ComponentTemplateSource templateSource, 058 ComponentRequestSelectorAnalyzer componentRequestSelectorAnalyzer) 059 { 060 this.pageContentTypeAnalyzer = pageContentTypeAnalyzer; 061 this.cache = cache; 062 this.templateSource = templateSource; 063 this.componentRequestSelectorAnalyzer = componentRequestSelectorAnalyzer; 064 } 065 066 public MarkupWriter newMarkupWriter(ContentType contentType) 067 { 068 return constructMarkupWriter(contentType, false, false); 069 } 070 071 public MarkupWriter newPartialMarkupWriter(ContentType contentType) 072 { 073 return constructMarkupWriter(contentType, true, false); 074 } 075 076 private MarkupWriter constructMarkupWriter(ContentType contentType, boolean partial, boolean HTML5) 077 { 078 final String mimeType = contentType.getMimeType(); 079 boolean isHTML = mimeType.equalsIgnoreCase("text/html"); 080 081 MarkupModel model; 082 083 if(isHTML) 084 model = HTML5 ? (partial ? html5PartialModel : html5Model) : (partial ? htmlPartialModel : htmlModel); 085 else 086 model = partial ? xmlPartialModel : xmlModel; 087 // The charset parameter sets the encoding attribute of the XML declaration, if 088 // not null and if using the XML model. 089 090 return new MarkupWriterImpl(model, contentType.getCharset(), mimeType); 091 } 092 093 public MarkupWriter newMarkupWriter(String pageName) 094 { 095 Page page = cache.get(pageName); 096 097 return newMarkupWriter(page); 098 } 099 100 private boolean hasHTML5Doctype(Page page) 101 { 102 ComponentModel componentModel = page.getRootComponent().getComponentResources().getComponentModel(); 103 104 ComponentResourceSelector selector = componentRequestSelectorAnalyzer.buildSelectorForRequest(); 105 106 List<TemplateToken> tokens = templateSource.getTemplate(componentModel, selector).getTokens(); 107 108 DTDToken dtd = null; 109 110 for(TemplateToken token : tokens) 111 { 112 if(token.getTokenType() == TokenType.DTD) 113 { 114 dtd = (DTDToken) token; 115 break; 116 } 117 } 118 119 return dtd != null && dtd.name.equalsIgnoreCase("html") && dtd.publicId == null && dtd.systemId == null; 120 } 121 122 public MarkupWriter newMarkupWriter(Page page) 123 { 124 boolean isHTML5 = hasHTML5Doctype(page); 125 126 ContentType contentType = pageContentTypeAnalyzer.findContentType(page); 127 128 return constructMarkupWriter(contentType, false, isHTML5); 129 } 130 131 public MarkupWriter newPartialMarkupWriter(Page page) 132 { 133 boolean isHTML5 = hasHTML5Doctype(page); 134 135 ContentType contentType = pageContentTypeAnalyzer.findContentType(page); 136 137 return constructMarkupWriter(contentType, true, isHTML5); 138 } 139 140 public MarkupWriter newPartialMarkupWriter(String pageName) 141 { 142 Page page = cache.get(pageName); 143 144 return newPartialMarkupWriter(page); 145 } 146}