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.ContentType;
020import org.apache.tapestry5.MarkupWriter;
021import org.apache.tapestry5.dom.DefaultMarkupModel;
022import org.apache.tapestry5.dom.Html5MarkupModel;
023import org.apache.tapestry5.dom.MarkupModel;
024import org.apache.tapestry5.dom.XMLMarkupModel;
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        boolean isHTML = contentType.getMimeType().equalsIgnoreCase("text/html");
079
080        MarkupModel model;
081        
082        if(isHTML)
083            model = HTML5 ? (partial ? html5PartialModel : html5Model) : (partial ? htmlPartialModel : htmlModel);
084        else
085            model = partial ? xmlPartialModel : xmlModel;
086        // The charset parameter sets the encoding attribute of the XML declaration, if
087        // not null and if using the XML model.
088
089        return new MarkupWriterImpl(model, contentType.getCharset());
090    }
091
092    public MarkupWriter newMarkupWriter(String pageName)
093    {
094        Page page = cache.get(pageName);
095
096        return newMarkupWriter(page);
097    }
098    
099    private boolean hasHTML5Doctype(Page page)
100    {
101        ComponentModel componentModel = page.getRootComponent().getComponentResources().getComponentModel();
102        
103        ComponentResourceSelector selector = componentRequestSelectorAnalyzer.buildSelectorForRequest();
104        
105        List<TemplateToken> tokens = templateSource.getTemplate(componentModel, selector).getTokens();
106        
107        DTDToken dtd = null;
108        
109        for(TemplateToken token : tokens)
110        {
111            if(token.getTokenType() == TokenType.DTD)
112            {
113                dtd = (DTDToken) token;
114                break;
115            }
116        }
117        
118        return dtd != null && dtd.name.equalsIgnoreCase("html") && dtd.publicId == null && dtd.systemId == null;
119    }
120
121    public MarkupWriter newMarkupWriter(Page page)
122    {
123        boolean isHTML5 = hasHTML5Doctype(page);
124        
125        ContentType contentType = pageContentTypeAnalyzer.findContentType(page);
126        
127        return constructMarkupWriter(contentType, false, isHTML5);
128    }
129
130    public MarkupWriter newPartialMarkupWriter(Page page)
131    {
132        boolean isHTML5 = hasHTML5Doctype(page);
133        
134        ContentType contentType = pageContentTypeAnalyzer.findContentType(page);
135        
136        return constructMarkupWriter(contentType, true, isHTML5);
137    }
138
139    public MarkupWriter newPartialMarkupWriter(String pageName)
140    {
141        Page page = cache.get(pageName);
142        
143        return newPartialMarkupWriter(page);
144    }
145}