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