/* * ============================================================================= * * Copyright (c) 2011-2016, The THYMELEAF team (http://www.thymeleaf.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.thymeleaf.engine; import java.io.IOException; import java.io.Writer; import org.thymeleaf.model.IDocType; import org.thymeleaf.model.IModelVisitor; /* * Engine implementation of IDocType. * * @author Daniel Fernandez * @since 3.0.0 */ final class DocType extends AbstractTemplateEvent implements IDocType, IEngineTemplateEvent { // DOCTYPE nodes do not exist in text parsing, so we are safe expliciting markup structures here public static final String DEFAULT_KEYWORD = "DOCTYPE"; public static final String DEFAULT_ELEMENT_NAME = "html"; public static final String DEFAULT_TYPE_PUBLIC = "PUBLIC"; public static final String DEFAULT_TYPE_SYSTEM = "SYSTEM"; private final String keyword; private final String elementName; private final String type; private final String publicId; private final String systemId; private final String internalSubset; private final String docType; DocType() { this(null, null); } DocType(final String publicId, final String systemId) { this(DEFAULT_KEYWORD, DEFAULT_ELEMENT_NAME, publicId, systemId, null); } DocType( final String keyword, final String elementName, final String publicId, final String systemId, final String internalSubset) { super(); this.keyword = keyword; this.elementName = elementName; this.type = computeType(publicId, systemId); this.publicId = publicId; this.systemId = systemId; this.internalSubset = internalSubset; this.docType = computeDocType(); } DocType( final String docType, final String keyword, final String elementName, final String publicId, final String systemId, final String internalSubset, final String templateName, final int line, final int col) { super(templateName, line, col); this.keyword = keyword; this.elementName = elementName; this.type = computeType(publicId, systemId); this.publicId = publicId; this.systemId = systemId; this.internalSubset = internalSubset; this.docType = (docType != null? docType : computeDocType()); } public String getKeyword() { return this.keyword; } public String getElementName() { return this.elementName; } public String getType() { return this.type; } public String getPublicId() { return this.publicId; } public String getSystemId() { return this.systemId; } public String getInternalSubset() { return this.internalSubset; } public String getDocType() { return this.docType; } private String computeDocType() { final StringBuilder strBuilder = new StringBuilder(120); strBuilder.append("<!"); strBuilder.append(this.keyword); strBuilder.append(' '); strBuilder.append(this.elementName); if (this.type != null) { strBuilder.append(' '); strBuilder.append(type); if (this.publicId != null) { strBuilder.append(" \""); strBuilder.append(this.publicId); strBuilder.append('"'); } strBuilder.append(" \""); strBuilder.append(this.systemId); strBuilder.append('"'); } if (this.internalSubset != null) { strBuilder.append(" ["); strBuilder.append(this.internalSubset); strBuilder.append(']'); } strBuilder.append('>'); return strBuilder.toString(); } private static String computeType(final String publicId, final String systemId) { if (publicId != null && systemId == null) { throw new IllegalArgumentException( "DOCTYPE clause cannot have a non-null PUBLIC ID and a null SYSTEM ID"); } if (publicId == null && systemId == null) { return null; } if (publicId != null) { return DEFAULT_TYPE_PUBLIC; } return DEFAULT_TYPE_SYSTEM; } public void accept(final IModelVisitor visitor) { visitor.visit(this); } public void write(final Writer writer) throws IOException { writer.write(this.docType); } // Meant to be called only from within the engine static DocType asEngineDocType(final IDocType docType) { if (docType instanceof DocType) { return (DocType) docType; } return new DocType( null, docType.getKeyword(), docType.getElementName(), docType.getPublicId(), docType.getSystemId(), docType.getInternalSubset(), docType.getTemplateName(), docType.getLine(), docType.getCol()); } @Override public void beHandled(final ITemplateHandler handler) { handler.handleDocType(this); } @Override public String toString() { return getDocType(); } }