Author: gvanmatre
Date: Sun Aug 28 20:11:31 2005
New Revision: 264040

URL: http://svn.apache.org/viewcvs?rev=264040&view=rev
Log:
Bug#:  35839  [shale] Clay processes components inside HTML comments

Added:
    
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommentBuilder.java
Modified:
    
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/Bundle.properties
    
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/AttributeTokenizer.java
    
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Node.java
    
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/NodeTokenizer.java
    
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java
    
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Token.java
    
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java
    
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java

Modified: 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/Bundle.properties
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/Bundle.properties?rev=264040&r1=264039&r2=264040&view=diff
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/Bundle.properties 
(original)
+++ 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/Bundle.properties 
Sun Aug 28 20:11:31 2005
@@ -26,10 +26,12 @@
 parser.load.file=Loading file "{0}".
 parser.load.error=Exception parsing file "{0}".
 parser.load.rules=Loading digester rules.
+parser.unmatched.endtoken=Unmatched ending non-option token: {0}
+parser.unmatched.begintoken=Unmatched begining token: {0}
 
 #org.apache.shale.clay.parser.NodeTokenizer
 node.document.size=Indexing Document containing {0} character(s).
-node.token.range=Node token range ({0} - {1}).
+node.token.range=Node token range ({0} - {1}) on line# {2} begining offset {3}.
 
 #org.apache.shale.clay.parser.AttributeTokenizer
 attribute.range=Attribute parse offset range({0} - {1}).

Modified: 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/AttributeTokenizer.java
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/AttributeTokenizer.java?rev=264040&r1=264039&r2=264040&view=diff
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/AttributeTokenizer.java
 (original)
+++ 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/AttributeTokenizer.java
 Sun Aug 28 20:11:31 2005
@@ -77,17 +77,30 @@
     private int endOffset = 0;
     
     /**
+     * <p>Line number the target node is located in.</p>
+     */
+    private int lineNumber = 0;
+    
+    /**
+     * <p>Line begining document offset where the target node is located.</p>
+     */    
+    private int lineBeginOffset = 0;
+
+    
+    /**
      * <p>
      * Overloaded constructor that is passed the complete document and the
      * starting and ending offset of the node body within the document
      * </p>
      */
     public AttributeTokenizer(StringBuffer buffer, int beginOffset,
-            int endOffset) {
+            int endOffset, int lineNumber, int lineBeginOffset) {
         this.buffer = buffer;
         this.beginOffset = beginOffset;
         this.endOffset = endOffset;
-        
+        this.lineBeginOffset = lineBeginOffset;
+        this.lineNumber = lineNumber;
+
     }
     
     /**
@@ -128,6 +141,24 @@
             }
             return pickel;
         }
+        
+        public int getLineNumber() {
+           return lineNumber;  
+        }
+
+        public int getLineBeginOffset() {
+           return lineBeginOffset;  
+        }
+        
+        public String toString() {
+            return messages.getMessage("node.token.range",
+                    new Object[] {
+                new Integer(beginOffset),
+                        new Integer(endOffset),
+                        new Integer(lineNumber),
+                        new Integer(lineBeginOffset)});            
+        }
+
     }
     
     /**

Modified: 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Node.java
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Node.java?rev=264040&r1=264039&r2=264040&view=diff
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Node.java 
(original)
+++ 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Node.java 
Sun Aug 28 20:11:31 2005
@@ -33,6 +33,12 @@
 public class Node {
     
     /**
+     * <p>Indicates the node is a comment or within a comment
+     * block.</p>
+     */
+    private boolean isComment = false; 
+        
+    /**
      * <p>Indicates the node is a starting node</p>
      */
     private boolean isStart = false;
@@ -233,5 +239,25 @@
         
.append(isWellFormed).append("\n").append(token).append("\n").append(attributes);
         return buff.toString();
     }
+
+    /**
+     * <p> Returns the <code>true</code> if the node is
+     * a comment; otherwise; the default is <code>false</code>
+     * </p>.
+     */
+    public boolean isComment() {
+        return isComment;
+    }
+    
+
+    /**
+     * <p>Sets a boolean value that identifies this node as
+     * being a comment.  This could be a starting, ending or
+     * within the body.</p>
+     */
+    public void setComment(boolean isComment) {
+        this.isComment = isComment;
+    }
+     
     
 }

