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