001/* 002 * Copyright 2002-2016 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.io.IOException; 020import javax.servlet.jsp.JspException; 021import javax.servlet.jsp.tagext.BodyContent; 022import javax.servlet.jsp.tagext.BodyTag; 023 024import org.springframework.util.StringUtils; 025 026/** 027 * Convenient super class for many html tags that render content using the databinding 028 * features of the {@link AbstractHtmlElementTag AbstractHtmlElementTag}. The only thing 029 * sub-tags need to do is override {@link #renderDefaultContent(TagWriter)}. 030 * 031 * @author Rob Harrop 032 * @author Juergen Hoeller 033 * @since 2.0 034 */ 035@SuppressWarnings("serial") 036public abstract class AbstractHtmlElementBodyTag extends AbstractHtmlElementTag implements BodyTag { 037 038 private BodyContent bodyContent; 039 040 private TagWriter tagWriter; 041 042 043 @Override 044 protected int writeTagContent(TagWriter tagWriter) throws JspException { 045 onWriteTagContent(); 046 this.tagWriter = tagWriter; 047 if (shouldRender()) { 048 exposeAttributes(); 049 return EVAL_BODY_BUFFERED; 050 } 051 else { 052 return SKIP_BODY; 053 } 054 } 055 056 /** 057 * If {@link #shouldRender rendering}, flush any buffered 058 * {@link BodyContent} or, if no {@link BodyContent} is supplied, 059 * {@link #renderDefaultContent render the default content}. 060 * @return a {@link javax.servlet.jsp.tagext.Tag#EVAL_PAGE} result 061 */ 062 @Override 063 public int doEndTag() throws JspException { 064 if (shouldRender()) { 065 if (this.bodyContent != null && StringUtils.hasText(this.bodyContent.getString())) { 066 renderFromBodyContent(this.bodyContent, this.tagWriter); 067 } 068 else { 069 renderDefaultContent(this.tagWriter); 070 } 071 } 072 return EVAL_PAGE; 073 } 074 075 /** 076 * Render the tag contents based on the supplied {@link BodyContent}. 077 * <p>The default implementation simply {@link #flushBufferedBodyContent flushes} 078 * the {@link BodyContent} directly to the output. Subclasses may choose to 079 * override this to add additional content to the output. 080 */ 081 protected void renderFromBodyContent(BodyContent bodyContent, TagWriter tagWriter) throws JspException { 082 flushBufferedBodyContent(bodyContent); 083 } 084 085 /** 086 * Clean up any attributes and stored resources. 087 */ 088 @Override 089 public void doFinally() { 090 super.doFinally(); 091 removeAttributes(); 092 this.tagWriter = null; 093 this.bodyContent = null; 094 } 095 096 097 //--------------------------------------------------------------------- 098 // Template methods 099 //--------------------------------------------------------------------- 100 101 /** 102 * Called at the start of {@link #writeTagContent} allowing subclasses to perform 103 * any precondition checks or setup tasks that might be necessary. 104 */ 105 protected void onWriteTagContent() { 106 } 107 108 /** 109 * Should rendering of this tag proceed at all. Returns '{@code true}' by default 110 * causing rendering to occur always, Subclasses can override this if they 111 * provide conditional rendering. 112 */ 113 protected boolean shouldRender() throws JspException { 114 return true; 115 } 116 117 /** 118 * Called during {@link #writeTagContent} allowing subclasses to add any attributes to the 119 * {@link javax.servlet.jsp.PageContext} as needed. 120 */ 121 protected void exposeAttributes() throws JspException { 122 } 123 124 /** 125 * Called by {@link #doFinally} allowing subclasses to remove any attributes from the 126 * {@link javax.servlet.jsp.PageContext} as needed. 127 */ 128 protected void removeAttributes() { 129 } 130 131 /** 132 * The user customised the output of the error messages - flush the 133 * buffered content into the main {@link javax.servlet.jsp.JspWriter}. 134 */ 135 protected void flushBufferedBodyContent(BodyContent bodyContent) throws JspException { 136 try { 137 bodyContent.writeOut(bodyContent.getEnclosingWriter()); 138 } 139 catch (IOException ex) { 140 throw new JspException("Unable to write buffered body content.", ex); 141 } 142 } 143 144 protected abstract void renderDefaultContent(TagWriter tagWriter) throws JspException; 145 146 147 //--------------------------------------------------------------------- 148 // BodyTag implementation 149 //--------------------------------------------------------------------- 150 151 @Override 152 public void doInitBody() throws JspException { 153 // no op 154 } 155 156 @Override 157 public void setBodyContent(BodyContent bodyContent) { 158 this.bodyContent = bodyContent; 159 } 160 161}