001/*
002 * Copyright 2002-2013 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.servlet.tags.form;
018
019import java.beans.PropertyEditor;
020import javax.servlet.jsp.JspException;
021
022import org.springframework.util.ObjectUtils;
023import org.springframework.web.servlet.tags.HtmlEscapingAwareTag;
024
025/**
026 * Base class for all JSP form tags. Provides utility methods for
027 * null-safe EL evaluation and for accessing and working with a {@link TagWriter}.
028 *
029 * <p>Subclasses should implement the {@link #writeTagContent(TagWriter)} to perform
030 * actual tag rendering.
031 *
032 * <p>Subclasses (or test classes) can override the {@link #createTagWriter()} method to
033 * redirect output to a {@link java.io.Writer} other than the {@link javax.servlet.jsp.JspWriter}
034 * associated with the current {@link javax.servlet.jsp.PageContext}.
035 *
036 * @author Rob Harrop
037 * @author Juergen Hoeller
038 * @since 2.0
039 */
040@SuppressWarnings("serial")
041public abstract class AbstractFormTag extends HtmlEscapingAwareTag {
042
043        /**
044         * Evaluate the supplied value for the supplied attribute name.
045         * <p>The default implementation simply returns the given value as-is.
046         */
047        protected Object evaluate(String attributeName, Object value) throws JspException {
048                return value;
049        }
050
051        /**
052         * Optionally writes the supplied value under the supplied attribute name into the supplied
053         * {@link TagWriter}. In this case, the supplied value is {@link #evaluate evaluated} first
054         * and then the {@link ObjectUtils#getDisplayString String representation} is written as the
055         * attribute value. If the resultant {@code String} representation is {@code null}
056         * or empty, no attribute is written.
057         * @see TagWriter#writeOptionalAttributeValue(String, String)
058         */
059        protected final void writeOptionalAttribute(TagWriter tagWriter, String attributeName, String value)
060                        throws JspException {
061
062                if (value != null) {
063                        tagWriter.writeOptionalAttributeValue(attributeName, getDisplayString(evaluate(attributeName, value)));
064                }
065        }
066
067        /**
068         * Create the {@link TagWriter} which all output will be written to. By default,
069         * the {@link TagWriter} writes its output to the {@link javax.servlet.jsp.JspWriter}
070         * for the current {@link javax.servlet.jsp.PageContext}. Subclasses may choose to
071         * change the {@link java.io.Writer} to which output is actually written.
072         */
073        protected TagWriter createTagWriter() {
074                return new TagWriter(this.pageContext);
075        }
076
077        /**
078         * Provide a simple template method that calls {@link #createTagWriter()} and passes
079         * the created {@link TagWriter} to the {@link #writeTagContent(TagWriter)} method.
080         * @return the value returned by {@link #writeTagContent(TagWriter)}
081         */
082        @Override
083        protected final int doStartTagInternal() throws Exception {
084                return writeTagContent(createTagWriter());
085        }
086
087        /**
088         * Get the display value of the supplied {@code Object}, HTML escaped
089         * as required. This version is <strong>not</strong> {@link PropertyEditor}-aware.
090         */
091        protected String getDisplayString(Object value) {
092                return ValueFormatter.getDisplayString(value, isHtmlEscape());
093        }
094
095        /**
096         * Get the display value of the supplied {@code Object}, HTML escaped
097         * as required. If the supplied value is not a {@link String} and the supplied
098         * {@link PropertyEditor} is not null then the {@link PropertyEditor} is used
099         * to obtain the display value.
100         */
101        protected String getDisplayString(Object value, PropertyEditor propertyEditor) {
102                return ValueFormatter.getDisplayString(value, propertyEditor, isHtmlEscape());
103        }
104
105        /**
106         * Overridden to default to {@code true} in case of no explicit default given.
107         */
108        @Override
109        protected boolean isDefaultHtmlEscape() {
110                Boolean defaultHtmlEscape = getRequestContext().getDefaultHtmlEscape();
111                return (defaultHtmlEscape == null || defaultHtmlEscape.booleanValue());
112        }
113
114
115        /**
116         * Subclasses should implement this method to perform tag content rendering.
117         * @return valid tag render instruction as per {@link javax.servlet.jsp.tagext.Tag#doStartTag()}.
118         */
119        protected abstract int writeTagContent(TagWriter tagWriter) throws JspException;
120
121}