You are viewing a plain text version of this content. The canonical link for it is here.
Posted to torque-dev@db.apache.org by tf...@apache.org on 2010/08/24 16:45:41 UTC

svn commit: r988576 - in /db/torque/torque4/trunk/torque-generator/src: main/java/org/apache/torque/generator/outlet/java/JavadocOutlet.java test/java/org/apache/torque/generator/outlet/java/JavadocOutletTest.java

Author: tfischer
Date: Tue Aug 24 14:45:40 2010
New Revision: 988576

URL: http://svn.apache.org/viewvc?rev=988576&view=rev
Log:
Add new java outlet which can produce nicely formatted javadoc.
This is currently not needed in the Torque templates but comes in handy for a general-purpose code generator.

Added:
    db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/outlet/java/JavadocOutlet.java
    db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/outlet/java/JavadocOutletTest.java

Added: db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/outlet/java/JavadocOutlet.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/outlet/java/JavadocOutlet.java?rev=988576&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/outlet/java/JavadocOutlet.java (added)
+++ db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/outlet/java/JavadocOutlet.java Tue Aug 24 14:45:40 2010
@@ -0,0 +1,379 @@
+package org.apache.torque.generator.outlet.java;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.torque.generator.GeneratorException;
+import org.apache.torque.generator.control.ControllerState;
+import org.apache.torque.generator.outlet.OutletImpl;
+import org.apache.torque.generator.qname.QualifiedName;
+
+/**
+ * An outlet for creating correctly formatted javadoc.
+ * 
+ * @version $Id:$
+ */
+public class JavadocOutlet extends OutletImpl
+{
+    /** The name of the mergepoint which output is used as javadoc body. */
+    public static final String BODY_MERGEPOINT_NAME = "body";
+    
+    /** The name of the mergepoint which contains the javadoc attributes. */
+    public static final String ATTRIBUTES_MERGEPOINT_NAME = "atttributes";
+    
+    /** The first line of the javadoc. */
+    private static String START_LINE = "/**";
+
+    /** The last line of the javadoc. */
+    private static String END_LINE = " */";
+
+    /** The character which starts a javadoc attribute. */
+    private static String JAVADOC_ATTRIBUTE_START = "@";
+    
+    /** The line break string. */
+    private String lineBreak = "\n";
+
+    /** How long a line can be before it will be wrapped, -1 for no wrapping */
+    private int maxLineLength = 80;
+    
+    /** The indent to use in front of each line. */
+    private String indent = "    ";
+
+    /**
+     * At which characters a line can be wrapped 
+     * with the character removed.
+     */
+    private String removableWrapCharacters = " ";
+
+    /**
+     * After which characters a line can be wrapped 
+     * without the character removed.
+     */
+    private String wrapAfterCharacters = ".;,-";
+
+    /**
+     * Constructor.
+     *
+     * @param qualifiedName the qualified name of the outlet, not null.
+     */
+    public JavadocOutlet(QualifiedName qualifiedName)
+    {
+        super(qualifiedName);
+    }
+    
+    @Override
+    public String execute(ControllerState controllerState)
+            throws GeneratorException
+    {
+        StringBuilder result = new StringBuilder();
+        result.append(indent).append(START_LINE).append(lineBreak);
+        String body = mergepoint(BODY_MERGEPOINT_NAME, controllerState);
+        result.append(wrapLinesAndIndent(body));
+        {
+            String attributes = mergepoint(
+                    ATTRIBUTES_MERGEPOINT_NAME,
+                    controllerState);
+            if (!StringUtils.isEmpty(attributes) 
+                && !StringUtils.isEmpty(body))
+            {
+                result.append(indent).append(" *").append(lineBreak);
+            }
+            if (!StringUtils.isEmpty(attributes))
+            {
+                 result.append(wrapLinesAndIndent(attributes));
+            }
+        }
+        
+        result.append(indent).append(END_LINE).append(lineBreak);
+        return result.toString();
+    }
+
+    /**
+     * Wraps the content string such that the line length is not longer than
+     * maxLineLength characters, if that can be achieved by wrapping at the
+     * wrap characters. All resulting lines are also indented.
+     * 
+     * @param content The content to wrap, may be null.
+     * 
+     * @return the wrapped and indented content, not null.
+     */
+    String wrapLinesAndIndent(String content)
+    {
+        if (StringUtils.isBlank(content))
+        {
+            return "";
+        }
+        StringTokenizer tokenizer 
+                = new StringTokenizer(
+                        content.trim(),
+                        removableWrapCharacters 
+                            + wrapAfterCharacters 
+                            + "\r\n"
+                            + JAVADOC_ATTRIBUTE_START,
+                        true);
+        StringBuilder result = new StringBuilder();
+        result.append(indent).append(" * ");
+        int currentLineLength = indent.length() + 3;
+        boolean lineBreakPossible = false;
+        // last char is space so it can be removed
+        boolean lastCharRemovable = true;
+        String token = null;
+        String currentIndent = indent + " * ";
+        String lastJavadocAttribute = null;
+        while (tokenizer.hasMoreTokens() || token!= null)
+        {
+            if (token == null) 
+            {
+                // token has not been prefetched
+                token = tokenizer.nextToken();
+            }
+            if ("\r".equals(token))
+            {
+                // Assumption: no \r without line breaks
+                // always remove, will be added again if linebreak is \r\n
+                token = null;
+            }
+            else if ("\n".equals(token))
+            {
+                // line break does not count towards line length
+                result.append(lineBreak);
+                lineBreakPossible = false;
+                // because currentIndent ends with a space
+                // we can remove the last char
+                lastCharRemovable = true;
+                if (tokenizer.hasMoreTokens())
+                {
+                    result.append(currentIndent);
+                    currentLineLength = currentIndent.length();
+                }
+                token = null;
+            }
+            else if (JAVADOC_ATTRIBUTE_START.equals(token))
+            {
+                if (tokenizer.hasMoreTokens())
+                {
+                    
+                    token = tokenizer.nextToken();
+                    // 5 because of " * @" + space after attribute 
+                    currentIndent = StringUtils.rightPad(
+                            indent + " * ", 
+                            indent.length() + 5 + token.length());
+                    if (result.length() > indent.length() + 3)
+                    {
+                        // we could already be indented by a line break
+                        // in a previous param
+                        removeEnd(result, " \r\n");
+                        boolean alreadyIndented = false;
+                        if (result.toString().endsWith(indent + " *"))
+                        {
+                            alreadyIndented = true;
+                        }
+                        boolean doubleLineBreak = false;
+                        if (!token.equals(lastJavadocAttribute))
+                        {
+                            doubleLineBreak = true;
+                        }
+                        if (!alreadyIndented)
+                        {
+                            result.append(lineBreak).append(indent).append(" *");
+                        }
+                        if (doubleLineBreak)
+                        {
+                            result.append(lineBreak).append(indent).append(" *");
+                        }
+                        result.append(" ");
+                    }
+                    //+ 3 because " * "
+                    currentLineLength = indent.length() + 3;
+                    lastJavadocAttribute = token;
+                }
+                result.append(JAVADOC_ATTRIBUTE_START);
+                ++currentLineLength;
+                lineBreakPossible = false;
+                lastCharRemovable = false;
+            }
+            else if (maxLineLength == -1)
+            {
+                result.append(token);
+                token = null;
+            }
+            else if (removableWrapCharacters.indexOf(token) != -1)
+            {
+                if (currentLineLength + 1 > maxLineLength)
+                {
+                    result.append(lineBreak);
+                    if (tokenizer.hasMoreTokens())
+                    {
+                        result.append(currentIndent);
+                        currentLineLength = currentIndent.length();
+                    }
+                    lineBreakPossible = false;
+                    lastCharRemovable = false;
+                }
+                else
+                {
+                    result.append(token);
+                    currentLineLength++;
+                    lineBreakPossible = true;
+                    lastCharRemovable = true;
+                }
+                token = null;
+            }
+            else if (lineBreakPossible)
+            {
+                // we must check next token
+                String nextToken = null;
+                if (tokenizer.hasMoreTokens())
+                {
+                    nextToken = tokenizer.nextToken();
+                }
+                int unbreakableChunkSize;
+                if (nextToken == null
+                    || "\r".equals(nextToken) 
+                    || "\n".equals(nextToken)
+                    || wrapAfterCharacters.contains(token)
+                    || JAVADOC_ATTRIBUTE_START.equals(nextToken)
+                    || removableWrapCharacters.contains(nextToken))
+                {
+                    unbreakableChunkSize = token.length();
+                }
+                else
+                {
+                    unbreakableChunkSize = token.length() + nextToken.length();
+                }
+                if (currentLineLength + unbreakableChunkSize > maxLineLength)
+                {
+                    // break now
+                    if (lastCharRemovable)
+                    {
+                        result.replace(
+                                result.length() - 1,
+                                result.length(),
+                                "");
+                    }
+                    result.append(lineBreak).append(currentIndent).append(token);
+                    currentLineLength = currentIndent.length() + token.length();
+                }
+                else
+                {
+                    // no break necessary
+                    result.append(token);
+                    currentLineLength += token.length();
+                }
+                lastCharRemovable = false;
+                lineBreakPossible = wrapAfterCharacters.contains(token);
+                token = nextToken;
+            }
+            else
+            {
+                result.append(token);
+                currentLineLength += token.length();
+                lastCharRemovable = false;
+                lineBreakPossible = wrapAfterCharacters.contains(token);
+                token = null;
+            }
+        }
+        if (!result.toString().endsWith(lineBreak))
+        {
+            result.append(lineBreak);
+        }
+        return result.toString();
+    }
+
+    public String getLineBreak()
+    {
+        return lineBreak;
+    }
+
+    public void setLineBreak(String lineBreak)
+    {
+        if (!("\r".equals(lineBreak)) && !("\r\n".equals(lineBreak)))
+        {
+            throw new IllegalArgumentException(
+                    "lineBreak must be either \\r or \\r\\n");
+        }
+        this.lineBreak = lineBreak;
+    }
+
+    public int getMaxLineLength()
+    {
+        return maxLineLength;
+    }
+
+    public void setMaxLineLength(int maxLineLength)
+    {
+        this.maxLineLength = maxLineLength;
+    }
+
+    public String getIndent()
+    {
+        return indent;
+    }
+
+    public void setIndent(String indent)
+    {
+        this.indent = indent;
+    }
+
+    public String getRemovableWrapCharacters()
+    {
+        return removableWrapCharacters;
+    }
+
+    public void setRemovableWrapCharacters(String removableWrapCharacters)
+    {
+        this.removableWrapCharacters = removableWrapCharacters;
+    }
+
+    public String getWrapAfterCharacters()
+    {
+        return wrapAfterCharacters;
+    }
+
+    public void setWrapAfterCharacters(String wrapAfterCharacters)
+    {
+        this.wrapAfterCharacters = wrapAfterCharacters;
+    }
+    
+    static void removeEnd(StringBuilder stringBuilder, String removeChars)
+    {
+        Set<Character> removeCharSet = new HashSet<Character>();
+        for (char character : removeChars.toCharArray())
+        {
+            removeCharSet.add(character);
+        }
+        int index = stringBuilder.length();
+        while (index > 0)
+        {
+            if (!removeCharSet.contains(stringBuilder.charAt(index - 1)))
+            {
+                break;
+            }
+            index--;
+        }
+        // index is now last char in String which does not match pattern
+        // maybe -1 if all the string matches or the input is empty
+        stringBuilder.replace(index, stringBuilder.length(), "");
+    }
+}