Modified: 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/NodeTokenizer.java
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/NodeTokenizer.java?rev=264040&r1=264039&r2=264040&view=diff
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/NodeTokenizer.java
 (original)
+++ 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/NodeTokenizer.java
 Sun Aug 28 20:11:31 2005
@@ -79,8 +79,9 @@
      */
     private class TokenOffset implements Token {
         private int beginOffset = 0;
-        
         private int endOffset = 0;
+        private int lineNumber = 0;
+        private int lineBeginOffset = 0;
         
         /**
          * <p>
@@ -88,9 +89,11 @@
          * document of the [EMAIL PROTECTED] Node}.
          * </p>
          */
-        public TokenOffset(int beginOffset, int endOffset) {
+        public TokenOffset(int beginOffset, int endOffset, int lineNumber, int 
lineBeginOffset) {
             this.beginOffset = beginOffset;
             this.endOffset = endOffset;
+            this.lineNumber = lineNumber;
+            this.lineBeginOffset = lineBeginOffset;
         }
         
         /**
@@ -137,12 +140,28 @@
         }
         
         public String toString() {
-            StringBuffer msg = new StringBuffer();
-            msg.append("Offset range (").append(beginOffset).append(" - ")
-            .append(endOffset).append(")");
-            return msg.toString();
+            return messages.getMessage("node.token.range",
+                    new Object[] {
+                new Integer(beginOffset),
+                        new Integer(endOffset),
+                        new Integer(lineNumber),
+                        new Integer(lineBeginOffset)});            
         }
         
+        /**
+         * <p>Returns the line number in the document that the node starts.</p>
+         */
+        public int getLineNumber() {
+           return lineNumber;  
+        }
+
+        /**
+         * <p>Returns the line begining offset in the document that the node 
starts.</p>
+         */
+        public int getLineBeginOffset() {
+           return lineBeginOffset;  
+        }
+         
     }
     
     /**
@@ -153,6 +172,8 @@
      */
     protected void index(ArrayList tokenIndex) {
         int s = 0;
+        int lineNumber = 1;
+        int lineBeginOffset = 0;
         
         if (log.isDebugEnabled()) {
             log.debug(messages.getMessage("node.document.size",
@@ -164,45 +185,53 @@
             if (buffer.charAt(i) == '<') {
                 if (i > s && s < i) {
                     
-                    TokenOffset offset = new TokenOffset(s, i);
+                    TokenOffset offset = new TokenOffset(s, i, lineNumber, 
lineBeginOffset);
                     tokenIndex.add(offset);
                     
                     if (log.isDebugEnabled()) {
                         log.debug(messages.getMessage("node.token.range",
                                 new Object[] {
                             new Integer(offset.getBeginOffset()),
-                                    new Integer(offset.getEndOffset()) }));
+                                    new Integer(offset.getEndOffset()),
+                                    new Integer(offset.getLineNumber()),
+                                    new 
Integer(offset.getLineBeginOffset())}));
                     }
                     
                 }
                 s = i;
             } else if (buffer.charAt(i) == '>') {
                 if (i > s) {
-                    TokenOffset offset = new TokenOffset(s, i + 1);
+                    TokenOffset offset = new TokenOffset(s, i + 1, lineNumber, 
lineBeginOffset);
                     tokenIndex.add(offset);
                     
                     if (log.isDebugEnabled()) {
                         log.debug(messages.getMessage("node.token.range",
                                 new Object[] {
                             new Integer(offset.getBeginOffset()),
-                                    new Integer(offset.getEndOffset()) }));
+                                    new Integer(offset.getEndOffset()),
+                                    new Integer(offset.getLineNumber()),
+                                    new 
Integer(offset.getLineBeginOffset())}));
                     }
                 }
                 s = i + 1;
