001    package com.mockrunner.tag;
002    
003    import java.io.IOException;
004    import java.util.HashMap;
005    import java.util.List;
006    import java.util.Map;
007    
008    import javax.servlet.jsp.JspContext;
009    import javax.servlet.jsp.JspException;
010    import javax.servlet.jsp.tagext.JspFragment;
011    import javax.servlet.jsp.tagext.JspTag;
012    import javax.servlet.jsp.tagext.SimpleTag;
013    import javax.servlet.jsp.tagext.SimpleTagSupport;
014    import javax.servlet.jsp.tagext.TagSupport;
015    
016    import com.mockrunner.base.NestedApplicationException;
017    import com.mockrunner.mock.web.MockJspFragment;
018    
019    /**
020     * Implementation of {@link NestedTag} wrapping tags of
021     * type <code>SimpleTag</code>. <code>NestedSimpleTag</code> instances 
022     * are created with the help of {@link TagTestModule#createNestedTag}. 
023     * You do not need to create them on your own in the tests.
024     */
025    public class NestedSimpleTag extends SimpleTagSupport implements NestedTag
026    {
027        private SimpleTag tag;
028        private JspContext jspContext;
029        private JspFragment jspBody;
030        private Map attributes;
031        
032        /**
033         * Constructor for a tag with an empty attribute map.
034         * @param tag the tag
035         * @param jspContext the corresponding <code>JspContext</code>
036         */
037        public NestedSimpleTag(SimpleTag tag, JspContext jspContext)
038        {
039            this(tag, jspContext, new HashMap());
040        }
041        
042        /**
043         * Constructor for a tag with the specified attribute map.
044         * @param tag the tag
045         * @param jspContext the corresponding <code>JspContext</code>
046         * @param attributes the attribute map
047         */
048        public NestedSimpleTag(SimpleTag tag, JspContext jspContext, Map attributes)
049        {
050            this.tag = tag;
051            this.jspContext = jspContext;
052            jspBody = new MockJspFragment(jspContext, tag);
053            tag.setJspContext(jspContext);
054            tag.setJspBody(jspBody);
055            this.attributes = attributes;
056        }
057        
058        /**
059         * Constructor for a tag with an empty attribute map.
060         * @param tag the tag
061         * @param jspContext the corresponding <code>JspContext</code>
062         */
063        public NestedSimpleTag(SimpleTagSupport tag, JspContext jspContext)
064        {
065            this(tag, jspContext, new HashMap());
066        }
067        
068        /**
069         * Constructor for a tag with the specified attribute map.
070         * @param tag the tag
071         * @param jspContext the corresponding <code>JspContext</code>
072         * @param attributes the attribute map
073         */
074        public NestedSimpleTag(SimpleTagSupport tag, JspContext jspContext, Map attributes)
075        {
076            this((SimpleTag)tag, jspContext, attributes);
077        }
078        
079        /**
080         * Implementation of {@link NestedTag#setDoRelease}.
081         * Does nothing in this case.
082         */
083        public void setDoRelease(boolean doRelease)
084        {
085    
086        }
087        
088        /**
089         * Implementation of {@link NestedTag#setDoReleaseRecursive}.
090         * Does nothing in this case.
091         */
092        public void setDoReleaseRecursive(boolean doRelease)
093        {
094            
095        }
096        
097        /**
098         * @inheritDoc
099         */
100        public void populateAttributes()
101        {
102            TagUtil.populateTag(tag, attributes);
103        }
104        
105        /**
106         * Implementation of {@link NestedTag#doLifecycle} for simple
107         * tags. Returns <code>-1</code> in this case, because
108         * <code>doTag()</code> does not have a return value.
109         */
110        public int doLifecycle() throws JspException
111        {
112            try
113            {
114                populateAttributes();
115                tag.doTag();
116            } 
117            catch(IOException exc)
118            {
119                throw new NestedApplicationException(exc);
120            }
121            return -1;
122        }
123        
124        /**
125         * Implementation of {@link NestedTag#getTag}.
126         * Should not be called and throws a <code>RuntimeException</code>,
127         * because a simple tag is not an instance of <code>TagSupport</code>.
128         */
129        public TagSupport getTag()
130        {
131            throw new RuntimeException("getTag() method cannot be called for simple tags.");
132        }
133        
134        /**
135         * @inheritDoc
136         */
137        public JspTag getWrappedTag()
138        {
139            return tag;
140        }
141        
142        /**
143         * @inheritDoc
144         */
145        public void removeChilds()
146        {
147            if(null != jspBody && jspBody instanceof MockJspFragment)
148            {
149                ((MockJspFragment)jspBody).removeChilds();
150            }
151        }
152        
153        /**
154         * @inheritDoc
155         */
156        public List getChilds()
157        {
158            if(null != jspBody && jspBody instanceof MockJspFragment)
159            {
160                return ((MockJspFragment)jspBody).getChilds();
161            }
162            return null;
163        }
164        
165        /**
166         * @inheritDoc
167         */
168        public Object getChild(int index)
169        {
170            if(null != jspBody && jspBody instanceof MockJspFragment)
171            {
172                return ((MockJspFragment)jspBody).getChild(index);
173            }
174            return null;
175        }
176        
177        /**
178         * @inheritDoc
179         */
180        public void addTextChild(String text)
181        {
182            if(null != jspBody && jspBody instanceof MockJspFragment)
183            {
184                ((MockJspFragment)jspBody).addTextChild(text);
185            }
186        }
187        
188        /**
189         * @inheritDoc
190         */
191        public void addDynamicChild(DynamicChild child)
192        {
193            if(null != jspBody && jspBody instanceof MockJspFragment)
194            {
195                ((MockJspFragment)jspBody).addDynamicChild(child);
196            }
197        }
198        
199        /**
200         * @inheritDoc
201         */
202        public NestedTag addTagChild(Class tag)
203        {
204            if(null != jspBody && jspBody instanceof MockJspFragment)
205            {
206                return ((MockJspFragment)jspBody).addTagChild(tag);
207            }
208            return null;
209        }
210        
211        /**
212         * @inheritDoc
213         */
214        public NestedTag addTagChild(Class tag, Map attributeMap)
215        {
216            if(null != jspBody && jspBody instanceof MockJspFragment)
217            {
218                return ((MockJspFragment)jspBody).addTagChild(tag, attributeMap);
219            }
220            return null;
221        }
222        
223        /**
224         * @inheritDoc
225         */
226        public NestedTag addTagChild(TagSupport tag)
227        {
228            return addTagChild(tag, new HashMap());
229        }
230        
231        /**
232         * @inheritDoc
233         */
234        public NestedTag addTagChild(TagSupport tag, Map attributeMap)
235        {
236            return addTagChild((JspTag)tag, attributeMap);
237        }
238        
239        /**
240         * @inheritDoc
241         */
242        public NestedTag addTagChild(JspTag tag)
243        {
244            if(null != jspBody && jspBody instanceof MockJspFragment)
245            {
246                return ((MockJspFragment)jspBody).addTagChild(tag);
247            }
248            return null;
249        }
250        
251        /**
252         * @inheritDoc
253         */
254        public NestedTag addTagChild(JspTag tag, Map attributeMap)
255        {
256            if(null != jspBody && jspBody instanceof MockJspFragment)
257            {
258                return ((MockJspFragment)jspBody).addTagChild(tag, attributeMap);
259            }
260            return null;
261        }
262        
263        /**
264         * Delegates to wrapped tag.
265         */
266        public void doTag() throws JspException, IOException
267        {
268            tag.doTag();
269        }
270        
271        /**
272         * Returns the body fragment.
273         * @return the body fragment
274         */
275        public JspFragment getJspBody()
276        {
277            return jspBody;
278        }
279        
280        /**
281         * Returns the <code>JspContext</code>.
282         * @return the <code>JspContext</code>
283         */
284        public JspContext getJspContext()
285        {
286            return jspContext;
287        }
288        
289        /**
290         * Delegates to wrapped tag.
291         */
292        public JspTag getParent()
293        {
294            return tag.getParent();
295        }
296        
297        /**
298         * Delegates to wrapped tag.
299         */
300        public void setJspBody(JspFragment jspBody)
301        {
302            this.jspBody = jspBody;
303            tag.setJspBody(jspBody);
304        }
305        
306        /**
307         * Delegates to wrapped tag. Also calls <code>setJspContext</code>
308         * on the body fragment, if the body fragment is an instance of
309         * {@link com.mockrunner.mock.web.MockJspFragment}
310         */
311        public void setJspContext(JspContext jspContext)
312        {
313            this.jspContext = jspContext;
314            tag.setJspContext(jspContext);
315            if(null != jspBody && jspBody instanceof MockJspFragment)
316            {
317               ((MockJspFragment)jspBody).setJspContext(jspContext);
318            }
319        }
320        
321        /**
322         * Delegates to wrapped tag.
323         */
324        public void setParent(JspTag parent)
325        {
326            tag.setParent(parent);
327        }
328        
329        /**
330         * Dumps the content of this and the nested tags.
331         */
332        public String toString()
333        {
334            return TagUtil.dumpTag(this, new StringBuffer(), 0);
335        }
336    }