    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}