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