001 package com.mockrunner.mock.web;
002
003 import java.io.IOException;
004 import java.io.Writer;
005 import java.util.ArrayList;
006 import java.util.HashMap;
007 import java.util.List;
008 import java.util.Map;
009
010 import javax.servlet.jsp.JspContext;
011 import javax.servlet.jsp.JspException;
012 import javax.servlet.jsp.PageContext;
013 import javax.servlet.jsp.tagext.JspFragment;
014 import javax.servlet.jsp.tagext.JspTag;
015 import javax.servlet.jsp.tagext.SimpleTag;
016 import javax.servlet.jsp.tagext.Tag;
017 import javax.servlet.jsp.tagext.TagAdapter;
018
019 import com.mockrunner.tag.DynamicChild;
020 import com.mockrunner.tag.NestedTag;
021 import com.mockrunner.tag.TagUtil;
022
023
024 /**
025 * Mock implementation of <code>JspFragment</code>.
026 * The body of a simple tag is a <code>JspFragment</code>.
027 * All child handling methods of {@link com.mockrunner.tag.NestedSimpleTag}
028 * delegate to an underlying instance of this class.
029 */
030 public class MockJspFragment extends JspFragment
031 {
032 private JspContext jspContext;
033 private List childs;
034 private JspTag parent;
035
036 public MockJspFragment(JspContext jspContext)
037 {
038 this(jspContext, null);
039 }
040
041 public MockJspFragment(JspContext jspContext, JspTag parent)
042 {
043 this.jspContext = jspContext;
044 this.parent = parent;
045 childs = new ArrayList();
046 }
047
048 /**
049 * Returns the parent tag.
050 * @return the parent tag
051 */
052 public JspTag getParent()
053 {
054 return parent;
055 }
056
057 /**
058 * Sets the parent tag.
059 * @param parent the parent tag
060 */
061 public void setParent(JspTag parent)
062 {
063 this.parent = parent;
064 }
065
066 /**
067 * Returns the <code>JspContext</code>.
068 * @return the <code>JspContext</code>
069 */
070 public JspContext getJspContext()
071 {
072 return jspContext;
073 }
074
075 /**
076 * Sets the <code>JspContext</code>. Also calls <code>setJspContext</code>
077 * (or <code>setPageContext</code>) for all child tags.
078 * <code>setPageContext</code> is only called if the specified <code>JspContext</code>
079 * is an instance of <code>PageContext</code>.
080 * @param jspContext the <code>JspContext</code>
081 */
082 public void setJspContext(JspContext jspContext)
083 {
084 this.jspContext = jspContext;
085 for(int ii = 0; ii < childs.size(); ii++)
086 {
087 Object child = childs.get(ii);
088 if(child instanceof Tag && jspContext instanceof PageContext)
089 {
090 ((Tag)child).setPageContext((PageContext)jspContext);
091 }
092 else if(child instanceof SimpleTag)
093 {
094 ((SimpleTag)child).setJspContext(jspContext);
095 }
096 }
097 }
098
099 /**
100 * Executes the fragment and directs all output to the given Writer, or the JspWriter
101 * returned by the getOut() method of the JspContext associated with the fragment
102 * if out is null (copied from <code>JspFragment</code> JavaDoc).
103 * @param writer the Writer to output the fragment to, or null if output should be
104 * sent to JspContext.getOut().
105 */
106 public void invoke(Writer writer) throws JspException, IOException
107 {
108 if(null == jspContext) return;
109 if(null != writer)
110 {
111 jspContext.pushBody(writer);
112 }
113 TagUtil.evalBody(childs, jspContext);
114 jspContext.getOut().flush();
115 if(null != writer)
116 {
117 jspContext.popBody();
118 }
119 }
120
121 /**
122 * Removes all childs.
123 */
124 public void removeChilds()
125 {
126 childs.clear();
127 }
128
129 /**
130 * Returns the <code>List</code> of childs.
131 * @return the <code>List</code> of childs
132 */
133 public List getChilds()
134 {
135 return childs;
136 }
137
138 /**
139 * Returns a child specified by its index.
140 * @param index the index
141 * @return the child
142 */
143 public Object getChild(int index)
144 {
145 return childs.get(index);
146 }
147
148 /**
149 * Adds a text child simulating static body content.
150 * @param text the static text
151 */
152 public void addTextChild(String text)
153 {
154 if(null == text) text = "";
155 childs.add(text);
156 }
157
158 /**
159 * Adds a dynamic child simulating scriptlets and
160 * EL expressions. Check out
161 * {@link com.mockrunner.tag.TagUtil#evalBody(List, Object)}
162 * for details about child handling.
163 * @param child the dynamic child instance
164 */
165 public void addDynamicChild(DynamicChild child)
166 {
167 if(null == child) return;
168 childs.add(child);
169 }
170
171 /**
172 * Adds a tag child simulating nested tags.
173 * The corresponding <code>NestedTag</code> will be created
174 * automatically wrapping the specified tag. An empty attribute
175 * <code>Map</code> will be used for the tag.
176 * @param tag the tag class
177 */
178 public NestedTag addTagChild(Class tag)
179 {
180 return addTagChild(tag, new HashMap());
181 }
182
183 /**
184 * Adds a tag child simulating nested tags.
185 * The corresponding <code>NestedTag</code> will be created
186 * automatically wrapping the specified tag. The attributes
187 * <code>Map</code> contains the attributes of this tag
188 * (<i>propertyname</i> maps to <i>propertyvalue</i>).
189 * @param tag the tag class
190 * @param attributeMap the attribute map
191 */
192 public NestedTag addTagChild(Class tag, Map attributeMap)
193 {
194 Object childTag = TagUtil.createNestedTagInstance(tag, jspContext, attributeMap);
195 return addChild(childTag);
196 }
197
198 /**
199 * Adds a tag child simulating nested tags.
200 * <code>NestedTag</code> will be created automatically
201 * wrapping the specified tag. An empty attribute <code>Map</code>
202 * will be used for the tag.
203 * @param tag the tag
204 */
205 public NestedTag addTagChild(JspTag tag)
206 {
207 return addTagChild(tag, new HashMap());
208 }
209
210 /**
211 * Adds a tag child simulating nested tags.
212 * The corresponding <code>NestedTag</code> will be created
213 * automatically wrapping the specified tag. The attributes
214 * <code>Map</code> contains the attributes of this tag
215 * (<i>propertyname</i> maps to <i>propertyvalue</i>).
216 * @param tag the tag
217 * @param attributeMap the attribute map
218 */
219 public NestedTag addTagChild(JspTag tag, Map attributeMap)
220 {
221 Object childTag = TagUtil.createNestedTagInstance(tag, jspContext, attributeMap);
222 return addChild(childTag);
223 }
224
225 private NestedTag addChild(Object childTag)
226 {
227 if(childTag instanceof SimpleTag)
228 {
229 ((SimpleTag)childTag).setParent(parent);
230 }
231 else if(parent instanceof Tag)
232 {
233 if(childTag instanceof Tag)
234 {
235 ((Tag)childTag).setParent((Tag)parent);
236 }
237 }
238 else if(parent instanceof SimpleTag)
239 {
240 if(childTag instanceof Tag)
241 {
242 ((Tag)childTag).setParent(new TagAdapter((SimpleTag)parent));
243 }
244 }
245 childs.add(childTag);
246 return (NestedTag)childTag;
247 }
248 }