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 }