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