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