All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.web.servlet.tags.form.TagWriter Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2018 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.web.servlet.tags.form;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayDeque;
import java.util.Deque;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * Utility class for writing HTML content to a {@link Writer} instance.
 *
 * 

Intended to support output from JSP tag libraries. * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 */ public class TagWriter { /** * The {@link SafeWriter} to write to. */ private final SafeWriter writer; /** * Stores {@link TagStateEntry tag state}. Stack model naturally supports tag nesting. */ private final Deque tagState = new ArrayDeque<>(); /** * Create a new instance of the {@link TagWriter} class that writes to * the supplied {@link PageContext}. * @param pageContext the JSP PageContext to obtain the {@link Writer} from */ public TagWriter(PageContext pageContext) { Assert.notNull(pageContext, "PageContext must not be null"); this.writer = new SafeWriter(pageContext); } /** * Create a new instance of the {@link TagWriter} class that writes to * the supplied {@link Writer}. * @param writer the {@link Writer} to write tag content to */ public TagWriter(Writer writer) { Assert.notNull(writer, "Writer must not be null"); this.writer = new SafeWriter(writer); } /** * Start a new tag with the supplied name. Leaves the tag open so * that attributes, inner text or nested tags can be written into it. * @see #endTag() */ public void startTag(String tagName) throws JspException { if (inTag()) { closeTagAndMarkAsBlock(); } push(tagName); this.writer.append("<").append(tagName); } /** * Write an HTML attribute with the specified name and value. *

Be sure to write all attributes before writing * any inner text or nested tags. * @throws IllegalStateException if the opening tag is closed */ public void writeAttribute(String attributeName, String attributeValue) throws JspException { if (currentState().isBlockTag()) { throw new IllegalStateException("Cannot write attributes after opening tag is closed."); } this.writer.append(" ").append(attributeName).append("=\"") .append(attributeValue).append("\""); } /** * Write an HTML attribute if the supplied value is not {@code null} * or zero length. * @see #writeAttribute(String, String) */ public void writeOptionalAttributeValue(String attributeName, @Nullable String attributeValue) throws JspException { if (StringUtils.hasText(attributeValue)) { writeAttribute(attributeName, attributeValue); } } /** * Close the current opening tag (if necessary) and appends the * supplied value as inner text. * @throws IllegalStateException if no tag is open */ public void appendValue(String value) throws JspException { if (!inTag()) { throw new IllegalStateException("Cannot write tag value. No open tag available."); } closeTagAndMarkAsBlock(); this.writer.append(value); } /** * Indicate that the currently open tag should be closed and marked * as a block level element. *

Useful when you plan to write additional content in the body * outside the context of the current {@link TagWriter}. */ public void forceBlock() throws JspException { if (currentState().isBlockTag()) { return; // just ignore since we are already in the block } closeTagAndMarkAsBlock(); } /** * Close the current tag. *

Correctly writes an empty tag if no inner text or nested tags * have been written. */ public void endTag() throws JspException { endTag(false); } /** * Close the current tag, allowing to enforce a full closing tag. *

Correctly writes an empty tag if no inner text or nested tags * have been written. * @param enforceClosingTag whether a full closing tag should be * rendered in any case, even in case of a non-block tag */ public void endTag(boolean enforceClosingTag) throws JspException { if (!inTag()) { throw new IllegalStateException("Cannot write end of tag. No open tag available."); } boolean renderClosingTag = true; if (!currentState().isBlockTag()) { // Opening tag still needs to be closed... if (enforceClosingTag) { this.writer.append(">"); } else { this.writer.append("/>"); renderClosingTag = false; } } if (renderClosingTag) { this.writer.append(""); } this.tagState.pop(); } /** * Adds the supplied tag name to the {@link #tagState tag state}. */ private void push(String tagName) { this.tagState.push(new TagStateEntry(tagName)); } /** * Closes the current opening tag and marks it as a block tag. */ private void closeTagAndMarkAsBlock() throws JspException { if (!currentState().isBlockTag()) { currentState().markAsBlockTag(); this.writer.append(">"); } } private boolean inTag() { return !this.tagState.isEmpty(); } private TagStateEntry currentState() { return this.tagState.element(); } /** * Holds state about a tag and its rendered behavior. */ private static class TagStateEntry { private final String tagName; private boolean blockTag; public TagStateEntry(String tagName) { this.tagName = tagName; } public String getTagName() { return this.tagName; } public void markAsBlockTag() { this.blockTag = true; } public boolean isBlockTag() { return this.blockTag; } } /** * Simple {@link Writer} wrapper that wraps all * {@link IOException IOExceptions} in {@link JspException JspExceptions}. */ private static final class SafeWriter { @Nullable private PageContext pageContext; @Nullable private Writer writer; public SafeWriter(PageContext pageContext) { this.pageContext = pageContext; } public SafeWriter(Writer writer) { this.writer = writer; } public SafeWriter append(String value) throws JspException { try { getWriterToUse().write(String.valueOf(value)); return this; } catch (IOException ex) { throw new JspException("Unable to write to JspWriter", ex); } } private Writer getWriterToUse() { Writer writer = (this.pageContext != null ? this.pageContext.getOut() : this.writer); Assert.state(writer != null, "No Writer available"); return writer; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy