@Override public List<Node> selectNodes( String xPathExpression, String comparisonXPathExpression, boolean removeDuplicates) { return SAXReaderImpl.toNewNodes( _node.selectNodes(xPathExpression, comparisonXPathExpression, removeDuplicates)); }
@Override public Object selectObject(String xPathExpression) { Object obj = _node.selectObject(xPathExpression); if (obj == null) { return null; } else if (obj instanceof List<?>) { return SAXReaderImpl.toNewNodes((List<org.dom4j.Node>) obj); } else { return obj; } }
/** * @author Brian Wing Shun Chan * @author Igor Spasic * @author Wesley Gong * @author Hugo Huijser */ public abstract class BaseSourceProcessor implements SourceProcessor { public BaseSourceProcessor() { portalSource = _isPortalSource(); try { _properties = _getProperties(); } catch (Exception e) { ReflectionUtil.throwException(e); } } @Override public void format(boolean useProperties, boolean printErrors, boolean autoFix) throws Exception { _init(useProperties, printErrors, autoFix); format(); sourceFormatterHelper.close(); } @Override public String format(String fileName, boolean useProperties, boolean printErrors, boolean autoFix) throws Exception { try { _init(useProperties, printErrors, autoFix); return format(fileName); } finally { sourceFormatterHelper.close(); } } @Override public List<String> getErrorMessages() { List<String> errorMessages = new ArrayList<String>(); for (Map.Entry<String, List<String>> entry : _errorMessagesMap.entrySet()) { errorMessages.addAll(entry.getValue()); } return errorMessages; } @Override public SourceMismatchException getFirstSourceMismatchException() { return _firstSourceMismatchException; } protected static boolean isExcluded(List<String> exclusions, String absolutePath) { return isExcluded(exclusions, absolutePath, -1); } protected static boolean isExcluded(List<String> exclusions, String absolutePath, int lineCount) { return isExcluded(exclusions, absolutePath, lineCount, null); } protected static boolean isExcluded( List<String> exclusions, String absolutePath, int lineCount, String javaTermName) { if (ListUtil.isEmpty(exclusions)) { return false; } String absolutePathWithJavaTermName = null; if (Validator.isNotNull(javaTermName)) { absolutePathWithJavaTermName = absolutePath + StringPool.AT + javaTermName; } String absolutePathWithLineCount = null; if (lineCount > 0) { absolutePathWithLineCount = absolutePath + StringPool.AT + lineCount; } for (String exclusion : exclusions) { if (absolutePath.endsWith(exclusion) || ((absolutePathWithJavaTermName != null) && absolutePathWithJavaTermName.endsWith(exclusion)) || ((absolutePathWithLineCount != null) && absolutePathWithLineCount.endsWith(exclusion))) { return true; } } return false; } protected static void processErrorMessage(String fileName, String message) { List<String> errorMessages = _errorMessagesMap.get(fileName); if (errorMessages == null) { errorMessages = new ArrayList<String>(); } errorMessages.add(message); _errorMessagesMap.put(fileName, errorMessages); } protected void checkEmptyCollection(String line, String fileName, int lineCount) { // LPS-46028 Matcher matcher = emptyCollectionPattern.matcher(line); if (matcher.find()) { String collectionType = TextFormatter.format(matcher.group(1), TextFormatter.J); processErrorMessage( fileName, "Use Collections.empty" + collectionType + "(): " + fileName + " " + lineCount); } } protected void checkIfClauseParentheses(String ifClause, String fileName, int lineCount) { int quoteCount = StringUtil.count(ifClause, StringPool.QUOTE); if ((quoteCount % 2) == 1) { return; } ifClause = stripQuotes(ifClause, CharPool.QUOTE); ifClause = stripQuotes(ifClause, CharPool.APOSTROPHE); if (ifClause.contains(StringPool.DOUBLE_SLASH) || ifClause.contains("/*") || ifClause.contains("*/")) { return; } if (hasRedundantParentheses(ifClause, "||", "&&") || hasRedundantParentheses(ifClause, "&&", "||")) { processErrorMessage(fileName, "redundant parentheses: " + fileName + " " + lineCount); } ifClause = stripRedundantParentheses(ifClause); int level = 0; int max = StringUtil.count(ifClause, StringPool.OPEN_PARENTHESIS); int previousParenthesisPos = -1; int[] levels = new int[max]; for (int i = 0; i < ifClause.length(); i++) { char c = ifClause.charAt(i); if ((c == CharPool.OPEN_PARENTHESIS) || (c == CharPool.CLOSE_PARENTHESIS)) { if (previousParenthesisPos != -1) { String s = ifClause.substring(previousParenthesisPos + 1, i); if (hasMissingParentheses(s)) { processErrorMessage(fileName, "missing parentheses: " + fileName + " " + lineCount); } } previousParenthesisPos = i; if (c == CharPool.OPEN_PARENTHESIS) { levels[level] = i; level += 1; } else { int posOpenParenthesis = levels[level - 1]; if (level > 1) { char nextChar = ifClause.charAt(i + 1); char previousChar = ifClause.charAt(posOpenParenthesis - 1); if (!Character.isLetterOrDigit(nextChar) && (nextChar != CharPool.PERIOD) && !Character.isLetterOrDigit(previousChar)) { String s = ifClause.substring(posOpenParenthesis + 1, i); if (hasRedundantParentheses(s)) { processErrorMessage( fileName, "redundant parentheses: " + fileName + " " + lineCount); } } if ((previousChar == CharPool.OPEN_PARENTHESIS) && (nextChar == CharPool.CLOSE_PARENTHESIS)) { processErrorMessage(fileName, "redundant parentheses: " + fileName + " " + lineCount); } } level -= 1; } } } } protected void checkInefficientStringMethods( String line, String fileName, String absolutePath, int lineCount) { if (isRunsOutsidePortal(absolutePath)) { return; } String methodName = "toLowerCase"; int pos = line.indexOf(".toLowerCase()"); if (pos == -1) { methodName = "toUpperCase"; pos = line.indexOf(".toUpperCase()"); } if ((pos == -1) && !line.contains("StringUtil.equalsIgnoreCase(")) { methodName = "equalsIgnoreCase"; pos = line.indexOf(".equalsIgnoreCase("); } if (pos != -1) { processErrorMessage( fileName, "Use StringUtil." + methodName + ": " + fileName + " " + lineCount); } } protected void checkLanguageKeys(String fileName, String content, Pattern pattern) throws IOException { String fileExtension = fileUtil.getExtension(fileName); if (!portalSource || fileExtension.equals("vm")) { return; } if (_portalLanguageProperties == null) { _portalLanguageProperties = new Properties(); ClassLoader classLoader = BaseSourceProcessor.class.getClassLoader(); InputStream inputStream = classLoader.getResourceAsStream("content/Language.properties"); _portalLanguageProperties.load(inputStream); } Matcher matcher = pattern.matcher(content); while (matcher.find()) { String[] languageKeys = getLanguageKeys(matcher); for (String languageKey : languageKeys) { if (Validator.isNumber(languageKey) || languageKey.endsWith(StringPool.DASH) || languageKey.endsWith(StringPool.OPEN_BRACKET) || languageKey.endsWith(StringPool.PERIOD) || languageKey.endsWith(StringPool.UNDERLINE) || languageKey.startsWith(StringPool.DASH) || languageKey.startsWith(StringPool.OPEN_BRACKET) || languageKey.startsWith(StringPool.OPEN_CURLY_BRACE) || languageKey.startsWith(StringPool.PERIOD) || languageKey.startsWith(StringPool.UNDERLINE) || _portalLanguageProperties.containsKey(languageKey)) { continue; } Properties languageProperties = getLanguageProperties(fileName); if ((languageProperties == null) || !languageProperties.containsKey(languageKey)) { processErrorMessage( fileName, "missing language key: " + languageKey + StringPool.SPACE + fileName); } } } } protected void checkStringBundler(String line, String fileName, int lineCount) { if ((!line.startsWith("sb.append(") && !line.contains("SB.append(")) || !line.endsWith(");")) { return; } int pos = line.indexOf(".append("); line = line.substring(pos + 8, line.length() - 2); line = stripQuotes(line, CharPool.QUOTE); if (!line.contains(" + ")) { return; } String[] lineParts = StringUtil.split(line, " + "); for (String linePart : lineParts) { int closeParenthesesCount = StringUtil.count(linePart, StringPool.CLOSE_PARENTHESIS); int openParenthesesCount = StringUtil.count(linePart, StringPool.OPEN_PARENTHESIS); if (closeParenthesesCount != openParenthesesCount) { return; } if (Validator.isNumber(linePart)) { return; } } processErrorMessage(fileName, "plus: " + fileName + " " + lineCount); } protected abstract String doFormat( File file, String fileName, String absolutePath, String content) throws Exception; protected String fixCompatClassImports(String absolutePath, String content) throws IOException { if (portalSource || !_usePortalCompatImport || absolutePath.contains("/ext-") || absolutePath.contains("/portal-compat-shared/")) { return content; } Map<String, String> compatClassNamesMap = getCompatClassNamesMap(); String newContent = content; for (Map.Entry<String, String> entry : compatClassNamesMap.entrySet()) { String compatClassName = entry.getKey(); String extendedClassName = entry.getValue(); Pattern pattern = Pattern.compile(extendedClassName + "\\W"); while (true) { Matcher matcher = pattern.matcher(newContent); if (!matcher.find()) { break; } newContent = newContent.substring(0, matcher.start()) + compatClassName + newContent.substring(matcher.end() - 1); } } return newContent; } protected String fixCopyright(String content, String absolutePath, String fileName) throws IOException { if (_copyright == null) { _copyright = getContent("copyright.txt", 4); } String copyright = _copyright; if (fileName.endsWith(".vm") || Validator.isNull(copyright)) { return content; } if (_oldCopyright == null) { _oldCopyright = getContent("old-copyright.txt", 4); } if (Validator.isNotNull(_oldCopyright) && content.contains(_oldCopyright)) { content = StringUtil.replace(content, _oldCopyright, copyright); processErrorMessage(fileName, "old (c): " + fileName); } if (!content.contains(copyright)) { String customCopyright = getCustomCopyright(absolutePath); if (Validator.isNotNull(customCopyright)) { copyright = customCopyright; } if (!content.contains(copyright)) { processErrorMessage(fileName, "(c): " + fileName); } } if (fileName.endsWith(".jsp") || fileName.endsWith(".jspf")) { content = StringUtil.replace(content, "<%\n" + copyright + "\n%>", "<%--\n" + copyright + "\n--%>"); } int x = content.indexOf("* Copyright (c) 2000-"); if (x == -1) { return content; } int y = content.indexOf("Liferay", x); String contentCopyrightYear = content.substring(x, y); x = copyright.indexOf("* Copyright (c) 2000-"); if (x == -1) { return content; } y = copyright.indexOf("Liferay", x); String copyrightYear = copyright.substring(x, y); return StringUtil.replace(content, contentCopyrightYear, copyrightYear); } protected String fixIncorrectParameterTypeForLanguageUtil( String content, boolean autoFix, String fileName) { if (portalSource) { return content; } String expectedParameter = getProperty("languageutil.expected.parameter"); String incorrectParameter = getProperty("languageutil.incorrect.parameter"); if (!content.contains("LanguageUtil.format(" + incorrectParameter + ", ") && !content.contains("LanguageUtil.get(" + incorrectParameter + ", ")) { return content; } if (autoFix) { content = StringUtil.replace( content, new String[] { "LanguageUtil.format(" + incorrectParameter + ", ", "LanguageUtil.get(" + incorrectParameter + ", " }, new String[] { "LanguageUtil.format(" + expectedParameter + ", ", "LanguageUtil.get(" + expectedParameter + ", " }); } else { processErrorMessage( fileName, "(Unicode)LanguageUtil.format/get methods require " + expectedParameter + " parameter instead of " + incorrectParameter + " " + fileName); } return content; } protected String fixSessionKey(String fileName, String content, Pattern pattern) { Matcher matcher = pattern.matcher(content); if (!matcher.find()) { return content; } String newContent = content; do { String match = matcher.group(); String s = null; if (pattern.equals(sessionKeyPattern)) { s = StringPool.COMMA; } else if (pattern.equals(taglibSessionKeyPattern)) { s = "key="; } int x = match.indexOf(s); if (x == -1) { continue; } x = x + s.length(); String substring = match.substring(x).trim(); String quote = StringPool.BLANK; if (substring.startsWith(StringPool.APOSTROPHE)) { quote = StringPool.APOSTROPHE; } else if (substring.startsWith(StringPool.QUOTE)) { quote = StringPool.QUOTE; } else { continue; } int y = match.indexOf(quote, x); int z = match.indexOf(quote, y + 1); if ((y == -1) || (z == -1)) { continue; } String prefix = match.substring(0, y + 1); String suffix = match.substring(z); String oldKey = match.substring(y + 1, z); boolean alphaNumericKey = true; for (char c : oldKey.toCharArray()) { if (!Validator.isChar(c) && !Validator.isDigit(c) && (c != CharPool.DASH) && (c != CharPool.UNDERLINE)) { alphaNumericKey = false; } } if (!alphaNumericKey) { continue; } String newKey = TextFormatter.format(oldKey, TextFormatter.O); newKey = TextFormatter.format(newKey, TextFormatter.M); if (newKey.equals(oldKey)) { continue; } String oldSub = prefix.concat(oldKey).concat(suffix); String newSub = prefix.concat(newKey).concat(suffix); newContent = StringUtil.replaceFirst(newContent, oldSub, newSub); } while (matcher.find()); return newContent; } protected abstract void format() throws Exception; protected String format(File file, String fileName, String absolutePath, String content) throws Exception { _errorMessagesMap.remove(fileName); String newContent = doFormat(file, fileName, absolutePath, content); newContent = StringUtil.replace(newContent, StringPool.RETURN, StringPool.BLANK); if (content.equals(newContent)) { return content; } return format(file, fileName, absolutePath, newContent); } protected String format(String fileName) throws Exception { File file = new File(BASEDIR + fileName); fileName = StringUtil.replace(fileName, StringPool.BACK_SLASH, StringPool.SLASH); String absolutePath = getAbsolutePath(file); String content = fileUtil.read(file); String newContent = format(file, fileName, absolutePath, content); processFormattedFile(file, fileName, content, newContent); return newContent; } protected String formatJavaTerms( String fileName, String absolutePath, String content, String javaClassContent, List<String> javaTermSortExclusions, List<String> testAnnotationsExclusions) throws Exception { JavaClass javaClass = new JavaClass(fileName, absolutePath, javaClassContent, StringPool.TAB); String newJavaClassContent = javaClass.formatJavaTerms(javaTermSortExclusions, testAnnotationsExclusions); if (!javaClassContent.equals(newJavaClassContent)) { return StringUtil.replaceFirst(content, javaClassContent, newJavaClassContent); } return content; } protected String getAbsolutePath(File file) { String absolutePath = fileUtil.getAbsolutePath(file); return StringUtil.replace(absolutePath, "/./", StringPool.SLASH); } protected Map<String, String> getCompatClassNamesMap() throws IOException { if (_compatClassNamesMap != null) { return _compatClassNamesMap; } Map<String, String> compatClassNamesMap = new HashMap<String, String>(); String[] includes = new String[] {"**\\portal-compat-shared\\src\\com\\liferay\\compat\\**\\*.java"}; String basedir = BASEDIR; List<String> fileNames = new ArrayList<String>(); for (int i = 0; i < 3; i++) { fileNames = getFileNames(basedir, new String[0], includes); if (!fileNames.isEmpty()) { break; } basedir = "../" + basedir; } for (String fileName : fileNames) { File file = new File(basedir + fileName); String content = fileUtil.read(file); fileName = StringUtil.replace(fileName, StringPool.BACK_SLASH, StringPool.SLASH); fileName = StringUtil.replace(fileName, StringPool.SLASH, StringPool.PERIOD); int pos = fileName.indexOf("com."); String compatClassName = fileName.substring(pos); compatClassName = compatClassName.substring(0, compatClassName.length() - 5); String extendedClassName = StringUtil.replace(compatClassName, "compat.", StringPool.BLANK); if (content.contains("extends " + extendedClassName)) { compatClassNamesMap.put(compatClassName, extendedClassName); } } _compatClassNamesMap = compatClassNamesMap; return _compatClassNamesMap; } protected String getContent(String fileName, int level) throws IOException { File file = getFile(fileName, level); if (file != null) { String content = fileUtil.read(file); if (Validator.isNotNull(content)) { return content; } } return StringPool.BLANK; } protected String getCustomCopyright(String absolutePath) throws IOException { for (int x = absolutePath.length(); ; ) { x = absolutePath.lastIndexOf(StringPool.SLASH, x); if (x == -1) { break; } String copyright = fileUtil.read(absolutePath.substring(0, x + 1) + "copyright.txt"); if (Validator.isNotNull(copyright)) { return copyright; } x = x - 1; } return null; } protected File getFile(String fileName, int level) { for (int i = 0; i < level; i++) { if (fileUtil.exists(fileName)) { return new File(fileName); } fileName = "../" + fileName; } return null; } protected List<String> getFileNames(String basedir, String[] excludes, String[] includes) { DirectoryScanner directoryScanner = new DirectoryScanner(); directoryScanner.setBasedir(basedir); if (_excludes != null) { excludes = ArrayUtil.append(excludes, _excludes); } directoryScanner.setExcludes(excludes); directoryScanner.setIncludes(includes); return sourceFormatterHelper.scanForFiles(directoryScanner); } protected List<String> getFileNames(String[] excludes, String[] includes) { return getFileNames(BASEDIR, excludes, includes); } protected String[] getLanguageKeys(Matcher matcher) { int groupCount = matcher.groupCount(); if (groupCount == 1) { String languageKey = matcher.group(1); if (Validator.isNotNull(languageKey)) { return new String[] {languageKey}; } } else if (groupCount == 2) { String languageKey = matcher.group(2); languageKey = TextFormatter.format(languageKey, TextFormatter.P); return new String[] {languageKey}; } StringBundler sb = new StringBundler(); String match = matcher.group(); int count = 0; for (int i = 0; i < match.length(); i++) { char c = match.charAt(i); switch (c) { case CharPool.CLOSE_PARENTHESIS: if (count <= 1) { return new String[0]; } count--; break; case CharPool.OPEN_PARENTHESIS: count++; break; case CharPool.QUOTE: if (count > 1) { break; } while (i < match.length()) { i++; if (match.charAt(i) == CharPool.QUOTE) { String languageKey = sb.toString(); if (match.startsWith("names")) { return StringUtil.split(languageKey); } else { return new String[] {languageKey}; } } sb.append(match.charAt(i)); } } } return new String[0]; } protected Properties getLanguageProperties(String fileName) { StringBundler sb = new StringBundler(4); int pos = fileName.indexOf("/docroot/"); sb.append(BASEDIR); if (pos != -1) { sb.append(fileName.substring(0, pos + 9)); sb.append("WEB-INF/src/"); } else { pos = fileName.indexOf("/src/"); if (pos == -1) { return null; } sb.append(fileName.substring(0, pos + 5)); } sb.append("content/Language.properties"); try { Properties properties = new Properties(); InputStream inputStream = new FileInputStream(sb.toString()); properties.load(inputStream); return properties; } catch (Exception e) { } return null; } protected String getMainReleaseVersion() { if (_mainReleaseVersion != null) { return _mainReleaseVersion; } String releaseVersion = ReleaseInfo.getVersion(); int pos = releaseVersion.lastIndexOf(StringPool.PERIOD); _mainReleaseVersion = releaseVersion.substring(0, pos) + ".0"; return _mainReleaseVersion; } protected String getProperty(String key) { return _properties.getProperty(key); } protected List<String> getPropertyList(String key) { return ListUtil.fromString(GetterUtil.getString(getProperty(key)), StringPool.COMMA); } protected boolean hasMissingParentheses(String s) { if (Validator.isNull(s)) { return false; } boolean containsAndOperator = s.contains("&&"); boolean containsOrOperator = s.contains("||"); if (containsAndOperator && containsOrOperator) { return true; } boolean containsCompareOperator = (s.contains(" == ") || s.contains(" != ") || s.contains(" < ") || s.contains(" > ") || s.contains(" =< ") || s.contains(" => ") || s.contains(" <= ") || s.contains(" >= ")); boolean containsMathOperator = (s.contains(" = ") || s.contains(" - ") || s.contains(" + ") || s.contains(" & ") || s.contains(" % ") || s.contains(" * ") || s.contains(" / ")); if (containsCompareOperator && (containsAndOperator || containsOrOperator || (containsMathOperator && !s.contains(StringPool.OPEN_BRACKET)))) { return true; } return false; } protected boolean hasRedundantParentheses(String s) { if (!s.contains("&&") && !s.contains("||")) { for (int x = 0; ; ) { x = s.indexOf(StringPool.CLOSE_PARENTHESIS); if (x == -1) { break; } int y = s.substring(0, x).lastIndexOf(StringPool.OPEN_PARENTHESIS); if (y == -1) { break; } s = s.substring(0, y) + s.substring(x + 1); } } if (Validator.isNotNull(s) && !s.contains(StringPool.SPACE)) { return true; } else { return false; } } protected boolean hasRedundantParentheses(String s, String operator1, String operator2) { String[] parts = StringUtil.split(s, operator1); if (parts.length < 3) { return false; } for (int i = 1; i < (parts.length - 1); i++) { String part = parts[i]; if (part.contains(operator2) || part.contains("!(")) { continue; } int closeParenthesesCount = StringUtil.count(part, StringPool.CLOSE_PARENTHESIS); int openParenthesesCount = StringUtil.count(part, StringPool.OPEN_PARENTHESIS); if (Math.abs(closeParenthesesCount - openParenthesesCount) == 1) { return true; } } return false; } protected boolean isAttributName(String attributeName) { if (Validator.isNull(attributeName)) { return false; } Matcher matcher = attributeNamePattern.matcher(attributeName); return matcher.matches(); } protected boolean isRunsOutsidePortal(String absolutePath) { if (_runOutsidePortalExclusions == null) { _runOutsidePortalExclusions = getPropertyList("run.outside.portal.excludes"); } for (String runOutsidePortalExclusions : _runOutsidePortalExclusions) { if (absolutePath.contains(runOutsidePortalExclusions)) { return true; } } return false; } protected void processFormattedFile(File file, String fileName, String content, String newContent) throws IOException { if (_printErrors) { List<String> errorMessages = _errorMessagesMap.get(fileName); if (errorMessages != null) { for (String errorMessage : errorMessages) { sourceFormatterHelper.printError(fileName, errorMessage); } } } if (content.equals(newContent)) { return; } if (_autoFix) { fileUtil.write(file, newContent); } else if (_firstSourceMismatchException == null) { _firstSourceMismatchException = new SourceMismatchException(fileName, content, newContent); } if (_printErrors) { sourceFormatterHelper.printError(fileName, file); } } protected String replacePrimitiveWrapperInstantiation( String fileName, String line, int lineCount) { if (true) { return line; } String newLine = StringUtil.replace( line, new String[] { "new Boolean(", "new Byte(", "new Character(", "new Integer(", "new Long(", "new Short(" }, new String[] { "Boolean.valueOf(", "Byte.valueOf(", "Character.valueOf(", "Integer.valueOf(", "Long.valueOf(", "Short.valueOf(" }); if (!line.equals(newLine)) { processErrorMessage(fileName, "> new Primitive(: " + fileName + " " + lineCount); } return newLine; } protected String sortAttributes( String fileName, String line, int lineCount, boolean allowApostropheDelimeter) { String s = line; int x = s.indexOf(StringPool.SPACE); if (x == -1) { return line; } s = s.substring(x + 1); String previousAttribute = null; String previousAttributeAndValue = null; boolean wrongOrder = false; for (x = 0; ; ) { x = s.indexOf(StringPool.EQUAL); if ((x == -1) || (s.length() <= (x + 1))) { return line; } String attribute = s.substring(0, x); if (!isAttributName(attribute)) { return line; } if (Validator.isNotNull(previousAttribute) && (previousAttribute.compareTo(attribute) > 0)) { wrongOrder = true; } s = s.substring(x + 1); char delimeter = s.charAt(0); if ((delimeter != CharPool.APOSTROPHE) && (delimeter != CharPool.QUOTE)) { if (delimeter != CharPool.AMPERSAND) { processErrorMessage(fileName, "delimeter: " + fileName + " " + lineCount); } return line; } s = s.substring(1); String value = null; int y = -1; while (true) { y = s.indexOf(delimeter, y + 1); if ((y == -1) || (s.length() <= (y + 1))) { return line; } value = s.substring(0, y); if (value.startsWith("<%")) { int endJavaCodeSignCount = StringUtil.count(value, "%>"); int startJavaCodeSignCount = StringUtil.count(value, "<%"); if (endJavaCodeSignCount == startJavaCodeSignCount) { break; } } else { int greaterThanCount = StringUtil.count(value, StringPool.GREATER_THAN); int lessThanCount = StringUtil.count(value, StringPool.LESS_THAN); if (greaterThanCount == lessThanCount) { break; } } } if (delimeter == CharPool.APOSTROPHE) { if (!value.contains(StringPool.QUOTE)) { line = StringUtil.replace( line, StringPool.APOSTROPHE + value + StringPool.APOSTROPHE, StringPool.QUOTE + value + StringPool.QUOTE); return sortAttributes(fileName, line, lineCount, allowApostropheDelimeter); } else if (!allowApostropheDelimeter) { String newValue = StringUtil.replace(value, StringPool.QUOTE, """); line = StringUtil.replace( line, StringPool.APOSTROPHE + value + StringPool.APOSTROPHE, StringPool.QUOTE + newValue + StringPool.QUOTE); return sortAttributes(fileName, line, lineCount, allowApostropheDelimeter); } } StringBundler sb = new StringBundler(5); sb.append(attribute); sb.append(StringPool.EQUAL); sb.append(delimeter); sb.append(value); sb.append(delimeter); String currentAttributeAndValue = sb.toString(); if (wrongOrder) { if ((StringUtil.count(line, currentAttributeAndValue) == 1) && (StringUtil.count(line, previousAttributeAndValue) == 1)) { line = StringUtil.replaceFirst(line, previousAttributeAndValue, currentAttributeAndValue); line = StringUtil.replaceLast(line, currentAttributeAndValue, previousAttributeAndValue); return sortAttributes(fileName, line, lineCount, allowApostropheDelimeter); } return line; } s = s.substring(y + 1); if (s.startsWith(StringPool.GREATER_THAN)) { x = s.indexOf(StringPool.SPACE); if (x == -1) { return line; } s = s.substring(x + 1); previousAttribute = null; previousAttributeAndValue = null; } else { s = StringUtil.trimLeading(s); previousAttribute = attribute; previousAttributeAndValue = currentAttributeAndValue; } } } protected String stripLine(String s, char startDelimeter, char endDelimeter) { boolean insideDelimeters = false; int level = 0; StringBundler sb = new StringBundler(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (insideDelimeters) { if (c == endDelimeter) { if (level > 0) { level -= 1; } else { if ((c > 1) && (s.charAt(i - 1) == CharPool.BACK_SLASH) && (s.charAt(i - 2) != CharPool.BACK_SLASH)) { continue; } insideDelimeters = false; } } else if (c == startDelimeter) { level += 1; } } else if (c == startDelimeter) { insideDelimeters = true; } else { sb.append(c); } } return sb.toString(); } protected String stripQuotes(String s, char delimeter) { return stripLine(s, delimeter, delimeter); } protected String stripRedundantParentheses(String s) { for (int x = 0; ; ) { x = s.indexOf(StringPool.OPEN_PARENTHESIS, x + 1); int y = s.indexOf(StringPool.CLOSE_PARENTHESIS, x); if ((x == -1) || (y == -1)) { return s; } String linePart = s.substring(x + 1, y); linePart = StringUtil.replace(linePart, StringPool.COMMA, StringPool.BLANK); if (Validator.isAlphanumericName(linePart) || Validator.isNull(linePart)) { s = s.substring(0, x) + s.substring(y + 1); } } } protected String trimContent(String content, boolean allowLeadingSpaces) throws IOException { StringBundler sb = new StringBundler(); UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(new UnsyncStringReader(content)); String line = null; while ((line = unsyncBufferedReader.readLine()) != null) { sb.append(trimLine(line, allowLeadingSpaces)); sb.append("\n"); } unsyncBufferedReader.close(); content = sb.toString(); if (content.endsWith("\n")) { content = content.substring(0, content.length() - 1); } return content; } protected String trimLine(String line, boolean allowLeadingSpaces) { if (line.trim().length() == 0) { return StringPool.BLANK; } line = StringUtil.trimTrailing(line); if (allowLeadingSpaces || !line.startsWith(StringPool.SPACE) || line.startsWith(" *")) { return line; } if (!line.startsWith(StringPool.FOUR_SPACES)) { while (line.startsWith(StringPool.SPACE)) { line = StringUtil.replaceFirst(line, StringPool.SPACE, StringPool.BLANK); } } else { int pos = 0; String temp = line; while (temp.startsWith(StringPool.FOUR_SPACES)) { line = StringUtil.replaceFirst(line, StringPool.FOUR_SPACES, StringPool.TAB); pos++; temp = line.substring(pos); } } return line; } protected static final String BASEDIR = "./"; protected static Pattern attributeNamePattern = Pattern.compile("[a-z]+[-_a-zA-Z0-9]*"); protected static Pattern emptyCollectionPattern = Pattern.compile("Collections\\.EMPTY_(LIST|MAP|SET)"); protected static FileImpl fileUtil = FileImpl.getInstance(); protected static Pattern languageKeyPattern = Pattern.compile("LanguageUtil.(?:get|format)\\([^;%]+|Liferay.Language.get\\('([^']+)"); protected static boolean portalSource; protected static SAXReaderImpl saxReaderUtil = SAXReaderImpl.getInstance(); protected static Pattern sessionKeyPattern = Pattern.compile( "SessionErrors.(?:add|contains|get)\\([^;%&|!]+|" .concat("SessionMessages.(?:add|contains|get)\\([^;%&|!]+"), Pattern.MULTILINE); protected static SourceFormatterHelper sourceFormatterHelper; protected static Pattern taglibSessionKeyPattern = Pattern.compile("<liferay-ui:error [^>]+>|<liferay-ui:success [^>]+>", Pattern.MULTILINE); private String[] _getExcludes() { List<String> excludesList = ListUtil.fromString(GetterUtil.getString(System.getProperty("source.formatter.excludes"))); excludesList.addAll(getPropertyList("source.formatter.excludes")); String[] includes = new String[] {"**\\source_formatter.ignore"}; List<String> ignoreFileNames = getFileNames(new String[0], includes); for (String ignoreFileName : ignoreFileNames) { excludesList.add(ignoreFileName.substring(0, ignoreFileName.length() - 23) + "**"); } return excludesList.toArray(new String[excludesList.size()]); } private Properties _getProperties() throws Exception { String fileName = "source-formatter.properties"; Properties properties = new Properties(); if (portalSource) { ClassLoader classLoader = BaseSourceProcessor.class.getClassLoader(); properties.load( classLoader.getResourceAsStream("com/liferay/portal/tools/dependencies/" + fileName)); return properties; } List<Properties> propertiesList = new ArrayList<Properties>(); for (int i = 0; i <= 2; i++) { try { InputStream inputStream = new FileInputStream(fileName); Properties props = new Properties(); props.load(inputStream); propertiesList.add(props); } catch (FileNotFoundException fnfe) { } fileName = "../" + fileName; } if (propertiesList.isEmpty()) { return properties; } properties = propertiesList.get(0); if (propertiesList.size() == 1) { return properties; } for (int i = 1; i < propertiesList.size(); i++) { Properties props = propertiesList.get(i); Enumeration<String> enu = (Enumeration<String>) props.propertyNames(); while (enu.hasMoreElements()) { String key = enu.nextElement(); String value = props.getProperty(key); if (Validator.isNull(value)) { continue; } if (properties.containsKey(key)) { String existingValue = properties.getProperty(key); if (Validator.isNotNull(existingValue)) { value = existingValue + StringPool.COMMA + value; } } properties.put(key, value); } } return properties; } private void _init(boolean useProperties, boolean printErrors, boolean autoFix) throws Exception { _errorMessagesMap = new HashMap<String, List<String>>(); sourceFormatterHelper = new SourceFormatterHelper(useProperties); sourceFormatterHelper.init(); _autoFix = autoFix; _excludes = _getExcludes(); _printErrors = printErrors; _usePortalCompatImport = GetterUtil.getBoolean(getProperty("use.portal.compat.import")); } private boolean _isPortalSource() { if (getFile("portal-impl", 4) != null) { return true; } else { return false; } } private static Map<String, List<String>> _errorMessagesMap = new HashMap<String, List<String>>(); private static boolean _printErrors; private boolean _autoFix; private Map<String, String> _compatClassNamesMap; private String _copyright; private String[] _excludes; private SourceMismatchException _firstSourceMismatchException; private String _mainReleaseVersion; private String _oldCopyright; private Properties _portalLanguageProperties; private Properties _properties; private List<String> _runOutsidePortalExclusions; private boolean _usePortalCompatImport; }
@Override public List<Node> selectNodes(String xPathExpression, String comparisonXPathExpression) { return SAXReaderImpl.toNewNodes(_node.selectNodes(xPathExpression, comparisonXPathExpression)); }
public void setProcessingInstructions(List<ProcessingInstruction> processingInstructions) { _branch.setProcessingInstructions( SAXReaderImpl.toOldProcessingInstructions(processingInstructions)); }
public List<Node> content() { return SAXReaderImpl.toNewNodes(_branch.content()); }
public void setContent(List<Node> content) { _branch.setContent(SAXReaderImpl.toOldNodes(content)); }
public List<ProcessingInstruction> processingInstructions(String target) { return SAXReaderImpl.toNewProcessingInstructions(_branch.processingInstructions(target)); }
public List<ProcessingInstruction> processingInstructions() { return SAXReaderImpl.toNewProcessingInstructions(_branch.processingInstructions()); }
/** * @author Brian Wing Shun Chan * @author Connor McKay * @author James Hinkey * @author Hugo Huijser */ public class JavadocFormatter { public static void main(String[] args) { try { new JavadocFormatter(args); } catch (Exception e) { e.printStackTrace(); } } public JavadocFormatter(String[] args) throws Exception { Map<String, String> arguments = ArgumentsUtil.parseArguments(args); String init = arguments.get("javadoc.init"); if (Validator.isNotNull(init) && !init.startsWith("$")) { _initializeMissingJavadocs = GetterUtil.getBoolean(init); } _inputDir = GetterUtil.getString(arguments.get("javadoc.input.dir")); if (_inputDir.startsWith("$")) { _inputDir = "./"; } if (!_inputDir.endsWith("/")) { _inputDir += "/"; } System.out.println("Input directory is " + _inputDir); String limit = arguments.get("javadoc.limit"); _outputFilePrefix = GetterUtil.getString(arguments.get("javadoc.output.file.prefix")); if (_outputFilePrefix.startsWith("$")) { _outputFilePrefix = "javadocs"; } String update = arguments.get("javadoc.update"); if (Validator.isNotNull(update) && !update.startsWith("$")) { _updateJavadocs = GetterUtil.getBoolean(update); } DirectoryScanner directoryScanner = new DirectoryScanner(); directoryScanner.setBasedir(_inputDir); directoryScanner.setExcludes(new String[] {"**\\classes\\**", "**\\portal-client\\**"}); List<String> includes = new ArrayList<String>(); if (Validator.isNotNull(limit) && !limit.startsWith("$")) { System.out.println("Limit on " + limit); String[] limitArray = StringUtil.split(limit, '/'); for (String curLimit : limitArray) { includes.add("**\\" + StringUtil.replace(curLimit, ".", "\\") + "\\**\\*.java"); includes.add("**\\" + curLimit + ".java"); } } else { includes.add("**\\*.java"); } directoryScanner.setIncludes(includes.toArray(new String[includes.size()])); directoryScanner.scan(); String[] fileNames = directoryScanner.getIncludedFiles(); if ((fileNames.length == 0) && Validator.isNotNull(limit) && !limit.startsWith("$")) { StringBundler sb = new StringBundler("Limit file not found: "); sb.append(limit); if (limit.contains(".")) { sb.append(" Specify limit filename without package path or "); sb.append("file type suffix."); } System.out.println(sb.toString()); } _languagePropertiesFile = new File("src/content/Language.properties"); if (_languagePropertiesFile.exists()) { _languageProperties = new Properties(); _languageProperties.load(new FileInputStream(_languagePropertiesFile.getAbsolutePath())); } for (String fileName : fileNames) { fileName = StringUtil.replace(fileName, "\\", "/"); _format(fileName); } for (Map.Entry<String, Tuple> entry : _javadocxXmlTuples.entrySet()) { Tuple tuple = entry.getValue(); File javadocsXmlFile = (File) tuple.getObject(1); String oldJavadocsXmlContent = (String) tuple.getObject(2); Document javadocsXmlDocument = (Document) tuple.getObject(3); Element javadocsXmlRootElement = javadocsXmlDocument.getRootElement(); javadocsXmlRootElement.sortElementsByChildElement("javadoc", "type"); String newJavadocsXmlContent = javadocsXmlDocument.formattedString(); if (!oldJavadocsXmlContent.equals(newJavadocsXmlContent)) { _fileUtil.write(javadocsXmlFile, newJavadocsXmlContent); } _detachUnnecessaryTypes(javadocsXmlRootElement); File javadocsRuntimeXmlFile = new File(StringUtil.replaceLast(javadocsXmlFile.toString(), "-all.xml", "-rt.xml")); String oldJavadocsRuntimeXmlContent = StringPool.BLANK; if (javadocsRuntimeXmlFile.exists()) { oldJavadocsRuntimeXmlContent = _fileUtil.read(javadocsRuntimeXmlFile); } String newJavadocsRuntimeXmlContent = javadocsXmlDocument.compactString(); if (!oldJavadocsRuntimeXmlContent.equals(newJavadocsRuntimeXmlContent)) { _fileUtil.write(javadocsRuntimeXmlFile, newJavadocsRuntimeXmlContent); } } } private List<Tuple> _addAncestorJavaClassTuples( JavaClass javaClass, List<Tuple> ancestorJavaClassTuples) { JavaClass superJavaClass = javaClass.getSuperJavaClass(); if (superJavaClass != null) { ancestorJavaClassTuples.add(new Tuple(superJavaClass)); ancestorJavaClassTuples = _addAncestorJavaClassTuples(superJavaClass, ancestorJavaClassTuples); } Type[] implementz = javaClass.getImplements(); for (Type implement : implementz) { Type[] actualTypeArguments = implement.getActualTypeArguments(); JavaClass implementedInterface = implement.getJavaClass(); if (actualTypeArguments == null) { ancestorJavaClassTuples.add(new Tuple(implementedInterface)); } else { ancestorJavaClassTuples.add(new Tuple(implementedInterface, actualTypeArguments)); } ancestorJavaClassTuples = _addAncestorJavaClassTuples(implementedInterface, ancestorJavaClassTuples); } return ancestorJavaClassTuples; } private void _addClassCommentElement(Element rootElement, JavaClass javaClass) { String comment = _getCDATA(javaClass); if (comment.startsWith("Copyright (c)")) { comment = StringPool.BLANK; } if (Validator.isNull(comment)) { return; } Element commentElement = rootElement.addElement("comment"); commentElement.addCDATA(comment); } private void _addDocletElements( Element parentElement, AbstractJavaEntity abstractJavaEntity, String name) throws Exception { DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name); for (DocletTag docletTag : docletTags) { String value = docletTag.getValue(); value = _trimMultilineText(value); value = StringUtil.replace(value, " </", "</"); Element element = parentElement.addElement(name); element.addCDATA(value); } if ((docletTags.length == 0) && name.equals("author")) { Element element = parentElement.addElement(name); element.addCDATA(ServiceBuilder.AUTHOR); } } private String _addDocletTags( Element parentElement, String[] tagNames, String indent, boolean publicAccess) { List<String> allTagNames = new ArrayList<String>(); List<String> customTagNames = new ArrayList<String>(); List<String> requiredTagNames = new ArrayList<String>(); for (String tagName : tagNames) { List<Element> elements = parentElement.elements(tagName); for (Element element : elements) { Element commentElement = element.element("comment"); String comment = null; // Get comment by comment element's text or the element's text if (commentElement != null) { comment = commentElement.getText(); } else { comment = element.getText(); } if (tagName.equals("param") || tagName.equals("return") || tagName.equals("throws")) { if (Validator.isNotNull(comment)) { requiredTagNames.add(tagName); } else if (tagName.equals("param")) { if (GetterUtil.getBoolean(element.elementText("required"))) { requiredTagNames.add(tagName); } } else if (tagName.equals("throws")) { if (GetterUtil.getBoolean(element.elementText("required"))) { requiredTagNames.add(tagName); } } } else { customTagNames.add(tagName); } allTagNames.add(tagName); } } int maxTagNameLength = 0; List<String> maxTagNameLengthTags = new ArrayList<String>(); if (_initializeMissingJavadocs) { maxTagNameLengthTags.addAll(allTagNames); } else if (_updateJavadocs) { if (!requiredTagNames.isEmpty()) { maxTagNameLengthTags.addAll(allTagNames); } else { maxTagNameLengthTags.addAll(customTagNames); maxTagNameLengthTags.addAll(requiredTagNames); } } else { maxTagNameLengthTags.addAll(customTagNames); maxTagNameLengthTags.addAll(requiredTagNames); } for (String name : maxTagNameLengthTags) { if (name.length() > maxTagNameLength) { maxTagNameLength = name.length(); } } // There should be an @ sign before the tag and a space after it maxTagNameLength += 2; String tagNameIndent = _getSpacesIndent(maxTagNameLength); StringBundler sb = new StringBundler(); for (String tagName : tagNames) { List<Element> elements = parentElement.elements(tagName); for (Element element : elements) { Element commentElement = element.element("comment"); String comment = null; if (commentElement != null) { comment = commentElement.getText(); } else { comment = element.getText(); } String elementName = element.elementText("name"); if (Validator.isNotNull(comment)) { comment = _assembleTagComment(tagName, elementName, comment, indent, tagNameIndent); sb.append(comment); } else { if (_initializeMissingJavadocs && publicAccess) { // Write out all tags comment = _assembleTagComment(tagName, elementName, comment, indent, tagNameIndent); sb.append(comment); } else if (_updateJavadocs && publicAccess) { if (!tagName.equals("param") && !tagName.equals("return") && !tagName.equals("throws")) { // Write out custom tag comment = _assembleTagComment(tagName, elementName, comment, indent, tagNameIndent); sb.append(comment); } else if (!requiredTagNames.isEmpty()) { // Write out all tags comment = _assembleTagComment(tagName, elementName, comment, indent, tagNameIndent); sb.append(comment); } else { // Skip empty common tag } } else { if (!tagName.equals("param") && !tagName.equals("return") && !tagName.equals("throws")) { // Write out custom tag comment = _assembleTagComment(tagName, elementName, comment, indent, tagNameIndent); sb.append(comment); } else if (tagName.equals("param") || tagName.equals("return") || tagName.equals("throws")) { if (GetterUtil.getBoolean(element.elementText("required"))) { elementName = element.elementText("name"); comment = _assembleTagComment(tagName, elementName, comment, indent, tagNameIndent); sb.append(comment); } } else { // Skip empty common tag } } } } } return sb.toString(); } private void _addFieldElement(Element rootElement, JavaField javaField) throws Exception { Element fieldElement = rootElement.addElement("field"); DocUtil.add(fieldElement, "name", javaField.getName()); String comment = _getCDATA(javaField); if (Validator.isNotNull(comment)) { Element commentElement = fieldElement.addElement("comment"); commentElement.addCDATA(comment); } _addDocletElements(fieldElement, javaField, "version"); _addDocletElements(fieldElement, javaField, "see"); _addDocletElements(fieldElement, javaField, "since"); _addDocletElements(fieldElement, javaField, "deprecated"); } private void _addMethodElement(Element rootElement, JavaMethod javaMethod) throws Exception { Element methodElement = rootElement.addElement("method"); DocUtil.add(methodElement, "name", javaMethod.getName()); String comment = _getCDATA(javaMethod); if (Validator.isNotNull(comment)) { Element commentElement = methodElement.addElement("comment"); commentElement.addCDATA(_getCDATA(javaMethod)); } _addDocletElements(methodElement, javaMethod, "version"); _addParamElements(methodElement, javaMethod); _addReturnElement(methodElement, javaMethod); _addThrowsElements(methodElement, javaMethod); _addDocletElements(methodElement, javaMethod, "see"); _addDocletElements(methodElement, javaMethod, "since"); _addDocletElements(methodElement, javaMethod, "deprecated"); } private void _addParamElement( Element methodElement, JavaParameter javaParameter, DocletTag[] paramDocletTags) { String name = javaParameter.getName(); String value = null; for (DocletTag paramDocletTag : paramDocletTags) { String curValue = paramDocletTag.getValue(); if (!curValue.startsWith(name)) { continue; } else { value = curValue; break; } } Element paramElement = methodElement.addElement("param"); DocUtil.add(paramElement, "name", name); DocUtil.add(paramElement, "type", _getTypeValue(javaParameter)); if (value != null) { value = value.substring(name.length()); DocUtil.add(paramElement, "required", true); } value = _trimMultilineText(value); Element commentElement = paramElement.addElement("comment"); commentElement.addCDATA(value); } private void _addParamElements(Element methodElement, JavaMethod javaMethod) { JavaParameter[] javaParameters = javaMethod.getParameters(); DocletTag[] paramDocletTags = javaMethod.getTagsByName("param"); for (JavaParameter javaParameter : javaParameters) { _addParamElement(methodElement, javaParameter, paramDocletTags); } } private void _addReturnElement(Element methodElement, JavaMethod javaMethod) throws Exception { Type returns = javaMethod.getReturns(); if (returns == null) { return; } String returnsValue = returns.getValue(); if (returnsValue.equals("void")) { return; } Element returnElement = methodElement.addElement("return"); DocletTag[] returnDocletTags = javaMethod.getTagsByName("return"); String comment = StringPool.BLANK; if (returnDocletTags.length > 0) { DocletTag returnDocletTag = returnDocletTags[0]; comment = GetterUtil.getString(returnDocletTag.getValue()); DocUtil.add(returnElement, "required", true); } comment = _trimMultilineText(comment); Element commentElement = returnElement.addElement("comment"); commentElement.addCDATA(comment); } private void _addThrowsElement( Element methodElement, Type exceptionType, DocletTag[] throwsDocletTags) { JavaClass javaClass = exceptionType.getJavaClass(); String name = javaClass.getName(); String value = null; for (DocletTag throwsDocletTag : throwsDocletTags) { String curValue = throwsDocletTag.getValue(); if (!curValue.startsWith(name)) { continue; } else { value = curValue; break; } } Element throwsElement = methodElement.addElement("throws"); DocUtil.add(throwsElement, "name", name); DocUtil.add(throwsElement, "type", exceptionType.getValue()); if (value != null) { value = value.substring(name.length()); DocUtil.add(throwsElement, "required", true); } value = _trimMultilineText(value); Element commentElement = throwsElement.addElement("comment"); commentElement.addCDATA(_getCDATA(value)); } private void _addThrowsElements(Element methodElement, JavaMethod javaMethod) { Type[] exceptionTypes = javaMethod.getExceptions(); DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws"); for (Type exceptionType : exceptionTypes) { _addThrowsElement(methodElement, exceptionType, throwsDocletTags); } } private String _assembleTagComment( String tagName, String elementName, String comment, String indent, String tagNameIndent) { String indentAndTagName = indent + StringPool.AT + tagName; if (Validator.isNotNull(elementName)) { if (Validator.isNotNull(comment)) { comment = elementName + StringPool.SPACE + comment; } else { comment = elementName; } // <name indent> elementName [comment] comment = _wrapText(comment, indent + tagNameIndent); // * @name <name indent> elementName [comment] comment = indentAndTagName + comment.substring(indentAndTagName.length()); } else { if (Validator.isNotNull(comment)) { // <name indent> comment comment = _wrapText(comment, indent + tagNameIndent); // * @name <name indent> comment comment = indentAndTagName + comment.substring(indentAndTagName.length()); } else { // * @name comment = indentAndTagName + "\n"; } } return comment; } private void _detachUnnecessaryTypes(Element rootElement) { List<Element> elements = rootElement.elements(); for (Element element : elements) { String type = element.elementText("type"); if (!type.contains(".service.") || !type.endsWith("ServiceImpl")) { element.detach(); } } } private void _format(String fileName) throws Exception { InputStream inputStream = new FileInputStream(_inputDir + fileName); byte[] bytes = new byte[inputStream.available()]; inputStream.read(bytes); inputStream.close(); String originalContent = new String(bytes, StringPool.UTF8); if (fileName.endsWith("JavadocFormatter.java") || fileName.endsWith("SourceFormatter.java") || _hasGeneratedTag(originalContent)) { return; } JavaClass javaClass = _getJavaClass(fileName, new UnsyncStringReader(originalContent)); String javadocLessContent = _removeJavadocFromJava(javaClass, originalContent); Document document = _getJavadocDocument(javaClass); _updateJavadocsXmlFile(fileName, javaClass, document); _updateJavaFromDocument(fileName, originalContent, javadocLessContent, document); } private String _formatCDATA(String cdata, String exclude) { StringBundler sb = new StringBundler(); String startTag = "<" + exclude + ">"; String endTag = "</" + exclude + ">"; String[] cdataParts = cdata.split(startTag); for (String cdataPart : cdataParts) { if (!cdataPart.contains(endTag)) { cdataPart = _getCDATA(cdataPart); } if (cdataPart.contains("</" + exclude + ">")) { sb.append(startTag); } sb.append(cdataPart); } return sb.toString(); } private String _formatInlines(String text) { // Capitalize ID text = text.replaceAll("[?@param id](?i)\\bid(s)?\\b", " ID$1"); // Wrap special constants in code tags text = text.replaceAll("(?i)(?<!<code>|\\w)(null|false|true)(?!\\w)", "<code>$1</code>"); return text; } private String _getCDATA(AbstractJavaEntity abstractJavaEntity) { return _getCDATA(abstractJavaEntity.getComment()); } private String _getCDATA(String cdata) { if (cdata == null) { return StringPool.BLANK; } else if (cdata.contains("<pre>")) { cdata = _formatCDATA(cdata, "pre"); } else if (cdata.contains("<table>")) { cdata = _formatCDATA(cdata, "table"); } else { cdata = cdata.replaceAll("(?s)\\s*<(p|[ou]l)>\\s*(.*?)\\s*</\\1>\\s*", "\n\n<$1>\n$2\n</$1>\n\n"); cdata = cdata.replaceAll("(?s)\\s*<li>\\s*(.*?)\\s*</li>\\s*", "\n<li>\n$1\n</li>\n"); cdata = StringUtil.replace(cdata, "</li>\n\n<li>", "</li>\n<li>"); cdata = cdata.replaceAll("\n\\s+\n", "\n\n"); cdata.replaceAll(" +", " "); // Trim whitespace inside paragraph tags or in the first paragraph Pattern pattern = Pattern.compile("(^.*?(?=\n\n|$)+|(?<=<p>\n).*?(?=\n</p>))", Pattern.DOTALL); Matcher matcher = pattern.matcher(cdata); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String trimmed = _trimMultilineText(matcher.group()); // Escape dollar signs trimmed = trimmed.replaceAll("\\$", "\\\\\\$"); matcher.appendReplacement(sb, trimmed); } matcher.appendTail(sb); cdata = sb.toString(); } return cdata.trim(); } private String _getClassName(String fileName) { int pos = fileName.indexOf("src/"); if (pos == -1) { pos = fileName.indexOf("test/integration/"); if (pos != -1) { pos = fileName.indexOf("integration/", pos); } } if (pos == -1) { pos = fileName.indexOf("test/unit/"); if (pos != -1) { pos = fileName.indexOf("unit/", pos); } } if (pos == -1) { pos = fileName.indexOf("test/"); } if (pos == -1) { pos = fileName.indexOf("service/"); } if (pos == -1) { throw new RuntimeException(fileName); } pos = fileName.indexOf("/", pos); String srcFile = fileName.substring(pos + 1, fileName.length()); return StringUtil.replace(srcFile.substring(0, srcFile.length() - 5), "/", "."); } private String _getFieldKey(Element fieldElement) { return fieldElement.elementText("name"); } private String _getFieldKey(JavaField javaField) { return javaField.getName(); } private String _getIndent(String[] lines, AbstractBaseJavaEntity abstractBaseJavaEntity) { String line = lines[abstractBaseJavaEntity.getLineNumber() - 1]; String indent = StringPool.BLANK; for (char c : line.toCharArray()) { if (Character.isWhitespace(c)) { indent += c; } else { break; } } return indent; } private int _getIndentLength(String indent) { int indentLength = 0; for (char c : indent.toCharArray()) { if (c == '\t') { indentLength = indentLength + 4; } else { indentLength++; } } return indentLength; } private JavaClass _getJavaClass(String fileName, Reader reader) throws Exception { String className = _getClassName(fileName); JavaDocBuilder javadocBuilder = new JavaDocBuilder(); if (reader == null) { File file = new File(fileName); if (!file.exists()) { return null; } javadocBuilder.addSource(file); } else { javadocBuilder.addSource(reader); } return javadocBuilder.getClassByName(className); } private String _getJavaClassComment(Element rootElement, JavaClass javaClass) { StringBundler sb = new StringBundler(); String indent = StringPool.BLANK; sb.append("/**\n"); String comment = rootElement.elementText("comment"); if (Validator.isNotNull(comment)) { sb.append(_wrapText(comment, indent + " * ")); } String docletTags = _addDocletTags( rootElement, new String[] {"author", "version", "see", "since", "serial", "deprecated"}, indent + " * ", _hasPublicModifier(javaClass)); if (Validator.isNotNull(docletTags)) { if (_initializeMissingJavadocs || Validator.isNotNull(comment)) { sb.append(" *\n"); } sb.append(docletTags); } sb.append(" */\n"); return sb.toString(); } private int _getJavaClassLineNumber(JavaClass javaClass) { int lineNumber = javaClass.getLineNumber(); Annotation[] annotations = javaClass.getAnnotations(); if (annotations.length == 0) { return lineNumber; } for (Annotation annotation : annotations) { int annotationLineNumber = annotation.getLineNumber(); Map<String, String> propertyMap = annotation.getPropertyMap(); if (propertyMap.isEmpty()) { annotationLineNumber--; } if (annotationLineNumber < lineNumber) { lineNumber = annotationLineNumber; } } return lineNumber; } private Document _getJavadocDocument(JavaClass javaClass) throws Exception { Element rootElement = _saxReaderUtil.createElement("javadoc"); Document document = _saxReaderUtil.createDocument(rootElement); DocUtil.add(rootElement, "name", javaClass.getName()); DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName()); _addClassCommentElement(rootElement, javaClass); _addDocletElements(rootElement, javaClass, "author"); _addDocletElements(rootElement, javaClass, "version"); _addDocletElements(rootElement, javaClass, "see"); _addDocletElements(rootElement, javaClass, "since"); _addDocletElements(rootElement, javaClass, "serial"); _addDocletElements(rootElement, javaClass, "deprecated"); JavaMethod[] javaMethods = javaClass.getMethods(); for (JavaMethod javaMethod : javaMethods) { _addMethodElement(rootElement, javaMethod); } JavaField[] javaFields = javaClass.getFields(); for (JavaField javaField : javaFields) { _addFieldElement(rootElement, javaField); } return document; } private Tuple _getJavadocsXmlTuple(String fileName) throws Exception { File file = new File(_inputDir + fileName); String absolutePath = file.getAbsolutePath(); absolutePath = StringUtil.replace(absolutePath, "\\", "/"); absolutePath = StringUtil.replace(absolutePath, "/./", "/"); int pos = absolutePath.indexOf("/portal-impl/src/"); String srcDirName = null; if (pos != -1) { srcDirName = absolutePath.substring(0, pos + 17); } if (srcDirName == null) { pos = absolutePath.indexOf("/portal-kernel/src/"); if (pos == -1) { pos = absolutePath.indexOf("/portal-service/src/"); } if (pos == -1) { pos = absolutePath.indexOf("/util-bridges/src/"); } if (pos == -1) { pos = absolutePath.indexOf("/util-java/src/"); } if (pos == -1) { pos = absolutePath.indexOf("/util-taglib/src/"); } if (pos != -1) { srcDirName = absolutePath.substring(0, pos) + "/portal-impl/src/"; } } if (srcDirName == null) { pos = absolutePath.indexOf("/WEB-INF/src/"); if (pos != -1) { srcDirName = absolutePath.substring(0, pos + 13); } } if (srcDirName == null) { return null; } Tuple tuple = _javadocxXmlTuples.get(srcDirName); if (tuple != null) { return tuple; } File javadocsXmlFile = new File(srcDirName, "META-INF/" + _outputFilePrefix + "-all.xml"); if (!javadocsXmlFile.exists()) { _fileUtil.write(javadocsXmlFile, "<?xml version=\"1.0\"?>\n\n<javadocs>\n</javadocs>"); } String javadocsXmlContent = _fileUtil.read(javadocsXmlFile); Document javadocsXmlDocument = _saxReaderUtil.read(javadocsXmlContent); tuple = new Tuple(srcDirName, javadocsXmlFile, javadocsXmlContent, javadocsXmlDocument); _javadocxXmlTuples.put(srcDirName, tuple); return tuple; } private String _getJavaFieldComment( String[] lines, Map<String, Element> fieldElementsMap, JavaField javaField) { String fieldKey = _getFieldKey(javaField); Element fieldElement = fieldElementsMap.get(fieldKey); if (fieldElement == null) { return null; } String indent = _getIndent(lines, javaField); StringBundler sb = new StringBundler(); sb.append(indent); sb.append("/**\n"); String comment = fieldElement.elementText("comment"); if (Validator.isNotNull(comment)) { sb.append(_wrapText(comment, indent + " * ")); } String docletTags = _addDocletTags( fieldElement, new String[] {"version", "see", "since", "deprecated"}, indent + " * ", _hasPublicModifier(javaField)); if (Validator.isNotNull(docletTags)) { if (_initializeMissingJavadocs || Validator.isNotNull(comment)) { sb.append(indent); sb.append(" *\n"); } sb.append(docletTags); } sb.append(indent); sb.append(" */\n"); if (!_initializeMissingJavadocs && Validator.isNull(comment) && Validator.isNull(docletTags)) { return null; } if (!_hasPublicModifier(javaField) && Validator.isNull(comment) && Validator.isNull(docletTags)) { return null; } return sb.toString(); } private String _getJavaMethodComment( String[] lines, Map<String, Element> methodElementsMap, JavaMethod javaMethod) { String methodKey = _getMethodKey(javaMethod); Element methodElement = methodElementsMap.get(methodKey); if (methodElement == null) { return null; } String indent = _getIndent(lines, javaMethod); StringBundler sb = new StringBundler(); sb.append(indent); sb.append("/**\n"); String comment = methodElement.elementText("comment"); if (Validator.isNotNull(comment)) { sb.append(_wrapText(comment, indent + " * ")); } String docletTags = _addDocletTags( methodElement, new String[] {"version", "param", "return", "throws", "see", "since", "deprecated"}, indent + " * ", _hasPublicModifier(javaMethod)); if (Validator.isNotNull(docletTags)) { if (_initializeMissingJavadocs || Validator.isNotNull(comment)) { sb.append(indent); sb.append(" *\n"); } sb.append(docletTags); } sb.append(indent); sb.append(" */\n"); if (!_initializeMissingJavadocs && Validator.isNull(comment) && Validator.isNull(docletTags)) { return null; } if (!_hasPublicModifier(javaMethod) && Validator.isNull(comment) && Validator.isNull(docletTags)) { return null; } return sb.toString(); } private String _getMethodKey(Element methodElement) { StringBundler sb = new StringBundler(); sb.append(methodElement.elementText("name")); sb.append(StringPool.OPEN_PARENTHESIS); List<Element> paramElements = methodElement.elements("param"); for (Element paramElement : paramElements) { sb.append(paramElement.elementText("name")); sb.append("|"); sb.append(paramElement.elementText("type")); sb.append(","); } sb.append(StringPool.CLOSE_PARENTHESIS); return sb.toString(); } private String _getMethodKey(JavaMethod javaMethod) { StringBundler sb = new StringBundler(); sb.append(javaMethod.getName()); sb.append(StringPool.OPEN_PARENTHESIS); JavaParameter[] javaParameters = javaMethod.getParameters(); for (JavaParameter javaParameter : javaParameters) { sb.append(javaParameter.getName()); sb.append("|"); sb.append(_getTypeValue(javaParameter)); sb.append(","); } sb.append(StringPool.CLOSE_PARENTHESIS); return sb.toString(); } private String _getSpacesIndent(int length) { String indent = StringPool.BLANK; for (int i = 0; i < length; i++) { indent += StringPool.SPACE; } return indent; } private String _getTypeValue(JavaParameter javaParameter) { Type type = javaParameter.getType(); String typeValue = type.getValue(); if (type.isArray()) { typeValue += "[]"; } return typeValue; } private boolean _hasAnnotation( AbstractBaseJavaEntity abstractBaseJavaEntity, String annotationName) { Annotation[] annotations = abstractBaseJavaEntity.getAnnotations(); if (annotations == null) { return false; } for (int i = 0; i < annotations.length; i++) { Type type = annotations[i].getType(); JavaClass javaClass = type.getJavaClass(); if (annotationName.equals(javaClass.getName())) { return true; } } return false; } private boolean _hasGeneratedTag(String content) { if (content.contains("* @generated") || content.contains("$ANTLR")) { return true; } else { return false; } } private boolean _hasPublicModifier(AbstractJavaEntity abstractJavaEntity) { String[] modifiers = abstractJavaEntity.getModifiers(); if (modifiers == null) { return false; } for (String modifier : modifiers) { if (modifier.equals("public")) { return true; } } return false; } private boolean _isOverrideMethod( JavaClass javaClass, JavaMethod javaMethod, Collection<Tuple> ancestorJavaClassTuples) { if (javaMethod.isConstructor() || javaMethod.isPrivate() || javaMethod.isStatic()) { return false; } String methodName = javaMethod.getName(); JavaParameter[] javaParameters = javaMethod.getParameters(); Type[] types = new Type[javaParameters.length]; for (int i = 0; i < javaParameters.length; i++) { types[i] = javaParameters[i].getType(); } // Check for matching method in each ancestor for (Tuple ancestorJavaClassTuple : ancestorJavaClassTuples) { JavaClass ancestorJavaClass = (JavaClass) ancestorJavaClassTuple.getObject(0); JavaMethod ancestorJavaMethod = null; if (ancestorJavaClassTuple.getSize() > 1) { // LPS-35613 Type[] ancestorActualTypeArguments = (Type[]) ancestorJavaClassTuple.getObject(1); Type[] genericTypes = new Type[types.length]; for (int i = 0; i < types.length; i++) { Type type = types[i]; String typeValue = type.getValue(); boolean useGenericType = false; for (int j = 0; j < ancestorActualTypeArguments.length; j++) { if (typeValue.equals(ancestorActualTypeArguments[j].getValue())) { useGenericType = true; break; } } if (useGenericType) { genericTypes[i] = new Type("java.lang.Object"); } else { genericTypes[i] = type; } } ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(methodName, genericTypes); } else { ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(methodName, types); } if (ancestorJavaMethod == null) { continue; } boolean samePackage = false; JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage(); if (ancestorJavaPackage != null) { samePackage = ancestorJavaPackage.equals(javaClass.getPackage()); } // Check if the method is in scope if (samePackage) { return !ancestorJavaMethod.isPrivate(); } else { if (ancestorJavaMethod.isProtected() || ancestorJavaMethod.isPublic()) { return true; } else { return false; } } } return false; } private String _removeJavadocFromJava(JavaClass javaClass, String content) { Set<Integer> lineNumbers = new HashSet<Integer>(); lineNumbers.add(_getJavaClassLineNumber(javaClass)); JavaMethod[] javaMethods = javaClass.getMethods(); for (JavaMethod javaMethod : javaMethods) { lineNumbers.add(javaMethod.getLineNumber()); } JavaField[] javaFields = javaClass.getFields(); for (JavaField javaField : javaFields) { lineNumbers.add(javaField.getLineNumber()); } String[] lines = StringUtil.splitLines(content); for (int lineNumber : lineNumbers) { if (lineNumber == 0) { continue; } int pos = lineNumber - 2; String line = lines[pos]; if (line == null) { continue; } line = line.trim(); if (line.endsWith("*/")) { while (true) { lines[pos] = null; if (line.startsWith("/**") || line.startsWith("/*")) { break; } line = lines[--pos].trim(); } } } StringBundler sb = new StringBundler(content.length()); for (String line : lines) { if (line != null) { sb.append(line); sb.append("\n"); } } return sb.toString().trim(); } private String _trimMultilineText(String text) { String[] textArray = StringUtil.splitLines(text); for (int i = 0; i < textArray.length; i++) { textArray[i] = textArray[i].trim(); } return StringUtil.merge(textArray, " "); } private void _updateJavadocsXmlFile( String fileName, JavaClass javaClass, Document javaClassDocument) throws Exception { String javaClassFullyQualifiedName = javaClass.getFullyQualifiedName(); /*if (!javaClassFullyQualifiedName.contains(".service.") || !javaClassFullyQualifiedName.endsWith("ServiceImpl")) { return; }*/ Tuple javadocsXmlTuple = _getJavadocsXmlTuple(fileName); if (javadocsXmlTuple == null) { return; } Document javadocsXmlDocument = (Document) javadocsXmlTuple.getObject(3); Element javadocsXmlRootElement = javadocsXmlDocument.getRootElement(); List<Element> javadocElements = javadocsXmlRootElement.elements("javadoc"); for (Element javadocElement : javadocElements) { String type = javadocElement.elementText("type"); if (type.equals(javaClassFullyQualifiedName)) { Element javaClassRootElement = javaClassDocument.getRootElement(); if (Validator.equals( javadocElement.formattedString(), javaClassRootElement.formattedString())) { return; } javadocElement.detach(); break; } } javadocsXmlRootElement.add(javaClassDocument.getRootElement()); } private void _updateJavaFromDocument( String fileName, String originalContent, String javadocLessContent, Document document) throws Exception { String[] lines = StringUtil.splitLines(javadocLessContent); JavaClass javaClass = _getJavaClass(fileName, new UnsyncStringReader(javadocLessContent)); _updateLanguageProperties(document, javaClass.getName()); List<Tuple> ancestorJavaClassTuples = new ArrayList<Tuple>(); ancestorJavaClassTuples = _addAncestorJavaClassTuples(javaClass, ancestorJavaClassTuples); Element rootElement = document.getRootElement(); Map<Integer, String> commentsMap = new TreeMap<Integer, String>(); commentsMap.put( _getJavaClassLineNumber(javaClass), _getJavaClassComment(rootElement, javaClass)); Map<String, Element> methodElementsMap = new HashMap<String, Element>(); List<Element> methodElements = rootElement.elements("method"); for (Element methodElement : methodElements) { String methodKey = _getMethodKey(methodElement); methodElementsMap.put(methodKey, methodElement); } JavaMethod[] javaMethods = javaClass.getMethods(); for (JavaMethod javaMethod : javaMethods) { if (commentsMap.containsKey(javaMethod.getLineNumber())) { continue; } String javaMethodComment = _getJavaMethodComment(lines, methodElementsMap, javaMethod); // Handle override tag insertion if (!_hasAnnotation(javaMethod, "Override")) { if (_isOverrideMethod(javaClass, javaMethod, ancestorJavaClassTuples)) { String overrideLine = _getIndent(lines, javaMethod) + "@Override\n"; if (Validator.isNotNull(javaMethodComment)) { javaMethodComment = javaMethodComment + overrideLine; } else { javaMethodComment = overrideLine; } } } commentsMap.put(javaMethod.getLineNumber(), javaMethodComment); } Map<String, Element> fieldElementsMap = new HashMap<String, Element>(); List<Element> fieldElements = rootElement.elements("field"); for (Element fieldElement : fieldElements) { String fieldKey = _getFieldKey(fieldElement); fieldElementsMap.put(fieldKey, fieldElement); } JavaField[] javaFields = javaClass.getFields(); for (JavaField javaField : javaFields) { if (commentsMap.containsKey(javaField.getLineNumber())) { continue; } commentsMap.put( javaField.getLineNumber(), _getJavaFieldComment(lines, fieldElementsMap, javaField)); } StringBundler sb = new StringBundler(javadocLessContent.length()); for (int lineNumber = 1; lineNumber <= lines.length; lineNumber++) { String line = lines[lineNumber - 1]; String comments = commentsMap.get(lineNumber); if (comments != null) { sb.append(comments); } sb.append(line); sb.append("\n"); } String formattedContent = sb.toString().trim(); if (!originalContent.equals(formattedContent)) { File file = new File(_inputDir + fileName); _fileUtil.write(file, formattedContent.getBytes(StringPool.UTF8)); System.out.println("Writing " + file); } } private void _updateLanguageProperties(Document document, String className) throws IOException { if (_languageProperties == null) { return; } int index = className.indexOf("ServiceImpl"); if (index <= 0) { return; } StringBundler sb = new StringBundler(); sb.append(Character.toLowerCase(className.charAt(0))); for (int i = 1; i < index; i++) { char c = className.charAt(i); if (Character.isUpperCase(c)) { if (((i + 1) < index) && Character.isLowerCase(className.charAt(i + 1))) { sb.append(CharPool.DASH); } sb.append(Character.toLowerCase(c)); } else { sb.append(c); } } sb.append("-service-help"); String key = sb.toString(); String value = _languageProperties.getProperty(key); if (value == null) { return; } Element rootElement = document.getRootElement(); String comment = rootElement.elementText("comment"); if ((comment == null) || value.equals(comment)) { return; } index = comment.indexOf("\n\n"); if (index != -1) { value = comment.substring(0, index); } else { value = comment; } _updateLanguageProperties(key, value); } private void _updateLanguageProperties(String key, String value) throws IOException { UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(new FileReader(_languagePropertiesFile)); StringBundler sb = new StringBundler(); boolean begin = false; boolean firstLine = true; String linePrefix = key + "="; String line = null; while ((line = unsyncBufferedReader.readLine()) != null) { if (line.equals(StringPool.BLANK)) { begin = !begin; } if (firstLine) { firstLine = false; } else { sb.append(StringPool.NEW_LINE); } if (line.startsWith(linePrefix)) { sb.append(linePrefix + value); } else { sb.append(line); } } unsyncBufferedReader.close(); Writer writer = new OutputStreamWriter( new FileOutputStream(_languagePropertiesFile, false), StringPool.UTF8); writer.write(sb.toString()); writer.close(); System.out.println("Updating " + _languagePropertiesFile + " key " + key); } private String _wrapText(String text, int indentLength, String exclude) { StringBuffer sb = new StringBuffer(); StringBundler regexSB = new StringBundler("(?<=^|</"); regexSB.append(exclude); regexSB.append(">).+?(?=$|<"); regexSB.append(exclude); regexSB.append(">)"); Pattern pattern = Pattern.compile(regexSB.toString(), Pattern.DOTALL); Matcher matcher = pattern.matcher(text); while (matcher.find()) { String wrapped = _formatInlines(matcher.group()); wrapped = StringUtil.wrap(wrapped, 80 - indentLength, "\n"); matcher.appendReplacement(sb, wrapped); } matcher.appendTail(sb); return sb.toString(); } private String _wrapText(String text, String indent) { int indentLength = _getIndentLength(indent); if (text.contains("<pre>")) { text = _wrapText(text, indentLength, "pre"); } else if (text.contains("<table>")) { text = _wrapText(text, indentLength, "table"); } else { text = _formatInlines(text); text = StringUtil.wrap(text, 80 - indentLength, "\n"); } text = text.replaceAll("(?m)^", indent); text = text.replaceAll("(?m) +$", StringPool.BLANK); return text; } private static FileImpl _fileUtil = FileImpl.getInstance(); private static SAXReaderImpl _saxReaderUtil = SAXReaderImpl.getInstance(); private boolean _initializeMissingJavadocs; private String _inputDir; private Map<String, Tuple> _javadocxXmlTuples = new HashMap<String, Tuple>(); private Properties _languageProperties; private File _languagePropertiesFile; private String _outputFilePrefix; private boolean _updateJavadocs; }
/** @author Brian Wing Shun Chan */ public class JavadocBuilder { public static void main(String[] args) { try { new JavadocBuilder(args); } catch (Exception e) { e.printStackTrace(); } } public JavadocBuilder(String[] args) throws Exception { CmdLineParser cmdLineParser = new CmdLineParser(); CmdLineParser.Option commandOption = cmdLineParser.addStringOption("command"); CmdLineParser.Option limitOption = cmdLineParser.addStringOption("limit"); CmdLineParser.Option ignoreAutogeneratedOption = cmdLineParser.addBooleanOption("ignoreAutogenerated"); cmdLineParser.parse(args); String command = (String) cmdLineParser.getOptionValue(commandOption); String limit = (String) cmdLineParser.getOptionValue(limitOption); Boolean ignoreAutogenerated = (Boolean) cmdLineParser.getOptionValue(ignoreAutogeneratedOption); _process(command, limit, ignoreAutogenerated); } private void _addClassCommentElement(Element rootElement, JavaClass javaClass) { Element commentElement = rootElement.addElement("comment"); String comment = _getCDATA(javaClass); if (comment.startsWith("Copyright (c) 2000-2010 Liferay, Inc.")) { comment = StringPool.BLANK; } if (comment.startsWith("<a href=\"" + javaClass.getName() + ".java.html\">")) { int pos = comment.indexOf("</a>"); comment = comment.substring(pos + 4).trim(); } commentElement.addCDATA(comment); } private void _addDocletElements( Element parentElement, AbstractJavaEntity abstractJavaEntity, String name) { DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name); for (DocletTag docletTag : docletTags) { String value = docletTag.getValue(); if (name.equals("author") || name.equals("see") || name.equals("since") || name.equals("version")) { /*if (value.startsWith("Raymond Aug")) { value = "Raymond Aug\u00c3\u00a9"; }*/ DocUtil.add(parentElement, name, value); } else { Element element = parentElement.addElement(name); element.addCDATA(value); } } } private void _addDocletTags(Element parentElement, String name, String indent, StringBuilder sb) { List<Element> elements = parentElement.elements(name); for (Element element : elements) { sb.append(indent); sb.append(" * @"); sb.append(name); sb.append(" "); Element commentElement = element.element("comment"); if (commentElement != null) { sb.append(element.elementText("name")); sb.append(" "); sb.append(_getCDATA(element.elementText("comment"))); } else { sb.append(_getCDATA(element.getText())); } sb.append("\n"); } } private void _addFieldElement(Element rootElement, JavaField javaField) { Element fieldElement = rootElement.addElement("field"); DocUtil.add(fieldElement, "name", javaField.getName()); Element commentElement = fieldElement.addElement("comment"); commentElement.addCDATA(_getCDATA(javaField)); _addDocletElements(fieldElement, javaField, "deprecated"); _addDocletElements(fieldElement, javaField, "see"); _addDocletElements(fieldElement, javaField, "since"); _addDocletElements(fieldElement, javaField, "version"); } private void _addMethodElement(Element rootElement, JavaMethod javaMethod) { Element methodElement = rootElement.addElement("method"); DocUtil.add(methodElement, "name", javaMethod.getName()); Element commentElement = methodElement.addElement("comment"); commentElement.addCDATA(_getCDATA(javaMethod)); _addDocletElements(methodElement, javaMethod, "deprecated"); _addParamElements(methodElement, javaMethod); _addReturnElement(methodElement, javaMethod); _addDocletElements(methodElement, javaMethod, "see"); _addDocletElements(methodElement, javaMethod, "since"); _addThrowsElements(methodElement, javaMethod); _addDocletElements(methodElement, javaMethod, "version"); } private void _addParamElement( Element methodElement, JavaParameter javaParameter, DocletTag[] paramDocletTags) { String name = javaParameter.getName(); String type = javaParameter.getType().getValue(); String value = null; for (DocletTag paramDocletTag : paramDocletTags) { String curValue = paramDocletTag.getValue(); if (!curValue.startsWith(name)) { continue; } else { curValue = value; break; } } Element paramElement = methodElement.addElement("param"); DocUtil.add(paramElement, "name", name); DocUtil.add(paramElement, "type", type); if (value != null) { value = value.substring(name.length()); } Element commentElement = paramElement.addElement("comment"); commentElement.addCDATA(_getCDATA(value)); } private void _addParamElements(Element methodElement, JavaMethod javaMethod) { JavaParameter[] javaParameters = javaMethod.getParameters(); DocletTag[] paramDocletTags = javaMethod.getTagsByName("param"); for (JavaParameter javaParameter : javaParameters) { _addParamElement(methodElement, javaParameter, paramDocletTags); } } private void _addReturnElement(Element methodElement, JavaMethod javaMethod) { Type returns = javaMethod.getReturns(); if ((returns == null) || returns.getValue().equals("void")) { return; } _addDocletElements(methodElement, javaMethod, "return"); } private void _addThrowsElement( Element methodElement, Type exception, DocletTag[] throwsDocletTags) { String name = exception.getJavaClass().getName(); String value = null; for (DocletTag throwsDocletTag : throwsDocletTags) { String curValue = throwsDocletTag.getValue(); if (!curValue.startsWith(name)) { continue; } else { curValue = value; break; } } Element throwsElement = methodElement.addElement("throws"); DocUtil.add(throwsElement, "name", name); DocUtil.add(throwsElement, "type", exception.getValue()); if (value != null) { value = value.substring(name.length()); } Element commentElement = throwsElement.addElement("comment"); commentElement.addCDATA(_getCDATA(value)); } private void _addThrowsElements(Element methodElement, JavaMethod javaMethod) { Type[] exceptions = javaMethod.getExceptions(); DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws"); for (Type exception : exceptions) { _addThrowsElement(methodElement, exception, throwsDocletTags); } } private String _getCDATA(AbstractJavaEntity abstractJavaEntity) { return _getCDATA(abstractJavaEntity.getComment()); } private String _getCDATA(String cdata) { if (cdata == null) { return StringPool.BLANK; } cdata = StringUtil.replace( cdata, new String[] {"\n", "<p>", "</p>"}, new String[] {" ", " <p> ", " </p> "}); while (cdata.contains(" ")) { cdata = StringUtil.replace(cdata, " ", " "); } return cdata.trim(); } private String _getFieldKey(Element fieldElement) { return fieldElement.elementText("name"); } private String _getFieldKey(JavaField javaField) { return javaField.getName(); } private JavaClass _getJavaClass(String fileName) throws Exception { return _getJavaClass(fileName, null); } private JavaClass _getJavaClass(String fileName, Reader reader) throws Exception { int pos = fileName.indexOf("src/"); if (pos == -1) { pos = fileName.indexOf("test/"); } if (pos == -1) { throw new RuntimeException(fileName); } pos = fileName.indexOf("/", pos); String srcFile = fileName.substring(pos + 1, fileName.length()); String className = StringUtil.replace(srcFile.substring(0, srcFile.length() - 5), "/", "."); JavaDocBuilder builder = new JavaDocBuilder(); if (reader == null) { File file = new File(fileName); if (!file.exists()) { return null; } builder.addSource(file); } else { builder.addSource(reader); } return builder.getClassByName(className); } private String _getJavaClassComment(Element rootElement, JavaClass javaClass) { StringBuilder sb = new StringBuilder(); sb.append("/**\n"); sb.append(" * "); sb.append(_getCDATA(rootElement.elementText("comment"))); sb.append("\n"); sb.append(" *\n"); String indent = StringPool.BLANK; _addDocletTags(rootElement, "author", indent, sb); _addDocletTags(rootElement, "deprecated", indent, sb); _addDocletTags(rootElement, "see", indent, sb); _addDocletTags(rootElement, "serial", indent, sb); _addDocletTags(rootElement, "since", indent, sb); _addDocletTags(rootElement, "version", indent, sb); sb.append(" */\n"); return sb.toString(); } private String _getJavadocXml(JavaClass javaClass) throws Exception { Element rootElement = _saxReaderUtil.createElement("javadoc"); Document document = _saxReaderUtil.createDocument(rootElement); DocUtil.add(rootElement, "name", javaClass.getName()); DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName()); _addClassCommentElement(rootElement, javaClass); _addDocletElements(rootElement, javaClass, "author"); _addDocletElements(rootElement, javaClass, "deprecated"); _addDocletElements(rootElement, javaClass, "see"); _addDocletElements(rootElement, javaClass, "serial"); _addDocletElements(rootElement, javaClass, "since"); _addDocletElements(rootElement, javaClass, "version"); JavaMethod[] javaMethods = javaClass.getMethods(); for (JavaMethod javaMethod : javaMethods) { _addMethodElement(rootElement, javaMethod); } JavaField[] javaFields = javaClass.getFields(); for (JavaField javaField : javaFields) { _addFieldElement(rootElement, javaField); } return document.formattedString(); } private String _getJavaFieldComment( String[] lines, Map<String, Element> fieldElementsMap, JavaField javaField) { String fieldKey = _getFieldKey(javaField); Element fieldElement = fieldElementsMap.get(fieldKey); if (fieldElement == null) { return null; } String line = lines[javaField.getLineNumber() - 1]; String indent = StringPool.BLANK; for (char c : line.toCharArray()) { if (Character.isWhitespace(c)) { indent += c; } else { break; } } StringBuilder sb = new StringBuilder(); sb.append(indent); sb.append("/**\n"); sb.append(indent); sb.append(" * "); sb.append(fieldElement.elementText("comment")); sb.append("\n"); sb.append(indent); sb.append(" *\n"); _addDocletTags(fieldElement, "deprecated", indent, sb); _addDocletTags(fieldElement, "see", indent, sb); _addDocletTags(fieldElement, "since", indent, sb); _addDocletTags(fieldElement, "version", indent, sb); sb.append(indent); sb.append(" */\n"); return sb.toString(); } private String _getJavaMethodComment( String[] lines, Map<String, Element> methodElementsMap, JavaMethod javaMethod) { String methodKey = _getMethodKey(javaMethod); Element methodElement = methodElementsMap.get(methodKey); if (methodElement == null) { return null; } String line = lines[javaMethod.getLineNumber() - 1]; String indent = StringPool.BLANK; for (char c : line.toCharArray()) { if (Character.isWhitespace(c)) { indent += c; } else { break; } } StringBuilder sb = new StringBuilder(); sb.append(indent); sb.append("/**\n"); sb.append(indent); sb.append(" * "); sb.append(methodElement.elementText("comment")); sb.append("\n"); sb.append(indent); sb.append(" *\n"); _addDocletTags(methodElement, "deprecated", indent, sb); _addDocletTags(methodElement, "param", indent, sb); _addDocletTags(methodElement, "return", indent, sb); _addDocletTags(methodElement, "see", indent, sb); _addDocletTags(methodElement, "since", indent, sb); _addDocletTags(methodElement, "throws", indent, sb); _addDocletTags(methodElement, "version", indent, sb); sb.append(indent); sb.append(" */\n"); return sb.toString(); } private String _getMethodKey(Element methodElement) { StringBuilder sb = new StringBuilder(); sb.append(methodElement.elementText("name")); sb.append("("); List<Element> paramElements = methodElement.elements("param"); for (Element paramElement : paramElements) { sb.append(paramElement.elementText("name")); sb.append("|"); sb.append(paramElement.elementText("type")); sb.append(","); } sb.append(")"); return sb.toString(); } private String _getMethodKey(JavaMethod javaMethod) { StringBuilder sb = new StringBuilder(); sb.append(javaMethod.getName()); sb.append("("); JavaParameter[] javaParameters = javaMethod.getParameters(); for (JavaParameter javaParameter : javaParameters) { sb.append(javaParameter.getName()); sb.append("|"); sb.append(javaParameter.getType().getValue()); sb.append(","); } sb.append(")"); return sb.toString(); } private boolean _isGenerated(String content) { if (content.contains("<javadoc autogenerated=\"true\">")) { return true; } else { return false; } } private void _process(String command, String limit, Boolean ignoreAutogenerated) throws Exception { DirectoryScanner ds = new DirectoryScanner(); ds.setBasedir(_basedir); ds.setExcludes(new String[] {"**\\classes\\**", "**\\portal-client\\**", "**\\portal-web\\**"}); List<String> includes = new ArrayList<String>(); if (Validator.isNotNull(limit) && !limit.startsWith("$")) { String[] limitArray = StringUtil.split(limit, '/'); for (String curLimit : limitArray) { includes.add("**\\" + StringUtil.replace(curLimit, ".", "\\") + "\\**\\*.java"); includes.add("**\\" + curLimit + ".java"); } } else { includes.add("**\\*.java"); } ds.setIncludes(includes.toArray(new String[includes.size()])); ds.scan(); String[] fileNames = ds.getIncludedFiles(); for (String fileName : fileNames) { fileName = StringUtil.replace(fileName, "\\", "/"); /*if (!fileName.endsWith("Isolation.java")) { continue; }*/ if ((ignoreAutogenerated != null) && (ignoreAutogenerated.booleanValue())) { File file = new File(_basedir + fileName); if (file.exists()) { String oldContent = _fileUtil.read(_basedir + fileName + "doc"); if (_isGenerated(oldContent)) { continue; } } } if (command.equals("cleanup")) { _processGet(fileName); _processSave(fileName); _processDelete(fileName); } else if (command.equals("commit")) { _processSave(fileName); _processDelete(fileName); } else if (command.equals("delete")) { _processDelete(fileName); } else if (command.equals("get")) { _processGet(fileName); } else if (command.equals("save")) { _processSave(fileName); } } } private void _processDelete(String fileName) throws Exception { _removeJavadocFromJava(fileName, true); } private void _processGet(String fileName) throws Exception { File javadocFile = new File(_basedir + fileName + "doc"); if (!javadocFile.exists()) { _updateJavadocFromJava(fileName); } String javaWithoutJavadoc = _removeJavadocFromJava(fileName, false); _updateJavaFromJavadoc(fileName, javaWithoutJavadoc); } private void _processSave(String fileName) throws Exception { _updateJavadocFromJava(fileName); } private String _removeJavadocFromJava(String fileName, boolean log) throws Exception { File file = new File(_basedir + fileName); String oldContent = _fileUtil.read(file); String[] lines = StringUtil.splitLines(oldContent); JavaClass javaClass = _getJavaClass(fileName, new UnsyncStringReader(oldContent)); Set<Integer> lineNumbers = new HashSet<Integer>(); lineNumbers.add(javaClass.getLineNumber()); JavaMethod[] javaMethods = javaClass.getMethods(); for (JavaMethod javaMethod : javaMethods) { lineNumbers.add(javaMethod.getLineNumber()); } JavaField[] javaFields = javaClass.getFields(); for (JavaField javaField : javaFields) { lineNumbers.add(javaField.getLineNumber()); } for (int lineNumber : lineNumbers) { int pos = lineNumber - 2; String line = lines[pos].trim(); if (line.endsWith("*/")) { while (true) { lines[pos] = null; if (line.startsWith("/**")) { break; } line = lines[--pos].trim(); } } } StringBuilder sb = new StringBuilder(oldContent.length()); for (String line : lines) { if (line != null) { sb.append(line); sb.append("\n"); } } String newContent = sb.toString().trim(); if ((oldContent == null) || !oldContent.equals(newContent)) { _fileUtil.write(file, newContent); if (log) { System.out.println("Writing " + file); } } return newContent; } private void _updateJavadocFromJava(String fileName) throws Exception { File file = new File(_basedir + fileName + "doc"); String oldContent = null; if (file.exists()) { oldContent = _fileUtil.read(file); if (_isGenerated(oldContent)) { return; } } JavaClass javaClass = _getJavaClass(fileName); String newContent = _getJavadocXml(javaClass); if ((oldContent == null) || !oldContent.equals(newContent)) { _fileUtil.write(file, newContent.getBytes()); System.out.println("Writing " + file); } } private void _updateJavaFromJavadoc(String fileName, String oldContent) throws Exception { File javadocFile = new File(_basedir + fileName + "doc"); if (!javadocFile.exists()) { return; } File file = new File(_basedir + fileName); if (oldContent == null) { oldContent = _fileUtil.read(file); } String[] lines = StringUtil.splitLines(oldContent); JavaClass javaClass = _getJavaClass(fileName, new UnsyncStringReader(oldContent)); Document document = _saxReaderUtil.read(javadocFile); Element rootElement = document.getRootElement(); Map<Integer, String> commentsMap = new TreeMap<Integer, String>(); commentsMap.put(javaClass.getLineNumber(), _getJavaClassComment(rootElement, javaClass)); Map<String, Element> methodElementsMap = new HashMap<String, Element>(); List<Element> methodElements = rootElement.elements("method"); for (Element methodElement : methodElements) { String methodKey = _getMethodKey(methodElement); methodElementsMap.put(methodKey, methodElement); } JavaMethod[] javaMethods = javaClass.getMethods(); for (JavaMethod javaMethod : javaMethods) { if (commentsMap.containsKey(javaMethod.getLineNumber())) { continue; } commentsMap.put( javaMethod.getLineNumber(), _getJavaMethodComment(lines, methodElementsMap, javaMethod)); } Map<String, Element> fieldElementsMap = new HashMap<String, Element>(); List<Element> fieldElements = rootElement.elements("field"); for (Element fieldElement : fieldElements) { String fieldKey = _getFieldKey(fieldElement); fieldElementsMap.put(fieldKey, fieldElement); } JavaField[] javaFields = javaClass.getFields(); for (JavaField javaField : javaFields) { if (commentsMap.containsKey(javaField.getLineNumber())) { continue; } commentsMap.put( javaField.getLineNumber(), _getJavaFieldComment(lines, fieldElementsMap, javaField)); } StringBuilder sb = new StringBuilder(oldContent.length()); for (int lineNumber = 1; lineNumber <= lines.length; lineNumber++) { String line = lines[lineNumber - 1]; String comments = commentsMap.get(lineNumber); if (comments != null) { sb.append(comments); } sb.append(line); sb.append("\n"); } String newContent = sb.toString().trim(); if ((oldContent == null) || !oldContent.equals(newContent)) { _fileUtil.write(file, newContent); System.out.println("Writing " + file); } } private static FileImpl _fileUtil = FileImpl.getInstance(); private static SAXReaderImpl _saxReaderUtil = SAXReaderImpl.getInstance(); private String _basedir = "./"; }