001 /*
002 * Copyright 2004 The Apache Software Foundation
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package javax.servlet.jsp.tagext;
017
018 import javax.servlet.jsp.JspContext;
019 import javax.servlet.jsp.JspException;
020 import java.io.IOException;
021
022 /**
023 * A base class for defining tag handlers implementing SimpleTag.
024 * <p>
025 * The SimpleTagSupport class is a utility class intended to be used
026 * as the base class for new simple tag handlers. The SimpleTagSupport
027 * class implements the SimpleTag interface and adds additional
028 * convenience methods including getter methods for the properties in
029 * SimpleTag.
030 *
031 * @since 2.0
032 */
033 public class SimpleTagSupport implements SimpleTag {
034 /** Reference to the enclosing tag. */
035 private JspTag parentTag;
036
037 /** The JSP context for the upcoming tag invocation. */
038 private JspContext jspContext;
039
040 /** The body of the tag. */
041 private JspFragment jspBody;
042
043 /**
044 * Sole constructor. (For invocation by subclass constructors,
045 * typically implicit.)
046 */
047 public SimpleTagSupport() {
048 }
049
050 /**
051 * Default processing of the tag does nothing.
052 *
053 * @throws JspException Subclasses can throw JspException to indicate
054 * an error occurred while processing this tag.
055 * @throws javax.servlet.jsp.SkipPageException If the page that
056 * (either directly or indirectly) invoked this tag is to
057 * cease evaluation. A Simple Tag Handler generated from a
058 * tag file must throw this exception if an invoked Classic
059 * Tag Handler returned SKIP_PAGE or if an invoked Simple
060 * Tag Handler threw SkipPageException or if an invoked Jsp Fragment
061 * threw a SkipPageException.
062 * @throws IOException Subclasses can throw IOException if there was
063 * an error writing to the output stream
064 * @see SimpleTag#doTag()
065 */
066 public void doTag() throws JspException, IOException {
067 }
068
069 /**
070 * Sets the parent of this tag, for collaboration purposes.
071 * <p>
072 * The container invokes this method only if this tag invocation is
073 * nested within another tag invocation.
074 *
075 * @param parent the tag that encloses this tag
076 */
077 public void setParent(JspTag parent) {
078 this .parentTag = parent;
079 }
080
081 /**
082 * Returns the parent of this tag, for collaboration purposes.
083 *
084 * @return the parent of this tag
085 */
086 public JspTag getParent() {
087 return this .parentTag;
088 }
089
090 /**
091 * Stores the provided JSP context in the private jspContext field.
092 * Subclasses can access the <code>JspContext</code> via
093 * <code>getJspContext()</code>.
094 *
095 * @param pc the page context for this invocation
096 * @see SimpleTag#setJspContext
097 */
098 public void setJspContext(JspContext pc) {
099 this .jspContext = pc;
100 }
101
102 /**
103 * Returns the page context passed in by the container via
104 * setJspContext.
105 *
106 * @return the page context for this invocation
107 */
108 protected JspContext getJspContext() {
109 return this .jspContext;
110 }
111
112 /**
113 * Stores the provided JspFragment.
114 *
115 * @param jspBody The fragment encapsulating the body of this tag.
116 * If the action element is empty in the page, this method is
117 * not called at all.
118 * @see SimpleTag#setJspBody
119 */
120 public void setJspBody(JspFragment jspBody) {
121 this .jspBody = jspBody;
122 }
123
124 /**
125 * Returns the body passed in by the container via setJspBody.
126 *
127 * @return the fragment encapsulating the body of this tag, or
128 * null if the action element is empty in the page.
129 */
130 protected JspFragment getJspBody() {
131 return this .jspBody;
132 }
133
134 /**
135 * Find the instance of a given class type that is closest to a given
136 * instance.
137 * This method uses the getParent method from the Tag and/or SimpleTag
138 * interfaces. This method is used for coordination among
139 * cooperating tags.
140 *
141 * <p> For every instance of TagAdapter
142 * encountered while traversing the ancestors, the tag handler returned by
143 * <tt>TagAdapter.getAdaptee()</tt> - instead of the TagAdpater itself -
144 * is compared to <tt>klass</tt>. If the tag handler matches, it - and
145 * not its TagAdapter - is returned.
146 *
147 * <p>
148 * The current version of the specification only provides one formal
149 * way of indicating the observable type of a tag handler: its
150 * tag handler implementation class, described in the tag-class
151 * subelement of the tag element. This is extended in an
152 * informal manner by allowing the tag library author to
153 * indicate in the description subelement an observable type.
154 * The type should be a subtype of the tag handler implementation
155 * class or void.
156 * This addititional constraint can be exploited by a
157 * specialized container that knows about that specific tag library,
158 * as in the case of the JSP standard tag library.
159 *
160 * <p>
161 * When a tag library author provides information on the
162 * observable type of a tag handler, client programmatic code
163 * should adhere to that constraint. Specifically, the Class
164 * passed to findAncestorWithClass should be a subtype of the
165 * observable type.
166 *
167 *
168 * @param from The instance from where to start looking.
169 * @param klass The subclass of JspTag or interface to be matched
170 * @return the nearest ancestor that implements the interface
171 * or is an instance of the class specified
172 */
173 public static final JspTag findAncestorWithClass(JspTag from,
174 Class klass) {
175 boolean isInterface = false;
176
177 if (from == null
178 || klass == null
179 || (!JspTag.class.isAssignableFrom(klass) && !(isInterface = klass
180 .isInterface()))) {
181 return null;
182 }
183
184 for (;;) {
185 JspTag parent = null;
186 if (from instanceof SimpleTag) {
187 parent = ((SimpleTag) from).getParent();
188 } else if (from instanceof Tag) {
189 parent = ((Tag) from).getParent();
190 }
191 if (parent == null) {
192 return null;
193 }
194
195 if (parent instanceof TagAdapter) {
196 parent = ((TagAdapter) parent).getAdaptee();
197 }
198
199 if ((isInterface && klass.isInstance(parent))
200 || klass.isAssignableFrom(parent.getClass())) {
201 return parent;
202 }
203
204 from = parent;
205 }
206 }
207 }
|