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 * @inheritDoc 092 */ 093 public void setDoRelease(boolean doRelease) 094 { 095 this.doRelease = doRelease; 096 } 097 098 /** 099 * @inheritDoc 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 * @inheritDoc 116 */ 117 public void populateAttributes() 118 { 119 TagUtil.populateTag(tag, attributes); 120 } 121 122 /** 123 * @inheritDoc 124 */ 125 public int doLifecycle() throws JspException 126 { 127 populateAttributes(); 128 int returnValue = -1; 129 try 130 { 131 int result = tag.doStartTag(); 132 if(Tag.EVAL_BODY_INCLUDE == result) 133 { 134 TagUtil.evalBody(childs, pageContext); 135 while(IterationTag.EVAL_BODY_AGAIN == doAfterBody()) 136 { 137 TagUtil.evalBody(childs, pageContext); 138 } 139 } 140 else if(BodyTag.EVAL_BODY_BUFFERED == result) 141 { 142 MockBodyContent bodyContent = (MockBodyContent)pageContext.pushBody(); 143 tag.setBodyContent(bodyContent); 144 tag.doInitBody(); 145 TagUtil.evalBody(childs, pageContext); 146 while(IterationTag.EVAL_BODY_AGAIN == doAfterBody()) 147 { 148 TagUtil.evalBody(childs, pageContext); 149 } 150 pageContext.popBody(); 151 } 152 returnValue = tag.doEndTag(); 153 } 154 catch(Throwable exc) 155 { 156 TagUtil.handleException(tag, exc); 157 } 158 finally 159 { 160 TagUtil.handleFinally(tag); 161 } 162 if(doRelease) tag.release(); 163 return returnValue; 164 } 165 166 /** 167 * @inheritDoc 168 * @throws <code>RuntimeException</code>, if the wrapped tag 169 * is not an instance of <code>TagSupport</code> 170 */ 171 public TagSupport getTag() 172 { 173 checkTagSupport(); 174 return (TagSupport)tag; 175 } 176 177 /** 178 * @inheritDoc 179 */ 180 public JspTag getWrappedTag() 181 { 182 return tag; 183 } 184 185 /** 186 * @inheritDoc 187 */ 188 public void removeChilds() 189 { 190 childs.clear(); 191 } 192 193 /** 194 * @inheritDoc 195 */ 196 public List getChilds() 197 { 198 return childs; 199 } 200 201 /** 202 * @inheritDoc 203 */ 204 public Object getChild(int index) 205 { 206 return childs.get(index); 207 } 208 209 /** 210 * @inheritDoc 211 */ 212 public void addTextChild(String text) 213 { 214 if(null == text) text = ""; 215 childs.add(text); 216 } 217 218 /** 219 * @inheritDoc 220 */ 221 public void addDynamicChild(DynamicChild child) 222 { 223 if(null == child) return; 224 childs.add(child); 225 } 226 227 /** 228 * @inheritDoc 229 */ 230 public NestedTag addTagChild(Class tag) 231 { 232 return addTagChild(tag, new HashMap()); 233 } 234 235 /** 236 * @inheritDoc 237 */ 238 public NestedTag addTagChild(Class tag, Map attributeMap) 239 { 240 Object childTag = TagUtil.createNestedTagInstance(tag, this.pageContext, attributeMap); 241 return (NestedTag)addChild(childTag); 242 } 243 244 /** 245 * @inheritDoc 246 */ 247 public NestedTag addTagChild(TagSupport tag) 248 { 249 return addTagChild(tag, new HashMap()); 250 } 251 252 /** 253 * @inheritDoc 254 */ 255 public NestedTag addTagChild(TagSupport tag, Map attributeMap) 256 { 257 Object childTag = (Object)TagUtil.createNestedTagInstance(tag, this.pageContext, attributeMap); 258 return (NestedTag)addChild(childTag); 259 } 260 261 /** 262 * @inheritDoc 263 */ 264 public NestedTag addTagChild(JspTag tag) 265 { 266 return addTagChild(tag, new HashMap()); 267 } 268 269 /** 270 * @inheritDoc 271 */ 272 public NestedTag addTagChild(JspTag tag, Map attributeMap) 273 { 274 Object childTag = TagUtil.createNestedTagInstance(tag, this.pageContext, attributeMap); 275 return (NestedTag)addChild(childTag); 276 } 277 278 /** 279 * Delegates to wrapped tag. 280 */ 281 public int doAfterBody() throws JspException 282 { 283 return tag.doAfterBody(); 284 } 285 286 /** 287 * Delegates to wrapped tag. 288 */ 289 public int doEndTag() throws JspException 290 { 291 return tag.doEndTag(); 292 } 293 294 /** 295 * Delegates to wrapped tag. 296 */ 297 public int doStartTag() throws JspException 298 { 299 return tag.doStartTag(); 300 } 301 302 /** 303 * Delegates to wrapped tag. 304 * @throws <code>RuntimeException</code>, if the wrapped tag 305 * is not an instance of <code>TagSupport</code> 306 */ 307 public String getId() 308 { 309 checkTagSupport(); 310 return ((TagSupport)tag).getId(); 311 } 312 313 /** 314 * Delegates to wrapped tag. 315 */ 316 public Tag getParent() 317 { 318 return tag.getParent(); 319 } 320 321 /** 322 * Delegates to wrapped tag. 323 * @throws <code>RuntimeException</code>, if the wrapped tag 324 * is not an instance of <code>TagSupport</code> 325 */ 326 public Object getValue(String key) 327 { 328 checkTagSupport(); 329 return ((TagSupport)tag).getValue(key); 330 } 331 332 /** 333 * Delegates to wrapped tag. 334 * @throws <code>RuntimeException</code>, if the wrapped tag 335 * is not an instance of <code>TagSupport</code> 336 */ 337 public Enumeration getValues() 338 { 339 checkTagSupport(); 340 return ((TagSupport)tag).getValues(); 341 } 342 343 /** 344 * Delegates to wrapped tag. 345 */ 346 public void release() 347 { 348 tag.release(); 349 } 350 351 /** 352 * Delegates to wrapped tag. 353 * @throws <code>RuntimeException</code>, if the wrapped tag 354 * is not an instance of <code>TagSupport</code> 355 */ 356 public void removeValue(String value) 357 { 358 checkTagSupport(); 359 ((TagSupport)tag).removeValue(value); 360 } 361 362 /** 363 * Delegates to wrapped tag. 364 * @throws <code>RuntimeException</code>, if the wrapped tag 365 * is not an instance of <code>TagSupport</code> 366 */ 367 public void setId(String id) 368 { 369 checkTagSupport(); 370 ((TagSupport)tag).setId(id); 371 } 372 373 /** 374 * Delegates to wrapped tag. Also calls <code>setPageContext</code> 375 * for all child tags. 376 */ 377 public void setPageContext(PageContext pageContext) 378 { 379 this.pageContext = pageContext; 380 tag.setPageContext(pageContext); 381 for(int ii = 0; ii < childs.size(); ii++) 382 { 383 Object child = childs.get(ii); 384 if(child instanceof Tag) 385 { 386 ((Tag)child).setPageContext(pageContext); 387 } 388 else if(child instanceof SimpleTag) 389 { 390 ((SimpleTag)child).setJspContext(pageContext); 391 } 392 } 393 } 394 395 /** 396 * Delegates to wrapped tag. 397 */ 398 public void setParent(Tag parent) 399 { 400 tag.setParent(parent); 401 } 402 403 /** 404 * Delegates to wrapped tag. 405 * @throws <code>RuntimeException</code>, if the wrapped tag 406 * is not an instance of <code>TagSupport</code> 407 */ 408 public void setValue(String key, Object value) 409 { 410 checkTagSupport(); 411 ((TagSupport)tag).setValue(key, value); 412 } 413 414 /** 415 * Delegates to wrapped tag. 416 */ 417 public void doInitBody() throws JspException 418 { 419 tag.doInitBody(); 420 } 421 422 /** 423 * Delegates to wrapped tag. 424 * @throws <code>RuntimeException</code>, if the wrapped tag 425 * is not an instance of <code>BodyTagSupport</code> 426 */ 427 public BodyContent getBodyContent() 428 { 429 checkTagSupport(); 430 return ((BodyTagSupport)tag).getBodyContent(); 431 } 432 433 /** 434 * Delegates to wrapped tag. 435 * @throws <code>RuntimeException</code>, if the wrapped tag 436 * is not an instance of <code>BodyTagSupport</code> 437 */ 438 public JspWriter getPreviousOut() 439 { 440 checkTagSupport(); 441 return ((BodyTagSupport)tag).getPreviousOut(); 442 } 443 444 /** 445 * Delegates to wrapped tag. 446 */ 447 public void setBodyContent(BodyContent content) 448 { 449 tag.setBodyContent(content); 450 } 451 452 /** 453 * Dumps the content of this and the nested tags. 454 */ 455 public String toString() 456 { 457 return TagUtil.dumpTag(this, new StringBuffer(), 0); 458 } 459 460 private NestedTag addChild(Object childTag) 461 { 462 if(childTag instanceof Tag) 463 { 464 ((Tag)childTag).setParent(this.tag); 465 } 466 else if(childTag instanceof SimpleTag) 467 { 468 ((SimpleTag)childTag).setParent(this.tag); 469 } 470 childs.add(childTag); 471 return (NestedTag)childTag; 472 } 473 474 private void checkTagSupport() 475 { 476 if(!(tag instanceof BodyTagSupport)) 477 { 478 throw new RuntimeException("This method can only be called if the wrapped tag is an instance of BodyTagSupport."); 479 } 480 } 481 }