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