Added: db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/outlet/java/JavadocOutletTest.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/outlet/java/JavadocOutletTest.java?rev=988576&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/outlet/java/JavadocOutletTest.java (added)
+++ db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/outlet/java/JavadocOutletTest.java Tue Aug 24 14:45:40 2010
@@ -0,0 +1,321 @@
+package org.apache.torque.generator.outlet.java;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.torque.generator.configuration.mergepoint.MergepointMapping;
+import org.apache.torque.generator.control.ControllerState;
+import org.apache.torque.generator.control.action.MergepointAction;
+import org.apache.torque.generator.control.action.OutputAction;
+import org.apache.torque.generator.qname.QualifiedName;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JavadocOutletTest
+{
+    private JavadocOutlet javadocOutlet;
+    
+    @Before
+    public void setUp()
+    {
+        javadocOutlet = new JavadocOutlet(new QualifiedName("jacadocOutlet"));
+        javadocOutlet.setMaxLineLength(20);
+    }
+
+    /**
+     * Tests that the javadoc contains both the body and the attributes 
+     * and both are properly line wrapped.
+     */
+    @Test
+    public void testCompleteJavadoc() throws Exception
+    {
+        List<MergepointAction> mergepointActions
+                = new ArrayList<MergepointAction>();
+        mergepointActions.add(new OutputAction("Test-body for.a,javadoc"));
+        javadocOutlet.setMergepointMapping(
+                new MergepointMapping(
+                        JavadocOutlet.BODY_MERGEPOINT_NAME,
+                        mergepointActions));
+        mergepointActions = new ArrayList<MergepointAction>();
+        mergepointActions.add(
+                new OutputAction("@param param1 description,of param1"));
+        javadocOutlet.setMergepointMapping(
+                new MergepointMapping(
+                        JavadocOutlet.ATTRIBUTES_MERGEPOINT_NAME,
+                        mergepointActions));
+        String result = javadocOutlet.execute(new ControllerState());
+        assertEquals(
+                    "    /**\n"
+                  + "     * Test-body\n"
+                  + "     * for.a,javadoc\n"
+                  + "     *\n"
+                  + "     * @param param1\n"
+                  + "     *        description,\n"
+                  + "     *        of\n"
+                  + "     *        param1\n"
+                  + "     */\n",
+              result);
+        System.out.println(result);
+    }
+
+    /**
+     * Checks that a break-after character can cause a line break , and that
+     * a single space after such a break is removed. The boundary cases
+     * maxLineLength + 1 and maxLineLength are checked. 
+     */
+    @Test
+    public void testWrapAfterNotRemovedCharacters()
+    {
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "Test-body111-breaking.at1.  111111 not;  removed1111,characters");
+        assertEquals(
+                    "     * Test-body111-\n"
+                  + "     * breaking.at1.\n"
+                  + "     *  111111 not; \n"
+                  + "     * removed1111,\n"
+                  + "     * characters\n",
+                result);
+    }
+    
+    /**
+     * Checks that a space can cause a line break and the space is removed 
+     * in the output. The boundary cases maxLineLength + 1 and maxLineLength
+     * are checked.
+     */
+    @Test
+    public void testSpaceAtEndRemoved()
+    {
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "Test body1111 breaking at1 space");
+        assertEquals(
+                    "     * Test body1111\n"
+                  + "     * breaking at1\n"
+                  + "     * space\n",
+                result);
+    }
+
+    /**
+     * Checks that a new javadoc attribute causes a double line wrap 
+     */
+    @Test
+    public void testDoubleWrapAtNewAttribute()
+    {
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "body @since 1 2 3 4 5");
+        assertEquals(
+                    "     * body\n"
+                  + "     *\n"
+                  + "     * @since 1 2 3\n"
+                  + "     *        4 5\n",
+                result);
+    }
+
+    /**
+     * Checks that between different javadoc attributes,
+     * a double line wrap is inserted.
+     */
+    @Test
+    public void testDoubleWrapAtDifferentAttributes()
+    {
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "@since 1 @see y");
+        assertEquals(
+                    "     * @since 1\n"
+                  + "     *\n"
+                  + "     * @see y\n",
+                result);
+    }
+
+    /**
+     * Checks that between different javadoc attributes 
+     * where the first ends with a line break,
+     * a double line wrap is inserted.
+     */
+    @Test
+    public void testDoubleWrapAtDifferentAttributesWithLineBreak()
+    {
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "@since 1\n@see y");
+        assertEquals(
+                    "     * @since 1\n"
+                  + "     *\n"
+                  + "     * @see y\n",
+                result);
+    }
+
+    /**
+     * Checks that a preceding \n or two same javadoc attribute
+     * cause a single line wrap 
+     */
+    @Test
+    public void testSingleWrapAtAttribute()
+    {
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "body\n@since 11 2 3 4 5 @since x");
+        assertEquals(
+                    "     * body\n"
+                  + "     *\n"
+                  + "     * @since 11 2 3\n"
+                  + "     *        4 5\n"
+                  + "     * @since x\n",
+                result);
+    }
+
+    /**
+     * Checks that a preceding \n or two same javadoc attribute
+     * cause a single line wrap 
+     */
+    @Test
+    public void testSingleWrapAtAttributeWithLineBreak()
+    {
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "@since x\n@since y");
+        assertEquals(
+                    "     * @since x\n"
+                  + "     * @since y\n",
+                result);
+    }
+
+    /**
+     * Checks that setWrapAfterCharacters works as expected.
+     */
+    @Test
+    public void testSetWrapAfterCharacters()
+    {
+        javadocOutlet.setWrapAfterCharacters(".");
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "123-456,789;012.345");
+        assertEquals(
+                    "     * 123-456,789;012.\n"
+                  + "     * 345\n",
+                result);
+    }
+
+    /**
+     * Checks that setIndent works as expected.
+     */
+    @Test
+    public void testSetIndent()
+    {
+        javadocOutlet.setIndent("        ");
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "123-456,789;012");
+        assertEquals(
+                    "         * 123-456,\n"
+                  + "         * 789;012\n",
+                result);
+    }
+
+    /**
+     * Checks that setLineBreak works as expected.
+     */
+    @Test
+    public void testSetLineBreak()
+    {
+        javadocOutlet.setLineBreak("\r\n");
+        String result = javadocOutlet.wrapLinesAndIndent(
+                "xxx123-456,789\n012.345");
+        assertEquals(
+                    "     * xxx123-456,\r\n"
+                  + "     * 789\r\n"
+                  + "     * 012.345\r\n",
+                result);
+    }
+
+    /**
+     * Checks that setLineBreak works as expected.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testSetLineBreakIllegalInput()
+    {
+        javadocOutlet.setLineBreak("\n\r");
+    }
+
+    /**
+     * Tests that removeEnd works for an empty String.
+     */
+   @Test
+    public void testRemoveEndEmptyString()
+    {
+        StringBuilder builder = new StringBuilder();
+        JavadocOutlet.removeEnd(builder, " \r\n");
+        assertEquals("", builder.toString());
+    }
+
+   /**
+    * Tests that removeEnd works if everything is removed.
+    */
+    @Test
+    public void testRemoveEndEverythingRemoved()
+    {
+        StringBuilder builder = new StringBuilder().append(" \r\r\n   \n");
+        JavadocOutlet.removeEnd(builder, " \r\n");
+        assertEquals("", builder.toString());
+    }
+
+    /**
+     * Tests that removeEnd works if nothing is removed.
+     */
+    @Test
+    public void testRemoveEndNothingRemoved()
+    {
+        StringBuilder builder = new StringBuilder().append(" \r\r\n   \na");
+        JavadocOutlet.removeEnd(builder, " \r\n");
+        assertEquals(" \r\r\n   \na", builder.toString());
+    }
+    
+    /**
+     * Tests that removeEnd works if a part is removed.
+     */
+    @Test
+    public void testRemoveEndPartRemoved()
+    {
+        StringBuilder builder = new StringBuilder().append(" \r\r\n x \r \n");
+        JavadocOutlet.removeEnd(builder, " \r\n");
+        assertEquals(" \r\r\n x", builder.toString());
+    }
+
+    /**
+     * Tests that removeEnd works if everything but the first character
+     * is removed.
+     */
+    @Test
+    public void testRemoveEndAllButFirstCharacterRemoved()
+    {
+        StringBuilder builder = new StringBuilder().append("x\r\r\n  \r \n");
+        JavadocOutlet.removeEnd(builder, " \r\n");
+        assertEquals("x", builder.toString());
+    }
+
+    /**
+     * Tests that removeEnd works if only the last character is removed.
+     */
+    @Test
+    public void testRemoveEndOnlyLastCharacterRemoved()
+    {
+        StringBuilder builder = new StringBuilder().append("\r\r\n  \rx ");
+        JavadocOutlet.removeEnd(builder, " \r\n");
+        assertEquals("\r\r\n  \rx", builder.toString());
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscribe@db.apache.org
For additional commands, e-mail: torque-dev-help@db.apache.org