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 }