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 035 implements SimpleTag 036 { 037 /** Reference to the enclosing tag. */ 038 private JspTag parentTag; 039 040 /** The JSP context for the upcoming tag invocation. */ 041 private JspContext jspContext; 042 043 /** The body of the tag. */ 044 private JspFragment jspBody; 045 046 /** 047 * Sole constructor. (For invocation by subclass constructors, 048 * typically implicit.) 049 */ 050 public SimpleTagSupport() { 051 } 052 053 /** 054 * Default processing of the tag does nothing. 055 * 056 * @throws JspException Subclasses can throw JspException to indicate 057 * an error occurred while processing this tag. 058 * @throws javax.servlet.jsp.SkipPageException If the page that 059 * (either directly or indirectly) invoked this tag is to 060 * cease evaluation. A Simple Tag Handler generated from a 061 * tag file must throw this exception if an invoked Classic 062 * Tag Handler returned SKIP_PAGE or if an invoked Simple 063 * Tag Handler threw SkipPageException or if an invoked Jsp Fragment 064 * threw a SkipPageException. 065 * @throws IOException Subclasses can throw IOException if there was 066 * an error writing to the output stream 067 * @see SimpleTag#doTag() 068 */ 069 public void doTag() 070 throws JspException, IOException 071 { 072 } 073 074 /** 075 * Sets the parent of this tag, for collaboration purposes. 076 * <p> 077 * The container invokes this method only if this tag invocation is 078 * nested within another tag invocation. 079 * 080 * @param parent the tag that encloses this tag 081 */ 082 public void setParent( JspTag parent ) { 083 this.parentTag = parent; 084 } 085 086 /** 087 * Returns the parent of this tag, for collaboration purposes. 088 * 089 * @return the parent of this tag 090 */ 091 public JspTag getParent() { 092 return this.parentTag; 093 } 094 095 /** 096 * Stores the provided JSP context in the private jspContext field. 097 * Subclasses can access the <code>JspContext</code> via 098 * <code>getJspContext()</code>. 099 * 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 }