+            } else if (buffer.charAt(i) == '\n') { 
+                lineNumber++;
+                lineBeginOffset = i;
             }
             
         }
         
         if ((buffer.length()) > s + 1) {
-            TokenOffset offset = new TokenOffset(s + 1, (buffer.length() - 1));
+            TokenOffset offset = new TokenOffset(s + 1, (buffer.length() - 1), 
lineNumber, lineBeginOffset);
             tokenIndex.add(offset);
             
             if (log.isDebugEnabled()) {
-                StringBuffer msg = new StringBuffer();
-                msg.append("token offset range (").append(
-                        offset.getBeginOffset()).append(" - ").append(
-                        offset.getEndOffset()).append(").");
-                log.debug(msg.toString());
+                log.debug(messages.getMessage("node.token.range",
+                        new Object[] {
+                    new Integer(offset.getBeginOffset()),
+                            new Integer(offset.getEndOffset()),
+                            new Integer(offset.getLineNumber()),
+                            new Integer(offset.getLineBeginOffset())}));
             }
             
         }

Modified: 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java?rev=264040&r1=264039&r2=264040&view=diff
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java
 (original)
+++ 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java
 Sun Aug 28 20:11:31 2005
@@ -25,6 +25,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.shale.util.Messages;
 
 /**
  * <p>Parses the document into a tree of nodes using the
@@ -47,6 +48,16 @@
     static {
         log = LogFactory.getLog(Parser.class);
     }
+   
+    /**
+     * <p>
+     * Message resources for this class.
+     * </p>
+     */
+    private static Messages messages = new Messages(
+            "org.apache.shale.clay.Bundle", NodeTokenizer.class
+            .getClassLoader());
+    
     
     /**
      * <p>This inner class is a subclass of a <code>TreeMap</code>.
@@ -182,6 +193,43 @@
         return false;
     }
     
+    protected Node findBeginingNode(Node current, Node node) {
+ 
+        pop: while (true) {
+            if (current == null)
+                break pop;
+            
+            if (isNodeNameEqual(current, node)) {
+                
+                // isWellFormed indicates a beginning tag and ending tag
+                // was found
+                current.setWellFormed(true);
+                
+                // nodes are equal, make the parent of the
+                // begin tag the current node
+                current = current.getParent();
+                
+                break pop;
+            }
+            
+            if (isOptionalEndingTag(current.getName())) 
+               current.setWellFormed(true);
+            
+            if (current.getParent() == null) {
+               throw new RuntimeException(
+                               messages.getMessage("parser.unmatched.endtoken",
+                               new Object[] {node.getToken()}));              
+            }
+            
+            current = (Node) current.getParent();
+            
+        }
+
+        return current;
+               
+    }
+    
+    
     /**
         * <p>
         * Parse a document fragment into graphs of [EMAIL PROTECTED] Node}. 
The resulting
@@ -197,38 +245,45 @@
         Node root = new Node(null);
         Node current = root;
         current.setName("namingContainer");
+        root.setWellFormed(true);
         
         NodeTokenizer t = new NodeTokenizer(document);
         Iterator i = t.iterator();
-        while (i.hasNext()) {
+        next: while (i.hasNext()) {
             Token token = (Token) i.next();
             
             Node node = buildNode(token);
             
-            if (!node.isStart() && node.isEnd()) {
-                                
-                pop: while (true) {
-                    if (current == null)
-                        break pop;
-                    
-                    if (isNodeNameEqual(current, node)) {
-                        
-                        // isWellFormed indicates a beginning tag and ending 
tag
-                        // was found
-                        current.setWellFormed(true);
-                        
-                        // nodes are equal, make the parent of the
-                        // begin tag the current node
-                        current = current.getParent();
-                        break pop;
-                    }
-                   
-                    if (isOptionalEndingTag(current.getName())) 
-                        current.setWellFormed(true);
-
-                    current = (Node) current.getParent();
+            //play forward on comments making all nodes child nodes until a 
+            //ending comment is hit
+            if (node.isComment() && node.isStart()) {
+                
+                //not self contained comment
+                if (!node.isEnd()) {
                     
-                }
+                    trash: while (i.hasNext()) {
+                        token = (Token) i.next();
+                        Node bodyNode = buildNode(token);
+                        if (bodyNode.isComment() && bodyNode.isEnd()) { 
+                            node.addChild(bodyNode);  
+                            node.setEnd(true);
+                            node.setWellFormed(true);
+                            break trash;
+                        } else {
+                            node.addChild(bodyNode);
+                        }                        
+                    } // end while
+                
+                } 
+                
+                current.addChild(node);
+                continue next;
+                
+            } // end is comment
+            
+            if (!node.isStart() && node.isEnd()) {
+                          
+                current = findBeginingNode(current, node);
                 
             } else if (node.isStart() && !node.isEnd()) {
                 
@@ -256,32 +311,10 @@
                     // simulate having ending nodes
                     
                     if (isOptionalEndingTag(node.getName()) && 
isValidOptionalEndingTagParent(current.getName(), node.getName())) {
-                        
-                        pop: while (true) {
-                            if (current == null)
-                                break pop;
-                            
-                            if (isNodeNameEqual(current, node)) {
-                                
-                                // isWellFormed indicates a beginning tag and 
ending tag
-                                // was found
-                                current.setWellFormed(true);
-                                
-                                // nodes are equal, make the parent of the
-                                // begin tag the current node
-                                current = current.getParent();
-                                                               
current.addChild(node);
-                                                               current = node;
-                                                               
-                                break pop;
-                            }
-                            
-                            if (isOptionalEndingTag(current.getName())) 
-                               current.setWellFormed(true);
-                            
-                            current = (Node) current.getParent();
-                            
-                        }
+                                                
+                        current = this.findBeginingNode(current, node);
+                        current.addChild(node);
+                        current = node;
                         
                     } else {
                     
@@ -301,12 +334,33 @@
         
         t = null;
         i = null;
+           
+        simpleWellFormedCheck(root);
         
         return root.getChildren();
         
     }
     
     /**
+     * <p>A simple check to make sure that all nodes have been terminated 
including
+     * tags with optional ending tags.</p>
+     */
+    private void simpleWellFormedCheck(Node node) {
+        if (node.getName() != null && !node.isWellFormed()) {
+            throw new RuntimeException(
+                    messages.getMessage("parser.unmatched.begintoken",
+                    new Object[] {node.getToken()}));              
+        }
+          
+        if (!node.isComment()) {
+            Iterator ci = node.getChildren().iterator();
+            while (ci.hasNext()) {
+                simpleWellFormedCheck((Node)(ci.next()));
+            }
+        }
+    }
+    
+    /**
      * <p>Compares two [EMAIL PROTECTED] Node} instances by <code>name</code>.
      * This method is used to match a beginning tag with an ending tag
      * while building the document stack.  Returns <code>true</code> if
@@ -400,13 +454,12 @@
             isComment = true;
         } else if (token.getDocument().charAt(token.getBeginOffset()) == '<'
             && token.getDocument().charAt(token.getBeginOffset() + 1) == '!'
-            && token.getDocument().charAt(token.getEndOffset() - 1) != '>') {
+            && token.getDocument().charAt(token.getBeginOffset() + 2) == '-') {
             // begin comment tag found
             isEndTag = false;
             isBeginTag = true; 
             isComment = true;
-        } else if (token.getDocument().charAt(token.getBeginOffset()) != '<'
-            && token.getDocument().charAt(token.getEndOffset() - 2) == '-'
+        } else if (token.getDocument().charAt(token.getEndOffset() - 2) == '-'
             && token.getDocument().charAt(token.getEndOffset() - 1) == '>') {
             // ending comment tag found
             isEndTag = true;
@@ -429,7 +482,7 @@
             if (isComment) {
                 
                 nodeName = "--";
-                
+                                
             } else {
                 // find the node name delimiter
                 int e = token.getDocument().indexOf(" ", 
token.getBeginOffset() + 2);
@@ -466,7 +519,7 @@
                 
                 // find the tokens and load them into the attributes map
                 AttributeTokenizer tokenizer = new AttributeTokenizer(token
-                        .getDocument(), s, e);
+                        .getDocument(), s, e, token.getLineNumber(), 
token.getLineBeginOffset());
                 Iterator at = tokenizer.iterator();
                 while (at.hasNext()) {
                     Map.Entry attribute = (Map.Entry) at.next();
@@ -486,6 +539,7 @@
         Node node = new Node(token);
         node.setEnd(isEndTag);
         node.setStart(isBeginTag);
+        node.setComment(isComment);
         node.setAttributes((Map) attributes);
         
         // begin and end tag found on a self terminating node <xxx/>

Modified: 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Token.java
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Token.java?rev=264040&r1=264039&r2=264040&view=diff
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Token.java 
(original)
+++ 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Token.java 
Sun Aug 28 20:11:31 2005
@@ -49,4 +49,15 @@
      * <p>Returns a reference to the complete document.</p>
      */
     public StringBuffer getDocument();
