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.endsWith("JavadocFormatter.java") ||
781                            fileName.endsWith("SourceFormatter.java") ||
782                            _hasGeneratedTag(originalContent)) {
783    
784                            return;
785                    }
786    
787                    JavaClass javaClass = _getJavaClass(
788                            fileName, new UnsyncStringReader(originalContent));
789    
790                    String javadocLessContent = _removeJavadocFromJava(
791                            javaClass, originalContent);
792    
793                    Document document = _getJavadocDocument(javaClass);
794    
795                    _updateJavadocsXmlFile(fileName, javaClass, document);
796    
797                    _updateJavaFromDocument(
798                            fileName, originalContent, javadocLessContent, document);
799            }
800    
801            private String _formatCDATA(String cdata) {
802                    cdata = cdata.replaceAll(
803                            "(?s)\\s*<(p|[ou]l)>\\s*(.*?)\\s*</\\1>\\s*",
804                            "\n\n<$1>\n$2\n</$1>\n\n");
805                    cdata = cdata.replaceAll(
806                            "(?s)\\s*<li>\\s*(.*?)\\s*</li>\\s*", "\n<li>\n$1\n</li>\n");
807                    cdata = StringUtil.replace(cdata, "</li>\n\n<li>", "</li>\n<li>");
808                    cdata = cdata.replaceAll("\n\\s+\n", "\n\n");
809                    cdata = cdata.replaceAll(" +", " ");
810    
811                    // Trim whitespace inside paragraph tags or in the first paragraph
812    
813                    Matcher matcher = _paragraphTagPattern.matcher(cdata);
814    
815                    StringBuffer sb = new StringBuffer();
816    
817                    while (matcher.find()) {
818                            String trimmed = _trimMultilineText(matcher.group());
819    
820                            // Escape dollar signs
821    
822                            trimmed = StringUtil.replace(trimmed, "$", "\\$");
823    
824                            matcher.appendReplacement(sb, trimmed);
825                    }
826    
827                    matcher.appendTail(sb);
828    
829                    cdata = sb.toString();
830    
831                    return cdata.trim();
832            }
833    
834            private String _formatInlines(String text) {
835    
836                    // Capitalize ID
837    
838                    text = text.replaceAll("[?@param id](?i)\\bid(s)?\\b", " ID$1");
839    
840                    // Wrap special constants in code tags
841    
842                    text = text.replaceAll(
843                            "(?i)(?<!<code>|\\w)(null|false|true)(?!\\w)", "<code>$1</code>");
844    
845                    return text;
846            }
847    
848            private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
849                    return _getCDATA(abstractJavaEntity.getComment());
850            }
851    
852            private String _getCDATA(String cdata) {
853                    StringBundler sb = new StringBundler();
854    
855                    if ((cdata == null) || cdata.isEmpty()) {
856                            return StringPool.BLANK;
857                    }
858    
859                    int cdataBeginIndex = 0;
860    
861                    while (!cdata.isEmpty()) {
862                            int preTagIndex = cdata.indexOf("<pre>");
863                            int tableTagIndex = cdata.indexOf("<table>");
864    
865                            boolean hasPreTag = (preTagIndex != -1) ? true : false;
866                            boolean hasTableTag = (tableTagIndex != -1) ? true : false;
867    
868                            if (!hasPreTag && !hasTableTag) {
869                                    sb.append(_formatCDATA(cdata));
870    
871                                    break;
872                            }
873    
874                            boolean startsWithPreTag = (preTagIndex == 0) ? true : false;
875                            boolean startsWithTableTag = (tableTagIndex == 0) ? true : false;
876    
877                            if (startsWithPreTag || startsWithTableTag) {
878                                    sb.append("\n");
879    
880                                    String tagName = null;
881    
882                                    if (preTagIndex == 0) {
883                                            tagName = "pre";
884                                    }
885                                    else {
886                                            tagName = "table";
887                                    }
888    
889                                    String startTag = "<" + tagName + ">";
890                                    String endTag = "</" + tagName + ">";
891    
892                                    int startTagLength = startTag.length();
893                                    int endTagLength = endTag.length();
894    
895                                    int endTagIndex = cdata.indexOf(endTag, startTagLength - 1);
896    
897                                    sb.append(cdata.substring(0, endTagIndex + endTagLength));
898    
899                                    sb.append("\n");
900    
901                                    cdataBeginIndex = endTagIndex + endTagLength;
902                            }
903                            else {
904    
905                                    // Format the cdata up to the next pre or table tag
906    
907                                    int startTagIndex = 0;
908    
909                                    if (hasPreTag && hasTableTag) {
910                                            if (preTagIndex < tableTagIndex) {
911                                                    startTagIndex = preTagIndex;
912                                            }
913                                            else {
914                                                    startTagIndex = tableTagIndex;
915                                            }
916                                    }
917                                    else if (hasPreTag && !hasTableTag) {
918                                            startTagIndex = preTagIndex;
919                                    }
920                                    else {
921    
922                                            // Must have table tag and no pre tag
923    
924                                            startTagIndex = tableTagIndex;
925                                    }
926    
927                                    sb.append(_formatCDATA(cdata.substring(0, startTagIndex)));
928    
929                                    cdataBeginIndex = startTagIndex;
930                            }
931    
932                            cdata = cdata.substring(cdataBeginIndex);
933                    }
934    
935                    cdata = sb.toString();
936    
937                    return cdata.trim();
938            }
939    
940            private String _getClassName(String fileName) {
941                    int pos = fileName.indexOf("src/");
942    
943                    if (pos == -1) {
944                            pos = fileName.indexOf("test/integration/");
945    
946                            if (pos != -1) {
947                                    pos = fileName.indexOf("integration/", pos);
948                            }
949                    }
950    
951                    if (pos == -1) {
952                            pos = fileName.indexOf("test/unit/");
953    
954                            if (pos != -1) {
955                                    pos = fileName.indexOf("unit/", pos);
956                            }
957                    }
958    
959                    if (pos == -1) {
960                            pos = fileName.indexOf("test/");
961                    }
962    
963                    if (pos == -1) {
964                            pos = fileName.indexOf("service/");
965                    }
966    
967                    if (pos == -1) {
968                            throw new RuntimeException(fileName);
969                    }
970    
971                    pos = fileName.indexOf("/", pos);
972    
973                    String srcFile = fileName.substring(pos + 1, fileName.length());
974    
975                    return StringUtil.replace(
976                            srcFile.substring(0, srcFile.length() - 5), "/", ".");
977            }
978    
979            private String _getFieldKey(Element fieldElement) {
980                    return fieldElement.elementText("name");
981            }
982    
983            private String _getFieldKey(JavaField javaField) {
984                    return javaField.getName();
985            }
986    
987            private String _getIndent(
988                    String[] lines, AbstractBaseJavaEntity abstractBaseJavaEntity) {
989    
990                    String line = lines[abstractBaseJavaEntity.getLineNumber() - 1];
991    
992                    String indent = StringPool.BLANK;
993    
994                    for (char c : line.toCharArray()) {
995                            if (Character.isWhitespace(c)) {
996                                    indent += c;
997                            }
998                            else {
999                                    break;
1000                            }
1001                    }
1002    
1003                    return indent;
1004            }
1005    
1006            private int _getIndentLength(String indent) {
1007                    int indentLength = 0;
1008    
1009                    for (char c : indent.toCharArray()) {
1010                            if (c == '\t') {
1011                                    indentLength = indentLength + 4;
1012                            }
1013                            else {
1014                                    indentLength++;
1015                            }
1016                    }
1017    
1018                    return indentLength;
1019            }
1020    
1021            private JavaClass _getJavaClass(String fileName, Reader reader)
1022                    throws Exception {
1023    
1024                    String className = _getClassName(fileName);
1025    
1026                    JavaDocBuilder javadocBuilder = new JavaDocBuilder();
1027    
1028                    if (reader == null) {
1029                            File file = new File(fileName);
1030    
1031                            if (!file.exists()) {
1032                                    return null;
1033                            }
1034    
1035                            javadocBuilder.addSource(file);
1036                    }
1037                    else {
1038                            javadocBuilder.addSource(reader);
1039                    }
1040    
1041                    return javadocBuilder.getClassByName(className);
1042            }
1043    
1044            private String _getJavaClassComment(
1045                    Element rootElement, JavaClass javaClass) {
1046    
1047                    StringBundler sb = new StringBundler();
1048    
1049                    String indent = StringPool.BLANK;
1050    
1051                    sb.append("/**\n");
1052    
1053                    String comment = rootElement.elementText("comment");
1054    
1055                    if (Validator.isNotNull(comment)) {
1056                            sb.append(_wrapText(comment, indent + " * "));
1057                    }
1058    
1059                    String docletTags = _addDocletTags(
1060                            rootElement,
1061                            new String[] {
1062                                    "author", "version", "see", "since", "serial", "deprecated"
1063                            },
1064                            indent + " * ", _hasPublicModifier(javaClass));
1065    
1066                    if (Validator.isNotNull(docletTags)) {
1067                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1068                                    sb.append(" *\n");
1069                            }
1070    
1071                            sb.append(docletTags);
1072                    }
1073    
1074                    sb.append(" */\n");
1075    
1076                    return sb.toString();
1077            }
1078    
1079            private int _getJavaClassLineNumber(JavaClass javaClass) {
1080                    int lineNumber = javaClass.getLineNumber();
1081    
1082                    Annotation[] annotations = javaClass.getAnnotations();
1083    
1084                    if (annotations.length == 0) {
1085                            return lineNumber;
1086                    }
1087    
1088                    for (Annotation annotation : annotations) {
1089                            int annotationLineNumber = annotation.getLineNumber();
1090    
1091                            Map<String, String> propertyMap = annotation.getPropertyMap();
1092    
1093                            if (propertyMap.isEmpty()) {
1094                                    annotationLineNumber--;
1095                            }
1096    
1097                            if (annotationLineNumber < lineNumber) {
1098                                    lineNumber = annotationLineNumber;
1099                            }
1100                    }
1101    
1102                    return lineNumber;
1103            }
1104    
1105            private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
1106                    Element rootElement = _saxReaderUtil.createElement("javadoc");
1107    
1108                    Document document = _saxReaderUtil.createDocument(rootElement);
1109    
1110                    DocUtil.add(rootElement, "name", javaClass.getName());
1111                    DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
1112    
1113                    _addClassCommentElement(rootElement, javaClass);
1114                    _addDocletElements(rootElement, javaClass, "author");
1115                    _addDocletElements(rootElement, javaClass, "version");
1116                    _addDocletElements(rootElement, javaClass, "see");
1117                    _addDocletElements(rootElement, javaClass, "since");
1118                    _addDocletElements(rootElement, javaClass, "serial");
1119                    _addDocletElements(rootElement, javaClass, "deprecated");
1120    
1121                    JavaMethod[] javaMethods = javaClass.getMethods();
1122    
1123                    for (JavaMethod javaMethod : javaMethods) {
1124                            _addMethodElement(rootElement, javaMethod);
1125                    }
1126    
1127                    JavaField[] javaFields = javaClass.getFields();
1128    
1129                    for (JavaField javaField : javaFields) {
1130                            _addFieldElement(rootElement, javaField);
1131                    }
1132    
1133                    return document;
1134            }
1135    
1136            private Tuple _getJavadocsXmlTuple(String fileName) throws Exception {
1137                    File file = new File(_inputDir + fileName);
1138    
1139                    String absolutePath = file.getAbsolutePath();
1140    
1141                    absolutePath = StringUtil.replace(absolutePath, "\\", "/");
1142                    absolutePath = StringUtil.replace(absolutePath, "/./", "/");
1143    
1144                    int pos = absolutePath.indexOf("/portal-impl/src/");
1145    
1146                    String srcDirName = null;
1147    
1148                    if (pos != -1) {
1149                            srcDirName = absolutePath.substring(0, pos + 17);
1150                    }
1151    
1152                    if (srcDirName == null) {
1153                            pos = absolutePath.indexOf("/portal-kernel/src/");
1154    
1155                            if (pos == -1) {
1156                                    pos = absolutePath.indexOf("/portal-service/src/");
1157                            }
1158    
1159                            if (pos == -1) {
1160                                    pos = absolutePath.indexOf("/util-bridges/src/");
1161                            }
1162    
1163                            if (pos == -1) {
1164                                    pos = absolutePath.indexOf("/util-java/src/");
1165                            }
1166    
1167                            if (pos == -1) {
1168                                    pos = absolutePath.indexOf("/util-taglib/src/");
1169                            }
1170    
1171                            if (pos != -1) {
1172                                    srcDirName =
1173                                            absolutePath.substring(0, pos) + "/portal-impl/src/";
1174                            }
1175                    }
1176    
1177                    if (srcDirName == null) {
1178                            pos = absolutePath.indexOf("/WEB-INF/src/");
1179    
1180                            if (pos != -1) {
1181                                    srcDirName = absolutePath.substring(0, pos + 13);
1182                            }
1183                    }
1184    
1185                    if (srcDirName == null) {
1186                            return null;
1187                    }
1188    
1189                    Tuple tuple = _javadocxXmlTuples.get(srcDirName);
1190    
1191                    if (tuple != null) {
1192                            return tuple;
1193                    }
1194    
1195                    File javadocsXmlFile = new File(
1196                            srcDirName, "META-INF/" + _outputFilePrefix + "-all.xml");
1197    
1198                    if (!javadocsXmlFile.exists()) {
1199                            _fileUtil.write(
1200                                    javadocsXmlFile,
1201                                    "<?xml version=\"1.0\"?>\n\n<javadocs>\n</javadocs>");
1202                    }
1203    
1204                    String javadocsXmlContent = _fileUtil.read(javadocsXmlFile);
1205    
1206                    Document javadocsXmlDocument = _saxReaderUtil.read(javadocsXmlContent);
1207    
1208                    tuple = new Tuple(
1209                            srcDirName, javadocsXmlFile, javadocsXmlContent,
1210                            javadocsXmlDocument);
1211    
1212                    _javadocxXmlTuples.put(srcDirName, tuple);
1213    
1214                    return tuple;
1215            }
1216    
1217            private String _getJavaFieldComment(
1218                    Map<String, Element> fieldElementsMap, JavaField javaField,
1219                    String indent) {
1220    
1221                    String fieldKey = _getFieldKey(javaField);
1222    
1223                    Element fieldElement = fieldElementsMap.get(fieldKey);
1224    
1225                    if (fieldElement == null) {
1226                            return null;
1227                    }
1228    
1229                    StringBundler sb = new StringBundler();
1230    
1231                    sb.append(indent);
1232                    sb.append("/**\n");
1233    
1234                    String comment = fieldElement.elementText("comment");
1235    
1236                    if (Validator.isNotNull(comment)) {
1237                            sb.append(_wrapText(comment, indent + " * "));
1238                    }
1239    
1240                    String docletTags = _addDocletTags(
1241                            fieldElement,
1242                            new String[] {"version", "see", "since", "deprecated"},
1243                            indent + " * ", _hasPublicModifier(javaField));
1244    
1245                    if (Validator.isNotNull(docletTags)) {
1246                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1247                                    sb.append(indent);
1248                                    sb.append(" *\n");
1249                            }
1250    
1251                            sb.append(docletTags);
1252                    }
1253    
1254                    sb.append(indent);
1255                    sb.append(" */\n");
1256    
1257                    if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1258                            Validator.isNull(docletTags)) {
1259    
1260                            return null;
1261                    }
1262    
1263                    if (!_hasPublicModifier(javaField) && Validator.isNull(comment) &&
1264                            Validator.isNull(docletTags)) {
1265    
1266                            return null;
1267                    }
1268    
1269                    return sb.toString();
1270            }
1271    
1272            private String _getJavaMethodComment(
1273                    Map<String, Element> methodElementsMap, JavaMethod javaMethod,
1274                    String indent) {
1275    
1276                    String methodKey = _getMethodKey(javaMethod);
1277    
1278                    Element methodElement = methodElementsMap.get(methodKey);
1279    
1280                    if (methodElement == null) {
1281                            return null;
1282                    }
1283    
1284                    StringBundler sb = new StringBundler();
1285    
1286                    sb.append(indent);
1287                    sb.append("/**\n");
1288    
1289                    String comment = methodElement.elementText("comment");
1290    
1291                    if (Validator.isNotNull(comment)) {
1292                            sb.append(_wrapText(comment, indent + " * "));
1293                    }
1294    
1295                    String docletTags = _addDocletTags(
1296                            methodElement,
1297                            new String[] {
1298                                    "version", "param", "return", "throws", "see", "since",
1299                                    "deprecated"
1300                            },
1301                            indent + " * ", _hasPublicModifier(javaMethod));
1302    
1303                    if (Validator.isNotNull(docletTags)) {
1304                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1305                                    sb.append(indent);
1306                                    sb.append(" *\n");
1307                            }
1308    
1309                            sb.append(docletTags);
1310                    }
1311    
1312                    sb.append(indent);
1313                    sb.append(" */\n");
1314    
1315                    if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1316                            Validator.isNull(docletTags)) {
1317    
1318                            return null;
1319                    }
1320    
1321                    if (!_hasPublicModifier(javaMethod) && Validator.isNull(comment) &&
1322                            Validator.isNull(docletTags)) {
1323    
1324                            return null;
1325                    }
1326    
1327                    return sb.toString();
1328            }
1329    
1330            private String _getMethodKey(Element methodElement) {
1331                    StringBundler sb = new StringBundler();
1332    
1333                    sb.append(methodElement.elementText("name"));
1334                    sb.append(StringPool.OPEN_PARENTHESIS);
1335    
1336                    List<Element> paramElements = methodElement.elements("param");
1337    
1338                    for (Element paramElement : paramElements) {
1339                            sb.append(paramElement.elementText("name"));
1340                            sb.append("|");
1341                            sb.append(paramElement.elementText("type"));
1342                            sb.append(",");
1343                    }
1344    
1345                    sb.append(StringPool.CLOSE_PARENTHESIS);
1346    
1347                    return sb.toString();
1348            }
1349    
1350            private String _getMethodKey(JavaMethod javaMethod) {
1351                    StringBundler sb = new StringBundler();
1352    
1353                    sb.append(javaMethod.getName());
1354                    sb.append(StringPool.OPEN_PARENTHESIS);
1355    
1356                    JavaParameter[] javaParameters = javaMethod.getParameters();
1357    
1358                    for (JavaParameter javaParameter : javaParameters) {
1359                            sb.append(javaParameter.getName());
1360                            sb.append("|");
1361                            sb.append(_getTypeValue(javaParameter));
1362                            sb.append(",");
1363                    }
1364    
1365                    sb.append(StringPool.CLOSE_PARENTHESIS);
1366    
1367                    return sb.toString();
1368            }
1369    
1370            private String _getSpacesIndent(int length) {
1371                    String indent = StringPool.BLANK;
1372    
1373                    for (int i = 0; i < length; i++) {
1374                            indent += StringPool.SPACE;
1375                    }
1376    
1377                    return indent;
1378            }
1379    
1380            private String _getTypeValue(JavaParameter javaParameter) {
1381                    Type type = javaParameter.getType();
1382    
1383                    String typeValue = type.getValue();
1384    
1385                    if (type.isArray()) {
1386                            typeValue += "[]";
1387                    }
1388    
1389                    return typeValue;
1390            }
1391    
1392            private boolean _hasGeneratedTag(String content) {
1393                    if (content.contains("* @generated") || content.contains("$ANTLR")) {
1394                            return true;
1395                    }
1396                    else {
1397                            return false;
1398                    }
1399            }
1400    
1401            private boolean _hasPublicModifier(AbstractJavaEntity abstractJavaEntity) {
1402                    String[] modifiers = abstractJavaEntity.getModifiers();
1403    
1404                    if (modifiers == null) {
1405                            return false;
1406                    }
1407    
1408                    for (String modifier : modifiers) {
1409                            if (modifier.equals("public")) {
1410                                    return true;
1411                            }
1412                    }
1413    
1414                    return false;
1415            }
1416    
1417            private boolean _isOverrideMethod(
1418                    JavaClass javaClass, JavaMethod javaMethod,
1419                    Collection<Tuple> ancestorJavaClassTuples) {
1420    
1421                    if (javaMethod.isConstructor() || javaMethod.isPrivate() ||
1422                            javaMethod.isStatic() ||
1423                            _overridesHigherJavaAPIVersion(javaMethod)) {
1424    
1425                            return false;
1426                    }
1427    
1428                    String methodName = javaMethod.getName();
1429    
1430                    JavaParameter[] javaParameters = javaMethod.getParameters();
1431    
1432                    Type[] types = new Type[javaParameters.length];
1433    
1434                    for (int i = 0; i < javaParameters.length; i++) {
1435                            types[i] = javaParameters[i].getType();
1436                    }
1437    
1438                    // Check for matching method in each ancestor
1439    
1440                    for (Tuple ancestorJavaClassTuple : ancestorJavaClassTuples) {
1441                            JavaClass ancestorJavaClass =
1442                                    (JavaClass)ancestorJavaClassTuple.getObject(0);
1443    
1444                            JavaMethod ancestorJavaMethod = null;
1445    
1446                            if (ancestorJavaClassTuple.getSize() > 1) {
1447    
1448                                    // LPS-35613
1449    
1450                                    Type[] ancestorActualTypeArguments =
1451                                            (Type[])ancestorJavaClassTuple.getObject(1);
1452    
1453                                    Type[] genericTypes = new Type[types.length];
1454    
1455                                    for (int i = 0; i < types.length; i++) {
1456                                            Type type = types[i];
1457    
1458                                            String typeValue = type.getValue();
1459    
1460                                            boolean useGenericType = false;
1461    
1462                                            for (int j = 0; j < ancestorActualTypeArguments.length;
1463                                                            j++) {
1464    
1465                                                    if (typeValue.equals(
1466                                                                    ancestorActualTypeArguments[j].getValue())) {
1467    
1468                                                            useGenericType = true;
1469    
1470                                                            break;
1471                                                    }
1472                                            }
1473    
1474                                            if (useGenericType) {
1475                                                    genericTypes[i] = new Type("java.lang.Object");
1476                                            }
1477                                            else {
1478                                                    genericTypes[i] = type;
1479                                            }
1480                                    }
1481    
1482                                    ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1483                                            methodName, genericTypes);
1484                            }
1485                            else {
1486                                    ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1487                                            methodName, types);
1488                            }
1489    
1490                            if (ancestorJavaMethod == null) {
1491                                    continue;
1492                            }
1493    
1494                            boolean samePackage = false;
1495    
1496                            JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage();
1497    
1498                            if (ancestorJavaPackage != null) {
1499                                    samePackage = ancestorJavaPackage.equals(
1500                                            javaClass.getPackage());
1501                            }
1502    
1503                            // Check if the method is in scope
1504    
1505                            if (samePackage) {
1506                                    return !ancestorJavaMethod.isPrivate();
1507                            }
1508    
1509                            if (ancestorJavaMethod.isProtected() ||
1510                                    ancestorJavaMethod.isPublic()) {
1511    
1512                                    return true;
1513                            }
1514                            else {
1515                                    return false;
1516                            }
1517                    }
1518    
1519                    return false;
1520            }
1521    
1522            private boolean _overridesHigherJavaAPIVersion(JavaMethod javaMethod) {
1523                    Annotation[] annotations = javaMethod.getAnnotations();
1524    
1525                    if (annotations == null) {
1526                            return false;
1527                    }
1528    
1529                    for (Annotation annotation : annotations) {
1530                            Type type = annotation.getType();
1531    
1532                            JavaClass javaClass = type.getJavaClass();
1533    
1534                            String javaClassName = javaClass.getFullyQualifiedName();
1535    
1536                            if (javaClassName.equals(SinceJava.class.getName())) {
1537                                    AnnotationValue annotationValue = annotation.getProperty(
1538                                            "value");
1539    
1540                                    double sinceJava = GetterUtil.getDouble(
1541                                            annotationValue.getParameterValue());
1542    
1543                                    if (sinceJava > _LOWEST_SUPPORTED_JAVA_VERSION) {
1544                                            return true;
1545                                    }
1546                            }
1547                    }
1548    
1549                    return false;
1550            }
1551    
1552            private String _removeJavadocFromJava(JavaClass javaClass, String content) {
1553                    Set<Integer> lineNumbers = new HashSet<Integer>();
1554    
1555                    lineNumbers.add(_getJavaClassLineNumber(javaClass));
1556    
1557                    JavaMethod[] javaMethods = javaClass.getMethods();
1558    
1559                    for (JavaMethod javaMethod : javaMethods) {
1560                            lineNumbers.add(javaMethod.getLineNumber());
1561                    }
1562    
1563                    JavaField[] javaFields = javaClass.getFields();
1564    
1565                    for (JavaField javaField : javaFields) {
1566                            lineNumbers.add(javaField.getLineNumber());
1567                    }
1568    
1569                    String[] lines = StringUtil.splitLines(content);
1570    
1571                    for (int lineNumber : lineNumbers) {
1572                            if (lineNumber == 0) {
1573                                    continue;
1574                            }
1575    
1576                            int pos = lineNumber - 2;
1577    
1578                            String line = lines[pos];
1579    
1580                            if (line == null) {
1581                                    continue;
1582                            }
1583    
1584                            line = line.trim();
1585    
1586                            if (line.endsWith("*/")) {
1587                                    while (true) {
1588                                            lines[pos] = null;
1589    
1590                                            if (line.startsWith("/**") || line.startsWith("/*")) {
1591                                                    break;
1592                                            }
1593    
1594                                            line = lines[--pos].trim();
1595                                    }
1596                            }
1597                    }
1598    
1599                    StringBundler sb = new StringBundler(content.length());
1600    
1601                    for (String line : lines) {
1602                            if (line != null) {
1603                                    sb.append(line);
1604                                    sb.append("\n");
1605                            }
1606                    }
1607    
1608                    content = sb.toString();
1609    
1610                    return content.trim();
1611            }
1612    
1613            private String _trimMultilineText(String text) {
1614                    String[] lines = StringUtil.splitLines(text);
1615    
1616                    StringBundler sb = new StringBundler();
1617    
1618                    for (int i = 0; i < lines.length; i++) {
1619                            String line = lines[i].trim();
1620    
1621                            sb.append(line);
1622    
1623                            if (!line.endsWith(StringPool.OPEN_PARENTHESIS) &&
1624                                    (i < (lines.length - 1))) {
1625    
1626                                    sb.append(StringPool.SPACE);
1627                            }
1628                    }
1629    
1630                    return sb.toString();
1631            }
1632    
1633            private void _updateJavadocsXmlFile(
1634                            String fileName, JavaClass javaClass, Document javaClassDocument)
1635                    throws Exception {
1636    
1637                    String javaClassFullyQualifiedName = javaClass.getFullyQualifiedName();
1638    
1639                    /*if (!javaClassFullyQualifiedName.contains(".service.") ||
1640                            !javaClassFullyQualifiedName.endsWith("ServiceImpl")) {
1641    
1642                            return;
1643                    }*/
1644    
1645                    Tuple javadocsXmlTuple = _getJavadocsXmlTuple(fileName);
1646    
1647                    if (javadocsXmlTuple == null) {
1648                            return;
1649                    }
1650    
1651                    Document javadocsXmlDocument = (Document)javadocsXmlTuple.getObject(3);
1652    
1653                    Element javadocsXmlRootElement = javadocsXmlDocument.getRootElement();
1654    
1655                    List<Element> javadocElements = javadocsXmlRootElement.elements(
1656                            "javadoc");
1657    
1658                    for (Element javadocElement : javadocElements) {
1659                            String type = javadocElement.elementText("type");
1660    
1661                            if (type.equals(javaClassFullyQualifiedName)) {
1662                                    Element javaClassRootElement =
1663                                            javaClassDocument.getRootElement();
1664    
1665                                    if (Validator.equals(
1666                                                    javadocElement.formattedString(),
1667                                                    javaClassRootElement.formattedString())) {
1668    
1669                                            return;
1670                                    }
1671    
1672                                    javadocElement.detach();
1673    
1674                                    break;
1675                            }
1676                    }
1677    
1678                    javadocsXmlRootElement.add(javaClassDocument.getRootElement());
1679            }
1680    
1681            private void _updateJavaFromDocument(
1682                            String fileName, String originalContent, String javadocLessContent,
1683                            Document document)
1684                    throws Exception {
1685    
1686                    String[] lines = StringUtil.splitLines(javadocLessContent);
1687    
1688                    JavaClass javaClass = _getJavaClass(
1689                            fileName, new UnsyncStringReader(javadocLessContent));
1690    
1691                    _updateLanguageProperties(document, javaClass.getName());
1692    
1693                    List<Tuple> ancestorJavaClassTuples = new ArrayList<Tuple>();
1694    
1695                    ancestorJavaClassTuples = _addAncestorJavaClassTuples(
1696                            javaClass, ancestorJavaClassTuples);
1697    
1698                    Element rootElement = document.getRootElement();
1699    
1700                    Map<Integer, String> commentsMap = new TreeMap<Integer, String>();
1701    
1702                    String javaClassComment = _getJavaClassComment(rootElement, javaClass);
1703    
1704                    javaClassComment = _addDeprecatedTag(
1705                            javaClassComment, javaClass, StringPool.BLANK);
1706    
1707                    commentsMap.put(_getJavaClassLineNumber(javaClass), javaClassComment);
1708    
1709                    Map<String, Element> methodElementsMap = new HashMap<String, Element>();
1710    
1711                    List<Element> methodElements = rootElement.elements("method");
1712    
1713                    for (Element methodElement : methodElements) {
1714                            String methodKey = _getMethodKey(methodElement);
1715    
1716                            methodElementsMap.put(methodKey, methodElement);
1717                    }
1718    
1719                    JavaMethod[] javaMethods = javaClass.getMethods();
1720    
1721                    for (JavaMethod javaMethod : javaMethods) {
1722                            if (commentsMap.containsKey(javaMethod.getLineNumber())) {
1723                                    continue;
1724                            }
1725    
1726                            String indent = _getIndent(lines, javaMethod);
1727    
1728                            String javaMethodComment = _getJavaMethodComment(
1729                                    methodElementsMap, javaMethod, indent);
1730    
1731                            javaMethodComment = _addDeprecatedTag(
1732                                    javaMethodComment, javaMethod, indent);
1733    
1734                            // Handle override tag insertion
1735    
1736                            if (!ServiceBuilder.hasAnnotation(javaMethod, "Override")) {
1737                                    if (_isOverrideMethod(
1738                                                    javaClass, javaMethod, ancestorJavaClassTuples)) {
1739    
1740                                            String overrideLine = indent + "@Override\n";
1741    
1742                                            if (Validator.isNotNull(javaMethodComment)) {
1743                                                    javaMethodComment = javaMethodComment + overrideLine;
1744                                            }
1745                                            else {
1746                                                    javaMethodComment = overrideLine;
1747                                            }
1748                                    }
1749                            }
1750    
1751                            commentsMap.put(javaMethod.getLineNumber(), javaMethodComment);
1752                    }
1753    
1754                    Map<String, Element> fieldElementsMap = new HashMap<String, Element>();
1755    
1756                    List<Element> fieldElements = rootElement.elements("field");
1757    
1758                    for (Element fieldElement : fieldElements) {
1759                            String fieldKey = _getFieldKey(fieldElement);
1760    
1761                            fieldElementsMap.put(fieldKey, fieldElement);
1762                    }
1763    
1764                    JavaField[] javaFields = javaClass.getFields();
1765    
1766                    for (JavaField javaField : javaFields) {
1767                            if (commentsMap.containsKey(javaField.getLineNumber())) {
1768                                    continue;
1769                            }
1770    
1771                            String indent = _getIndent(lines, javaField);
1772    
1773                            String javaFieldComment = _getJavaFieldComment(
1774                                    fieldElementsMap, javaField, indent);
1775    
1776                            javaFieldComment = _addDeprecatedTag(
1777                                    javaFieldComment, javaField, indent);
1778    
1779                            commentsMap.put(javaField.getLineNumber(), javaFieldComment);
1780                    }
1781    
1782                    StringBundler sb = new StringBundler(javadocLessContent.length());
1783    
1784                    for (int lineNumber = 1; lineNumber <= lines.length; lineNumber++) {
1785                            String line = lines[lineNumber - 1];
1786    
1787                            String comments = commentsMap.get(lineNumber);
1788    
1789                            if (comments != null) {
1790                                    sb.append(comments);
1791                            }
1792    
1793                            sb.append(line);
1794                            sb.append("\n");
1795                    }
1796    
1797                    String formattedContent = sb.toString();
1798    
1799                    formattedContent = formattedContent.trim();
1800    
1801                    if (!originalContent.equals(formattedContent)) {
1802                            File file = new File(_inputDir + fileName);
1803    
1804                            _fileUtil.write(file, formattedContent.getBytes(StringPool.UTF8));
1805    
1806                            System.out.println("Writing " + file);
1807                    }
1808            }
1809    
1810            private void _updateLanguageProperties(Document document, String className)
1811                    throws IOException {
1812    
1813                    if (_languageProperties == null) {
1814                            return;
1815                    }
1816    
1817                    int index = className.indexOf("ServiceImpl");
1818    
1819                    if (index <= 0) {
1820                            return;
1821                    }
1822    
1823                    StringBundler sb = new StringBundler();
1824    
1825                    sb.append(Character.toLowerCase(className.charAt(0)));
1826    
1827                    for (int i = 1; i < index; i++) {
1828                            char c = className.charAt(i);
1829    
1830                            if (Character.isUpperCase(c)) {
1831                                    if (((i + 1) < index) &&
1832                                            Character.isLowerCase(className.charAt(i + 1))) {
1833    
1834                                            sb.append(CharPool.DASH);
1835                                    }
1836    
1837                                    sb.append(Character.toLowerCase(c));
1838                            }
1839                            else {
1840                                    sb.append(c);
1841                            }
1842                    }
1843    
1844                    sb.append("-service-help");
1845    
1846                    String key = sb.toString();
1847    
1848                    String value = _languageProperties.getProperty(key);
1849    
1850                    if (value == null) {
1851                            return;
1852                    }
1853    
1854                    Element rootElement = document.getRootElement();
1855    
1856                    String comment = rootElement.elementText("comment");
1857    
1858                    if ((comment == null) || value.equals(comment)) {
1859                            return;
1860                    }
1861    
1862                    index = comment.indexOf("\n\n");
1863    
1864                    if (index != -1) {
1865                            value = comment.substring(0, index);
1866                    }
1867                    else {
1868                            value = comment;
1869                    }
1870    
1871                    _updateLanguageProperties(key, value);
1872            }
1873    
1874            private void _updateLanguageProperties(String key, String value)
1875                    throws IOException {
1876    
1877                    StringBundler sb = new StringBundler();
1878    
1879                    try (UnsyncBufferedReader unsyncBufferedReader = 
1880                                    new UnsyncBufferedReader(
1881                                            new FileReader(_languagePropertiesFile))) {
1882    
1883                            boolean begin = false;
1884                            boolean firstLine = true;
1885                            String linePrefix = key + "=";
1886    
1887                            String line = null;
1888    
1889                            while ((line = unsyncBufferedReader.readLine()) != null) {
1890                                    if (line.equals(StringPool.BLANK)) {
1891                                            begin = !begin;
1892                                    }
1893    
1894                                    if (firstLine) {
1895                                            firstLine = false;
1896                                    }
1897                                    else {
1898                                            sb.append(StringPool.NEW_LINE);
1899                                    }
1900    
1901                                    if (line.startsWith(linePrefix)) {
1902                                            sb.append(linePrefix);
1903                                            sb.append(value);
1904                                    }
1905                                    else {
1906                                            sb.append(line);
1907                                    }
1908                            }
1909                    }
1910    
1911                    try (Writer writer = new OutputStreamWriter(
1912                                    new FileOutputStream(_languagePropertiesFile, false),
1913                                    StringPool.UTF8)) {
1914    
1915                            sb.writeTo(writer);
1916                    }
1917    
1918                    System.out.println(
1919                            "Updating " + _languagePropertiesFile + " key " + key);
1920            }
1921    
1922            private String _wrapText(String text, int indentLength, String exclude) {
1923                    StringBuffer sb = new StringBuffer();
1924    
1925                    StringBundler regexSB = new StringBundler("(?<=^|</");
1926    
1927                    regexSB.append(exclude);
1928                    regexSB.append(">).+?(?=$|<");
1929                    regexSB.append(exclude);
1930                    regexSB.append(">)");
1931    
1932                    Pattern pattern = Pattern.compile(regexSB.toString(), Pattern.DOTALL);
1933    
1934                    Matcher matcher = pattern.matcher(text);
1935    
1936                    while (matcher.find()) {
1937                            String wrapped = _formatInlines(matcher.group());
1938    
1939                            wrapped = StringUtil.wrap(wrapped, 80 - indentLength, "\n");
1940    
1941                            matcher.appendReplacement(sb, wrapped);
1942                    }
1943    
1944                    matcher.appendTail(sb);
1945    
1946                    return sb.toString();
1947            }
1948    
1949            private String _wrapText(String text, String indent) {
1950                    int indentLength = _getIndentLength(indent);
1951    
1952                    if (text.contains("<pre>")) {
1953                            text = _wrapText(text, indentLength, "pre");
1954                    }
1955                    else if (text.contains("<table>")) {
1956                            text = _wrapText(text, indentLength, "table");
1957                    }
1958                    else {
1959                            text = _formatInlines(text);
1960                            text = StringUtil.wrap(text, 80 - indentLength, "\n");
1961                    }
1962    
1963                    text = text.replaceAll("(?m)^", indent);
1964                    text = text.replaceAll("(?m) +$", StringPool.BLANK);
1965    
1966                    return text;
1967            }
1968    
1969            private static final double _LOWEST_SUPPORTED_JAVA_VERSION = 1.7;
1970    
1971            private static FileImpl _fileUtil = FileImpl.getInstance();
1972            private static SAXReaderImpl _saxReaderUtil = SAXReaderImpl.getInstance();
1973    
1974            private boolean _initializeMissingJavadocs;
1975            private String _inputDir;
1976            private Map<String, Tuple> _javadocxXmlTuples =
1977                    new HashMap<String, Tuple>();
1978            private Properties _languageProperties;
1979            private File _languagePropertiesFile;
1980            private String _outputFilePrefix;
1981            private Pattern _paragraphTagPattern = Pattern.compile(
1982                    "(^.*?(?=\n\n|$)+|(?<=<p>\n).*?(?=\n</p>))", Pattern.DOTALL);
1983            private boolean _updateJavadocs;
1984    
1985    }