View Javadoc

1   /**
2    *
3    * Copyright 2003-2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  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  
18  //
19  // This source code implements specifications defined by the Java
20  // Community Process. In order to remain compliant with the specification
21  // DO NOT add / change / or delete method signatures!
22  //
23  
24  package javax.servlet.jsp.tagext;
25  
26  import java.io.IOException;
27  
28  import javax.servlet.jsp.JspContext;
29  import javax.servlet.jsp.JspException;
30  
31  /**
32   * A base class for defining tag handlers implementing SimpleTag.
33   * <p>
34   * The SimpleTagSupport class is a utility class intended to be used
35   * as the base class for new simple tag handlers.  The SimpleTagSupport
36   * class implements the SimpleTag interface and adds additional
37   * convenience methods including getter methods for the properties in
38   * SimpleTag.
39   *
40   * @since 2.0
41   */
42  public class SimpleTagSupport 
43      implements SimpleTag
44  {
45      /** Reference to the enclosing tag. */
46      private JspTag parentTag;
47      
48      /** The JSP context for the upcoming tag invocation. */
49      private JspContext jspContext;
50      
51      /** The body of the tag. */
52      private JspFragment jspBody;
53      
54      /**
55       * Sole constructor. (For invocation by subclass constructors, 
56       * typically implicit.)
57       */
58      public SimpleTagSupport() {
59      }
60      
61      /** 
62       * Default processing of the tag does nothing.
63       *
64       * @throws JspException Subclasses can throw JspException to indicate
65       *     an error occurred while processing this tag.
66       * @throws javax.servlet.jsp.SkipPageException If the page that
67       *     (either directly or indirectly) invoked this tag is to
68       *     cease evaluation.  A Simple Tag EventHandler generated from a 
69       *     tag file must throw this exception if an invoked Classic 
70       *     Tag EventHandler returned SKIP_PAGE or if an invoked Simple
71       *     Tag EventHandler threw SkipPageException or if an invoked Jsp Fragment
72       *     threw a SkipPageException.
73       * @throws IOException Subclasses can throw IOException if there was
74       *     an error writing to the output stream
75       * @see SimpleTag#doTag()
76       */ 
77      public void doTag() 
78          throws JspException, IOException
79      {
80      }
81      
82      /**
83       * Sets the parent of this tag, for collaboration purposes.
84       * <p>
85       * The container invokes this method only if this tag invocation is
86       * nested within another tag invocation.
87       *
88       * @param parent the tag that encloses this tag
89       */
90      public void setParent( JspTag parent ) {
91          this.parentTag = parent;
92      }
93      
94      /**
95       * Returns the parent of this tag, for collaboration purposes.
96       *
97       * @return the parent of this tag
98       */ 
99      public JspTag getParent() {
100         return this.parentTag;
101     }
102     
103     /**
104      * Stores the provided JSP context in the private jspContext field.
105      * Subclasses can access the <code>JspContext</code> via 
106      * <code>getJspContext()</code>.
107      * 
108      * @param pc the page context for this invocation
109      * @see SimpleTag#setJspContext
110      */
111     public void setJspContext( JspContext pc ) {
112         this.jspContext = pc;
113     }
114     
115     /**
116      * Returns the page context passed in by the container via 
117      * setJspContext.
118      *
119      * @return the page context for this invocation
120      */
121     protected JspContext getJspContext() {
122         return this.jspContext;
123     }
124                 
125     /** 
126      * Stores the provided JspFragment.
127      *
128      * @param jspBody The fragment encapsulating the body of this tag.
129      *     If the action element is empty in the page, this method is 
130      *     not called at all.
131      * @see SimpleTag#setJspBody
132      */ 
133     public void setJspBody( JspFragment jspBody ) {
134         this.jspBody = jspBody;
135     }
136     
137     /**
138      * Returns the body passed in by the container via setJspBody.
139      *
140      * @return the fragment encapsulating the body of this tag, or
141      *    null if the action element is empty in the page.
142      */
143     protected JspFragment getJspBody() {
144         return this.jspBody;
145     }
146 
147     /**
148      * Find the instance of a given class type that is closest to a given
149      * instance.
150      * This method uses the getParent method from the Tag and/or SimpleTag
151      * interfaces.  This method is used for coordination among 
152      * cooperating tags.
153      *
154      * <p> For every instance of TagAdapter
155      * encountered while traversing the ancestors, the tag handler returned by
156      * <tt>TagAdapter.getAdaptee()</tt> - instead of the TagAdpater itself -
157      * is compared to <tt>klass</tt>. If the tag handler matches, it - and
158      * not its TagAdapter - is returned.
159      *
160      * <p>
161      * The current version of the specification only provides one formal
162      * way of indicating the observable type of a tag handler: its
163      * tag handler implementation class, described in the tag-class
164      * subelement of the tag element.  This is extended in an
165      * informal manner by allowing the tag library author to
166      * indicate in the description subelement an observable type.
167      * The type should be a subtype of the tag handler implementation
168      * class or void.
169      * This addititional constraint can be exploited by a
170      * specialized container that knows about that specific tag library,
171      * as in the case of the JSP standard tag library.
172      *
173      * <p>
174      * When a tag library author provides information on the
175      * observable type of a tag handler, client programmatic code
176      * should adhere to that constraint.  Specifically, the Class
177      * passed to findAncestorWithClass should be a subtype of the
178      * observable type.
179      * 
180      *
181      * @param from The instance from where to start looking.
182      * @param klass The subclass of JspTag or interface to be matched
183      * @return the nearest ancestor that implements the interface
184      * or is an instance of the class specified
185      */
186     public static final JspTag findAncestorWithClass(
187 	JspTag from, Class klass) 
188     {
189 	boolean isInterface = false;
190 
191 	if (from == null || klass == null
192 	        || (!JspTag.class.isAssignableFrom(klass)
193 		    && !(isInterface = klass.isInterface()))) {
194 	    return null;
195 	}
196 
197 	for (;;) {
198 	    JspTag parent = null;
199 	    if( from instanceof SimpleTag ) {
200 		parent = ((SimpleTag)from).getParent();
201 	    }
202 	    else if( from instanceof Tag ) {
203 		parent = ((Tag)from).getParent();
204 	    }
205 	    if (parent == null) {
206 		return null;
207 	    }
208 
209 	    if (parent instanceof TagAdapter) {
210 		parent = ((TagAdapter) parent).getAdaptee();
211 	    }
212 
213 	    if ((isInterface && klass.isInstance(parent))
214 		    || klass.isAssignableFrom(parent.getClass())) {
215 		return parent;
216 	    }
217 
218 	    from = parent;
219 	}
220     }    
221 }