+    
+    /**
+     * <p>Returns the line number in the document that the node starts.</p>
+     */
+    public int getLineNumber();
+
+    /**
+     * <p>Returns the line begining offset in the document that the node 
starts.</p>
+     */
+    public int getLineBeginOffset();
+
 }

Added: 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommentBuilder.java
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommentBuilder.java?rev=264040&view=auto
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommentBuilder.java
 (added)
+++ 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommentBuilder.java
 Sun Aug 28 20:11:31 2005
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Id$
+ */
+package org.apache.shale.clay.parser.builder;
+
+import java.util.Iterator;
+
+import org.apache.shale.clay.config.beans.AttributeBean;
+import org.apache.shale.clay.config.beans.ComponentBean;
+import org.apache.shale.clay.config.beans.ElementBean;
+import org.apache.shale.clay.parser.Node;
+
+/**
+ * <p>This [EMAIL PROTECTED] Builder} will render a HTML [EMAIL PROTECTED] 
Node} as
+ * an HTML comment.  All nodes under the comment will be concatenated 
+ * as their original raw text value within the HTML document. 
+ * </p>
+ *
+ */
+public class CommentBuilder extends VerbatimBuilder {
+
+    /**
+     * <p>This method is overridden to return a true value indicating 
+     * that this [EMAIL PROTECTED] Builder{ will handle child nodes under the 
+     * associated HTML [EMAIL PROTECTED] Node}.  This method can easily be 
confused 
+     * with the <code>isChildrenAllowed()</code> method of the super 
+     * class [EMAIL PROTECTED] Builder}.  The distinction is that the 
+     * <code>isChildrenAllowed()</code> method signifies that the 
+     * associated JSF component supports children components. This method 
+     * signifies that this builder will handle building child nodes 
+     * similarly to the jsf component's <code>getRendersChildren()</code> 
method.
+     */
+    protected boolean getBuildNodeBody(Node node, ElementBean target) {
+        return true;       
+    }
+
+    /**
+     * <p>The super implementation is invoked to build a target [EMAIL 
PROTECTED] ElementBean}.  
+     * The body of the comment is constructed by capturing the text of all 
child 
+     * HTML nodes within the comment body.</p>
+     */   
+    protected void encodeBegin(Node node, ElementBean target, ComponentBean 
root) {
+        super.encodeBegin(node, target, root);
+        
+        AttributeBean valueAttr = (AttributeBean) target.getAttribute("value");
+        StringBuffer comment = new StringBuffer(valueAttr.getValue());
+        captureComment(node, comment);
+        valueAttr.setValue(comment.toString());
+        
+    }
+    
+    /**
+     * <p>Recursively traverses the children of the HTML [EMAIL PROTECTED] 
Node} concatenating 
+     * the raw text of each [EMAIL PROTECTED] Token} into the 
<code>commentBody</code>.</p>
+     */
+    protected void captureComment(Node node, StringBuffer commentBody) {
+        Iterator ni = node.getChildren().iterator();
+        while (ni.hasNext()) {
+           Node child = (Node) ni.next();
+           commentBody.append(child.getToken().getRawText());
+           captureComment(child, commentBody);
+        }
+    }
+
+
+    /**
+     * <p>This override cancels the super implementation.  The overridden 
+     * <code>encodeBegin(Node, ElementBean, ComponentBean) method handles 
+     * the ending comment tag, "-->".</p>
+     */
+    protected void encodeEnd(Node node, ElementBean target, ComponentBean 
root) {
+
+    }
+    
+
+}

