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 public static final Tag findAncestorWithClass(Tag from,
76 // TCK signature test fails with generics
77 @SuppressWarnings("unchecked")
78 Class klass) {
79 boolean isInterface = false;
80
81 if (from == null ||
82 klass == null ||
83 (!Tag.class.isAssignableFrom(klass) &&
84 !(isInterface = klass.isInterface()))) {
85 return null;
86 }
87
88 for (;;) {
89 Tag tag = from.getParent();
90
91 if (tag == null) {
92 return null;
93 }
94
95 if ((isInterface && klass.isInstance(tag)) ||
96 klass.isAssignableFrom(tag.getClass()))
97 return tag;
98 else
99 from = tag;
100 }
101 }
102
103 /**
104 * Default constructor, all subclasses are required to define only
105 * a public constructor with the same signature, and to call the
106 * superclass constructor.
107 *
108 * This constructor is called by the code generated by the JSP
109 * translator.
110 */
111
112 public TagSupport() { }
113
114 /**
115 * Default processing of the start tag, returning SKIP_BODY.
116 *
117 * @return SKIP_BODY
118 * @throws JspException if an error occurs while processing this tag
119 *
120 * @see Tag#doStartTag()
121 */
122
123 public int doStartTag() throws JspException {
124 return SKIP_BODY;
125 }
126
127 /**
128 * Default processing of the end tag returning EVAL_PAGE.
129 *
130 * @return EVAL_PAGE
131 * @throws JspException if an error occurs while processing this tag
132 *
133 * @see Tag#doEndTag()
134 */
135
136 public int doEndTag() throws JspException {
137 return EVAL_PAGE;
138 }
139
140
141 /**
142 * Default processing for a body.
143 *
144 * @return SKIP_BODY
145 * @throws JspException if an error occurs while processing this tag
146 *
147 * @see IterationTag#doAfterBody()
148 */
149
150 public int doAfterBody() throws JspException {
151 return SKIP_BODY;
152 }
153
154 // Actions related to body evaluation
155
156
157 /**
158 * Release state.
159 *
160 * @see Tag#release()
161 */
162
163 public void release() {
164 parent = null;
165 id = null;
166 if( values != null ) {
167 values.clear();
168 }
169 values = null;
170 }
171
172 /**
173 * Set the nesting tag of this tag.
174 *
175 * @param t The parent Tag.
176 * @see Tag#setParent(Tag)
177 */
178
179 public void setParent(Tag t) {
180 parent = t;
181 }
182
183 /**
184 * The Tag instance most closely enclosing this tag instance.
185 * @see Tag#getParent()
186 *
187 * @return the parent tag instance or null
188 */
189
190 public Tag getParent() {
191 return parent;
192 }
193
194 /**
195 * Set the id attribute for this tag.
196 *
197 * @param id The String for the id.
198 */
199
200 public void setId(String id) {
201 this.id = id;
202 }
203
204 /**
205 * The value of the id attribute of this tag; or null.
206 *
207 * @return the value of the id attribute, or null
208 */
209
210 public String getId() {
211 return id;
212 }
213
214 /**
215 * Set the page context.
216 *
217 * @param pageContext The PageContext.
218 * @see Tag#setPageContext
219 */
220
221 public void setPageContext(PageContext pageContext) {
222 this.pageContext = pageContext;
223 }
224
225 /**
226 * Associate a value with a String key.
227 *
228 * @param k The key String.
229 * @param o The value to associate.
230 */
231
232 public void setValue(String k, Object o) {
233 if (values == null) {
234 values = new Hashtable<String, Object>();
235 }
236 values.put(k, o);
237 }
238
239 /**
240 * Get a the value associated with a key.
241 *
242 * @param k The string key.
243 * @return The value associated with the key, or null.
244 */
245
246 public Object getValue(String k) {
247 if (values == null) {
248 return null;
249 } else {
250 return values.get(k);
251 }
252 }
253
254 /**
255 * Remove a value associated with a key.
256 *
257 * @param k The string key.
258 */
259
260 public void removeValue(String k) {
261 if (values != null) {
262 values.remove(k);
263 }
264 }
265
266 /**
267 * Enumerate the keys for the values kept by this tag handler.
268 *
269 * @return An enumeration of all the keys for the values set,
270 * or null or an empty Enumeration if no values have been set.
271 */
272
273 public Enumeration<String> getValues() {
274 if (values == null) {
275 return null;
276 }
277 return values.keys();
278 }
279
280 // private fields
281
282 private Tag parent;
283 private Hashtable<String, Object> values;
284 /**
285 * The value of the id attribute of this tag; or null.
286 */
287 protected String id;
288
289 // protected fields
290
291 /**
292 * The PageContext.
293 */
294 protected PageContext pageContext;
295 }
296