You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/09/15 16:21:35 UTC

svn commit: r695481 [1/2] - in /incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH: doc/ tests/com/ecyrd/jspwiki/ui/stripes/ tests/com/ecyrd/jspwiki/util/

Author: ajaquith
Date: Mon Sep 15 07:21:34 2008
New Revision: 695481

URL: http://svn.apache.org/viewvc?rev=695481&view=rev
Log:
Moved Stripes JSP migrator classes to own package, com.ecyrd.jspwiki.ui.stripes. This will probably change. Massive refactoring of the migrator utilities.

Added:
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractJspTransformer.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractNode.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AllTests.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/Attribute.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformer.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformerTest.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDirective.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocument.java
      - copied, changed from r692772, incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/util/JspDocument.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocumentTest.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMarkup.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMigrator.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspParser.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspParserTest.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspTransformer.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/Node.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/NodeType.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/StripesJspTransformer.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/StripesJspTransformerTest.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/Tag.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/Text.java
Removed:
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/util/JspDocument.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/util/StripesJspMigrator.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/util/StripesJspMigratorTest.java
Modified:
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/doc/README - Stripes Migration
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/util/AllTests.java

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/doc/README - Stripes Migration
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/doc/README%20-%20Stripes%20Migration?rev=695481&r1=695480&r2=695481&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/doc/README - Stripes Migration (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/doc/README - Stripes Migration Mon Sep 15 07:21:34 2008
@@ -398,15 +398,9 @@
 
 JSP Migration
 -------------
-<form> becomes <stripes:form>, </form> becomes </stripes:form>
-Remove <form> onsubmit="return Wiki.submitOnce(this);" because Stripes takes care of double-submits. accept-charset becomes "acceptcharset" and should use the following EL expression.
-
-    acceptcharset="${wikiEngine.contentEncoding}"
-    
-If a form action URL has an & appended to it, these should be added back as <stripes:param> tags. E.g., 
-    <form action="Login.jsp?tab=profile>
-means <stripes:param name="tab" value="profile">
+.<form> becomes <stripes:form>, </form> becomes </stripes:form>
 
+(b)
 <input type="text"> becomes <stripes:text>; type attribute goes away. Value attribute contents should be moved into the body of the tag. So:
 
     <input type="text" size="24" value="<wiki:Variable var='uid' default='' />" name="j_username" id="j_username" />
@@ -418,6 +412,7 @@
 <input type="password"> becomes <stripes:password>; type attribute goes away
 <input type="checkbox"> becomes <stripes:checkbox>; type attribute goes away
 
+(c)
 <input type="submit"> becomes <stripes:submit>; type attribute goes away. "Name" should be the name of the event handler for the ActionBean that is executed. The value attribute should be moved into the body of the tag. So:
 
     <input type="submit" name="login" value="<fmt:message key='login.submit.login'/>" />
@@ -426,11 +421,28 @@
 
     <stripes:submit name="login"><fmt:message key="login.submit.login"/></stripes:submit>
 
+(c)    
+If a form action URL has an & appended to it, these should be added back as <stripes:param> tags. E.g., 
+    <form action="Login.jsp?tab=profile>
+means <stripes:param name="tab" value="profile">
+
+
+Items processed by JspMigrator + JSPWikiJspTransformer:
+
+(a)
+Remove <form> onsubmit="return Wiki.submitOnce(this);" because Stripes takes care of double-submits
+
+(b) 
+accept-charset becomes "acceptcharset" and should use UTF-8.
+
+    acceptcharset="${wikiEngine.contentEncoding}"
 
+(c) INFO
 Hidden values are PROBABLY candidates to become bean properties that are automatically bound. E.g., in LoginForm.jsp,
 <input type="hidden" name="redirect" value="<wiki:Variable var='redirect' default='' />" /> disappears because setRedirect() is already part of LoginActionBean.
 
-Replace:
+(d) INFO
+Consider replacing:
         <wiki:Messages div="error" topic="login"
                     prefix='<%=LocaleSupport.getLocalizedMessage(pageContext,"login.errorprefix")%>' />
 

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractJspTransformer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractJspTransformer.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractJspTransformer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractJspTransformer.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,34 @@
+package com.ecyrd.jspwiki.ui.stripes;
+
+import java.util.Map;
+
+
+/**
+ * Abstract implementation of JspTransformer that contains utility methods for subclasses, such as logging.
+ */
+public abstract class AbstractJspTransformer implements JspTransformer
+{
+
+    public abstract void transform( Map<String, Object> sharedState, JspDocument doc );
+
+    /**
+     * Prints a standard message for a node, prefixed by the line, position and character range.
+     * @param node the node the message pertains to
+     * @param message the message, which will be printed after the prefix
+     */
+    protected void message( Node node, String message )
+    {
+        String nodename;
+        if ( node.getType() == NodeType.ATTRIBUTE )
+        {
+            nodename = "<" + node.getParent().getName() + "> \"" + node.getName() + "\" attribute";
+        }
+        else
+        {
+            nodename = "<" + node.getName() + ">";
+        }
+        System.out.println( "(line " + node.getLine() + "," + node.getColumn() + " chars " + node.getStart() + ":"
+                            + node.getEnd() + ") " + nodename + " - " + message );
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractNode.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractNode.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractNode.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AbstractNode.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,353 @@
+package com.ecyrd.jspwiki.ui.stripes;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Element that has been parsed.
+ */
+public abstract class AbstractNode implements Node
+{
+    protected NodeType m_type;
+
+    protected int m_start = POSITION_NOT_SET;
+
+    protected int m_end = POSITION_NOT_SET;
+
+    protected int m_line = POSITION_NOT_SET;
+
+    protected int m_col = POSITION_NOT_SET;
+
+    protected Node m_parent = null;
+
+    protected String m_name = null;
+
+    protected JspDocument m_doc = null;
+
+    protected List<Node> m_children = new ArrayList<Node>();
+
+    /**
+     * Constructs a new Node.
+     * 
+     * @param doc the parent JspDocument
+     * @param type the node type
+     */
+    AbstractNode( JspDocument doc, NodeType type )
+    {
+        m_doc = doc;
+        m_type = type;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#addChild(com.ecyrd.jspwiki.ui.stripes.Node)
+     */
+    public void addChild( Node node )
+    {
+        // Set parent/child relationships
+        node.setParent( this );
+        m_children.add( node );
+
+        // If this node is a "combined node," split it into two
+        if( m_type == NodeType.HTML_COMBINED_TAG )
+        {
+            // Check that this node has a parent
+            if( m_parent == null )
+            {
+                throw new IllegalStateException( "Node has no parent!" );
+            }
+
+            // Change node type to start tag
+            m_type = NodeType.HTML_START_TAG;
+
+            // Build new end tag & set its parent
+            Tag endNode = new Tag( m_doc, NodeType.HTML_END_TAG );
+            endNode.setName( m_name );
+            // FIXME
+            // endNode.setText( NodeType.HTML_END_TAG.getTagEnd() + m_name +
+            // NodeType.HTML_END_TAG.getTagEnd() );
+            endNode.setParent( m_parent );
+
+            // Insert as sibling of this node
+            List<Node> siblings = m_parent.getChildren();
+            int index = siblings.indexOf( this );
+            if( index == siblings.size() - 1 )
+            {
+                siblings.add( endNode );
+            }
+            else
+            {
+                siblings.add( index, endNode );
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getChildren()
+     */
+    public List<Node> getChildren()
+    {
+        List<Node> nodesCopy = new ArrayList<Node>();
+        nodesCopy.addAll( m_children );
+        return Collections.unmodifiableList( nodesCopy );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getColumn()
+     */
+    public int getColumn()
+    {
+        return m_col;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getEnd()
+     */
+    public int getEnd()
+    {
+        return m_end;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getLevel()
+     */
+    public int getLevel()
+    {
+        if( m_parent == null )
+        {
+            return -1;
+        }
+
+        int level = 0;
+        Node node = this;
+        while ( node.getType() != NodeType.ROOT )
+        {
+            level++;
+            node = node.getParent();
+        }
+        return level;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getLine()
+     */
+    public int getLine()
+    {
+        return m_line;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getName()
+     */
+    public String getName()
+    {
+        return m_name;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getParent()
+     */
+    public Node getParent()
+    {
+        return m_parent;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getSiblings()
+     */
+    public List<Node> getSiblings()
+    {
+        List<Node> siblings = new ArrayList<Node>();
+        for( Node sibling : m_parent.getChildren() )
+        {
+            if( !this.equals( sibling ) )
+            {
+                siblings.add( sibling );
+            }
+        }
+        return Collections.unmodifiableList( siblings );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getStart()
+     */
+    public int getStart()
+    {
+        return m_start;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getType()
+     */
+    public NodeType getType()
+    {
+        return m_type;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#isHtmlNode()
+     */
+    public boolean isHtmlNode()
+    {
+        return m_type == NodeType.HTML_START_TAG || m_type == NodeType.HTML_COMBINED_TAG || m_type == NodeType.UNRESOLVED_HTML_TAG
+               || m_type == NodeType.HTML_END_TAG;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#isJspNode()
+     */
+    public boolean isJspNode()
+    {
+        return m_type == NodeType.JSP_COMMENT || m_type == NodeType.JSP_DECLARATION || m_type == NodeType.JSP_EXPRESSION
+               || m_type == NodeType.SCRIPTLET || m_type == NodeType.JSP_DIRECTIVE || m_type == NodeType.UNRESOLVED_JSP_TAG;
+    }
+
+    /**
+     * Returns <code>true</code> if the node can contain attributes,
+     * <code>false</code> otherwise.
+     * 
+     * @return the result
+     */
+    public boolean isTagWithAttributes()
+    {
+        return m_type == NodeType.HTML_START_TAG || m_type == NodeType.HTML_COMBINED_TAG || m_type == NodeType.UNRESOLVED_HTML_TAG;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#removeChild(com.ecyrd.jspwiki.ui.stripes.Node)
+     */
+    public void removeChild( Node node )
+    {
+        m_children.remove( node );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#setColumn(int)
+     */
+    public void setColumn( int i )
+    {
+        m_col = i;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#setEnd(int)
+     */
+    public void setEnd( int pos )
+    {
+        m_end = pos;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#setLine(int)
+     */
+    public void setLine( int i )
+    {
+        m_line = i;
+    }
+
+    /**
+     * Sets the name value of the Node to a supplied string. This method
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#setName(Node)
+     */
+    public void setName( String name )
+    {
+        m_name = name;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#setParent(com.ecyrd.jspwiki.ui.stripes.Node)
+     */
+    public void setParent( Node parent )
+    {
+        m_parent = parent;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#setStart(int)
+     */
+    public void setStart( int pos )
+    {
+        m_start = pos;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#setType(com.ecyrd.jspwiki.ui.stripes.NodeType)
+     */
+    public void setType( NodeType type )
+    {
+        m_type = type;
+    }
+
+    public JspDocument getJspDocument()
+    {
+        return m_doc;
+    }
+    
+    
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.ecyrd.jspwiki.ui.stripes.Node#getValue()
+     */
+    public String getValue()
+    {
+        StringBuilder builder = new StringBuilder();
+        for ( Node child : m_children )
+        {
+            builder.append( child.toString() );
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Replaces all children of the Tag with a single Text node.
+     * @param value the string to set
+     */
+    public void setValue( String value )
+    {
+        m_children.clear();
+        Text node = new Text( m_doc );
+        node.setValue( value );
+        m_children.add( node );
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AllTests.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AllTests.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AllTests.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/AllTests.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,19 @@
+package com.ecyrd.jspwiki.ui.stripes;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class AllTests extends TestCase
+{
+    public static Test suite()
+    {
+        TestSuite suite = new TestSuite("JSP migration tests");
+        suite.addTest( JspParserTest.suite() );
+        suite.addTest( JspDocumentTest.suite() );
+        suite.addTest( JSPWikiJspTransformerTest.suite() );
+        suite.addTest( StripesJspTransformerTest.suite() );
+        return suite;
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/Attribute.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/Attribute.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/Attribute.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/Attribute.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,50 @@
+package com.ecyrd.jspwiki.ui.stripes;
+
+/**
+ * Represents an HTML attribute
+ */
+public class Attribute extends AbstractNode
+{
+    private char m_quote = '\"';
+    
+    public Attribute( JspDocument doc )
+    {
+        super(doc, NodeType.ATTRIBUTE);
+    }
+
+    public char getAttributeDelimiter()
+    {
+        return m_quote;
+    }
+    
+    public void setAttributeDelimiter( char quote )
+    {
+        m_quote = quote;
+    }
+    
+    /**
+     * Always throws an {@link java.lang.UnsupportedOperationException}
+     */
+    @Override
+    public void setType( NodeType type )
+    {
+        throw new UnsupportedOperationException( "Attributes are always of type NodeType.ATTRIBUTE; illegal to call this method." );
+    }
+
+    /**
+     * Returns the string that represents the Attribute, including the name and value, which may include embedded tags.
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append(  m_name );
+        sb.append( '=' );
+        sb.append( m_quote );
+        for ( Node valueNode : m_children )
+        {
+            sb.append( valueNode.toString() );
+        }
+        sb.append( m_quote );
+        return sb.toString();
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformer.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformer.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,71 @@
+package com.ecyrd.jspwiki.ui.stripes;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Transforms a JspDocument from standard JSP markup to Stripes markup.
+ */
+public class JSPWikiJspTransformer extends AbstractJspTransformer
+{
+
+    public void transform( Map<String, Object> sharedState, JspDocument doc )
+    {
+        List<Node> nodes = doc.getNodes();
+
+        for( Node node : nodes )
+        {
+            // For all HTML tags...
+            if( node.isHtmlNode() )
+            {
+                Tag tag = (Tag)node;
+                
+                // Check any form or stripes:form elements
+                if( "form".equals( tag.getName() ) || "stripes:form".equals( tag.getName() ) )
+                {
+                    // Change "accept-charset" or "acceptcharset" values to UTF-8
+                    Attribute attribute = tag.getAttribute( "accept-charset" );
+                    if ( attribute == null )
+                    {
+                        attribute = tag.getAttribute( "acceptcharset" );
+                    }
+                    if( attribute != null )
+                    {
+                        message( attribute, "Changed value to \"UTF-8\"." );
+                        attribute.setValue( "UTF-8" );
+                    }
+                    
+                    // Remove onsubmit() attribute and warn the user
+                    attribute = tag.getAttribute( "onsubmit" );
+                    if( attribute != null )
+                    {
+                        String value = attribute.getValue();
+                        message( attribute, "Removed JavaScript call \"" + value + "\". REASON: it probably does not work with Stripes." );
+                        tag.removeAttribute( attribute );
+                    }
+                }
+                
+                // Advise user about <input type="hidden"> tags
+                boolean isTypeHidden = false;
+                isTypeHidden = "stripes:form".equals( tag.getName() );
+                if( "input".equals( tag.getName() ) )
+                {
+                    Attribute attribute = tag.getAttribute( "type" );
+                    isTypeHidden = "hidden".equals( attribute.getValue() );
+                }
+                if( isTypeHidden )
+                {
+                    Attribute hidden = tag.getAttribute( "name" );
+                    message( hidden, "NOTE: hidden form input \"" + hidden.getValue() +"\" should probably correspond to a Stripes ActionBean getter/settter. Refactor?"  );
+                }
+                
+                // Tell user about <wiki:Messages> tags.
+                if ( "wiki:Messages".equals( tag.getName() ) )
+                {
+                    message( tag, "Consider using <stripes:errors> tags instead of <wiki:Messages> for displaying validation errors." );
+                }
+            }
+        }
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformerTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformerTest.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformerTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JSPWikiJspTransformerTest.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,58 @@
+package com.ecyrd.jspwiki.ui.stripes;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+public class JSPWikiJspTransformerTest extends TestCase
+{
+    protected Map<String,Object> m_sharedState = new HashMap<String,Object>();
+    protected JspTransformer m_transformer = new JSPWikiJspTransformer();
+    protected JspDocument m_doc = new JspDocument();
+    
+    public JSPWikiJspTransformerTest( String s )
+    {
+        super( s );
+    }
+
+    public void testAcceptCharset() throws Exception
+    {
+        String s = "<form accept-charset=\"ISO\" method=\"POST\" />";
+        JspDocument doc = new JspParser().parse( s );
+        m_transformer.transform( m_sharedState, doc );
+
+        assertEquals( 1, doc.getNodes().size() );
+        Node node = doc.getNodes().get( 0 );
+        assertEquals( "form", node.getName() );
+        
+        assertEquals( 2, ((Tag)node).getAttributes().size() );
+        Node attribute = ((Tag)node).getAttributes().get( 0 );
+        assertEquals( "accept-charset", attribute.getName() );
+        assertEquals( "UTF-8", attribute.getValue() );
+    }
+
+    public void testOnSubmit() throws Exception
+    {
+        String s = "<form method=\"POST\" onsubmit=\"return Wiki.submitOnce(this);\" />";
+        JspDocument doc = new JspParser().parse( s );
+        m_transformer.transform( m_sharedState, doc );
+
+        assertEquals( 1, doc.getNodes().size() );
+        Node node = doc.getNodes().get( 0 );
+        assertEquals( "form", node.getName() );
+        
+        assertEquals( 1, ((Tag)node).getAttributes().size() );
+        Node attribute = ((Tag)node).getAttributes().get( 0 );
+        assertEquals( "method", attribute.getName() );
+        assertEquals( "POST", attribute.getValue() );
+    }
+
+    public static Test suite()
+    {
+        return new TestSuite( JSPWikiJspTransformerTest.class );
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDirective.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDirective.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDirective.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDirective.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,133 @@
+/**
+ * 
+ */
+package com.ecyrd.jspwiki.ui.stripes;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Node implementation representing a JSP directive node.
+ */
+public class JspDirective extends AbstractNode
+{
+    private List<Attribute> m_attributes = new ArrayList<Attribute>();
+
+    /**
+     * 
+     * @param doc the parent JspDocument
+     * @param type
+     */
+    public JspDirective ( JspDocument doc )
+    {
+        super( doc, NodeType.JSP_DIRECTIVE );
+    }
+    
+    /**
+     * Always throws an {@link java.lang.UnsupportedOperationException}
+     */
+    @Override
+    public void setType( NodeType type )
+    {
+        throw new UnsupportedOperationException( "Attributes are always of type NodeType.JSP_DIRECTIVE; illegal to call this method." );
+    }
+
+
+    public void addAttribute( Attribute attribute )
+    {
+        m_attributes.add( attribute );
+    }
+
+    /**
+     * Returns the attribute whose name matches a supplied string, or
+     * <code>null</code> if not found.
+     * 
+     * @param name the named attribute to search for
+     * @return the attribute if found, or <code>null</code>
+     */
+    public Attribute getAttribute( String name )
+    {
+        if( name == null )
+        {
+            throw new IllegalArgumentException( "Name cannot be null. " );
+        }
+        for( Attribute attribute : m_attributes )
+        {
+            if( name.equals( attribute.getName() ) )
+            {
+                return attribute;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the attributes of this node, as a defensive copy of the
+     * internally-cached list.
+     * 
+     * @return
+     */
+    public List<Attribute> getAttributes()
+    {
+        List<Attribute> attributesCopy = new ArrayList<Attribute>();
+        attributesCopy.addAll( m_attributes );
+        return Collections.unmodifiableList( attributesCopy );
+    }
+
+    public void removeAttribute( Attribute attribute )
+    {
+        m_attributes.remove( attribute );
+    }
+
+    public String  getValue()
+    {
+        return m_value;
+    }
+    
+    public void setValue( String value )
+    {
+        m_value = value;
+    }
+    
+    private String m_value;
+    
+    /**
+     * Returns the string that represents the Tag, including the name and attributes, but not any child nodes.
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append( m_type.getTagStart() );
+        
+        // HTML nodes and JSP directives are formatted in mostly the same way.
+        if ( isHtmlNode() || m_type == NodeType.JSP_DIRECTIVE )
+        {
+            if ( m_type == NodeType.JSP_DIRECTIVE )
+            {
+                sb.append( ' ' );
+            }
+            sb.append(  m_name );
+            if( m_attributes.size() > 0 )
+            {
+                for( Attribute attr : m_attributes )
+                {
+                    sb.append( ' ' );
+                    sb.append( attr.toString() );
+                }
+            }
+        }
+        
+        // Everything else is just the start/end tags plus the children nodes
+        else {
+            for ( Node child : m_children )
+            {
+                sb.append( child.toString() );
+            }
+        }
+        
+        sb.append( m_type.getTagEnd() );
+        return sb.toString();
+    }
+
+}

Copied: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocument.java (from r692772, incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/util/JspDocument.java)
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocument.java?p2=incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocument.java&p1=incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/util/JspDocument.java&r1=692772&r2=695481&rev=695481&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/util/JspDocument.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocument.java Mon Sep 15 07:21:34 2008
@@ -1,325 +1,15 @@
-package com.ecyrd.jspwiki.util;
+package com.ecyrd.jspwiki.ui.stripes;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import java.util.Stack;
 
 /**
  * Tree structure that represents a JSP document.
  */
 class JspDocument
 {
-    private static final int POSITION_NOT_SET = -1;
-
-    public static class Attribute
-    {
-        Attribute()
-        {
-            super();
-        }
-
-        public int getStart()
-        {
-            return start;
-        }
-
-        public int getEnd()
-        {
-            return end;
-        }
-
-        public String getName()
-        {
-            return name;
-        }
-
-        public Node getValue()
-        {
-            return value;
-        }
-
-        /**
-         * Returns the quote character used to delimit the attribute value; by
-         * definition, either ' or ".
-         * 
-         * @return the quote character
-         */
-        public char getQuoteChar()
-        {
-            return quote;
-        }
-
-        private String name = null;
-
-        private Node value = new JspDocument.Node( Node.Type.UNDEFINED );
-
-        private int start = POSITION_NOT_SET;
-
-        private int end = POSITION_NOT_SET;
-
-        private char quote = QUOTE_NOT_SET;
-    }
-
-    /**
-     * Element that has been parsed.
-     */
-    public static class Node
-    {
-        public enum Type
-        {
-            /** Root node */
-            ROOT("ROOT", null, null),
-            /** Text node */
-            TEXT("TEXT", "", ""),
-            /** HTML start tag */
-            HTML_START_TAG("HTML_START_TAG", "<", ">"),
-            /** HTML end tag */
-            HTML_END_TAG("HTML_END_TAG", "</", ">"),
-            /** HTML end tag */
-            HTML_COMBINED_TAG("HTML_COMBINED_TAG", "<", "/>"),
-            /** HTML tag, but not sure whether it's a start, end or combined tag. */
-            UNDEFINED_HTML_TAG("UNDEFINED_HTML_TAG", "<", null),
-            /** JSP comments, e.g., &lt;%-- comment --%&gt; */
-            JSP_COMMENT("JSP_COMMENT", "<%--", "--%>"),
-            /**
-             * JSP declaration, e.g., &lt;%! declaration; [ declaration; ]+ ...
-             * %&gt;
-             */
-            JSP_DECLARATION("JSP_DECLARATION", "<%!", "%>"),
-            /** JSP expression, e.g., &lt;%= expression %&gt; */
-            JSP_EXPRESSION("JSP_EXPRESSION", "<%=", "%>"),
-            /**
-             * JSP scriptlet, e.g., &lt;% code fragment %&gt;. Note the
-             * whitespace after the %.
-             */
-            SCRIPTLET("SCRIPTLET", "<%", "%>"),
-            /**
-             * JSP page, import or taglib directive, e.g., &lt;%@ include...
-             * %&gt; &lt;%@ page... %&gt; &lt;%@ taglib... %&gt;
-             */
-            JSP_DIRECTIVE("JSP_DIRECTIVE", "<%@", "%>"),
-            /** JSP tag, but not sure what kind.. */
-            UNDEFINED_JSP_TAG("UNEFINED_JSP_TAG", null, null),
-            /** Parser has seen &lt;, but hasn't figured out what it is yet. */
-            UNDEFINED("UNDEFINED", null, null);
-            Type( String description, String tagStart, String tagEnd )
-            {
-                this.description = description;
-                this.tagStart = tagStart;
-                this.tagEnd = tagEnd;
-            }
-
-            private final String description;
-
-            private final String tagStart;
-
-            private final String tagEnd;
-        }
-
-        private Node.Type type;
-
-        private String text = null;
-
-        private List<JspDocument.Attribute> attributes = new ArrayList<JspDocument.Attribute>();
-
-        private int level = 0;
-
-        private int start = POSITION_NOT_SET;
-
-        private int end = POSITION_NOT_SET;
-
-        private int line = POSITION_NOT_SET;
-
-        private int col = POSITION_NOT_SET;
-
-        private Node parent = null;
-
-        private String name = null;
-
-        private List<Node> children = new ArrayList<Node>();
-
-        /**
-         * Returns the value of the node, which will be equal to the text of the
-         * node, minus the start and end delimiters specified for the node type.
-         * Thus, a node whose text is set to <code>&lt;/endtag&gt;</code> and
-         * whose type is {@link Node.Type#HTML_END_TAG} would return the value
-         * <code>endtag</code>.
-         * 
-         * @return the value
-         */
-        public String getValue()
-        {
-            if( text == null )
-            {
-                return null;
-            }
-            return text.substring( type.tagStart.length(), text.length() - type.tagEnd.length() );
-        }
-
-        /**
-         * Returns the name of the tag, if the node is an HTML start, end, or
-         * combined tag, or the directive name if a JSP directive; <code>null</code> otherwise.
-         * 
-         * @return the tag name
-         */
-        public String getName()
-        {
-            return name;
-        }
-
-        /**
-         * Returns the line of the source text the node starts on.
-         * 
-         * @return the line
-         */
-        public int getLine()
-        {
-            return line;
-        }
-
-        /**
-         * Returns the starting character position of the node, inclusive,
-         * relative to the beginning of the source text.
-         * 
-         * @return the start position
-         */
-        public int getStartChar()
-        {
-            return start;
-        }
-
-        public List<JspDocument.Attribute> getAttributes()
-        {
-            return attributes;
-        }
-
-        /**
-         * Returns the exnding character position of the node, exclusive,
-         * relative to the beginning of the source text.
-         * 
-         * @return the end position
-         */
-        public int getEndChar()
-        {
-            return end;
-        }
-
-        /**
-         * Returns the type of the node.
-         * 
-         * @return the type
-         */
-        public Node.Type getType()
-        {
-            return type;
-        }
-
-        /**
-         * Returns the column the node starts on, relative to the beginning of
-         * the line in the source text.
-         * 
-         * @return the column
-         */
-        public int getColumn()
-        {
-            return col;
-        }
-
-        /**
-         * Returns the "level" of the tag; that is, how far from the top-level
-         * nodes (which are level 1).
-         * 
-         * @return
-         */
-        public int getLevel()
-        {
-            return level;
-        }
-
-        /**
-         * Returns the "child" nodes relative to the current one.
-         * 
-         * @return the children
-         */
-        public List<Node> getChildren()
-        {
-            return children;
-        }
-
-        /**
-         * Returns the siblings of this node.
-         * 
-         * @return the siblings
-         */
-        public List<Node> getSiblings()
-        {
-            List<Node> siblings = new ArrayList<Node>();
-            for( Node sibling : parent.children )
-            {
-                if( !this.equals( sibling ) )
-                {
-                    siblings.add( sibling );
-                }
-            }
-            return siblings;
-        }
-
-        /**
-         * Returns the parent of this node, which may be null if a top-level
-         * node.
-         * 
-         * @return the parent
-         */
-        public Node getParent()
-        {
-            return parent.type == Node.Type.ROOT ? null : parent;
-        }
-
-        /**
-         * Constructs a new Node. Callers should use the
-         * {@link JspDocument#createNode(com.ecyrd.jspwiki.util.JspDocument.Node.Type, int)}
-         * method instead
-         * 
-         * @param type the node type
-         */
-        private Node( Node.Type type )
-        {
-            this.type = type;
-        }
-
-        public boolean isJspNode()
-        {
-            return type == Type.JSP_COMMENT || type == Type.JSP_DECLARATION || type == Type.JSP_EXPRESSION
-                   || type == Type.SCRIPTLET || type == Type.JSP_DIRECTIVE || type == Type.UNDEFINED_JSP_TAG;
-        }
-
-        /**
-         * Returns <code>true</code> if the node can contain attributes,
-         * <code>false</code> otherwise.
-         * 
-         * @return the result
-         */
-        public boolean isTag()
-        {
-            return type == Type.HTML_START_TAG || type == Type.HTML_COMBINED_TAG || type == Type.UNDEFINED_HTML_TAG;
-        }
-
-        public String toString()
-        {
-            return "[" + type.description + "(pos=" + line + ":" + col + ",chars=" + start + ":" + end + ",L" + level + "):\""
-                   + text + "\"]";
-        }
-    }
-
-    private static final char QUOTE_NOT_SET = 0;
-
-    private final Stack<JspDocument.Node> nodeStack = new Stack<JspDocument.Node>();
-
-    private final List<JspDocument.Node> allNodes = new ArrayList<JspDocument.Node>();
-
-    private final List<Integer> lineBreaks = new ArrayList<Integer>();
-
-    private Node root = null;
+    private final AbstractNode root;
 
     /**
      * Constructs a new JspDocument.
@@ -327,17 +17,21 @@
     public JspDocument()
     {
         super();
+        root = new Tag( this, NodeType.ROOT );
     }
 
     /**
      * Returns the list of nodes parsed by {@link #parse(String)}, in the order
-     * parsed.
+     * parsed (depth-first search). The list returned is a defensive copy of the
+     * internally cached list.
      * 
      * @return the list of nodes
      */
-    public List<JspDocument.Node> getNodes()
+    public List<Node> getNodes()
     {
-        return allNodes;
+        List<Node> allNodes = new ArrayList<Node>();
+        visitChildren( allNodes, root.getChildren() );
+        return Collections.unmodifiableList( allNodes );
     }
 
     /**
@@ -346,12 +40,12 @@
      * 
      * @return the list of nodes
      */
-    public List<JspDocument.Node> getNodes( JspDocument.Node.Type type )
+    public List<Node> getNodes( NodeType type )
     {
-        List<JspDocument.Node> typeNodes = new ArrayList<JspDocument.Node>();
-        for( JspDocument.Node node : allNodes )
+        List<Node> typeNodes = new ArrayList<Node>();
+        for( Node node : getNodes() )
         {
-            if( node.type == type )
+            if( node.getType() == type )
             {
                 typeNodes.add( node );
             }
@@ -360,395 +54,45 @@
     }
 
     /**
-     * Factory method that constructs and returns a new Node. This node is
-     * appended to the internal list of Nodes. When constructed, the node's
-     * start position, line number, column number and level are set
-     * automatically based on JspDocument's internal cache of line-breaks and
-     * nodes.
-     * 
-     * @param type the node type
-     * @param pos the start position for the node
-     * @return the new Node
-     */
-    protected JspDocument.Node createNode( JspDocument.Node.Type type, int pos )
+     * Returns all of the child nodes for a supplied Tag, recursively.
+     * @param start
+     * @return the list of tags
+     */
+    public List<Node> getChildren( Tag start )
+    {
+        List<Node> allChildren = new ArrayList<Node>();
+        visitChildren( allChildren, start.getChildren() );
+        return allChildren;
+    }
+    
+    public AbstractNode getRoot()
     {
-        // If last node added has no length (i.e., is null), get rid of it
-        Node parent = nodeStack.peek();
-        if( allNodes.size() > 0 )
-        {
-            JspDocument.Node lastNode = allNodes.get( allNodes.size() - 1 );
-            if( lastNode.start == lastNode.end )
-            {
-                allNodes.remove( lastNode );
-                parent.children.remove( lastNode );
-            }
-        }
-
-        // Create new Node and set parent/child relationships
-        JspDocument.Node node = new JspDocument.Node( type );
-        node.parent = parent;
-        parent.children.add( node );
-        allNodes.add( node );
-
-        // Set the start, end, linebreak and level
-        node.start = pos;
-        int lastLineBreakPos = lineBreaks.size() == 0 ? POSITION_NOT_SET : lineBreaks.get( lineBreaks.size() - 1 );
-        node.line = lineBreaks.size() + 1;
-        node.col = pos - lastLineBreakPos;
-        node.level = nodeStack.size();
-
-        return node;
+        return root;
     }
 
-    /**
-     * Parses a JSP file, supplied as a String, into Nodes.
-     * 
-     * @param source the JSP file contents
-     */
-    public void parse( String source )
+    private void visitChildren( List<Node> collection, List<Node> children )
     {
-        // First, break the raw text into Nodes
-        parseNodes( source );
-
-        // Now, visit each Node and extract attributes (for HTML tags) or the directive name (for JSP directives)
-        for( Node node : allNodes )
+        for( Node child : children )
         {
-            if( node.isTag() || node.getType() == Node.Type.JSP_DIRECTIVE )
+            collection.add( child );
+            if( child.getChildren().size() >= 0 )
             {
-                String nodeValue = node.getValue().substring( node.getValue().indexOf( node.name ) + node.name.length() );
-                parseAttributes( node, nodeValue );
+                visitChildren( collection, child.getChildren() );
             }
         }
     }
     
     /**
-     * Extracts the attributes for a supplied Node.
-     * @param source the text to parse
-     */
-    protected void parseAttributes( Node node, String source )
-    {
-        // Get the node text starting just after the tag name.
-        if ( source.length() == 0 )
-        {
-            return;
-        }
-
-        // Parse the node's value string, character by character
-        int pos = 0;
-        JspDocument.Attribute attribute = null;
-        for( char ch : source.toCharArray() )
-        {
-            switch( ch )
-            {
-                case ('<'): {
-                    // If attribute already set, the left bracket will always
-                    // signal a nested JSP expression
-                    if( attribute != null && attribute.value.start == POSITION_NOT_SET )
-                    {
-                        attribute.value.start = pos;
-                        attribute.value.type = JspDocument.Node.Type.JSP_EXPRESSION;
-                    }
-                    break;
-                }
-
-                case (' '):
-                case ('\t'):
-                case ('\r'):
-                case ('\n'):
-                case ('\u000B'):
-                case ('\u000C'):
-                case ('\u001C'):
-                case ('\u001D'):
-                case ('\u001E'):
-                case ('\u001F'): {
-                    // If no current attribute, whitespace marks the
-                    // start
-                    if( attribute == null )
-                    {
-                        attribute = new Attribute();
-                    }
-                    break;
-                }
-
-                    // If single/double quote and HTML tag, start/stop/continue
-                    // an attribute
-                case ('\''):
-                case ('\"'): {
-                    if( attribute != null )
-                    {
-                        // If the same as the quote char used to start the
-                        // attribute, we're done; extract the attribute value
-                        if( attribute.quote == ch )
-                        {
-                            attribute.value.end = pos;
-                            attribute.value.text = source.substring( attribute.value.start, attribute.value.end );
-                            node.attributes.add( attribute );
-                            attribute = null;
-                        }
-                        else if( attribute.quote == QUOTE_NOT_SET )
-                        {
-                            attribute.quote = ch;
-                        }
-                        break;
-                    }
-                }
-
-                case ('='):
-                {
-                    if( attribute != null && attribute.name == null )
-                    {
-                        attribute.name = source.substring( attribute.start, pos );
-                    }
-                    break;
-                }
-
-                default: {
-                    // If inside an attribute, set the start position if not set
-                    if( attribute != null )
-                    {
-                        if( attribute.start == POSITION_NOT_SET )
-                        {
-                            attribute.start = pos;
-                        }
-                        else if( attribute.quote != QUOTE_NOT_SET && attribute.value.start == POSITION_NOT_SET )
-                        {
-                            attribute.value.start = pos;
-                            attribute.value.type = JspDocument.Node.Type.TEXT;
-                        }
-                    }
-                }
-            }
-            pos++;
-        }
-    }
-
-    /**
-     * Parses a supplied String into its component Nodes. For simplicity's sake,
-     * this method does <em>not</em> parse each Node's attributes.
-     * 
-     * @param source the string to parse
+     * Returns the JspDocument as a String, reconstructed from the Nodes it contains.
      */
-    protected void parseNodes( String source )
+    public String toString()
     {
-        // Clear out the node cache and stack
-        nodeStack.clear();
-        allNodes.clear();
-
-        // Create a root node that contains all top-level siblings
-        root = new JspDocument.Node( Node.Type.ROOT );
-        nodeStack.push( root );
-
-        // Reset the character counter
-        char lastCh = ' ';
-        int pos = 0;
-        int directiveNameStart = POSITION_NOT_SET;
-        JspDocument.Node node = createNode( JspDocument.Node.Type.TEXT, pos );
-
-        // Parse the file, character by character
-        for( char ch : source.toCharArray() )
+        StringBuilder builder = new StringBuilder();
+        List<Node> allNodes = getNodes();
+        for ( Node node : allNodes )
         {
-            switch( ch )
-            {
-                // The left angle bracket ALWAYS starts a new node
-                case ('<'): {
-                    node.end = pos;
-                    if( node.type == JspDocument.Node.Type.TEXT )
-                    {
-                        if( pos > 0 )
-                        {
-                            if( node.end > node.start )
-                            {
-                                node.text = source.substring( node.start, node.end );
-                            }
-                        }
-                    }
-                    else
-                    {
-                        nodeStack.push( node );
-                    }
-                    node = createNode( JspDocument.Node.Type.UNDEFINED, pos );
-                    break;
-                }
-
-                    // Slash following left angle bracket </ means HTML
-                    // end-tag
-                    // if
-                    // we're not inside JSP item
-                case ('/'): {
-                    if( lastCh == '<' && !node.isJspNode() )
-                    {
-                        node.type = JspDocument.Node.Type.HTML_END_TAG;
-                    }
-                    break;
-                }
-
-                    // Right angle bracket always means end of a tag
-                case ('>'): {
-
-                    node.end = pos + 1;
-                    node.text = source.substring( node.start, node.end );
-                    if( node.type == JspDocument.Node.Type.UNDEFINED_HTML_TAG )
-                    {
-                        if( lastCh == '/' )
-                        {
-                            node.type = JspDocument.Node.Type.HTML_COMBINED_TAG;
-                        }
-                        else
-                        {
-                            node.type = JspDocument.Node.Type.HTML_START_TAG;
-                        }
-                    }
-
-                    // If the last node added was a blank/empty text node,
-                    // remove it
-                    if( nodeStack.size() > 1 )
-                    {
-                        node = nodeStack.pop();
-                    }
-                    else
-                    {
-                        node = createNode( JspDocument.Node.Type.TEXT, pos + 1 );
-                    }
-                    break;
-                }
-
-                case (' '):
-                case ('\t'):
-                case ('\r'):
-                case ('\n'):
-                case ('\u000B'):
-                case ('\u000C'):
-                case ('\u001C'):
-                case ('\u001D'):
-                case ('\u001E'):
-                case ('\u001F'): {
-                    if( node.type != JspDocument.Node.Type.TEXT )
-                    {
-                        // If inside the start of JSP tag, space following
-                        // percent means scriptlet
-                        if( node.type == JspDocument.Node.Type.UNDEFINED_JSP_TAG )
-                        {
-                            if( lastCh == '%' )
-                            {
-                                node.type = JspDocument.Node.Type.SCRIPTLET;
-                            }
-                        }
-                        else if( node.type == JspDocument.Node.Type.UNDEFINED )
-                        {
-                            node.type = JspDocument.Node.Type.UNDEFINED_HTML_TAG;
-                        }
-
-                        // If inside JSP directive and name not set, set it
-                        if ( node.type == JspDocument.Node.Type.JSP_DIRECTIVE )
-                        {
-                            if ( node.name == null &&  directiveNameStart != POSITION_NOT_SET )
-                            {
-                                node.name = source.substring( directiveNameStart, pos );
-                            }
-                        }
-                        
-                        // If inside HTML tag, whitespace marks the end of the
-                        // tag name
-                        if( node.isTag() )
-                        {
-                            // Set the tag name if still empty
-                            if( node.name == null )
-                            {
-                                node.name = source.substring( node.start + node.type.tagStart.length(), pos );
-                            }
-                        }
-                    }
-
-                    // Reset the line/column counters if we encounter linebreaks
-                    if( ch == '\r' || ch == '\n' )
-                    {
-                        lineBreaks.add( pos );
-                    }
-                    break;
-                }
-
-                    // Percent after starting < means JSP tag of some kind
-                case ('%'): {
-                    if( node.type == JspDocument.Node.Type.UNDEFINED )
-                    {
-                        node.type = JspDocument.Node.Type.UNDEFINED_JSP_TAG;
-                        directiveNameStart = POSITION_NOT_SET;
-                    }
-                    break;
-                }
-
-                    // Dash after starting <% means hidden JSP comment
-                case ('-'): {
-                    if( node.type == JspDocument.Node.Type.UNDEFINED_JSP_TAG && lastCh == '%' )
-                    {
-                        node.type = JspDocument.Node.Type.JSP_COMMENT;
-                    }
-                    break;
-                }
-
-                    // Bang after starting <% means JSP declaration
-                case ('!'): {
-                    if( node.type == JspDocument.Node.Type.UNDEFINED_JSP_TAG && lastCh == '%' )
-                    {
-                        node.type = JspDocument.Node.Type.JSP_DECLARATION;
-                    }
-                    break;
-                }
-
-                    // Equals after starting <% means JSP expression; inside
-                    // attribute means end of name
-                case ('='): {
-                    if( node.type == JspDocument.Node.Type.UNDEFINED_JSP_TAG && lastCh == '%' )
-                    {
-                        node.type = JspDocument.Node.Type.JSP_EXPRESSION;
-                    }
-                    break;
-                }
-
-                    // At-sign after starting <% means JSP directive
-                case ('@'): {
-                    if( node.type == JspDocument.Node.Type.UNDEFINED_JSP_TAG && lastCh == '%' )
-                    {
-                        node.type = JspDocument.Node.Type.JSP_DIRECTIVE;
-                    }
-                    break;
-                }
-
-                default: {
-                    // If node is still undefined, any other character is by
-                    // definition part of a text block
-                    if( node.type == JspDocument.Node.Type.UNDEFINED )
-                    {
-                        node.type = JspDocument.Node.Type.UNDEFINED_HTML_TAG;
-                    }
-                    
-                    // If in JSP directive and name start not set, start it here
-                    else if ( node.type == JspDocument.Node.Type.JSP_DIRECTIVE && directiveNameStart == POSITION_NOT_SET )
-                    {
-                        directiveNameStart = pos;
-                    }
-                }
-            }
-
-            // Increment the character position and line metrics
-            lastCh = ch;
-            pos++;
-        }
-
-        // Set the end point for the last node
-        if( node != null )
-        {
-            node.end = pos;
-            if( node.start == node.end )
-            {
-                allNodes.remove( node );
-                node.parent.children.remove( node );
-            }
-            else
-            {
-                node.text = source.substring( node.start, node.end );
-            }
+            builder.append( node.toString() );
         }
+        return builder.toString();
     }
-
 }

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocumentTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocumentTest.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocumentTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspDocumentTest.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,41 @@
+package com.ecyrd.jspwiki.ui.stripes;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class JspDocumentTest extends TestCase
+{
+    public JspDocumentTest( String s )
+    {
+        super( s );
+    }
+
+    public void testSetName() throws Exception
+    {
+        // Parse <foo></foo>
+        JspParser parser = new JspParser();
+        String s = "<foo></foo>";
+        JspDocument doc = parser.parse( s );
+
+        assertEquals( 2, doc.getNodes().size() );
+        assertEquals( s, doc.toString() );
+
+        // Make sure 2 tags were parsed correctly.
+        Node startTag = doc.getNodes().get( 0 );
+        Node endTag = doc.getNodes().get( 1 );
+        assertEquals( 0, startTag.getStart() );
+        assertEquals( 5, startTag.getEnd() );
+        assertEquals( "foo", startTag.getName() );
+        assertEquals( 5, endTag.getStart() );
+        assertEquals( 11, endTag.getEnd() );
+        assertEquals( "foo", endTag.getName() );
+
+        Node child = new Tag( doc, NodeType.HTML_COMBINED_TAG );
+    }
+
+    public static Test suite()
+    {
+        return new TestSuite( JspDocumentTest.class );
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMarkup.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMarkup.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMarkup.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMarkup.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,45 @@
+/**
+ * 
+ */
+package com.ecyrd.jspwiki.ui.stripes;
+
+/**
+ * Node implementation representing a JSP comment, declaration, scriptlet or expression.
+ */
+public class JspMarkup extends AbstractNode
+{
+    /**
+     * 
+     * @param doc the parent JspDocument
+     * @param type
+     */
+    public JspMarkup ( JspDocument doc, NodeType type )
+    {
+        super( doc, type );
+    }
+    
+    private String m_value;
+    
+    public String  getValue()
+    {
+        return m_value;
+    }
+    
+    public void setValue( String value )
+    {
+        m_value = value;
+    }
+    
+    /**
+     * Returns the string that represents the JSP comment, declaration, scriptlet or expression.
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append( m_type.getTagStart() );
+        sb.append( m_value );
+        sb.append( m_type.getTagEnd() );
+        return sb.toString();
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMigrator.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMigrator.java?rev=695481&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMigrator.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/ui/stripes/JspMigrator.java Mon Sep 15 07:21:34 2008
@@ -0,0 +1,166 @@
+package com.ecyrd.jspwiki.ui.stripes;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class JspMigrator
+{
+
+    /**
+     * @param args
+     */
+    public static void main( String[] args )
+    {
+        if( args.length != 2 )
+        {
+            throw new IllegalArgumentException( "Must supply source and destination directories." );
+        }
+        File src = new File( args[0] );
+        File dest = new File( args[1] );
+        if( !src.exists() )
+        {
+            throw new IllegalArgumentException( "Source directory " + src.getAbsolutePath() + " does not exist." );
+        }
+        if( !src.isDirectory() )
+        {
+            throw new IllegalArgumentException( "Source " + src.getAbsolutePath() + " is not a directory." );
+        }
+        if( !dest.exists() )
+        {
+            throw new IllegalArgumentException( "Destination directory " + dest.getAbsolutePath() + " does not exist!" );
+        }
+        if( !src.isDirectory() )
+        {
+            throw new IllegalArgumentException( "Destination " + dest.getAbsolutePath() + " is not a directory." );
+        }
+        if( src.equals( dest ) )
+        {
+            throw new IllegalArgumentException( "Source and destination cannot be the same." );
+        }
+        JspMigrator migrator = new JspMigrator();
+        try
+        {
+            migrator.migrate( src, dest );
+        }
+        catch( IOException e )
+        {
+            e.printStackTrace();
+        }
+    }
+
+    private List<JspTransformer> m_transformers = new ArrayList<JspTransformer>();
+
+    private Map<String, Object> m_sharedState = new HashMap<String, Object>();
+
+    /**
+     * Adds a {@link JspTransformer} to the chain of transformers that will be
+     * applied to each file as it is migrated.
+     * 
+     * @param transformer the transformer to add to the chain
+     */
+    public void addTransformer( JspTransformer transformer )
+    {
+        m_transformers.add( transformer );
+    }
+
+    /**
+     * Migrates the contents of an entire directory from one location to
+     * another.
+     * 
+     * @param srcDir the source directory
+     * @param destDir the destination directory
+     */
+    public void migrate( File srcDir, File destDir ) throws IOException
+    {
+        // Create the destination directory if it does not already exist
+        if( !destDir.exists() )
+        {
+            destDir.mkdir();
+        }
+
+        // Clear the shared state
+        m_sharedState.clear();
+
+        // Assemble list of files
+        for( File src : srcDir.listFiles() )
+        {
+            // If directory, migrate everything in it recursively
+            File dest = new File( destDir, src.getName() );
+            if( src.isDirectory() )
+            {
+                migrate( src, dest );
+            }
+
+            // Otherwise it's a file, so migrate it if it's a JSP
+            else
+            {
+                if( src.getName().endsWith( ".jsp" ) )
+                {
+                    migrateFile( src, dest );
+                }
+            }
+        }
+    }
+
+    /**
+     * Migrates a single file.
+     * 
+     * @param src the source file
+     * @param dest the destination file
+     */
+    protected void migrateFile( File src, File dest ) throws IOException
+    {
+        // Read in the file
+        System.out.println( "Migrating " + src.getPath() + " ----> " + dest.getPath() );
+        String s = readSource( src );
+
+        // Parse the contents of the file
+        JspParser parser = new JspParser();
+        JspDocument doc = parser.parse( s.toString() );
+
+        // Apply any transformations
+        for( JspTransformer transformer : m_transformers )
+        {
+            transformer.transform( m_sharedState, doc );
+        }
+
+        // Write the transformed contents to disk
+        writeDestination( dest, doc.toString() );
+        System.out.println( "    done [" + s.length() + " chars]." );
+    }
+
+    /**
+     * Writes a String to a file.
+     * 
+     * @param dest the destination file
+     * @param contents the String to write to the file
+     * @throws IOException
+     */
+    private void writeDestination( File dest, String contents ) throws IOException
+    {
+        FileWriter writer = new FileWriter( dest );
+        writer.append( contents );
+        writer.close();
+    }
+
+    protected String readSource( File src ) throws IOException
+    {
+        // Read in the file
+        FileReader reader = new FileReader( src );
+        StringBuffer s = new StringBuffer();
+        int ch = 0;
+        while ( (ch = reader.read()) != -1 )
+        {
+            s.append( (char) ch );
+        }
+        reader.close();
+        return s.toString();
+    }
+
+}