/*
 * 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
 *
 *      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.springframework.web.servlet.tags.form;

import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;

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

Convenient super class for many html tags that render content using the databinding features of the AbstractHtmlElementTag. The only thing sub-tags need to do is override renderDefaultContent(TagWriter).
Author:Rob Harrop, Juergen Hoeller
Since:2.0
/** * Convenient super class for many html tags that render content using the databinding * features of the {@link AbstractHtmlElementTag AbstractHtmlElementTag}. The only thing * sub-tags need to do is override {@link #renderDefaultContent(TagWriter)}. * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 */
@SuppressWarnings("serial") public abstract class AbstractHtmlElementBodyTag extends AbstractHtmlElementTag implements BodyTag { @Nullable private BodyContent bodyContent; @Nullable private TagWriter tagWriter; @Override protected int writeTagContent(TagWriter tagWriter) throws JspException { onWriteTagContent(); this.tagWriter = tagWriter; if (shouldRender()) { exposeAttributes(); return EVAL_BODY_BUFFERED; } else { return SKIP_BODY; } }
If rendering, flush any buffered BodyContent or, if no BodyContent is supplied, render the default content.
Returns:a Tag.EVAL_PAGE result
/** * If {@link #shouldRender rendering}, flush any buffered * {@link BodyContent} or, if no {@link BodyContent} is supplied, * {@link #renderDefaultContent render the default content}. * @return a {@link javax.servlet.jsp.tagext.Tag#EVAL_PAGE} result */
@Override public int doEndTag() throws JspException { if (shouldRender()) { Assert.state(this.tagWriter != null, "No TagWriter set"); if (this.bodyContent != null && StringUtils.hasText(this.bodyContent.getString())) { renderFromBodyContent(this.bodyContent, this.tagWriter); } else { renderDefaultContent(this.tagWriter); } } return EVAL_PAGE; }
Render the tag contents based on the supplied BodyContent.

The default implementation simply flushes the BodyContent directly to the output. Subclasses may choose to override this to add additional content to the output.

/** * Render the tag contents based on the supplied {@link BodyContent}. * <p>The default implementation simply {@link #flushBufferedBodyContent flushes} * the {@link BodyContent} directly to the output. Subclasses may choose to * override this to add additional content to the output. */
protected void renderFromBodyContent(BodyContent bodyContent, TagWriter tagWriter) throws JspException { flushBufferedBodyContent(bodyContent); }
Clean up any attributes and stored resources.
/** * Clean up any attributes and stored resources. */
@Override public void doFinally() { super.doFinally(); removeAttributes(); this.tagWriter = null; this.bodyContent = null; } //--------------------------------------------------------------------- // Template methods //---------------------------------------------------------------------
Called at the start of writeTagContent allowing subclasses to perform any precondition checks or setup tasks that might be necessary.
/** * Called at the start of {@link #writeTagContent} allowing subclasses to perform * any precondition checks or setup tasks that might be necessary. */
protected void onWriteTagContent() { }
Should rendering of this tag proceed at all. Returns 'true' by default causing rendering to occur always, Subclasses can override this if they provide conditional rendering.
/** * Should rendering of this tag proceed at all. Returns '{@code true}' by default * causing rendering to occur always, Subclasses can override this if they * provide conditional rendering. */
protected boolean shouldRender() throws JspException { return true; }
Called during writeTagContent allowing subclasses to add any attributes to the PageContext as needed.
/** * Called during {@link #writeTagContent} allowing subclasses to add any attributes to the * {@link javax.servlet.jsp.PageContext} as needed. */
protected void exposeAttributes() throws JspException { }
Called by doFinally allowing subclasses to remove any attributes from the PageContext as needed.
/** * Called by {@link #doFinally} allowing subclasses to remove any attributes from the * {@link javax.servlet.jsp.PageContext} as needed. */
protected void removeAttributes() { }
The user customised the output of the error messages - flush the buffered content into the main JspWriter.
/** * The user customised the output of the error messages - flush the * buffered content into the main {@link javax.servlet.jsp.JspWriter}. */
protected void flushBufferedBodyContent(BodyContent bodyContent) throws JspException { try { bodyContent.writeOut(bodyContent.getEnclosingWriter()); } catch (IOException ex) { throw new JspException("Unable to write buffered body content.", ex); } } protected abstract void renderDefaultContent(TagWriter tagWriter) throws JspException; //--------------------------------------------------------------------- // BodyTag implementation //--------------------------------------------------------------------- @Override public void doInitBody() throws JspException { // no op } @Override public void setBodyContent(BodyContent bodyContent) { this.bodyContent = bodyContent; } }