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