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