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) && !(isInterface = klass
082: .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: /**
114: * Default processing of the start tag, returning SKIP_BODY.
115: *
116: * @return SKIP_BODY
117: * @throws JspException if an error occurs while processing this tag
118: *
119: * @see Tag#doStartTag()
120: */
121:
122: public int doStartTag() throws JspException {
123: return SKIP_BODY;
124: }
125:
126: /**
127: * Default processing of the end tag returning EVAL_PAGE.
128: *
129: * @return EVAL_PAGE
130: * @throws JspException if an error occurs while processing this tag
131: *
132: * @see Tag#doEndTag()
133: */
134:
135: public int doEndTag() throws JspException {
136: return EVAL_PAGE;
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: * Release state.
156: *
157: * @see Tag#release()
158: */
159:
160: public void release() {
161: parent = null;
162: id = null;
163: if (values != null) {
164: values.clear();
165: }
166: values = null;
167: }
168:
169: /**
170: * Set the nesting tag of this tag.
171: *
172: * @param t The parent Tag.
173: * @see Tag#setParent(Tag)
174: */
175:
176: public void setParent(Tag t) {
177: parent = t;
178: }
179:
180: /**
181: * The Tag instance most closely enclosing this tag instance.
182: * @see Tag#getParent()
183: *
184: * @return the parent tag instance or null
185: */
186:
187: public Tag getParent() {
188: return parent;
189: }
190:
191: /**
192: * Set the id attribute for this tag.
193: *
194: * @param id The String for the id.
195: */
196:
197: public void setId(String id) {
198: this .id = id;
199: }
200:
201: /**
202: * The value of the id attribute of this tag; or null.
203: *
204: * @return the value of the id attribute, or null
205: */
206:
207: public String getId() {
208: return id;
209: }
210:
211: /**
212: * Set the page context.
213: *
214: * @param pageContext The PageContext.
215: * @see Tag#setPageContext
216: */
217:
218: public void setPageContext(PageContext pageContext) {
219: this .pageContext = pageContext;
220: }
221:
222: /**
223: * Associate a value with a String key.
224: *
225: * @param k The key String.
226: * @param o The value to associate.
227: */
228:
229: public void setValue(String k, Object o) {
230: if (values == null) {
231: values = new Hashtable<String, Object>();
232: }
233: values.put(k, o);
234: }
235:
236: /**
237: * Get a the value associated with a key.
238: *
239: * @param k The string key.
240: * @return The value associated with the key, or null.
241: */
242:
243: public Object getValue(String k) {
244: if (values == null) {
245: return null;
246: } else {
247: return values.get(k);
248: }
249: }
250:
251: /**
252: * Remove a value associated with a key.
253: *
254: * @param k The string key.
255: */
256:
257: public void removeValue(String k) {
258: if (values != null) {
259: values.remove(k);
260: }
261: }
262:
263: /**
264: * Enumerate the keys for the values kept by this tag handler.
265: *
266: * @return An enumeration of all the keys for the values set,
267: * or null or an empty Enumeration if no values have been set.
268: */
269:
270: public Enumeration<String> getValues() {
271: if (values == null) {
272: return null;
273: }
274: return values.keys();
275: }
276:
277: // private fields
278:
279: private Tag parent;
280: private Hashtable<String, Object> values;
281: /**
282: * The value of the id attribute of this tag; or null.
283: */
284: protected String id;
285:
286: // protected fields
287:
288: /**
289: * The PageContext.
290: */
291: protected PageContext pageContext;
292: }
|