2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * $Id: ClayTagValidator.java 464373 2006-10-16 04:21:54Z rahul $
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 }