Modified: 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java?rev=264040&r1=264039&r2=264040&view=diff
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java
 (original)
+++ 
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java
 Sun Aug 28 20:11:31 2005
@@ -20,7 +20,11 @@
 
 import org.apache.commons.chain.Command;
 import org.apache.commons.chain.Context;
+import org.apache.shale.clay.parser.Node;
 import org.apache.shale.clay.parser.builder.Builder;
+import org.apache.shale.clay.parser.builder.BuilderFactory;
+import org.apache.shale.clay.parser.builder.CommentBuilder;
+import org.apache.shale.clay.parser.builder.OutputLinkBuilder;
 import org.apache.shale.clay.parser.builder.VerbatimBuilder;
 
 /**
@@ -41,19 +45,28 @@
      * Default static instance of [EMAIL PROTECTED] VerbatimBuilder}
      * <p>
      */    
-    private static final Builder builder = new VerbatimBuilder();
+    private static final Builder[] builders = {new CommentBuilder(), new 
VerbatimBuilder()};
   
     /**
      * <p>
      * Uses the [EMAIL PROTECTED] BuilderRuleContext} to find the current html
      * [EMAIL PROTECTED] org.apache.shale.clay.parser.Node}. This is the 
default rule that
-     * will always return a [EMAIL PROTECTED] VerbatimBuilder}.
+     * will return a [EMAIL PROTECTED] VerbatimBuilder} when the node is not a 
comment.  
+     * When the html node is the start of a comment, the [EMAIL PROTECTED] 
CommentBuilder}
+     * with handle creating the correct [EMAIL PROTECTED] 
org.apache.shale.config.beans.ElementBean}
+     * used to create a faces component.
      * </p>
      */    
     public boolean execute(Context context) throws Exception {
         
+
         BuilderRuleContext builderRuleContext = (BuilderRuleContext) context;
-        builderRuleContext.setBuilder(builder);
+        Node node = builderRuleContext.getNode();
+        if (node.getName() != null && node.getName().equalsIgnoreCase("--")) {
+            builderRuleContext.setBuilder(builders[0]);      
+        } else {
+            builderRuleContext.setBuilder(builders[1]);
+        }
         
         return true;
     }

