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}