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