001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
019    import com.liferay.portal.kernel.util.CharPool;
020    import com.liferay.portal.kernel.util.GetterUtil;
021    import com.liferay.portal.kernel.util.StringBundler;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.Tuple;
025    import com.liferay.portal.kernel.util.Validator;
026    import com.liferay.portal.kernel.xml.Document;
027    import com.liferay.portal.kernel.xml.Element;
028    import com.liferay.portal.tools.javadocformatter.SinceJava;
029    import com.liferay.portal.tools.servicebuilder.ServiceBuilder;
030    import com.liferay.portal.util.FileImpl;
031    import com.liferay.portal.xml.SAXReaderImpl;
032    import com.liferay.util.xml.DocUtil;
033    
034    import com.thoughtworks.qdox.JavaDocBuilder;
035    import com.thoughtworks.qdox.model.AbstractBaseJavaEntity;
036    import com.thoughtworks.qdox.model.AbstractJavaEntity;
037    import com.thoughtworks.qdox.model.Annotation;
038    import com.thoughtworks.qdox.model.DocletTag;
039    import com.thoughtworks.qdox.model.JavaClass;
040    import com.thoughtworks.qdox.model.JavaField;
041    import com.thoughtworks.qdox.model.JavaMethod;
042    import com.thoughtworks.qdox.model.JavaPackage;
043    import com.thoughtworks.qdox.model.JavaParameter;
044    import com.thoughtworks.qdox.model.Type;
045    import com.thoughtworks.qdox.model.annotation.AnnotationValue;
046    
047    import java.io.File;
048    import java.io.FileInputStream;
049    import java.io.FileOutputStream;
050    import java.io.FileReader;
051    import java.io.IOException;
052    import java.io.OutputStreamWriter;
053    import java.io.Reader;
054    import java.io.Writer;
055    
056    import java.nio.file.Files;
057    import java.nio.file.Paths;
058    import java.util.ArrayList;
059    import java.util.Collection;
060    import java.util.HashMap;
061    import java.util.HashSet;
062    import java.util.List;
063    import java.util.Map;
064    import java.util.Properties;
065    import java.util.Set;
066    import java.util.TreeMap;
067    import java.util.regex.Matcher;
068    import java.util.regex.Pattern;
069    
070    import org.apache.tools.ant.DirectoryScanner;
071    
072    /**
073     * @author Brian Wing Shun Chan
074     * @author Connor McKay
075     * @author James Hinkey
076     * @author Hugo Huijser
077     */
078    public class JavadocFormatter {
079    
080            public static void main(String[] args) {
081                    try {
082                            new JavadocFormatter(args);
083                    }
084                    catch (Exception e) {
085                            e.printStackTrace();
086                    }
087            }
088    
089            public JavadocFormatter(String[] args) throws Exception {
090                    Map<String, String> arguments = ArgumentsUtil.parseArguments(args);
091    
092                    String init = arguments.get("javadoc.init");
093    
094                    if (Validator.isNotNull(init) && !init.startsWith("$")) {
095                            _initializeMissingJavadocs = GetterUtil.getBoolean(init);
096                    }
097    
098                    _inputDir = GetterUtil.getString(arguments.get("javadoc.input.dir"));
099    
100                    if (_inputDir.startsWith("$")) {
101                            _inputDir = "./";
102                    }
103    
104                    if (!_inputDir.endsWith("/")) {
105                            _inputDir += "/";
106                    }
107    
108                    System.out.println("Input directory is " + _inputDir);
109    
110                    String[] limits = StringUtil.split(arguments.get("javadoc.limit"), ",");
111    
112                    _outputFilePrefix = GetterUtil.getString(
113                            arguments.get("javadoc.output.file.prefix"));
114    
115                    if (_outputFilePrefix.startsWith("$")) {
116                            _outputFilePrefix = "javadocs";
117                    }
118    
119                    String update = arguments.get("javadoc.update");
120    
121                    if (Validator.isNotNull(update) && !update.startsWith("$")) {
122                            _updateJavadocs = GetterUtil.getBoolean(update);
123                    }
124    
125                    DirectoryScanner directoryScanner = new DirectoryScanner();
126    
127                    directoryScanner.setBasedir(_inputDir);
128                    directoryScanner.setExcludes(
129                            new String[] {"**\\classes\\**", "**\\portal-client\\**"});
130    
131                    for (String limit : limits) {
132                            List<String> includes = new ArrayList<String>();
133    
134                            if (Validator.isNotNull(limit) && !limit.startsWith("$")) {
135                                    System.out.println("Limit on " + limit);
136    
137                                    String[] limitArray = StringUtil.split(limit, '/');
138    
139                                    for (String curLimit : limitArray) {
140                                            includes.add(
141                                                    "**\\" + StringUtil.replace(curLimit, ".", "\\") +
142                                                            "\\**\\*.java");
143                                            includes.add("**\\" + curLimit + ".java");
144                                    }
145                            }
146    
147                            else {
148                                    includes.add("**\\*.java");
149                            }
150    
151                            directoryScanner.setIncludes(
152                                    includes.toArray(new String[includes.size()]));
153    
154                            directoryScanner.scan();
155    
156                            String[] fileNames = StringPool.EMPTY_ARRAY;
157    
158                            fileNames = directoryScanner.getIncludedFiles();
159    
160                            if ((fileNames.length == 0) && Validator.isNotNull(limit) &&
161                                    !limit.startsWith("$")) {
162    
163                                    StringBundler sb = new StringBundler("Limit file not found: ");
164    
165                                    sb.append(limit);
166    
167                                    if (limit.contains(".")) {
168                                            sb.append(
169                                                    " Specify limit filename without package path or ");
170                                            sb.append("file type suffix.");
171                                    }
172    
173                                    System.out.println(sb.toString());
174                            }
175    
176                            _languagePropertiesFile = new File(
177                                    "src/content/Language.properties");
178    
179                            if (_languagePropertiesFile.exists()) {
180                                    _languageProperties = new Properties();
181    
182                                    _languageProperties.load(
183                                            new FileInputStream(
184                                                    _languagePropertiesFile.getAbsolutePath()));
185                            }
186    
187                            for (String fileName : fileNames) {
188                                    fileName = StringUtil.replace(fileName, "\\", "/");
189    
190                                    try {
191                                            _format(fileName);
192                                    }
193                                    catch (Exception e) {
194                                            throw new RuntimeException(
195                                                    "Unable to format file " + fileName, e);
196                                    }
197                            }
198                    }
199    
200                    for (Map.Entry<String, Tuple> entry : _javadocxXmlTuples.entrySet()) {
201                            Tuple tuple = entry.getValue();
202    
203                            File javadocsXmlFile = (File)tuple.getObject(1);
204                            String oldJavadocsXmlContent = (String)tuple.getObject(2);
205                            Document javadocsXmlDocument = (Document)tuple.getObject(3);
206    
207                            Element javadocsXmlRootElement =
208                                    javadocsXmlDocument.getRootElement();
209    
210                            javadocsXmlRootElement.sortElementsByChildElement(
211                                    "javadoc", "type");
212    
213                            String newJavadocsXmlContent =
214                                    javadocsXmlDocument.formattedString();
215    
216                            if (!oldJavadocsXmlContent.equals(newJavadocsXmlContent)) {
217                                    _fileUtil.write(javadocsXmlFile, newJavadocsXmlContent);
218                            }
219    
220                            _detachUnnecessaryTypes(javadocsXmlRootElement);
221    
222                            File javadocsRuntimeXmlFile = new File(
223                                    StringUtil.replaceLast(
224                                            javadocsXmlFile.toString(), "-all.xml", "-rt.xml"));
225    
226                            String oldJavadocsRuntimeXmlContent = StringPool.BLANK;
227    
228                            if (javadocsRuntimeXmlFile.exists()) {
229                                    oldJavadocsRuntimeXmlContent = _fileUtil.read(
230                                            javadocsRuntimeXmlFile);
231                            }
232    
233                            String newJavadocsRuntimeXmlContent =
234                                    javadocsXmlDocument.compactString();
235    
236                            if (!oldJavadocsRuntimeXmlContent.equals(
237                                            newJavadocsRuntimeXmlContent)) {
238    
239                                    _fileUtil.write(
240                                            javadocsRuntimeXmlFile, newJavadocsRuntimeXmlContent);
241                            }
242                    }
243            }
244    
245            private List<Tuple> _addAncestorJavaClassTuples(
246                    JavaClass javaClass, List<Tuple> ancestorJavaClassTuples) {
247    
248                    JavaClass superJavaClass = javaClass.getSuperJavaClass();
249    
250                    if (superJavaClass != null) {
251                            ancestorJavaClassTuples.add(new Tuple(superJavaClass));
252    
253                            ancestorJavaClassTuples = _addAncestorJavaClassTuples(
254                                    superJavaClass, ancestorJavaClassTuples);
255                    }
256    
257                    Type[] implementz = javaClass.getImplements();
258    
259                    for (Type implement : implementz) {
260                            Type[] actualTypeArguments = implement.getActualTypeArguments();
261                            JavaClass implementedInterface = implement.getJavaClass();
262    
263                            if (actualTypeArguments == null) {
264                                    ancestorJavaClassTuples.add(new Tuple(implementedInterface));
265                            }
266                            else {
267                                    ancestorJavaClassTuples.add(
268                                            new Tuple(implementedInterface, actualTypeArguments));
269                            }
270    
271                            ancestorJavaClassTuples = _addAncestorJavaClassTuples(
272                                    implementedInterface, ancestorJavaClassTuples);
273                    }
274    
275                    return ancestorJavaClassTuples;
276            }
277    
278            private void _addClassCommentElement(
279                    Element rootElement, JavaClass javaClass) {
280    
281                    String comment = _getCDATA(javaClass);
282    
283                    if (comment.startsWith("Copyright (c)")) {
284                            comment = StringPool.BLANK;
285                    }
286    
287                    if (Validator.isNull(comment)) {
288                            return;
289                    }
290    
291                    Element commentElement = rootElement.addElement("comment");
292    
293                    commentElement.addCDATA(comment);
294            }
295    
296            private String _addDeprecatedTag(
297                    String comment, AbstractBaseJavaEntity abstractBaseJavaEntity,
298                    String indent) {
299    
300                    if (comment == null) {
301                            return null;
302                    }
303    
304                    if (!comment.contains("* @deprecated ") ||
305                            ServiceBuilder.hasAnnotation(
306                                    abstractBaseJavaEntity, "Deprecated")) {
307    
308                            return comment;
309                    }
310    
311                    return comment + indent + "@Deprecated\n";
312            }
313    
314            private void _addDocletElements(
315                            Element parentElement, AbstractJavaEntity abstractJavaEntity,
316                            String name)
317                    throws Exception {
318    
319                    DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name);
320    
321                    for (DocletTag docletTag : docletTags) {
322                            String value = docletTag.getValue();
323    
324                            value = _trimMultilineText(value);
325    
326                            value = StringUtil.replace(value, " </", "</");
327    
328                            Element element = parentElement.addElement(name);
329    
330                            element.addCDATA(value);
331                    }
332    
333                    if ((docletTags.length == 0) && name.equals("author")) {
334                            Element element = parentElement.addElement(name);
335    
336                            element.addCDATA(ServiceBuilder.AUTHOR);
337                    }
338            }
339    
340            private String _addDocletTags(
341                    Element parentElement, String[] tagNames, String indent,
342                    boolean publicAccess) {
343    
344                    List<String> allTagNames = new ArrayList<String>();
345                    List<String> customTagNames = new ArrayList<String>();
346                    List<String> requiredTagNames = new ArrayList<String>();
347    
348                    for (String tagName : tagNames) {
349                            List<Element> elements = parentElement.elements(tagName);
350    
351                            for (Element element : elements) {
352                                    Element commentElement = element.element("comment");
353    
354                                    String comment = null;
355    
356                                    // Get comment by comment element's text or the element's text
357    
358                                    if (commentElement != null) {
359                                            comment = commentElement.getText();
360                                    }
361                                    else {
362                                            comment = element.getText();
363                                    }
364    
365                                    if (tagName.equals("param") || tagName.equals("return") ||
366                                            tagName.equals("throws")) {
367    
368                                            if (Validator.isNotNull(comment)) {
369                                                    requiredTagNames.add(tagName);
370                                            }
371                                            else if (tagName.equals("param")) {
372                                                    if (GetterUtil.getBoolean(
373                                                                    element.elementText("required"))) {
374    
375                                                            requiredTagNames.add(tagName);
376                                                    }
377                                            }
378                                            else if (tagName.equals("throws")) {
379                                                    if (GetterUtil.getBoolean(
380                                                                    element.elementText("required"))) {
381    
382                                                            requiredTagNames.add(tagName);
383                                                    }
384                                            }
385                                    }
386                                    else {
387                                            customTagNames.add(tagName);
388                                    }
389    
390                                    allTagNames.add(tagName);
391                            }
392                    }
393    
394                    int maxTagNameLength = 0;
395    
396                    List<String> maxTagNameLengthTags = new ArrayList<String>();
397    
398                    if (_initializeMissingJavadocs) {
399                            maxTagNameLengthTags.addAll(allTagNames);
400                    }
401                    else if (_updateJavadocs) {
402                            if (!requiredTagNames.isEmpty()) {
403                                    maxTagNameLengthTags.addAll(allTagNames);
404                            }
405                            else {
406                                    maxTagNameLengthTags.addAll(customTagNames);
407                                    maxTagNameLengthTags.addAll(requiredTagNames);
408                            }
409                    }
410                    else {
411                            maxTagNameLengthTags.addAll(customTagNames);
412                            maxTagNameLengthTags.addAll(requiredTagNames);
413                    }
414    
415                    for (String name : maxTagNameLengthTags) {
416                            if (name.length() > maxTagNameLength) {
417                                    maxTagNameLength = name.length();
418                            }
419                    }
420    
421                    // There should be an @ sign before the tag and a space after it
422    
423                    maxTagNameLength += 2;
424    
425                    String tagNameIndent = _getSpacesIndent(maxTagNameLength);
426    
427                    StringBundler sb = new StringBundler();
428    
429                    for (String tagName : tagNames) {
430                            List<Element> elements = parentElement.elements(tagName);
431    
432                            for (Element element : elements) {
433                                    Element commentElement = element.element("comment");
434    
435                                    String comment = null;
436    
437                                    if (commentElement != null) {
438                                            comment = commentElement.getText();
439                                    }
440                                    else {
441                                            comment = element.getText();
442                                    }
443    
444                                    String elementName = element.elementText("name");
445    
446                                    if (Validator.isNotNull(comment)) {
447                                            comment = _assembleTagComment(
448                                                    tagName, elementName, comment, indent, tagNameIndent);
449    
450                                            sb.append(comment);
451                                    }
452                                    else {
453                                            if (_initializeMissingJavadocs && publicAccess) {
454    
455                                                    // Write out all tags
456    
457                                                    comment = _assembleTagComment(
458                                                            tagName, elementName, comment, indent,
459                                                            tagNameIndent);
460    
461                                                    sb.append(comment);
462                                            }
463                                            else if (_updateJavadocs && publicAccess) {
464                                                    if (!tagName.equals("param") &&
465                                                            !tagName.equals("return") &&
466                                                            !tagName.equals("throws")) {
467    
468                                                            // Write out custom tag
469    
470                                                            comment = _assembleTagComment(
471                                                                    tagName, elementName, comment, indent,
472                                                                    tagNameIndent);
473    
474                                                            sb.append(comment);
475                                                    }
476                                                    else if (!requiredTagNames.isEmpty()) {
477    
478                                                            // Write out all tags
479    
480                                                            comment = _assembleTagComment(
481                                                                    tagName, elementName, comment, indent,
482                                                                    tagNameIndent);
483    
484                                                            sb.append(comment);
485                                                    }
486                                                    else {
487    
488                                                            // Skip empty common tag
489    
490                                                    }
491                                            }
492                                            else {
493                                                    if (!tagName.equals("param") &&
494                                                            !tagName.equals("return") &&
495                                                            !tagName.equals("throws")) {
496    
497                                                            // Write out custom tag
498    
499                                                            comment = _assembleTagComment(
500                                                                    tagName, elementName, comment, indent,
501                                                                    tagNameIndent);
502    
503                                                            sb.append(comment);
504                                                    }
505                                                    else if (tagName.equals("param") ||
506                                                                     tagName.equals("return") ||
507                                                                     tagName.equals("throws")) {
508    
509                                                            if (GetterUtil.getBoolean(
510                                                                            element.elementText("required"))) {
511    
512                                                                    elementName = element.elementText("name");
513    
514                                                                    comment = _assembleTagComment(
515                                                                            tagName, elementName, comment, indent,
516                                                                            tagNameIndent);
517    
518                                                                    sb.append(comment);
519                                                            }
520                                                    }
521                                                    else {
522    
523                                                            // Skip empty common tag
524    
525                                                    }
526                                            }
527                                    }
528                            }
529                    }
530    
531                    return sb.toString();
532            }
533    
534            private void _addFieldElement(Element rootElement, JavaField javaField)
535                    throws Exception {
536    
537                    Element fieldElement = rootElement.addElement("field");
538    
539                    DocUtil.add(fieldElement, "name", javaField.getName());
540    
541                    String comment = _getCDATA(javaField);
542    
543                    if (Validator.isNotNull(comment)) {
544                            Element commentElement = fieldElement.addElement("comment");
545    
546                            commentElement.addCDATA(comment);
547                    }
548    
549                    _addDocletElements(fieldElement, javaField, "version");
550                    _addDocletElements(fieldElement, javaField, "see");
551                    _addDocletElements(fieldElement, javaField, "since");
552                    _addDocletElements(fieldElement, javaField, "deprecated");
553            }
554    
555            private void _addMethodElement(Element rootElement, JavaMethod javaMethod)
556                    throws Exception {
557    
558                    Element methodElement = rootElement.addElement("method");
559    
560                    DocUtil.add(methodElement, "name", javaMethod.getName());
561    
562                    String comment = _getCDATA(javaMethod);
563    
564                    if (Validator.isNotNull(comment)) {
565                            Element commentElement = methodElement.addElement("comment");
566    
567                            commentElement.addCDATA(_getCDATA(javaMethod));
568                    }
569    
570                    _addDocletElements(methodElement, javaMethod, "version");
571                    _addParamElements(methodElement, javaMethod);
572                    _addReturnElement(methodElement, javaMethod);
573                    _addThrowsElements(methodElement, javaMethod);
574                    _addDocletElements(methodElement, javaMethod, "see");
575                    _addDocletElements(methodElement, javaMethod, "since");
576                    _addDocletElements(methodElement, javaMethod, "deprecated");
577            }
578    
579            private void _addParamElement(
580                    Element methodElement, JavaParameter javaParameter,
581                    DocletTag[] paramDocletTags) {
582    
583                    String name = javaParameter.getName();
584    
585                    String value = null;
586    
587                    for (DocletTag paramDocletTag : paramDocletTags) {
588                            String curValue = paramDocletTag.getValue();
589    
590                            if (curValue.equals(name) || curValue.startsWith(name + " ")) {
591                                    value = curValue;
592    
593                                    break;
594                            }
595                    }
596    
597                    Element paramElement = methodElement.addElement("param");
598    
599                    DocUtil.add(paramElement, "name", name);
600                    DocUtil.add(paramElement, "type", _getTypeValue(javaParameter));
601    
602                    if (value != null) {
603                            value = value.substring(name.length());
604    
605                            DocUtil.add(paramElement, "required", true);
606                    }
607    
608                    value = _trimMultilineText(value);
609    
610                    Element commentElement = paramElement.addElement("comment");
611    
612                    commentElement.addCDATA(value);
613            }
614    
615            private void _addParamElements(
616                    Element methodElement, JavaMethod javaMethod) {
617    
618                    JavaParameter[] javaParameters = javaMethod.getParameters();
619    
620                    DocletTag[] paramDocletTags = javaMethod.getTagsByName("param");
621    
622                    for (JavaParameter javaParameter : javaParameters) {
623                            _addParamElement(methodElement, javaParameter, paramDocletTags);
624                    }
625            }
626    
627            private void _addReturnElement(Element methodElement, JavaMethod javaMethod)
628                    throws Exception {
629    
630                    Type returns = javaMethod.getReturns();
631    
632                    if (returns == null) {
633                            return;
634                    }
635    
636                    String returnsValue = returns.getValue();
637    
638                    if (returnsValue.equals("void")) {
639                            return;
640                    }
641    
642                    Element returnElement = methodElement.addElement("return");
643    
644                    DocletTag[] returnDocletTags = javaMethod.getTagsByName("return");
645    
646                    String comment = StringPool.BLANK;
647    
648                    if (returnDocletTags.length > 0) {
649                            DocletTag returnDocletTag = returnDocletTags[0];
650    
651                            comment = GetterUtil.getString(returnDocletTag.getValue());
652    
653                            DocUtil.add(returnElement, "required", true);
654                    }
655    
656                    comment = _trimMultilineText(comment);
657    
658                    Element commentElement = returnElement.addElement("comment");
659    
660                    commentElement.addCDATA(comment);
661            }
662    
663            private void _addThrowsElement(
664                    Element methodElement, Type exceptionType,
665                    DocletTag[] throwsDocletTags) {
666    
667                    JavaClass javaClass = exceptionType.getJavaClass();
668    
669                    String name = javaClass.getName();
670    
671                    String value = null;
672    
673                    for (DocletTag throwsDocletTag : throwsDocletTags) {
674                            String curValue = throwsDocletTag.getValue();
675    
676                            if (!curValue.startsWith(name)) {
677                                    continue;
678                            }
679                            else {
680                                    value = curValue;
681    
682                                    break;
683                            }
684                    }
685    
686                    Element throwsElement = methodElement.addElement("throws");
687    
688                    DocUtil.add(throwsElement, "name", name);
689                    DocUtil.add(throwsElement, "type", exceptionType.getValue());
690    
691                    if (value != null) {
692                            value = value.substring(name.length());
693    
694                            DocUtil.add(throwsElement, "required", true);
695                    }
696    
697                    value = _trimMultilineText(value);
698    
699                    Element commentElement = throwsElement.addElement("comment");
700    
701                    commentElement.addCDATA(_getCDATA(value));
702            }
703    
704            private void _addThrowsElements(
705                    Element methodElement, JavaMethod javaMethod) {
706    
707                    Type[] exceptionTypes = javaMethod.getExceptions();
708    
709                    DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws");
710    
711                    for (Type exceptionType : exceptionTypes) {
712                            _addThrowsElement(methodElement, exceptionType, throwsDocletTags);
713                    }
714            }
715    
716            private String _assembleTagComment(
717                    String tagName, String elementName, String comment, String indent,
718                    String tagNameIndent) {
719    
720                    String indentAndTagName = indent + StringPool.AT + tagName;
721    
722                    if (Validator.isNotNull(elementName)) {
723                            if (Validator.isNotNull(comment)) {
724                                    comment = elementName + StringPool.SPACE + comment;
725                            }
726                            else {
727                                    comment = elementName;
728                            }
729    
730                            // <name indent> elementName [comment]
731    
732                            comment = _wrapText(comment, indent + tagNameIndent);
733    
734                            // * @name <name indent> elementName [comment]
735    
736                            comment =
737                                    indentAndTagName + comment.substring(indentAndTagName.length());
738                    }
739                    else {
740                            if (Validator.isNotNull(comment)) {
741    
742                                    // <name indent> comment
743    
744                                    comment = _wrapText(comment, indent + tagNameIndent);
745    
746                                    // * @name <name indent> comment
747    
748                                    comment =
749                                            indentAndTagName +
750                                                    comment.substring(indentAndTagName.length());
751                            }
752                            else {
753    
754                                    // * @name
755    
756                                    comment = indentAndTagName + "\n";
757                            }
758                    }
759    
760                    return comment;
761            }
762    
763            private void _detachUnnecessaryTypes(Element rootElement) {
764                    List<Element> elements = rootElement.elements();
765    
766                    for (Element element : elements) {
767                            String type = element.elementText("type");
768    
769                            if (!type.contains(".service.") || !type.endsWith("ServiceImpl")) {
770                                    element.detach();
771                            }
772                    }
773            }
774    
775            private void _format(String fileName) throws Exception {
776                    String originalContent = new String(
777                            Files.readAllBytes(Paths.get(_inputDir + fileName)),
778                            StringPool.UTF8);
779    
780                    if (fileName.contains("modules/third-party") ||
781                            fileName.endsWith("Application.java") ||
782                            fileName.endsWith("JavadocFormatter.java") ||
783                            fileName.endsWith("SourceFormatter.java") ||
784                            fileName.endsWith("WebProxyPortlet.java") ||
785                            _hasGeneratedTag(originalContent)) {
786    
787                            return;
788                    }
789    
790                    JavaClass javaClass = _getJavaClass(
791                            fileName, new UnsyncStringReader(originalContent));
792    
793                    String javadocLessContent = _removeJavadocFromJava(
794                            javaClass, originalContent);
795    
796                    Document document = _getJavadocDocument(javaClass);
797    
798                    _updateJavadocsXmlFile(fileName, javaClass, document);
799    
800                    _updateJavaFromDocument(
801                            fileName, originalContent, javadocLessContent, document);
802            }
803    
804            private String _formatCDATA(String cdata) {
805                    cdata = cdata.replaceAll(
806                            "(?s)\\s*<(p|[ou]l)>\\s*(.*?)\\s*</\\1>\\s*",
807                            "\n\n<$1>\n$2\n</$1>\n\n");
808                    cdata = cdata.replaceAll(
809                            "(?s)\\s*<li>\\s*(.*?)\\s*</li>\\s*", "\n<li>\n$1\n</li>\n");
810                    cdata = StringUtil.replace(cdata, "</li>\n\n<li>", "</li>\n<li>");
811                    cdata = cdata.replaceAll("\n\\s+\n", "\n\n");
812                    cdata = cdata.replaceAll(" +", " ");
813    
814                    // Trim whitespace inside paragraph tags or in the first paragraph
815    
816                    Matcher matcher = _paragraphTagPattern.matcher(cdata);
817    
818                    StringBuffer sb = new StringBuffer();
819    
820                    while (matcher.find()) {
821                            String trimmed = _trimMultilineText(matcher.group());
822    
823                            // Escape dollar signs
824    
825                            trimmed = StringUtil.replace(trimmed, "$", "\\$");
826    
827                            matcher.appendReplacement(sb, trimmed);
828                    }
829    
830                    matcher.appendTail(sb);
831    
832                    cdata = sb.toString();
833    
834                    return cdata.trim();
835            }
836    
837            private String _formatInlines(String text) {
838    
839                    // Capitalize ID
840    
841                    text = text.replaceAll("[?@param id](?i)\\bid(s)?\\b", " ID$1");
842    
843                    // Wrap special constants in code tags
844    
845                    text = text.replaceAll(
846                            "(?i)(?<!<code>|\\w)(null|false|true)(?!\\w)", "<code>$1</code>");
847    
848                    return text;
849            }
850    
851            private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
852                    return _getCDATA(abstractJavaEntity.getComment());
853            }
854    
855            private String _getCDATA(String cdata) {
856                    StringBundler sb = new StringBundler();
857    
858                    if ((cdata == null) || cdata.isEmpty()) {
859                            return StringPool.BLANK;
860                    }
861    
862                    int cdataBeginIndex = 0;
863    
864                    while (!cdata.isEmpty()) {
865                            int preTagIndex = cdata.indexOf("<pre>");
866                            int tableTagIndex = cdata.indexOf("<table>");
867    
868                            boolean hasPreTag = (preTagIndex != -1) ? true : false;
869                            boolean hasTableTag = (tableTagIndex != -1) ? true : false;
870    
871                            if (!hasPreTag && !hasTableTag) {
872                                    sb.append(_formatCDATA(cdata));
873    
874                                    break;
875                            }
876    
877                            boolean startsWithPreTag = (preTagIndex == 0) ? true : false;
878                            boolean startsWithTableTag = (tableTagIndex == 0) ? true : false;
879    
880                            if (startsWithPreTag || startsWithTableTag) {
881                                    sb.append("\n");
882    
883                                    String tagName = null;
884    
885                                    if (preTagIndex == 0) {
886                                            tagName = "pre";
887                                    }
888                                    else {
889                                            tagName = "table";
890                                    }
891    
892                                    String startTag = "<" + tagName + ">";
893                                    String endTag = "</" + tagName + ">";
894    
895                                    int startTagLength = startTag.length();
896                                    int endTagLength = endTag.length();
897    
898                                    int endTagIndex = cdata.indexOf(endTag, startTagLength - 1);
899    
900                                    sb.append(cdata.substring(0, endTagIndex + endTagLength));
901    
902                                    sb.append("\n");
903    
904                                    cdataBeginIndex = endTagIndex + endTagLength;
905                            }
906                            else {
907    
908                                    // Format the cdata up to the next pre or table tag
909    
910                                    int startTagIndex = 0;
911    
912                                    if (hasPreTag && hasTableTag) {
913                                            if (preTagIndex < tableTagIndex) {
914                                                    startTagIndex = preTagIndex;
915                                            }
916                                            else {
917                                                    startTagIndex = tableTagIndex;
918                                            }
919                                    }
920                                    else if (hasPreTag && !hasTableTag) {
921                                            startTagIndex = preTagIndex;
922                                    }
923                                    else {
924    
925                                            // Must have table tag and no pre tag
926    
927                                            startTagIndex = tableTagIndex;
928                                    }
929    
930                                    sb.append(_formatCDATA(cdata.substring(0, startTagIndex)));
931    
932                                    cdataBeginIndex = startTagIndex;
933                            }
934    
935                            cdata = cdata.substring(cdataBeginIndex);
936                    }
937    
938                    cdata = sb.toString();
939    
940                    return cdata.trim();
941            }
942    
943            private String _getClassName(String fileName) {
944                    int pos = fileName.indexOf("src/");
945    
946                    if (pos == -1) {
947                            pos = fileName.indexOf("test/integration/");
948    
949                            if (pos != -1) {
950                                    pos = fileName.indexOf("integration/", pos);
951                            }
952                    }
953    
954                    if (pos == -1) {
955                            pos = fileName.indexOf("test/unit/");
956    
957                            if (pos != -1) {
958                                    pos = fileName.indexOf("unit/", pos);
959                            }
960                    }
961    
962                    if (pos == -1) {
963                            pos = fileName.indexOf("test/");
964                    }
965    
966                    if (pos == -1) {
967                            pos = fileName.indexOf("service/");
968                    }
969    
970                    if (pos == -1) {
971                            throw new RuntimeException(fileName);
972                    }
973    
974                    pos = fileName.indexOf("/", pos);
975    
976                    String srcFile = fileName.substring(pos + 1, fileName.length());
977    
978                    return StringUtil.replace(
979                            srcFile.substring(0, srcFile.length() - 5), "/", ".");
980            }
981    
982            private String _getFieldKey(Element fieldElement) {
983                    return fieldElement.elementText("name");
984            }
985    
986            private String _getFieldKey(JavaField javaField) {
987                    return javaField.getName();
988            }
989    
990            private String _getIndent(
991                    String[] lines, AbstractBaseJavaEntity abstractBaseJavaEntity) {
992    
993                    String line = lines[abstractBaseJavaEntity.getLineNumber() - 1];
994    
995                    String indent = StringPool.BLANK;
996    
997                    for (char c : line.toCharArray()) {
998                            if (Character.isWhitespace(c)) {
999                                    indent += c;
1000                            }
1001                            else {
1002                                    break;
1003                            }
1004                    }
1005    
1006                    return indent;
1007            }
1008    
1009            private int _getIndentLength(String indent) {
1010                    int indentLength = 0;
1011    
1012                    for (char c : indent.toCharArray()) {
1013                            if (c == '\t') {
1014                                    indentLength = indentLength + 4;
1015                            }
1016                            else {
1017                                    indentLength++;
1018                            }
1019                    }
1020    
1021                    return indentLength;
1022            }
1023    
1024            private JavaClass _getJavaClass(String fileName, Reader reader)
1025                    throws Exception {
1026    
1027                    String className = _getClassName(fileName);
1028    
1029                    JavaDocBuilder javadocBuilder = new JavaDocBuilder();
1030    
1031                    if (reader == null) {
1032                            File file = new File(fileName);
1033    
1034                            if (!file.exists()) {
1035                                    return null;
1036                            }
1037    
1038                            javadocBuilder.addSource(file);
1039                    }
1040                    else {
1041                            javadocBuilder.addSource(reader);
1042                    }
1043    
1044                    return javadocBuilder.getClassByName(className);
1045            }
1046    
1047            private String _getJavaClassComment(
1048                    Element rootElement, JavaClass javaClass) {
1049    
1050                    StringBundler sb = new StringBundler();
1051    
1052                    String indent = StringPool.BLANK;
1053    
1054                    sb.append("/**\n");
1055    
1056                    String comment = rootElement.elementText("comment");
1057    
1058                    if (Validator.isNotNull(comment)) {
1059                            sb.append(_wrapText(comment, indent + " * "));
1060                    }
1061    
1062                    String docletTags = _addDocletTags(
1063                            rootElement,
1064                            new String[] {
1065                                    "author", "version", "see", "since", "serial", "deprecated"
1066                            },
1067                            indent + " * ", _hasPublicModifier(javaClass));
1068    
1069                    if (Validator.isNotNull(docletTags)) {
1070                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1071                                    sb.append(" *\n");
1072                            }
1073    
1074                            sb.append(docletTags);
1075                    }
1076    
1077                    sb.append(" */\n");
1078    
1079                    return sb.toString();
1080            }
1081    
1082            private int _getJavaClassLineNumber(JavaClass javaClass) {
1083                    int lineNumber = javaClass.getLineNumber();
1084    
1085                    Annotation[] annotations = javaClass.getAnnotations();
1086    
1087                    if (annotations.length == 0) {
1088                            return lineNumber;
1089                    }
1090    
1091                    for (Annotation annotation : annotations) {
1092                            int annotationLineNumber = annotation.getLineNumber();
1093    
1094                            Map<String, String> propertyMap = annotation.getPropertyMap();
1095    
1096                            if (propertyMap.isEmpty()) {
1097                                    annotationLineNumber--;
1098                            }
1099    
1100                            if (annotationLineNumber < lineNumber) {
1101                                    lineNumber = annotationLineNumber;
1102                            }
1103                    }
1104    
1105                    return lineNumber;
1106            }
1107    
1108            private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
1109                    Element rootElement = _saxReaderUtil.createElement("javadoc");
1110    
1111                    Document document = _saxReaderUtil.createDocument(rootElement);
1112    
1113                    DocUtil.add(rootElement, "name", javaClass.getName());
1114                    DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
1115    
1116                    _addClassCommentElement(rootElement, javaClass);
1117                    _addDocletElements(rootElement, javaClass, "author");
1118                    _addDocletElements(rootElement, javaClass, "version");
1119                    _addDocletElements(rootElement, javaClass, "see");
1120                    _addDocletElements(rootElement, javaClass, "since");
1121                    _addDocletElements(rootElement, javaClass, "serial");
1122                    _addDocletElements(rootElement, javaClass, "deprecated");
1123    
1124                    JavaMethod[] javaMethods = javaClass.getMethods();
1125    
1126                    for (JavaMethod javaMethod : javaMethods) {
1127                            _addMethodElement(rootElement, javaMethod);
1128                    }
1129    
1130                    JavaField[] javaFields = javaClass.getFields();
1131    
1132                    for (JavaField javaField : javaFields) {
1133                            _addFieldElement(rootElement, javaField);
1134                    }
1135    
1136                    return document;
1137            }
1138    
1139            private Tuple _getJavadocsXmlTuple(String fileName) throws Exception {
1140                    File file = new File(_inputDir + fileName);
1141    
1142                    String absolutePath = file.getAbsolutePath();
1143    
1144                    absolutePath = StringUtil.replace(absolutePath, "\\", "/");
1145                    absolutePath = StringUtil.replace(absolutePath, "/./", "/");
1146    
1147                    int pos = absolutePath.indexOf("/portal-impl/src/");
1148    
1149                    String srcDirName = null;
1150    
1151                    if (pos != -1) {
1152                            srcDirName = absolutePath.substring(0, pos + 17);
1153                    }
1154    
1155                    if (srcDirName == null) {
1156                            pos = absolutePath.indexOf("/portal-kernel/src/");
1157    
1158                            if (pos == -1) {
1159                                    pos = absolutePath.indexOf("/portal-service/src/");
1160                            }
1161    
1162                            if (pos == -1) {
1163                                    pos = absolutePath.indexOf("/util-bridges/src/");
1164                            }
1165    
1166                            if (pos == -1) {
1167                                    pos = absolutePath.indexOf("/util-java/src/");
1168                            }
1169    
1170                            if (pos == -1) {
1171                                    pos = absolutePath.indexOf("/util-taglib/src/");
1172                            }
1173    
1174                            if (pos != -1) {
1175                                    srcDirName =
1176                                            absolutePath.substring(0, pos) + "/portal-impl/src/";
1177                            }
1178                    }
1179    
1180                    if (srcDirName == null) {
1181                            pos = absolutePath.indexOf("/WEB-INF/src/");
1182    
1183                            if (pos != -1) {
1184                                    srcDirName = absolutePath.substring(0, pos + 13);
1185                            }
1186                    }
1187    
1188                    if (srcDirName == null) {
1189                            return null;
1190                    }
1191    
1192                    Tuple tuple = _javadocxXmlTuples.get(srcDirName);
1193    
1194                    if (tuple != null) {
1195                            return tuple;
1196                    }
1197    
1198                    File javadocsXmlFile = new File(
1199                            srcDirName, "META-INF/" + _outputFilePrefix + "-all.xml");
1200    
1201                    if (!javadocsXmlFile.exists()) {
1202                            _fileUtil.write(
1203                                    javadocsXmlFile,
1204                                    "<?xml version=\"1.0\"?>\n\n<javadocs>\n</javadocs>");
1205                    }
1206    
1207                    String javadocsXmlContent = _fileUtil.read(javadocsXmlFile);
1208    
1209                    Document javadocsXmlDocument = _saxReaderUtil.read(javadocsXmlContent);
1210    
1211                    tuple = new Tuple(
1212                            srcDirName, javadocsXmlFile, javadocsXmlContent,
1213                            javadocsXmlDocument);
1214    
1215                    _javadocxXmlTuples.put(srcDirName, tuple);
1216    
1217                    return tuple;
1218            }
1219    
1220            private String _getJavaFieldComment(
1221                    Map<String, Element> fieldElementsMap, JavaField javaField,
1222                    String indent) {
1223    
1224                    String fieldKey = _getFieldKey(javaField);
1225    
1226                    Element fieldElement = fieldElementsMap.get(fieldKey);
1227    
1228                    if (fieldElement == null) {
1229                            return null;
1230                    }
1231    
1232                    StringBundler sb = new StringBundler();
1233    
1234                    sb.append(indent);
1235                    sb.append("/**\n");
1236    
1237                    String comment = fieldElement.elementText("comment");
1238    
1239                    if (Validator.isNotNull(comment)) {
1240                            sb.append(_wrapText(comment, indent + " * "));
1241                    }
1242    
1243                    String docletTags = _addDocletTags(
1244                            fieldElement,
1245                            new String[] {"version", "see", "since", "deprecated"},
1246                            indent + " * ", _hasPublicModifier(javaField));
1247    
1248                    if (Validator.isNotNull(docletTags)) {
1249                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1250                                    sb.append(indent);
1251                                    sb.append(" *\n");
1252                            }
1253    
1254                            sb.append(docletTags);
1255                    }
1256    
1257                    sb.append(indent);
1258                    sb.append(" */\n");
1259    
1260                    if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1261                            Validator.isNull(docletTags)) {
1262    
1263                            return null;
1264                    }
1265    
1266                    if (!_hasPublicModifier(javaField) && Validator.isNull(comment) &&
1267                            Validator.isNull(docletTags)) {
1268    
1269                            return null;
1270                    }
1271    
1272                    return sb.toString();
1273            }
1274    
1275            private String _getJavaMethodComment(
1276                    Map<String, Element> methodElementsMap, JavaMethod javaMethod,
1277                    String indent) {
1278    
1279                    String methodKey = _getMethodKey(javaMethod);
1280    
1281                    Element methodElement = methodElementsMap.get(methodKey);
1282    
1283                    if (methodElement == null) {
1284                            return null;
1285                    }
1286    
1287                    StringBundler sb = new StringBundler();
1288    
1289                    sb.append(indent);
1290                    sb.append("/**\n");
1291    
1292                    String comment = methodElement.elementText("comment");
1293    
1294                    if (Validator.isNotNull(comment)) {
1295                            sb.append(_wrapText(comment, indent + " * "));
1296                    }
1297    
1298                    String docletTags = _addDocletTags(
1299                            methodElement,
1300                            new String[] {
1301                                    "version", "param", "return", "throws", "see", "since",
1302                                    "deprecated"
1303                            },
1304                            indent + " * ", _hasPublicModifier(javaMethod));
1305    
1306                    if (Validator.isNotNull(docletTags)) {
1307                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1308                                    sb.append(indent);
1309                                    sb.append(" *\n");
1310                            }
1311    
1312                            sb.append(docletTags);
1313                    }
1314    
1315                    sb.append(indent);
1316                    sb.append(" */\n");
1317    
1318                    if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1319                            Validator.isNull(docletTags)) {
1320    
1321                            return null;
1322                    }
1323    
1324                    if (!_hasPublicModifier(javaMethod) && Validator.isNull(comment) &&
1325                            Validator.isNull(docletTags)) {
1326    
1327                            return null;
1328                    }
1329    
1330                    return sb.toString();
1331            }
1332    
1333            private String _getMethodKey(Element methodElement) {
1334                    StringBundler sb = new StringBundler();
1335    
1336                    sb.append(methodElement.elementText("name"));
1337                    sb.append(StringPool.OPEN_PARENTHESIS);
1338    
1339                    List<Element> paramElements = methodElement.elements("param");
1340    
1341                    for (Element paramElement : paramElements) {
1342                            sb.append(paramElement.elementText("name"));
1343                            sb.append("|");
1344                            sb.append(paramElement.elementText("type"));
1345                            sb.append(",");
1346                    }
1347    
1348                    sb.append(StringPool.CLOSE_PARENTHESIS);
1349    
1350                    return sb.toString();
1351            }
1352    
1353            private String _getMethodKey(JavaMethod javaMethod) {
1354                    StringBundler sb = new StringBundler();
1355    
1356                    sb.append(javaMethod.getName());
1357                    sb.append(StringPool.OPEN_PARENTHESIS);
1358    
1359                    JavaParameter[] javaParameters = javaMethod.getParameters();
1360    
1361                    for (JavaParameter javaParameter : javaParameters) {
1362                            sb.append(javaParameter.getName());
1363                            sb.append("|");
1364                            sb.append(_getTypeValue(javaParameter));
1365                            sb.append(",");
1366                    }
1367    
1368                    sb.append(StringPool.CLOSE_PARENTHESIS);
1369    
1370                    return sb.toString();
1371            }
1372    
1373            private String _getSpacesIndent(int length) {
1374                    String indent = StringPool.BLANK;
1375    
1376                    for (int i = 0; i < length; i++) {
1377                            indent += StringPool.SPACE;
1378                    }
1379    
1380                    return indent;
1381            }
1382    
1383            private String _getTypeValue(JavaParameter javaParameter) {
1384                    Type type = javaParameter.getType();
1385    
1386                    String typeValue = type.getValue();
1387    
1388                    if (type.isArray()) {
1389                            typeValue += "[]";
1390                    }
1391    
1392                    return typeValue;
1393            }
1394    
1395            private boolean _hasGeneratedTag(String content) {
1396                    if (content.contains("* @generated") || content.contains("$ANTLR")) {
1397                            return true;
1398                    }
1399                    else {
1400                            return false;
1401                    }
1402            }
1403    
1404            private boolean _hasPublicModifier(AbstractJavaEntity abstractJavaEntity) {
1405                    String[] modifiers = abstractJavaEntity.getModifiers();
1406    
1407                    if (modifiers == null) {
1408                            return false;
1409                    }
1410    
1411                    for (String modifier : modifiers) {
1412                            if (modifier.equals("public")) {
1413                                    return true;
1414                            }
1415                    }
1416    
1417                    return false;
1418            }
1419    
1420            private boolean _isOverrideMethod(
1421                    JavaClass javaClass, JavaMethod javaMethod,
1422                    Collection<Tuple> ancestorJavaClassTuples) {
1423    
1424                    if (javaMethod.isConstructor() || javaMethod.isPrivate() ||
1425                            javaMethod.isStatic() ||
1426                            _overridesHigherJavaAPIVersion(javaMethod)) {
1427    
1428                            return false;
1429                    }
1430    
1431                    String methodName = javaMethod.getName();
1432    
1433                    JavaParameter[] javaParameters = javaMethod.getParameters();
1434    
1435                    Type[] types = new Type[javaParameters.length];
1436    
1437                    for (int i = 0; i < javaParameters.length; i++) {
1438                            types[i] = javaParameters[i].getType();
1439                    }
1440    
1441                    // Check for matching method in each ancestor
1442    
1443                    for (Tuple ancestorJavaClassTuple : ancestorJavaClassTuples) {
1444                            JavaClass ancestorJavaClass =
1445                                    (JavaClass)ancestorJavaClassTuple.getObject(0);
1446    
1447                            JavaMethod ancestorJavaMethod = null;
1448    
1449                            if (ancestorJavaClassTuple.getSize() > 1) {
1450    
1451                                    // LPS-35613
1452    
1453                                    Type[] ancestorActualTypeArguments =
1454                                            (Type[])ancestorJavaClassTuple.getObject(1);
1455    
1456                                    Type[] genericTypes = new Type[types.length];
1457    
1458                                    for (int i = 0; i < types.length; i++) {
1459                                            Type type = types[i];
1460    
1461                                            String typeValue = type.getValue();
1462    
1463                                            boolean useGenericType = false;
1464    
1465                                            for (int j = 0; j < ancestorActualTypeArguments.length;
1466                                                            j++) {
1467    
1468                                                    if (typeValue.equals(
1469                                                                    ancestorActualTypeArguments[j].getValue())) {
1470    
1471                                                            useGenericType = true;
1472    
1473                                                            break;
1474                                                    }
1475                                            }
1476    
1477                                            if (useGenericType) {
1478                                                    genericTypes[i] = new Type("java.lang.Object");
1479                                            }
1480                                            else {
1481                                                    genericTypes[i] = type;
1482                                            }
1483                                    }
1484    
1485                                    ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1486                                            methodName, genericTypes);
1487                            }
1488                            else {
1489                                    ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1490                                            methodName, types);
1491                            }
1492    
1493                            if (ancestorJavaMethod == null) {
1494                                    continue;
1495                            }
1496    
1497                            boolean samePackage = false;
1498    
1499                            JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage();
1500    
1501                            if (ancestorJavaPackage != null) {
1502                                    samePackage = ancestorJavaPackage.equals(
1503                                            javaClass.getPackage());
1504                            }
1505    
1506                            // Check if the method is in scope
1507    
1508                            if (samePackage) {
1509                                    return !ancestorJavaMethod.isPrivate();
1510                            }
1511    
1512                            if (ancestorJavaMethod.isProtected() ||
1513                                    ancestorJavaMethod.isPublic()) {
1514    
1515                                    return true;
1516                            }
1517                            else {
1518                                    return false;
1519                            }
1520                    }
1521    
1522                    return false;
1523            }
1524    
1525            private boolean _overridesHigherJavaAPIVersion(JavaMethod javaMethod) {
1526                    Annotation[] annotations = javaMethod.getAnnotations();
1527    
1528                    if (annotations == null) {
1529                            return false;
1530                    }
1531    
1532                    for (Annotation annotation : annotations) {
1533                            Type type = annotation.getType();
1534    
1535                            JavaClass javaClass = type.getJavaClass();
1536    
1537                            String javaClassName = javaClass.getFullyQualifiedName();
1538    
1539                            if (javaClassName.equals(SinceJava.class.getName())) {
1540                                    AnnotationValue annotationValue = annotation.getProperty(
1541                                            "value");
1542    
1543                                    double sinceJava = GetterUtil.getDouble(
1544                                            annotationValue.getParameterValue());
1545    
1546                                    if (sinceJava > _LOWEST_SUPPORTED_JAVA_VERSION) {
1547                                            return true;
1548                                    }
1549                            }
1550                    }
1551    
1552                    return false;
1553            }
1554    
1555            private String _removeJavadocFromJava(JavaClass javaClass, String content) {
1556                    Set<Integer> lineNumbers = new HashSet<Integer>();
1557    
1558                    lineNumbers.add(_getJavaClassLineNumber(javaClass));
1559    
1560                    JavaMethod[] javaMethods = javaClass.getMethods();
1561    
1562                    for (JavaMethod javaMethod : javaMethods) {
1563                            lineNumbers.add(javaMethod.getLineNumber());
1564                    }
1565    
1566                    JavaField[] javaFields = javaClass.getFields();
1567    
1568                    for (JavaField javaField : javaFields) {
1569                            lineNumbers.add(javaField.getLineNumber());
1570                    }
1571    
1572                    String[] lines = StringUtil.splitLines(content);
1573    
1574                    for (int lineNumber : lineNumbers) {
1575                            if (lineNumber == 0) {
1576                                    continue;
1577                            }
1578    
1579                            int pos = lineNumber - 2;
1580    
1581                            String line = lines[pos];
1582    
1583                            if (line == null) {
1584                                    continue;
1585                            }
1586    
1587                            int blankLines = 0;
1588    
1589                            while (line.equals(StringPool.BLANK)) {
1590                                    line = lines[--pos];
1591    
1592                                    blankLines++;
1593                            }
1594    
1595                            line = line.trim();
1596    
1597                            if (line.endsWith("*/")) {
1598                                    while (true) {
1599                                            lines[pos] = null;
1600    
1601                                            if (line.startsWith("/**") || line.startsWith("/*")) {
1602                                                    break;
1603                                            }
1604    
1605                                            line = lines[--pos].trim();
1606                                    }
1607    
1608                                    for (int i = 0; i < blankLines; i++) {
1609                                            lines[lineNumber - i - 2] = null;
1610                                    }
1611                            }
1612                    }
1613    
1614                    StringBundler sb = new StringBundler(content.length());
1615    
1616                    for (String line : lines) {
1617                            if (line != null) {
1618                                    sb.append(line);
1619                                    sb.append("\n");
1620                            }
1621                    }
1622    
1623                    content = sb.toString();
1624    
1625                    return content.trim();
1626            }
1627    
1628            private String _trimMultilineText(String text) {
1629                    String[] lines = StringUtil.splitLines(text);
1630    
1631                    StringBundler sb = new StringBundler();
1632    
1633                    for (int i = 0; i < lines.length; i++) {
1634                            String line = lines[i].trim();
1635    
1636                            sb.append(line);
1637    
1638                            if (!line.endsWith(StringPool.OPEN_PARENTHESIS) &&
1639                                    (i < (lines.length - 1))) {
1640    
1641                                    sb.append(StringPool.SPACE);
1642                            }
1643                    }
1644    
1645                    return sb.toString();
1646            }
1647    
1648            private void _updateJavadocsXmlFile(
1649                            String fileName, JavaClass javaClass, Document javaClassDocument)
1650                    throws Exception {
1651    
1652                    String javaClassFullyQualifiedName = javaClass.getFullyQualifiedName();
1653    
1654                    /*if (!javaClassFullyQualifiedName.contains(".service.") ||
1655                            !javaClassFullyQualifiedName.endsWith("ServiceImpl")) {
1656    
1657                            return;
1658                    }*/
1659    
1660                    Tuple javadocsXmlTuple = _getJavadocsXmlTuple(fileName);
1661    
1662                    if (javadocsXmlTuple == null) {
1663                            return;
1664                    }
1665    
1666                    Document javadocsXmlDocument = (Document)javadocsXmlTuple.getObject(3);
1667    
1668                    Element javadocsXmlRootElement = javadocsXmlDocument.getRootElement();
1669    
1670                    List<Element> javadocElements = javadocsXmlRootElement.elements(
1671                            "javadoc");
1672    
1673                    for (Element javadocElement : javadocElements) {
1674                            String type = javadocElement.elementText("type");
1675    
1676                            if (type.equals(javaClassFullyQualifiedName)) {
1677                                    Element javaClassRootElement =
1678                                            javaClassDocument.getRootElement();
1679    
1680                                    if (Validator.equals(
1681                                                    javadocElement.formattedString(),
1682                                                    javaClassRootElement.formattedString())) {
1683    
1684                                            return;
1685                                    }
1686    
1687                                    javadocElement.detach();
1688    
1689                                    break;
1690                            }
1691                    }
1692    
1693                    javadocsXmlRootElement.add(javaClassDocument.getRootElement());
1694            }
1695    
1696            private void _updateJavaFromDocument(
1697                            String fileName, String originalContent, String javadocLessContent,
1698                            Document document)
1699                    throws Exception {
1700    
1701                    String[] lines = StringUtil.splitLines(javadocLessContent);
1702    
1703                    JavaClass javaClass = _getJavaClass(
1704                            fileName, new UnsyncStringReader(javadocLessContent));
1705    
1706                    _updateLanguageProperties(document, javaClass.getName());
1707    
1708                    List<Tuple> ancestorJavaClassTuples = new ArrayList<Tuple>();
1709    
1710                    ancestorJavaClassTuples = _addAncestorJavaClassTuples(
1711                            javaClass, ancestorJavaClassTuples);
1712    
1713                    Element rootElement = document.getRootElement();
1714    
1715                    Map<Integer, String> commentsMap = new TreeMap<Integer, String>();
1716    
1717                    String javaClassComment = _getJavaClassComment(rootElement, javaClass);
1718    
1719                    javaClassComment = _addDeprecatedTag(
1720                            javaClassComment, javaClass, StringPool.BLANK);
1721    
1722                    commentsMap.put(_getJavaClassLineNumber(javaClass), javaClassComment);
1723    
1724                    Map<String, Element> methodElementsMap = new HashMap<String, Element>();
1725    
1726                    List<Element> methodElements = rootElement.elements("method");
1727    
1728                    for (Element methodElement : methodElements) {
1729                            String methodKey = _getMethodKey(methodElement);
1730    
1731                            methodElementsMap.put(methodKey, methodElement);
1732                    }
1733    
1734                    JavaMethod[] javaMethods = javaClass.getMethods();
1735    
1736                    for (JavaMethod javaMethod : javaMethods) {
1737                            if (commentsMap.containsKey(javaMethod.getLineNumber())) {
1738                                    continue;
1739                            }
1740    
1741                            String indent = _getIndent(lines, javaMethod);
1742    
1743                            String javaMethodComment = _getJavaMethodComment(
1744                                    methodElementsMap, javaMethod, indent);
1745    
1746                            javaMethodComment = _addDeprecatedTag(
1747                                    javaMethodComment, javaMethod, indent);
1748    
1749                            // Handle override tag insertion
1750    
1751                            if (!ServiceBuilder.hasAnnotation(javaMethod, "Override")) {
1752                                    if (_isOverrideMethod(
1753                                                    javaClass, javaMethod, ancestorJavaClassTuples)) {
1754    
1755                                            String overrideLine = indent + "@Override\n";
1756    
1757                                            if (Validator.isNotNull(javaMethodComment)) {
1758                                                    javaMethodComment = javaMethodComment + overrideLine;
1759                                            }
1760                                            else {
1761                                                    javaMethodComment = overrideLine;
1762                                            }
1763                                    }
1764                            }
1765    
1766                            commentsMap.put(javaMethod.getLineNumber(), javaMethodComment);
1767                    }
1768    
1769                    Map<String, Element> fieldElementsMap = new HashMap<String, Element>();
1770    
1771                    List<Element> fieldElements = rootElement.elements("field");
1772    
1773                    for (Element fieldElement : fieldElements) {
1774                            String fieldKey = _getFieldKey(fieldElement);
1775    
1776                            fieldElementsMap.put(fieldKey, fieldElement);
1777                    }
1778    
1779                    JavaField[] javaFields = javaClass.getFields();
1780    
1781                    for (JavaField javaField : javaFields) {
1782                            if (commentsMap.containsKey(javaField.getLineNumber())) {
1783                                    continue;
1784                            }
1785    
1786                            String indent = _getIndent(lines, javaField);
1787    
1788                            String javaFieldComment = _getJavaFieldComment(
1789                                    fieldElementsMap, javaField, indent);
1790    
1791                            javaFieldComment = _addDeprecatedTag(
1792                                    javaFieldComment, javaField, indent);
1793    
1794                            commentsMap.put(javaField.getLineNumber(), javaFieldComment);
1795                    }
1796    
1797                    StringBundler sb = new StringBundler(javadocLessContent.length());
1798    
1799                    for (int lineNumber = 1; lineNumber <= lines.length; lineNumber++) {
1800                            String line = lines[lineNumber - 1];
1801    
1802                            String comments = commentsMap.get(lineNumber);
1803    
1804                            if (comments != null) {
1805                                    sb.append(comments);
1806                            }
1807    
1808                            sb.append(line);
1809                            sb.append("\n");
1810                    }
1811    
1812                    String formattedContent = sb.toString();
1813    
1814                    formattedContent = formattedContent.trim();
1815    
1816                    if (!originalContent.equals(formattedContent)) {
1817                            File file = new File(_inputDir + fileName);
1818    
1819                            _fileUtil.write(file, formattedContent.getBytes(StringPool.UTF8));
1820    
1821                            System.out.println("Writing " + file);
1822                    }
1823            }
1824    
1825            private void _updateLanguageProperties(Document document, String className)
1826                    throws IOException {
1827    
1828                    if (_languageProperties == null) {
1829                            return;
1830                    }
1831    
1832                    int index = className.indexOf("ServiceImpl");
1833    
1834                    if (index <= 0) {
1835                            return;
1836                    }
1837    
1838                    StringBundler sb = new StringBundler();
1839    
1840                    sb.append(Character.toLowerCase(className.charAt(0)));
1841    
1842                    for (int i = 1; i < index; i++) {
1843                            char c = className.charAt(i);
1844    
1845                            if (Character.isUpperCase(c)) {
1846                                    if (((i + 1) < index) &&
1847                                            Character.isLowerCase(className.charAt(i + 1))) {
1848    
1849                                            sb.append(CharPool.DASH);
1850                                    }
1851    
1852                                    sb.append(Character.toLowerCase(c));
1853                            }
1854                            else {
1855                                    sb.append(c);
1856                            }
1857                    }
1858    
1859                    sb.append("-service-help");
1860    
1861                    String key = sb.toString();
1862    
1863                    String value = _languageProperties.getProperty(key);
1864    
1865                    if (value == null) {
1866                            return;
1867                    }
1868    
1869                    Element rootElement = document.getRootElement();
1870    
1871                    String comment = rootElement.elementText("comment");
1872    
1873                    if ((comment == null) || value.equals(comment)) {
1874                            return;
1875                    }
1876    
1877                    index = comment.indexOf("\n\n");
1878    
1879                    if (index != -1) {
1880                            value = comment.substring(0, index);
1881                    }
1882                    else {
1883                            value = comment;
1884                    }
1885    
1886                    _updateLanguageProperties(key, value);
1887            }
1888    
1889            private void _updateLanguageProperties(String key, String value)
1890                    throws IOException {
1891    
1892                    StringBundler sb = new StringBundler();
1893    
1894                    try (UnsyncBufferedReader unsyncBufferedReader = 
1895                                    new UnsyncBufferedReader(
1896                                            new FileReader(_languagePropertiesFile))) {
1897    
1898                            boolean begin = false;
1899                            boolean firstLine = true;
1900                            String linePrefix = key + "=";
1901    
1902                            String line = null;
1903    
1904                            while ((line = unsyncBufferedReader.readLine()) != null) {
1905                                    if (line.equals(StringPool.BLANK)) {
1906                                            begin = !begin;
1907                                    }
1908    
1909                                    if (firstLine) {
1910                                            firstLine = false;
1911                                    }
1912                                    else {
1913                                            sb.append(StringPool.NEW_LINE);
1914                                    }
1915    
1916                                    if (line.startsWith(linePrefix)) {
1917                                            sb.append(linePrefix);
1918                                            sb.append(value);
1919                                    }
1920                                    else {
1921                                            sb.append(line);
1922                                    }
1923                            }
1924                    }
1925    
1926                    try (Writer writer = new OutputStreamWriter(
1927                                    new FileOutputStream(_languagePropertiesFile, false),
1928                                    StringPool.UTF8)) {
1929    
1930                            sb.writeTo(writer);
1931                    }
1932    
1933                    System.out.println(
1934                            "Updating " + _languagePropertiesFile + " key " + key);
1935            }
1936    
1937            private String _wrapText(String text, int indentLength, String exclude) {
1938                    StringBuffer sb = new StringBuffer();
1939    
1940                    StringBundler regexSB = new StringBundler("(?<=^|</");
1941    
1942                    regexSB.append(exclude);
1943                    regexSB.append(">).+?(?=$|<");
1944                    regexSB.append(exclude);
1945                    regexSB.append(">)");
1946    
1947                    Pattern pattern = Pattern.compile(regexSB.toString(), Pattern.DOTALL);
1948    
1949                    Matcher matcher = pattern.matcher(text);
1950    
1951                    while (matcher.find()) {
1952                            String wrapped = _formatInlines(matcher.group());
1953    
1954                            wrapped = StringUtil.wrap(wrapped, 80 - indentLength, "\n");
1955    
1956                            matcher.appendReplacement(sb, wrapped);
1957                    }
1958    
1959                    matcher.appendTail(sb);
1960    
1961                    return sb.toString();
1962            }
1963    
1964            private String _wrapText(String text, String indent) {
1965                    int indentLength = _getIndentLength(indent);
1966    
1967                    if (text.contains("<pre>")) {
1968                            text = _wrapText(text, indentLength, "pre");
1969                    }
1970                    else if (text.contains("<table>")) {
1971                            text = _wrapText(text, indentLength, "table");
1972                    }
1973                    else {
1974                            text = _formatInlines(text);
1975                            text = StringUtil.wrap(text, 80 - indentLength, "\n");
1976                    }
1977    
1978                    text = text.replaceAll("(?m)^", indent);
1979                    text = text.replaceAll("(?m) +$", StringPool.BLANK);
1980    
1981                    return text;
1982            }
1983    
1984            private static final double _LOWEST_SUPPORTED_JAVA_VERSION = 1.7;
1985    
1986            private static FileImpl _fileUtil = FileImpl.getInstance();
1987            private static SAXReaderImpl _saxReaderUtil = SAXReaderImpl.getInstance();
1988    
1989            private boolean _initializeMissingJavadocs;
1990            private String _inputDir;
1991            private Map<String, Tuple> _javadocxXmlTuples =
1992                    new HashMap<String, Tuple>();
1993            private Properties _languageProperties;
1994            private File _languagePropertiesFile;
1995            private String _outputFilePrefix;
1996            private Pattern _paragraphTagPattern = Pattern.compile(
1997                    "(^.*?(?=\n\n|$)+|(?<=<p>\n).*?(?=\n</p>))", Pattern.DOTALL);
1998            private boolean _updateJavadocs;
1999    
2000    }