KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > tags > form > TagWriter


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.web.servlet.tags.form;
18
19 import org.springframework.util.StringUtils;
20 import org.springframework.util.Assert;
21
22 import javax.servlet.jsp.JspException JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.Writer JavaDoc;
25 import java.util.Stack JavaDoc;
26
27 /**
28  * Utility class for writing HTML content to a {@link Writer} instance.
29  *
30  * <p>Intended to support output from JSP tag libraries.
31  *
32  * @author Rob Harrop
33  * @since 2.0
34  */

35 public class TagWriter {
36
37     /**
38      * The {@link SafeWriter} to write to.
39      */

40     private final SafeWriter writer;
41
42
43     /**
44      * Stores {@link TagStateEntry tag state}. Stack model naturally supports tag nesting.
45      */

46     private Stack JavaDoc tagState = new Stack JavaDoc();
47
48
49     /**
50      * Creates a new instance of the {@link TagWriter} class that writes to
51      * the supplied {@link Writer}.
52      * @param writer the {@link Writer} to write tag content to
53      * @throws IllegalArgumentException oif the supplied {@link Writer} is <code>null</code>
54      */

55     public TagWriter(Writer JavaDoc writer) {
56         Assert.notNull(writer);
57         this.writer = new SafeWriter(writer);
58     }
59
60
61     /**
62      * Starts a new tag with the supplied name. Leaves the tag open so
63      * that attributes, inner text or nested tags can be written into it.
64      * @see #endTag()
65      */

66     public void startTag(String JavaDoc tagName) throws JspException JavaDoc {
67         if (inTag()) {
68             closeTagAndMarkAsBlock();
69         }
70         push(tagName);
71         this.writer.append("<").append(tagName);
72     }
73
74     /**
75      * Writes an HTML attribute with the specified name and value.
76      * <p>Be sure to write all attributes <strong>before</strong> writing
77      * any inner text or nested tags.
78      * @throws IllegalStateException if the opening tag is closed
79      */

80     public void writeAttribute(String JavaDoc attributeName, String JavaDoc attributeValue) throws JspException JavaDoc {
81         if (currentState().isBlockTag()) {
82             throw new IllegalStateException JavaDoc("Cannot write attributes after opening tag is closed.");
83         }
84         this.writer.append(" ").append(attributeName).append("=\"")
85                 .append(attributeValue).append("\"");
86     }
87
88     /**
89      * Writes an HTML attribute if the supplied value is not <code>null</code>
90      * or zero length.
91      * @see #writeAttribute(String, String)
92      */

93     public void writeOptionalAttributeValue(String JavaDoc attributeName, String JavaDoc attributeValue) throws JspException JavaDoc {
94         if (StringUtils.hasText(attributeValue)) {
95             writeAttribute(attributeName, attributeValue);
96         }
97     }
98
99     /**
100      * Closes the current opening tag (if necessary) and appends the
101      * supplied value as inner text.
102      * @throws IllegalStateException if no tag is open
103      */

104     public void appendValue(String JavaDoc value) throws JspException JavaDoc {
105         if (!inTag()) {
106             throw new IllegalStateException JavaDoc("Cannot write tag value. No open tag available.");
107         }
108         closeTagAndMarkAsBlock();
109         this.writer.append(value);
110     }
111
112
113     /**
114      * Indicates that the currently open tag should be closed and marked
115      * as a block level element.
116      * <p>Useful when you plan to write additional content in the body
117      * outside the context of the current {@link TagWriter}.
118      */

119     public void forceBlock() throws JspException JavaDoc {
120         if (currentState().isBlockTag()) {
121             return; // just ignore since we are already in the block
122
}
123         closeTagAndMarkAsBlock();
124     }
125
126     /**
127      * Closes the current tag.
128      * <p>Correctly writes an empty tag if no inner text or nested tags
129      * have been written.
130      */

131     public void endTag() throws JspException JavaDoc {
132         if (!inTag()) {
133             throw new IllegalStateException JavaDoc("Cannot write end of tag. No open tag available.");
134         }
135         if (currentState().isBlockTag()) {
136             // writing the end of the block - the opening tag was closed earlier.
137
this.writer.append("</").append(currentState().getTagName()).append(">");
138         }
139         else {
140             this.writer.append("/>");
141         }
142         this.tagState.pop();
143     }
144
145
146     /**
147      * Adds the supplied tag name to the {@link #tagState tag state}.
148      */

149     private void push(String JavaDoc tagName) {
150         this.tagState.push(new TagStateEntry(tagName));
151     }
152
153     /**
154      * Closes the current opening tag and marks it as a block tag.
155      */

156     private void closeTagAndMarkAsBlock() throws JspException JavaDoc {
157         if (!currentState().isBlockTag()) {
158             currentState().markAsBlockTag();
159             this.writer.append(">");
160         }
161     }
162
163     private boolean inTag() {
164         return this.tagState.size() > 0;
165     }
166
167     private TagStateEntry currentState() {
168         return (TagStateEntry) this.tagState.peek();
169     }
170
171
172     /**
173      * Holds state about a tag and its rendered behaviour.
174      */

175     private static final class TagStateEntry {
176
177         private final String JavaDoc tagName;
178
179         private boolean blockTag;
180
181
182         public TagStateEntry(String JavaDoc tagName) {
183             this.tagName = tagName;
184         }
185
186
187         public String JavaDoc getTagName() {
188             return tagName;
189         }
190
191         public boolean isBlockTag() {
192             return blockTag;
193         }
194
195
196         public void markAsBlockTag() {
197             this.blockTag = true;
198         }
199
200     }
201
202
203     /**
204      * Simple {@link Writer} wrapper that wraps all
205      * {@link IOException IOExceptions} in {@link JspException JspExceptions}.
206      */

207     private static final class SafeWriter {
208
209         private final Writer JavaDoc writer;
210
211         
212         public SafeWriter(Writer JavaDoc writer) {
213             this.writer = writer;
214         }
215
216         
217         public SafeWriter append(String JavaDoc value) throws JspException JavaDoc {
218             try {
219                 this.writer.write(String.valueOf(value));
220                 return this;
221             }
222             catch (IOException JavaDoc ex) {
223                 throw new JspException JavaDoc("Unable to write to JspWriter", ex);
224             }
225         }
226         
227     }
228
229 }
230
Popular Tags