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