2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.shale.clay.taglib;
22
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import javax.servlet.jsp.tagext.PageData;
29 import javax.servlet.jsp.tagext.TagLibraryValidator;
30 import javax.servlet.jsp.tagext.ValidationMessage;
31
32 import org.apache.shale.clay.parser.Node;
33 import org.apache.shale.clay.parser.Parser;
34 import org.apache.shale.util.Messages;
35
36 /***
37 * <p>Validates the JSP page for the clay namespace,
38 * "http://shale.apache.org/shale/clay-plugin". This tag
39 * validator checks to make sure that there are not any nested
40 * tags under the {@link ClayTag} with the exception of the
41 * {@link SymbolTag}.</p>
42 */
43 public class ClayTagValidator extends TagLibraryValidator {
44
45 /***
46 * <p>URI Namespace for the clay tag lib.</p>
47 */
48 private static final String CLAY_URI_NAMESPACE = "http://shale.apache.org/clay";
49
50 /***
51 * <p>Message resources for this class.</p>
52 */
53 private static Messages messages = new Messages("org.apache.shale.clay.Bundle",
54 ClayTagValidator.class.getClassLoader());
55
56 /***
57 * <p>Loads the <code>page</code> content into a <code>StringBuffer</code>.</p>
58 *
59 * @param page tag page data
60 * @return document in a string buffer
61 * @exception IOException error reading page data
62 */
63 protected StringBuffer loadTemplate(PageData page) throws IOException {
64
65
66 StringBuffer buff = new StringBuffer();
67 InputStream inputStream = page.getInputStream();
68
69 int c = 0;
70 done: while (true) {
71 c = inputStream.read();
72 if (c > -1) {
73 buff.append((char) c);
74 } else {
75 break done;
76 }
77
78 }
79
80 return buff;
81
82 }
83
84 /***
85 * <p>Creates a <code>ValidationMessage</code> for a {@link ClayTag} containing
86 * a child of anything other than the {@link SymbolTag}.</p>
87 *
88 * @param prefix qname
89 * @param clayNode markup
90 * @param childNode child markup
91 *
92 * @return message for the JSP compiler
93 */
94 private ValidationMessage getMessage(String prefix, Node clayNode, Node childNode) {
95 Object[] args = {clayNode.getToken().getRawText(),
96 childNode.getToken().getRawText(),
97 prefix};
98 String jspid = (String) childNode.getAttributes().get("jsp:id");
99 String message = messages.getMessage("invalid.nested.tag", args);
100 return new ValidationMessage(jspid, message);
101 }
102
103
104 /***
105 * <p>Checks the child nodes of the <code>clayNode</code> verifying that
106 * only the symbol node is present.</p>
107 *
108 * @param prefix qname
109 * @param clayNode markup
110 * @param messages error messages
111 */
112 private void checkForInvalidNestedTags(String prefix, Node clayNode, List messages) {
113 List children = clayNode.getChildren();
114 next: for (int i = 0; i < children.size(); i++) {
115 Node child = (Node) children.get(i);
116 if ((!child.isComment() && !child.isCdata()) && child.isWellFormed()) {
117 if (child.getQname() != null && child.getName() != null) {
118
119 if (child.getQname().equals("jsp") && child.getName().equals("text")) {
120 continue next;
121 } else if (!child.getName().equals("symbol") || !prefix.equals(child.getQname())) {
122 messages.add(getMessage(prefix, clayNode, child));
123 }
124 }
125
126 }
127 }
128 }
129
130 /***
131 * <p>Recursively walks the parsed document looking for clay component nodes. The children
132 * are checked to make sure the symbol tag is the only valid child tag.</p>
133 *
134 * @param prefix qname
135 * @param node markup
136 * @param messages list of errors
137 */
138 private void validateClayTags(String prefix, Node node, List messages) {
139 if ((!node.isComment() && !node.isCdata()) && node.isWellFormed()
140 && node.getName() != null && node.getName().equals("clay")
141 && node.getQname() != null && node.getQname().equals(prefix)) {
142
143 checkForInvalidNestedTags(prefix, node, messages);
144 return;
145 }
146
147 List children = node.getChildren();
148 for (int i = 0; i < children.size(); i++) {
149 Node child = (Node) children.get(i);
150 validateClayTags(prefix, child, messages);
151 }
152
153 }
154
155 /***
156 * <p>Validates the page for a directive with a uri of
157 * "<strong>http://shale.apache.org/shale/clay-plugin</strong>".
158 *
159 * @param prefix namespace
160 * @param uri namespace
161 * @param page normalized jsp page into XML
162 * @return error messages
163 */
164 public ValidationMessage[] validate(String prefix, String uri, PageData page) {
165 List messages = new ArrayList();
166
167 if (uri != null && CLAY_URI_NAMESPACE.equals(uri)) {
168 try {
169 StringBuffer buff = loadTemplate(page);
170 Parser p = new Parser();
171 List roots = p.parse(buff);
172
173 for (int i = 0; i < roots.size(); i++) {
174 Node node = (Node) roots.get(i);
175 validateClayTags(prefix, node, messages);
176 }
177
178 } catch (IOException e) {
179 messages.add(new ValidationMessage(null, e.getMessage()));
180 }
181 }
182
183 if (messages.isEmpty()) {
184 return null;
185 } else {
186 ValidationMessage[] validationMessages = new ValidationMessage[messages.size()];
187 messages.toArray(validationMessages);
188 return validationMessages;
189 }
190
191 }
192
193 }