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