001 package com.mockrunner.tag; 002 003 import java.util.ArrayList; 004 import java.util.Enumeration; 005 import java.util.HashMap; 006 import java.util.List; 007 import java.util.Map; 008 009 import javax.servlet.jsp.JspException; 010 import javax.servlet.jsp.JspWriter; 011 import javax.servlet.jsp.PageContext; 012 import javax.servlet.jsp.tagext.BodyContent; 013 import javax.servlet.jsp.tagext.BodyTag; 014 import javax.servlet.jsp.tagext.BodyTagSupport; 015 import javax.servlet.jsp.tagext.IterationTag; 016 import javax.servlet.jsp.tagext.JspTag; 017 import javax.servlet.jsp.tagext.SimpleTag; 018 import javax.servlet.jsp.tagext.Tag; 019 import javax.servlet.jsp.tagext.TagSupport; 020 021 import com.mockrunner.mock.web.MockBodyContent; 022 023 /** 024 * Implementation of {@link NestedTag} wrapping tags of 025 * type <code>BodyTag</code>. <code>NestedBodyTag</code> instances 026 * are created with the help of {@link TagTestModule#createNestedTag}. 027 * You do not need to create them on your own in the tests. 028 */ 029 public class NestedBodyTag extends BodyTagSupport implements NestedTag 030 { 031 private BodyTag tag; 032 private PageContext pageContext; 033 private Map attributes; 034 private List childs; 035 private boolean doRelease; 036 037 /** 038 * Constructor for a tag with an empty attribute map. 039 * If the specified tag is not an instance of <code>BodyTagSupport</code>, 040 * the methods that delegate to <code>BodyTagSupport</code> specific methods 041 * throw an exception. 042 * @param tag the tag 043 * @param pageContext the corresponding <code>PageContext</code> 044 */ 045 public NestedBodyTag(BodyTag tag, PageContext pageContext) 046 { 047 this(tag, pageContext, new HashMap()); 048 } 049 050 /** 051 * Constructor for a tag with the specified attribute map. 052 * If the specified tag is not an instance of <code>BodyTagSupport</code>, 053 * the methods that delegate to <code>BodyTagSupport</code> specific methods 054 * throw an exception. 055 * @param tag the tag 056 * @param pageContext the corresponding <code>PageContext</code> 057 * @param attributes the attribute map 058 */ 059 public NestedBodyTag(BodyTag tag, PageContext pageContext, Map attributes) 060 { 061 this.tag = tag; 062 this.pageContext = pageContext; 063 tag.setPageContext(pageContext); 064 childs = new ArrayList(); 065 this.attributes = attributes; 066 doRelease = false; 067 } 068 069 /** 070 * Constructor for a tag with an empty attribute map. 071 * @param tag the tag 072 * @param pageContext the corresponding <code>PageContext</code> 073 */ 074 public NestedBodyTag(BodyTagSupport tag, PageContext pageContext) 075 { 076 this(tag, pageContext, new HashMap()); 077 } 078 079 /** 080 * Constructor for a tag with the specified attribute map. 081 * @param tag the tag 082 * @param pageContext the corresponding <code>PageContext</code> 083 * @param attributes the attribute map 084 */ 085 public NestedBodyTag(BodyTagSupport tag, PageContext pageContext, Map attributes) 086 { 087 this((BodyTag)tag, pageContext, attributes); 088 } 089 090 /** 091 * Implementation of {@link NestedTag#setDoRelease}. 092 */ 093 public void setDoRelease(boolean doRelease) 094 { 095 this.doRelease = doRelease; 096 } 097 098 /** 099 * Implementation of {@link NestedTag#setDoReleaseRecursive}. 100 */ 101 public void setDoReleaseRecursive(boolean doRelease) 102 { 103 this.doRelease = doRelease; 104 for(int ii = 0; ii < childs.size(); ii++) 105 { 106 Object child = childs.get(ii); 107 if(child instanceof NestedTag) 108 { 109 ((NestedTag)child).setDoReleaseRecursive(doRelease); 110 } 111 } 112 } 113 114 /** 115 * Implementation of {@link NestedTag#populateAttributes}. 116 */ 117 public void populateAttributes() 118 { 119 TagUtil.populateTag(tag, attributes, doRelease); 120 } 121 122 /** 123 * Implementation of {@link NestedTag#doLifecycle} for body 124 * tags. 125 */ 126 public int doLifecycle() throws JspException 127 { 128 populateAttributes(); 129 int result = tag.doStartTag(); 130 if(Tag.EVAL_BODY_INCLUDE == result) 131 { 132 TagUtil.evalBody(childs, pageContext); 133 while(IterationTag.EVAL_BODY_AGAIN == doAfterBody()) 134 { 135 TagUtil.evalBody(childs, pageContext); 136 } 137 } 138 else if(BodyTag.EVAL_BODY_BUFFERED == result) 139 { 140 MockBodyContent bodyContent = (MockBodyContent)pageContext.pushBody(); 141 tag.setBodyContent(bodyContent); 142 tag.doInitBody(); 143 TagUtil.evalBody(childs, pageContext); 144 while(IterationTag.EVAL_BODY_AGAIN == doAfterBody()) 145 { 146 TagUtil.evalBody(childs, pageContext); 147 } 148 pageContext.popBody(); 149 } 150 return tag.doEndTag(); 151 } 152 153 /** 154 * Implementation of {@link NestedTag#getTag}. 155 * @throws <code>RuntimeException</code>, if the wrapped tag 156 * is not an instance of <code>TagSupport</code> 157 */ 158 public TagSupport getTag() 159 { 160 checkTagSupport(); 161 return (TagSupport)tag; 162 } 163 164 /** 165 * Implementation of {@link NestedTag#getWrappedTag}. 166 */ 167 public JspTag getWrappedTag() 168 { 169 return tag; 170 } 171 172 /** 173 * Implementation of {@link NestedTag#removeChilds}. 174 */ 175 public void removeChilds() 176 { 177 childs.clear(); 178 } 179 180 /** 181 * Implementation of {@link NestedTag#getChilds}. 182 */ 183 public List getChilds() 184 { 185 return childs; 186 } 187 188 /** 189 * Implementation of {@link NestedTag#getChild}. 190 */ 191 public Object getChild(int index) 192 { 193 return childs.get(index); 194 } 195 196 /** 197 * Implementation of {@link NestedTag#addTextChild}. 198 */ 199 public void addTextChild(String text) 200 { 201 if(null == text) text = ""; 202 childs.add(text); 203 } 204 205 /** 206 * Implementation of {@link NestedTag#addDynamicChild}. 207 */ 208 public void addDynamicChild(DynamicChild child) 209 { 210 if(null == child) return; 211 childs.add(child); 212 } 213 214 /** 215 * Implementation of {@link NestedTag#addTagChild(Class)}. 216 */ 217 public NestedTag addTagChild(Class tag) 218 { 219 return addTagChild(tag, new HashMap()); 220 } 221 222 /** 223 * Implementation of {@link NestedTag#addTagChild(Class, Map)}. 224 */ 225 public NestedTag addTagChild(Class tag, Map attributeMap) 226 { 227 Object childTag = TagUtil.createNestedTagInstance(tag, this.pageContext, attributeMap); 228 return (NestedTag)addChild(childTag); 229 } 230 231 /** 232 * Implementation of {@link NestedTag#addTagChild(TagSupport)}. 233 */ 234 public NestedTag addTagChild(TagSupport tag) 235 { 236 return addTagChild(tag, new HashMap()); 237 } 238 239 /** 240 * Implementation of {@link NestedTag#addTagChild(TagSupport, Map)}. 241 */ 242 public NestedTag addTagChild(TagSupport tag, Map attributeMap) 243 { 244 Object childTag = (Object)TagUtil.createNestedTagInstance(tag, this.pageContext, attributeMap); 245 return (NestedTag)addChild(childTag); 246 } 247 248 /** 249 * Implementation of {@link NestedTag#addTagChild(JspTag)}. 250 */ 251 public NestedTag addTagChild(JspTag tag) 252 { 253 return addTagChild(tag, new HashMap()); 254 } 255 256 /** 257 * Implementation of {@link NestedTag#addTagChild(JspTag, Map)}. 258 */ 259 public NestedTag addTagChild(JspTag tag, Map attributeMap) 260 { 261 Object childTag = TagUtil.createNestedTagInstance(tag, this.pageContext, attributeMap); 262 return (NestedTag)addChild(childTag); 263 } 264 265 /** 266 * Delegates to wrapped tag. 267 */ 268 public int doAfterBody() throws JspException 269 { 270 return tag.doAfterBody(); 271 } 272 273 /** 274 * Delegates to wrapped tag. 275 */ 276 public int doEndTag() throws JspException 277 { 278 return tag.doEndTag(); 279 } 280 281 /** 282 * Delegates to wrapped tag. 283 */ 284 public int doStartTag() throws JspException 285 { 286 return tag.doStartTag(); 287 } 288 289 /** 290 * Delegates to wrapped tag. 291 * @throws <code>RuntimeException</code>, if the wrapped tag 292 * is not an instance of <code>TagSupport</code> 293 */ 294 public String getId() 295 { 296 checkTagSupport(); 297 return ((TagSupport)tag).getId(); 298 } 299 300 /** 301 * Delegates to wrapped tag. 302 */ 303 public Tag getParent() 304 { 305 return tag.getParent(); 306 } 307 308 /** 309 * Delegates to wrapped tag. 310 * @throws <code>RuntimeException</code>, if the wrapped tag 311 * is not an instance of <code>TagSupport</code> 312 */ 313 public Object getValue(String key) 314 { 315 checkTagSupport(); 316 return ((TagSupport)tag).getValue(key); 317 } 318 319 /** 320 * Delegates to wrapped tag. 321 * @throws <code>RuntimeException</code>, if the wrapped tag 322 * is not an instance of <code>TagSupport</code> 323 */ 324 public Enumeration getValues() 325 { 326 checkTagSupport(); 327 return ((TagSupport)tag).getValues(); 328 } 329 330 /** 331 * Delegates to wrapped tag. 332 */ 333 public void release() 334 { 335 tag.release(); 336 } 337 338 /** 339 * Delegates to wrapped tag. 340 * @throws <code>RuntimeException</code>, if the wrapped tag 341 * is not an instance of <code>TagSupport</code> 342 */ 343 public void removeValue(String value) 344 { 345 checkTagSupport(); 346 ((TagSupport)tag).removeValue(value); 347 } 348 349 /** 350 * Delegates to wrapped tag. 351 * @throws <code>RuntimeException</code>, if the wrapped tag 352 * is not an instance of <code>TagSupport</code> 353 */ 354 public void setId(String id) 355 { 356 checkTagSupport(); 357 ((TagSupport)tag).setId(id); 358 } 359 360 /** 361 * Delegates to wrapped tag. Also calls <code>setPageContext</code> 362 * for all child tags. 363 */ 364 public void setPageContext(PageContext pageContext) 365 { 366 this.pageContext = pageContext; 367 tag.setPageContext(pageContext); 368 for(int ii = 0; ii < childs.size(); ii++) 369 { 370 Object child = childs.get(ii); 371 if(child instanceof Tag) 372 { 373 ((Tag)child).setPageContext(pageContext); 374 } 375 else if(child instanceof SimpleTag) 376 { 377 ((SimpleTag)child).setJspContext(pageContext); 378 } 379 } 380 } 381 382 /** 383 * Delegates to wrapped tag. 384 */ 385 public void setParent(Tag parent) 386 { 387 tag.setParent(parent); 388 } 389 390 /** 391 * Delegates to wrapped tag. 392 * @throws <code>RuntimeException</code>, if the wrapped tag 393 * is not an instance of <code>TagSupport</code> 394 */ 395 public void setValue(String key, Object value) 396 { 397 checkTagSupport(); 398 ((TagSupport)tag).setValue(key, value); 399 } 400 401 /** 402 * Delegates to wrapped tag. 403 */ 404 public void doInitBody() throws JspException 405 { 406 tag.doInitBody(); 407 } 408 409 /** 410 * Delegates to wrapped tag. 411 * @throws <code>RuntimeException</code>, if the wrapped tag 412 * is not an instance of <code>BodyTagSupport</code> 413 */ 414 public BodyContent getBodyContent() 415 { 416 checkTagSupport(); 417 return ((BodyTagSupport)tag).getBodyContent(); 418 } 419 420 /** 421 * Delegates to wrapped tag. 422 * @throws <code>RuntimeException</code>, if the wrapped tag 423 * is not an instance of <code>BodyTagSupport</code> 424 */ 425 public JspWriter getPreviousOut() 426 { 427 checkTagSupport(); 428 return ((BodyTagSupport)tag).getPreviousOut(); 429 } 430 431 /** 432 * Delegates to wrapped tag. 433 */ 434 public void setBodyContent(BodyContent content) 435 { 436 tag.setBodyContent(content); 437 } 438 439 /** 440 * Dumps the content of this and the nested tags. 441 */ 442 public String toString() 443 { 444 return TagUtil.dumpTag(this, new StringBuffer(), 0); 445 } 446 447 private NestedTag addChild(Object childTag) 448 { 449 if(childTag instanceof Tag) 450 { 451 ((Tag)childTag).setParent(this.tag); 452 } 453 else if(childTag instanceof SimpleTag) 454 { 455 ((SimpleTag)childTag).setParent(this.tag); 456 } 457 childs.add(childTag); 458 return (NestedTag)childTag; 459 } 460 461 private void checkTagSupport() 462 { 463 if(!(tag instanceof BodyTagSupport)) 464 { 465 throw new RuntimeException("This method can only be called if the wrapped tag is an instance of BodyTagSupport."); 466 } 467 } 468 }