Modified: 
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java?rev=264040&r1=264039&r2=264040&view=diff
==============================================================================
--- 
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java
 (original)
+++ 
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java
 Sun Aug 28 20:11:31 2005
@@ -53,7 +53,7 @@
         Parser p = new Parser();
         StringBuffer doc1 = new StringBuffer();
 
-        doc1.append("<p>").append(
+        doc1.append("<p><!-- self contained comment -->").append(
                 "<!--<input type=text size=10 maxsize=10 id=username>").append(
                 "<input type=text size=10 maxsize=10 id=password>-->").append(
                 "</p>").append("<!--This is a test.  Just a test-->").append(
@@ -63,19 +63,32 @@
         assertTrue("Has 3 root nodes", nodes1.size() == 3);
 
         Node node = (Node) nodes1.get(0);
-        assertTrue("first paragraph has 1 node", node.getChildren().size() == 
1);
+        assertTrue("first paragraph has 2 node", node.getChildren().size() == 
2);
 
-        node = (Node) node.getChildren().get(0);
-        assertTrue("first comment block has 2 nodes",
-                node.getChildren().size() == 2);
-
-        node = (Node) nodes1.get(1);
-        assertTrue("second root has 0 child nodes",
-                node.getChildren().size() == 0);
+        node = (Node) node.getChildren().get(1);
+        assertTrue("second comment block has 3 nodes",
+                node.getChildren().size() == 3);
 
         node = (Node) nodes1.get(2);
-        assertTrue("third root has 1 child node",
-                node.getChildren().size() == 1);
+        assertTrue("third comment has 7 child nodes", node.getChildren()
+                .size() == 7);
+
+        // truncate the buffer
+        doc1.setLength(0);
+        doc1
+                .append("<p>")
+                .append(
+                        "<!--</p><b><tr></table> we should have a single root 
with 5 children -->")
+                .append("</p>");
+
+        nodes1 = p.parse(doc1);
+        assertTrue("root has 1 child nodes", nodes1.size() == 1);
+
+        node = (Node) nodes1.get(0);
+        assertTrue("paragraph has 1 child node", node.getChildren().size() == 
1);
+
+        node = (Node) node.getChildren().get(0);
+        assertTrue("comment has 5 child nodes", node.getChildren().size() == 
5);
 
     }
 
@@ -213,16 +226,67 @@
     }
 
     /**
+     * <p>Check for an ending tag without a begining.</p>
+     *
+     */
+    public void testUnmatchedNonOptionalEnding() {
+
+        Parser p = new Parser();
+        StringBuffer doc = new StringBuffer();
+        doc.append("<html>\n")   
+           .append("<head/>\n")
+           .append("<body>\n")
+           .append("</p>\n")
+           .append("</body>\n")
+           .append("</html>");
+        
+        try {
+           List nodes = p.parse(doc);
+           assertTrue("Failed unmatched non-optional ending tag test", false);
+        } catch (Exception e) {
+           assertTrue("Failed unmatched non-optional ending tag test", 
e.getMessage().startsWith("Unmatched ending non-option token"));
+        }
+
+    }
+
+    /**
+     * <p>Check for a begining tag that was not terminated.</p>
+     *
+     */
+    public void testUnmatchedBegining() {
+
+        Parser p = new Parser();
+        StringBuffer doc = new StringBuffer();
+        doc.append("<html>\n")   
+           .append("<head/>\n")
+           .append("<body>\n")
+           .append("<p>\n")
+           .append("</body>\n")
+           .append("</html>");
+        
+        try {
+           List nodes = p.parse(doc);
+           assertTrue("Failed unmatched begining", false);
+        } catch (Exception e) {
+           assertTrue("Failed unmatched begining test", 
e.getMessage().startsWith("Unmatched begining token"));
+        }
+
+    }
+
+    
+    /**
      * Checks to see if nested tables parse correctly
      */
-public void testNestedTables() {
+    public void testNestedTables() {
         Parser p = new Parser();
         StringBuffer doc = new StringBuffer();
         doc
                 .append("<table>")
                 .append("<tr><td><table><tr><td></td></tr></table></td>")
-                .append("<td><span jsfid=\"tabs\"><ul id=\"menu\"><li 
id=\"nav\"><a href=\"#\">Tab 1</a></li><li id=\"nav-sel\"><a href=\"#\">Tab 
2</a></li><li id=\"nav\"><a href=\"#\">Tab 3</a></li></ul></span>")
-                .append("</td></tr>").append("</table>")
+                .append(
+                        "<td><span jsfid=\"tabs\"><ul id=\"menu\"><li 
id=\"nav\"><a href=\"#\">Tab 1</a></li><li id=\"nav-sel\"><a href=\"#\">Tab 
2</a></li><li id=\"nav\"><a href=\"#\">Tab 3</a></li></ul></span>")
+                .append("</td></tr>")
+                .append("</table>")
                 .append("<div id=\"contents\">")
                 .append("<table border=\"0\">")
                 .append("<tr><td rowspan=\"3\">")
@@ -237,27 +301,27 @@
                 .append("<td>")
                 .append("<a href=\"#\">ABC Company</a>")
                 .append("</td>")
-                .append("</tr>")   
+                .append("</tr>")
                 .append("<tr class=\"contactsRow2\">")
                 .append("<td>")
                 .append("<a href=\"#\">XYZ Company</a>")
                 .append("</td>")
-                .append("</tr>")  
+                .append("</tr>")
                 .append("</table>")
-                .append("</span>")  
+                .append("</span>")
                 .append("</td></tr>")
                 .append("<tr><td>")
                 .append("<table>")
-                .append("<tr><td><label style=\"color:#99CC66\" 
jsfid=\"contactNameLabel\">Name:</label></td><td><input jsfid=\"contactName\" 
type=text size=40 maxlength=\"50\"/></td><td><span style=\"color:red\" 
jsfid=\"contactNameMessage\">Mock Error 
Name</span></td></tr></table></td></tr>")
-                .append("</table>")
-                .append("</div>");
-        
-        
-        List nodes = p.parse(doc);
-        assertTrue("Well-formed nested table has 1 root node", nodes.size() == 
2);
+                .append(
+                        "<tr><td><label style=\"color:#99CC66\" 
jsfid=\"contactNameLabel\">Name:</label></td><td><input jsfid=\"contactName\" 
type=text size=40 maxlength=\"50\"/></td><td><span style=\"color:red\" 
jsfid=\"contactNameMessage\">Mock Error 
Name</span></td></tr></table></td></tr>")
+                .append("</table>").append("</div>");
 
+        List nodes = p.parse(doc);
+        assertTrue("Well-formed nested table has 1 root node",
+                nodes.size() == 2);
 
     }
+
     /**
      * <p>
      * Aserts that two trees of parsed HTML have the same number children and



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to