1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package javax.servlet.jsp.tagext;
18
19 import java.io.Serializable;
20 import java.util.Enumeration;
21 import java.util.Hashtable;
22
23 import javax.servlet.jsp.JspException;
24 import javax.servlet.jsp.PageContext;
25
26 /**
27 * A base class for defining new tag handlers implementing Tag.
28 *
29 * <p> The TagSupport class is a utility class intended to be used as
30 * the base class for new tag handlers. The TagSupport class
31 * implements the Tag and IterationTag interfaces and adds additional
32 * convenience methods including getter methods for the properties in
33 * Tag. TagSupport has one static method that is included to
34 * facilitate coordination among cooperating tags.
35 *
36 * <p> Many tag handlers will extend TagSupport and only redefine a
37 * few methods.
38 */
39
40 public class TagSupport implements IterationTag, Serializable {
41
42 /**
43 * Find the instance of a given class type that is closest to a given
44 * instance.
45 * This method uses the getParent method from the Tag
46 * interface.
47 * This method is used for coordination among cooperating tags.
48 *
49 * <p>
50 * The current version of the specification only provides one formal
51 * way of indicating the observable type of a tag handler: its
52 * tag handler implementation class, described in the tag-class
53 * subelement of the tag element. This is extended in an
54 * informal manner by allowing the tag library author to
55 * indicate in the description subelement an observable type.
56 * The type should be a subtype of the tag handler implementation
57 * class or void.
58 * This addititional constraint can be exploited by a
59 * specialized container that knows about that specific tag library,
60 * as in the case of the JSP standard tag library.
61 *
62 * <p>
63 * When a tag library author provides information on the
64 * observable type of a tag handler, client programmatic code
65 * should adhere to that constraint. Specifically, the Class
66 * passed to findAncestorWithClass should be a subtype of the
67 * observable type.
68 *
69 *
70 * @param from The instance from where to start looking.
71 * @param klass The subclass of Tag or interface to be matched
72 * @return the nearest ancestor that implements the interface
73 * or is an instance of the class specified
74 */
75
76 public static final Tag findAncestorWithClass(Tag from, Class klass) {
77 boolean isInterface = false;
78
79 if (from == null ||
80 klass == null ||
81 (!Tag.class.isAssignableFrom(klass) &&
82 !(isInterface = klass.isInterface()))) {
83 return null;
84 }
85
86 for (;;) {
87 Tag tag = from.getParent();
88
89 if (tag == null) {
90 return null;
91 }
92
93 if ((isInterface && klass.isInstance(tag)) ||
94 klass.isAssignableFrom(tag.getClass()))
95 return tag;
96 else
97 from = tag;
98 }
99 }
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