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