Java tutorial
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.outlet.OutletResult; import org.apache.torque.generator.qname.QualifiedName; /** * An outlet for creating correctly formatted javadoc. * * @version $Id: JavadocOutlet.java 1388635 2012-09-21 19:27:28Z tfischer $ */ 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 = "attributes"; /** The first line of the javadoc. */ private static final String START_LINE = "/**"; /** The mid line start of the javadoc. */ private static final String MID_LINE_START = " * "; /** The last line of the javadoc. */ private static final String END_LINE = " */"; /** The character which starts a javadoc attribute. */ private static final String JAVADOC_ATTRIBUTE_START = "@"; /** The default maximum line width. */ private static final int DEFAULT_MAX_LINEWIDTH = 80; /** 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 = DEFAULT_MAX_LINEWIDTH; /** 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 OutletResult 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 new OutletResult(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(MID_LINE_START); int currentLineLength = indent.length() + MID_LINE_START.length(); boolean lineBreakPossible = false; // last char is space so it can be removed boolean lastCharRemovable = true; String token = null; String currentIndent = indent + MID_LINE_START; 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(); // + 2 because of "@" + space after attribute currentIndent = StringUtils.rightPad(indent + MID_LINE_START, indent.length() + MID_LINE_START.length() + 2 + token.length()); if (result.length() > indent.length() + MID_LINE_START.length()) { // 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() + MID_LINE_START.length(); 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; } /** * Removes the trailing characters from a string builder. * The characters to be removed are passed in as parameter. * * @param stringBuilder the string builder to remove the end from, not null. * @param removeChars The characters to remove if they appear at the end, * not null. */ 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(), ""); } }