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 }