001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package javax.servlet.jsp.tagext; 018 019 import java.io.Serializable; 020 import java.util.Enumeration; 021 import java.util.Hashtable; 022 023 import javax.servlet.jsp.JspException; 024 import javax.servlet.jsp.PageContext; 025 026 /** 027 * A base class for defining new tag handlers implementing Tag. 028 * 029 * <p> The TagSupport class is a utility class intended to be used as 030 * the base class for new tag handlers. The TagSupport class 031 * implements the Tag and IterationTag interfaces and adds additional 032 * convenience methods including getter methods for the properties in 033 * Tag. TagSupport has one static method that is included to 034 * facilitate coordination among cooperating tags. 035 * 036 * <p> Many tag handlers will extend TagSupport and only redefine a 037 * few methods. 038 */ 039 040 public class TagSupport implements IterationTag, Serializable { 041 042 /** 043 * Find the instance of a given class type that is closest to a given 044 * instance. 045 * This method uses the getParent method from the Tag 046 * interface. 047 * This method is used for coordination among cooperating tags. 048 * 049 * <p> 050 * The current version of the specification only provides one formal 051 * way of indicating the observable type of a tag handler: its 052 * tag handler implementation class, described in the tag-class 053 * subelement of the tag element. This is extended in an 054 * informal manner by allowing the tag library author to 055 * indicate in the description subelement an observable type. 056 * The type should be a subtype of the tag handler implementation 057 * class or void. 058 * This addititional constraint can be exploited by a 059 * specialized container that knows about that specific tag library, 060 * as in the case of the JSP standard tag library. 061 * 062 * <p> 063 * When a tag library author provides information on the 064 * observable type of a tag handler, client programmatic code 065 * should adhere to that constraint. Specifically, the Class 066 * passed to findAncestorWithClass should be a subtype of the 067 * observable type. 068 * 069 * 070 * @param from The instance from where to start looking. 071 * @param klass The subclass of Tag or interface to be matched 072 * @return the nearest ancestor that implements the interface 073 * or is an instance of the class specified 074 */ 075 076 public static final Tag findAncestorWithClass(Tag from, Class klass) { 077 boolean isInterface = false; 078 079 if (from == null || 080 klass == null || 081 (!Tag.class.isAssignableFrom(klass) && 082 !(isInterface = klass.isInterface()))) { 083 return null; 084 } 085 086 for (;;) { 087 Tag tag = from.getParent(); 088 089 if (tag == null) { 090 return null; 091 } 092 093 if ((isInterface && klass.isInstance(tag)) || 094 klass.isAssignableFrom(tag.getClass())) 095 return tag; 096 else 097 from = tag; 098 } 099 } 100 101 /** 102 * Default constructor, all subclasses are required to define only 103 * a public constructor with the same signature, and to call the 104 * superclass constructor. 105 * 106 * This constructor is called by the code generated by the JSP 107 * translator. 108 */ 109 110 public TagSupport() { } 111 112 /** 113 * Default processing of the start tag, returning SKIP_BODY. 114 * 115 * @return SKIP_BODY 116 * @throws JspException if an error occurs while processing this tag 117 * 118 * @see Tag#doStartTag() 119 */ 120 121 public int doStartTag() throws JspException { 122 return SKIP_BODY; 123 } 124 125 /** 126 * Default processing of the end tag returning EVAL_PAGE. 127 * 128 * @return EVAL_PAGE 129 * @throws JspException if an error occurs while processing this tag 130 * 131 * @see Tag#doEndTag() 132 */ 133 134 public int doEndTag() throws JspException { 135 return EVAL_PAGE; 136 } 137 138 139 /** 140 * Default processing for a body. 141 * 142 * @return SKIP_BODY 143 * @throws JspException if an error occurs while processing this tag 144 * 145 * @see IterationTag#doAfterBody() 146 */ 147 148 public int doAfterBody() throws JspException { 149 return SKIP_BODY; 150 } 151 152 // Actions related to body evaluation 153 154 155 /** 156 * Release state. 157 * 158 * @see Tag#release() 159 */ 160 161 public void release() { 162 parent = null; 163 id = null; 164 if( values != null ) { 165 values.clear(); 166 } 167 values = null; 168 } 169 170 /** 171 * Set the nesting tag of this tag. 172 * 173 * @param t The parent Tag. 174 * @see Tag#setParent(Tag) 175 */ 176 177 public void setParent(Tag t) { 178 parent = t; 179 } 180 181 /** 182 * The Tag instance most closely enclosing this tag instance. 183 * @see Tag#getParent() 184 * 185 * @return the parent tag instance or null 186 */ 187 188 public Tag getParent() { 189 return parent; 190 } 191 192 /** 193 * Set the id attribute for this tag. 194 * 195 * @param id The String for the id. 196 */ 197 198 public void setId(String id) { 199 this.id = id; 200 } 201 202 /** 203 * The value of the id attribute of this tag; or null. 204 * 205 * @return the value of the id attribute, or null 206 */ 207 208 public String getId() { 209 return id; 210 } 211 212 /** 213 * Set the page context. 214 * 215 * @param pageContext The PageContext. 216 * @see Tag#setPageContext 217 */ 218 219 public void setPageContext(PageContext pageContext) { 220 this.pageContext = pageContext; 221 } 222 223 /** 224 * Associate a value with a String key. 225 * 226 * @param k The key String. 227 * @param o The value to associate. 228 */ 229 230 public void setValue(String k, Object o) { 231 if (values == null) { 232 values = new Hashtable<String, Object>(); 233 } 234 values.put(k, o); 235 } 236 237 /** 238 * Get a the value associated with a key. 239 * 240 * @param k The string key. 241 * @return The value associated with the key, or null. 242 */ 243 244 public Object getValue(String k) { 245 if (values == null) { 246 return null; 247 } else { 248 return values.get(k); 249 } 250 } 251 252 /** 253 * Remove a value associated with a key. 254 * 255 * @param k The string key. 256 */ 257 258 public void removeValue(String k) { 259 if (values != null) { 260 values.remove(k); 261 } 262 } 263 264 /** 265 * Enumerate the keys for the values kept by this tag handler. 266 * 267 * @return An enumeration of all the keys for the values set, 268 * or null or an empty Enumeration if no values have been set. 269 */ 270 271 public Enumeration<String> getValues() { 272 if (values == null) { 273 return null; 274 } 275 return values.keys(); 276 } 277 278 // private fields 279 280 private Tag parent; 281 private Hashtable<String, Object> values; 282 /** 283 * The value of the id attribute of this tag; or null. 284 */ 285 protected String id; 286 287 // protected fields 288 289 /** 290 * The PageContext. 291 */ 292 protected PageContext pageContext; 293 } 294