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