001
014
015 package com.liferay.portal.tools;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
019 import com.liferay.portal.kernel.util.CharPool;
020 import com.liferay.portal.kernel.util.GetterUtil;
021 import com.liferay.portal.kernel.util.StringBundler;
022 import com.liferay.portal.kernel.util.StringPool;
023 import com.liferay.portal.kernel.util.StringUtil;
024 import com.liferay.portal.kernel.util.Tuple;
025 import com.liferay.portal.kernel.util.Validator;
026 import com.liferay.portal.kernel.xml.Document;
027 import com.liferay.portal.kernel.xml.Element;
028 import com.liferay.portal.tools.javadocformatter.SinceJava;
029 import com.liferay.portal.tools.servicebuilder.ServiceBuilder;
030 import com.liferay.portal.util.FileImpl;
031 import com.liferay.portal.xml.SAXReaderImpl;
032 import com.liferay.util.xml.DocUtil;
033
034 import com.thoughtworks.qdox.JavaDocBuilder;
035 import com.thoughtworks.qdox.model.AbstractBaseJavaEntity;
036 import com.thoughtworks.qdox.model.AbstractJavaEntity;
037 import com.thoughtworks.qdox.model.Annotation;
038 import com.thoughtworks.qdox.model.DocletTag;
039 import com.thoughtworks.qdox.model.JavaClass;
040 import com.thoughtworks.qdox.model.JavaField;
041 import com.thoughtworks.qdox.model.JavaMethod;
042 import com.thoughtworks.qdox.model.JavaPackage;
043 import com.thoughtworks.qdox.model.JavaParameter;
044 import com.thoughtworks.qdox.model.Type;
045 import com.thoughtworks.qdox.model.annotation.AnnotationValue;
046
047 import java.io.File;
048 import java.io.FileInputStream;
049 import java.io.FileOutputStream;
050 import java.io.FileReader;
051 import java.io.IOException;
052 import java.io.OutputStreamWriter;
053 import java.io.Reader;
054 import java.io.Writer;
055
056 import java.nio.file.Files;
057 import java.nio.file.Paths;
058 import java.util.ArrayList;
059 import java.util.Collection;
060 import java.util.HashMap;
061 import java.util.HashSet;
062 import java.util.List;
063 import java.util.Map;
064 import java.util.Properties;
065 import java.util.Set;
066 import java.util.TreeMap;
067 import java.util.regex.Matcher;
068 import java.util.regex.Pattern;
069
070 import org.apache.tools.ant.DirectoryScanner;
071
072
078 public class JavadocFormatter {
079
080 public static void main(String[] args) {
081 try {
082 new JavadocFormatter(args);
083 }
084 catch (Exception e) {
085 e.printStackTrace();
086 }
087 }
088
089 public JavadocFormatter(String[] args) throws Exception {
090 Map<String, String> arguments = ArgumentsUtil.parseArguments(args);
091
092 String init = arguments.get("javadoc.init");
093
094 if (Validator.isNotNull(init) && !init.startsWith("$")) {
095 _initializeMissingJavadocs = GetterUtil.getBoolean(init);
096 }
097
098 _inputDir = GetterUtil.getString(arguments.get("javadoc.input.dir"));
099
100 if (_inputDir.startsWith("$")) {
101 _inputDir = "./";
102 }
103
104 if (!_inputDir.endsWith("/")) {
105 _inputDir += "/";
106 }
107
108 System.out.println("Input directory is " + _inputDir);
109
110 String[] limits = StringUtil.split(arguments.get("javadoc.limit"), ",");
111
112 _outputFilePrefix = GetterUtil.getString(
113 arguments.get("javadoc.output.file.prefix"));
114
115 if (_outputFilePrefix.startsWith("$")) {
116 _outputFilePrefix = "javadocs";
117 }
118
119 String update = arguments.get("javadoc.update");
120
121 if (Validator.isNotNull(update) && !update.startsWith("$")) {
122 _updateJavadocs = GetterUtil.getBoolean(update);
123 }
124
125 DirectoryScanner directoryScanner = new DirectoryScanner();
126
127 directoryScanner.setBasedir(_inputDir);
128 directoryScanner.setExcludes(
129 new String[] {"**\\classes\\**", "**\\portal-client\\**"});
130
131 for (String limit : limits) {
132 List<String> includes = new ArrayList<String>();
133
134 if (Validator.isNotNull(limit) && !limit.startsWith("$")) {
135 System.out.println("Limit on " + limit);
136
137 String[] limitArray = StringUtil.split(limit, '/');
138
139 for (String curLimit : limitArray) {
140 includes.add(
141 "**\\" + StringUtil.replace(curLimit, ".", "\\") +
142 "\\**\\*.java");
143 includes.add("**\\" + curLimit + ".java");
144 }
145 }
146
147 else {
148 includes.add("**\\*.java");
149 }
150
151 directoryScanner.setIncludes(
152 includes.toArray(new String[includes.size()]));
153
154 directoryScanner.scan();
155
156 String[] fileNames = StringPool.EMPTY_ARRAY;
157
158 fileNames = directoryScanner.getIncludedFiles();
159
160 if ((fileNames.length == 0) && Validator.isNotNull(limit) &&
161 !limit.startsWith("$")) {
162
163 StringBundler sb = new StringBundler("Limit file not found: ");
164
165 sb.append(limit);
166
167 if (limit.contains(".")) {
168 sb.append(
169 " Specify limit filename without package path or ");
170 sb.append("file type suffix.");
171 }
172
173 System.out.println(sb.toString());
174 }
175
176 _languagePropertiesFile = new File(
177 "src/content/Language.properties");
178
179 if (_languagePropertiesFile.exists()) {
180 _languageProperties = new Properties();
181
182 _languageProperties.load(
183 new FileInputStream(
184 _languagePropertiesFile.getAbsolutePath()));
185 }
186
187 for (String fileName : fileNames) {
188 fileName = StringUtil.replace(fileName, "\\", "/");
189
190 try {
191 _format(fileName);
192 }
193 catch (Exception e) {
194 throw new RuntimeException(
195 "Unable to format file " + fileName, e);
196 }
197 }
198 }
199
200 for (Map.Entry<String, Tuple> entry : _javadocxXmlTuples.entrySet()) {
201 Tuple tuple = entry.getValue();
202
203 File javadocsXmlFile = (File)tuple.getObject(1);
204 String oldJavadocsXmlContent = (String)tuple.getObject(2);
205 Document javadocsXmlDocument = (Document)tuple.getObject(3);
206
207 Element javadocsXmlRootElement =
208 javadocsXmlDocument.getRootElement();
209
210 javadocsXmlRootElement.sortElementsByChildElement(
211 "javadoc", "type");
212
213 String newJavadocsXmlContent =
214 javadocsXmlDocument.formattedString();
215
216 if (!oldJavadocsXmlContent.equals(newJavadocsXmlContent)) {
217 _fileUtil.write(javadocsXmlFile, newJavadocsXmlContent);
218 }
219
220 _detachUnnecessaryTypes(javadocsXmlRootElement);
221
222 File javadocsRuntimeXmlFile = new File(
223 StringUtil.replaceLast(
224 javadocsXmlFile.toString(), "-all.xml", "-rt.xml"));
225
226 String oldJavadocsRuntimeXmlContent = StringPool.BLANK;
227
228 if (javadocsRuntimeXmlFile.exists()) {
229 oldJavadocsRuntimeXmlContent = _fileUtil.read(
230 javadocsRuntimeXmlFile);
231 }
232
233 String newJavadocsRuntimeXmlContent =
234 javadocsXmlDocument.compactString();
235
236 if (!oldJavadocsRuntimeXmlContent.equals(
237 newJavadocsRuntimeXmlContent)) {
238
239 _fileUtil.write(
240 javadocsRuntimeXmlFile, newJavadocsRuntimeXmlContent);
241 }
242 }
243 }
244
245 private List<Tuple> _addAncestorJavaClassTuples(
246 JavaClass javaClass, List<Tuple> ancestorJavaClassTuples) {
247
248 JavaClass superJavaClass = javaClass.getSuperJavaClass();
249
250 if (superJavaClass != null) {
251 ancestorJavaClassTuples.add(new Tuple(superJavaClass));
252
253 ancestorJavaClassTuples = _addAncestorJavaClassTuples(
254 superJavaClass, ancestorJavaClassTuples);
255 }
256
257 Type[] implementz = javaClass.getImplements();
258
259 for (Type implement : implementz) {
260 Type[] actualTypeArguments = implement.getActualTypeArguments();
261 JavaClass implementedInterface = implement.getJavaClass();
262
263 if (actualTypeArguments == null) {
264 ancestorJavaClassTuples.add(new Tuple(implementedInterface));
265 }
266 else {
267 ancestorJavaClassTuples.add(
268 new Tuple(implementedInterface, actualTypeArguments));
269 }
270
271 ancestorJavaClassTuples = _addAncestorJavaClassTuples(
272 implementedInterface, ancestorJavaClassTuples);
273 }
274
275 return ancestorJavaClassTuples;
276 }
277
278 private void _addClassCommentElement(
279 Element rootElement, JavaClass javaClass) {
280
281 String comment = _getCDATA(javaClass);
282
283 if (comment.startsWith("Copyright (c)")) {
284 comment = StringPool.BLANK;
285 }
286
287 if (Validator.isNull(comment)) {
288 return;
289 }
290
291 Element commentElement = rootElement.addElement("comment");
292
293 commentElement.addCDATA(comment);
294 }
295
296 private String _addDeprecatedTag(
297 String comment, AbstractBaseJavaEntity abstractBaseJavaEntity,
298 String indent) {
299
300 if (comment == null) {
301 return null;
302 }
303
304 if (!comment.contains("* @deprecated ") ||
305 ServiceBuilder.hasAnnotation(
306 abstractBaseJavaEntity, "Deprecated")) {
307
308 return comment;
309 }
310
311 return comment + indent + "@Deprecated\n";
312 }
313
314 private void _addDocletElements(
315 Element parentElement, AbstractJavaEntity abstractJavaEntity,
316 String name)
317 throws Exception {
318
319 DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name);
320
321 for (DocletTag docletTag : docletTags) {
322 String value = docletTag.getValue();
323
324 value = _trimMultilineText(value);
325
326 value = StringUtil.replace(value, " </", "</");
327
328 Element element = parentElement.addElement(name);
329
330 element.addCDATA(value);
331 }
332
333 if ((docletTags.length == 0) && name.equals("author")) {
334 Element element = parentElement.addElement(name);
335
336 element.addCDATA(ServiceBuilder.AUTHOR);
337 }
338 }
339
340 private String _addDocletTags(
341 Element parentElement, String[] tagNames, String indent,
342 boolean publicAccess) {
343
344 List<String> allTagNames = new ArrayList<String>();
345 List<String> customTagNames = new ArrayList<String>();
346 List<String> requiredTagNames = new ArrayList<String>();
347
348 for (String tagName : tagNames) {
349 List<Element> elements = parentElement.elements(tagName);
350
351 for (Element element : elements) {
352 Element commentElement = element.element("comment");
353
354 String comment = null;
355
356
357
358 if (commentElement != null) {
359 comment = commentElement.getText();
360 }
361 else {
362 comment = element.getText();
363 }
364
365 if (tagName.equals("param") || tagName.equals("return") ||
366 tagName.equals("throws")) {
367
368 if (Validator.isNotNull(comment)) {
369 requiredTagNames.add(tagName);
370 }
371 else if (tagName.equals("param")) {
372 if (GetterUtil.getBoolean(
373 element.elementText("required"))) {
374
375 requiredTagNames.add(tagName);
376 }
377 }
378 else if (tagName.equals("throws")) {
379 if (GetterUtil.getBoolean(
380 element.elementText("required"))) {
381
382 requiredTagNames.add(tagName);
383 }
384 }
385 }
386 else {
387 customTagNames.add(tagName);
388 }
389
390 allTagNames.add(tagName);
391 }
392 }
393
394 int maxTagNameLength = 0;
395
396 List<String> maxTagNameLengthTags = new ArrayList<String>();
397
398 if (_initializeMissingJavadocs) {
399 maxTagNameLengthTags.addAll(allTagNames);
400 }
401 else if (_updateJavadocs) {
402 if (!requiredTagNames.isEmpty()) {
403 maxTagNameLengthTags.addAll(allTagNames);
404 }
405 else {
406 maxTagNameLengthTags.addAll(customTagNames);
407 maxTagNameLengthTags.addAll(requiredTagNames);
408 }
409 }
410 else {
411 maxTagNameLengthTags.addAll(customTagNames);
412 maxTagNameLengthTags.addAll(requiredTagNames);
413 }
414
415 for (String name : maxTagNameLengthTags) {
416 if (name.length() > maxTagNameLength) {
417 maxTagNameLength = name.length();
418 }
419 }
420
421
422
423 maxTagNameLength += 2;
424
425 String tagNameIndent = _getSpacesIndent(maxTagNameLength);
426
427 StringBundler sb = new StringBundler();
428
429 for (String tagName : tagNames) {
430 List<Element> elements = parentElement.elements(tagName);
431
432 for (Element element : elements) {
433 Element commentElement = element.element("comment");
434
435 String comment = null;
436
437 if (commentElement != null) {
438 comment = commentElement.getText();
439 }
440 else {
441 comment = element.getText();
442 }
443
444 String elementName = element.elementText("name");
445
446 if (Validator.isNotNull(comment)) {
447 comment = _assembleTagComment(
448 tagName, elementName, comment, indent, tagNameIndent);
449
450 sb.append(comment);
451 }
452 else {
453 if (_initializeMissingJavadocs && publicAccess) {
454
455
456
457 comment = _assembleTagComment(
458 tagName, elementName, comment, indent,
459 tagNameIndent);
460
461 sb.append(comment);
462 }
463 else if (_updateJavadocs && publicAccess) {
464 if (!tagName.equals("param") &&
465 !tagName.equals("return") &&
466 !tagName.equals("throws")) {
467
468
469
470 comment = _assembleTagComment(
471 tagName, elementName, comment, indent,
472 tagNameIndent);
473
474 sb.append(comment);
475 }
476 else if (!requiredTagNames.isEmpty()) {
477
478
479
480 comment = _assembleTagComment(
481 tagName, elementName, comment, indent,
482 tagNameIndent);
483
484 sb.append(comment);
485 }
486 else {
487
488
489
490 }
491 }
492 else {
493 if (!tagName.equals("param") &&
494 !tagName.equals("return") &&
495 !tagName.equals("throws")) {
496
497
498
499 comment = _assembleTagComment(
500 tagName, elementName, comment, indent,
501 tagNameIndent);
502
503 sb.append(comment);
504 }
505 else if (tagName.equals("param") ||
506 tagName.equals("return") ||
507 tagName.equals("throws")) {
508
509 if (GetterUtil.getBoolean(
510 element.elementText("required"))) {
511
512 elementName = element.elementText("name");
513
514 comment = _assembleTagComment(
515 tagName, elementName, comment, indent,
516 tagNameIndent);
517
518 sb.append(comment);
519 }
520 }
521 else {
522
523
524
525 }
526 }
527 }
528 }
529 }
530
531 return sb.toString();
532 }
533
534 private void _addFieldElement(Element rootElement, JavaField javaField)
535 throws Exception {
536
537 Element fieldElement = rootElement.addElement("field");
538
539 DocUtil.add(fieldElement, "name", javaField.getName());
540
541 String comment = _getCDATA(javaField);
542
543 if (Validator.isNotNull(comment)) {
544 Element commentElement = fieldElement.addElement("comment");
545
546 commentElement.addCDATA(comment);
547 }
548
549 _addDocletElements(fieldElement, javaField, "version");
550 _addDocletElements(fieldElement, javaField, "see");
551 _addDocletElements(fieldElement, javaField, "since");
552 _addDocletElements(fieldElement, javaField, "deprecated");
553 }
554
555 private void _addMethodElement(Element rootElement, JavaMethod javaMethod)
556 throws Exception {
557
558 Element methodElement = rootElement.addElement("method");
559
560 DocUtil.add(methodElement, "name", javaMethod.getName());
561
562 String comment = _getCDATA(javaMethod);
563
564 if (Validator.isNotNull(comment)) {
565 Element commentElement = methodElement.addElement("comment");
566
567 commentElement.addCDATA(_getCDATA(javaMethod));
568 }
569
570 _addDocletElements(methodElement, javaMethod, "version");
571 _addParamElements(methodElement, javaMethod);
572 _addReturnElement(methodElement, javaMethod);
573 _addThrowsElements(methodElement, javaMethod);
574 _addDocletElements(methodElement, javaMethod, "see");
575 _addDocletElements(methodElement, javaMethod, "since");
576 _addDocletElements(methodElement, javaMethod, "deprecated");
577 }
578
579 private void _addParamElement(
580 Element methodElement, JavaParameter javaParameter,
581 DocletTag[] paramDocletTags) {
582
583 String name = javaParameter.getName();
584
585 String value = null;
586
587 for (DocletTag paramDocletTag : paramDocletTags) {
588 String curValue = paramDocletTag.getValue();
589
590 if (curValue.equals(name) || curValue.startsWith(name + " ")) {
591 value = curValue;
592
593 break;
594 }
595 }
596
597 Element paramElement = methodElement.addElement("param");
598
599 DocUtil.add(paramElement, "name", name);
600 DocUtil.add(paramElement, "type", _getTypeValue(javaParameter));
601
602 if (value != null) {
603 value = value.substring(name.length());
604
605 DocUtil.add(paramElement, "required", true);
606 }
607
608 value = _trimMultilineText(value);
609
610 Element commentElement = paramElement.addElement("comment");
611
612 commentElement.addCDATA(value);
613 }
614
615 private void _addParamElements(
616 Element methodElement, JavaMethod javaMethod) {
617
618 JavaParameter[] javaParameters = javaMethod.getParameters();
619
620 DocletTag[] paramDocletTags = javaMethod.getTagsByName("param");
621
622 for (JavaParameter javaParameter : javaParameters) {
623 _addParamElement(methodElement, javaParameter, paramDocletTags);
624 }
625 }
626
627 private void _addReturnElement(Element methodElement, JavaMethod javaMethod)
628 throws Exception {
629
630 Type returns = javaMethod.getReturns();
631
632 if (returns == null) {
633 return;
634 }
635
636 String returnsValue = returns.getValue();
637
638 if (returnsValue.equals("void")) {
639 return;
640 }
641
642 Element returnElement = methodElement.addElement("return");
643
644 DocletTag[] returnDocletTags = javaMethod.getTagsByName("return");
645
646 String comment = StringPool.BLANK;
647
648 if (returnDocletTags.length > 0) {
649 DocletTag returnDocletTag = returnDocletTags[0];
650
651 comment = GetterUtil.getString(returnDocletTag.getValue());
652
653 DocUtil.add(returnElement, "required", true);
654 }
655
656 comment = _trimMultilineText(comment);
657
658 Element commentElement = returnElement.addElement("comment");
659
660 commentElement.addCDATA(comment);
661 }
662
663 private void _addThrowsElement(
664 Element methodElement, Type exceptionType,
665 DocletTag[] throwsDocletTags) {
666
667 JavaClass javaClass = exceptionType.getJavaClass();
668
669 String name = javaClass.getName();
670
671 String value = null;
672
673 for (DocletTag throwsDocletTag : throwsDocletTags) {
674 String curValue = throwsDocletTag.getValue();
675
676 if (!curValue.startsWith(name)) {
677 continue;
678 }
679 else {
680 value = curValue;
681
682 break;
683 }
684 }
685
686 Element throwsElement = methodElement.addElement("throws");
687
688 DocUtil.add(throwsElement, "name", name);
689 DocUtil.add(throwsElement, "type", exceptionType.getValue());
690
691 if (value != null) {
692 value = value.substring(name.length());
693
694 DocUtil.add(throwsElement, "required", true);
695 }
696
697 value = _trimMultilineText(value);
698
699 Element commentElement = throwsElement.addElement("comment");
700
701 commentElement.addCDATA(_getCDATA(value));
702 }
703
704 private void _addThrowsElements(
705 Element methodElement, JavaMethod javaMethod) {
706
707 Type[] exceptionTypes = javaMethod.getExceptions();
708
709 DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws");
710
711 for (Type exceptionType : exceptionTypes) {
712 _addThrowsElement(methodElement, exceptionType, throwsDocletTags);
713 }
714 }
715
716 private String _assembleTagComment(
717 String tagName, String elementName, String comment, String indent,
718 String tagNameIndent) {
719
720 String indentAndTagName = indent + StringPool.AT + tagName;
721
722 if (Validator.isNotNull(elementName)) {
723 if (Validator.isNotNull(comment)) {
724 comment = elementName + StringPool.SPACE + comment;
725 }
726 else {
727 comment = elementName;
728 }
729
730
731
732 comment = _wrapText(comment, indent + tagNameIndent);
733
734
735
736 comment =
737 indentAndTagName + comment.substring(indentAndTagName.length());
738 }
739 else {
740 if (Validator.isNotNull(comment)) {
741
742
743
744 comment = _wrapText(comment, indent + tagNameIndent);
745
746
747
748 comment =
749 indentAndTagName +
750 comment.substring(indentAndTagName.length());
751 }
752 else {
753
754
755
756 comment = indentAndTagName + "\n";
757 }
758 }
759
760 return comment;
761 }
762
763 private void _detachUnnecessaryTypes(Element rootElement) {
764 List<Element> elements = rootElement.elements();
765
766 for (Element element : elements) {
767 String type = element.elementText("type");
768
769 if (!type.contains(".service.") || !type.endsWith("ServiceImpl")) {
770 element.detach();
771 }
772 }
773 }
774
775 private void _format(String fileName) throws Exception {
776 String originalContent = new String(
777 Files.readAllBytes(Paths.get(_inputDir + fileName)),
778 StringPool.UTF8);
779
780 if (fileName.contains("modules/third-party") ||
781 fileName.endsWith("Application.java") ||
782 fileName.endsWith("JavadocFormatter.java") ||
783 fileName.endsWith("SourceFormatter.java") ||
784 fileName.endsWith("WebProxyPortlet.java") ||
785 _hasGeneratedTag(originalContent)) {
786
787 return;
788 }
789
790 JavaClass javaClass = _getJavaClass(
791 fileName, new UnsyncStringReader(originalContent));
792
793 String javadocLessContent = _removeJavadocFromJava(
794 javaClass, originalContent);
795
796 Document document = _getJavadocDocument(javaClass);
797
798 _updateJavadocsXmlFile(fileName, javaClass, document);
799
800 _updateJavaFromDocument(
801 fileName, originalContent, javadocLessContent, document);
802 }
803
804 private String _formatCDATA(String cdata) {
805 cdata = cdata.replaceAll(
806 "(?s)\\s*<(p|[ou]l)>\\s*(.*?)\\s*</\\1>\\s*",
807 "\n\n<$1>\n$2\n</$1>\n\n");
808 cdata = cdata.replaceAll(
809 "(?s)\\s*<li>\\s*(.*?)\\s*</li>\\s*", "\n<li>\n$1\n</li>\n");
810 cdata = StringUtil.replace(cdata, "</li>\n\n<li>", "</li>\n<li>");
811 cdata = cdata.replaceAll("\n\\s+\n", "\n\n");
812 cdata = cdata.replaceAll(" +", " ");
813
814
815
816 Matcher matcher = _paragraphTagPattern.matcher(cdata);
817
818 StringBuffer sb = new StringBuffer();
819
820 while (matcher.find()) {
821 String trimmed = _trimMultilineText(matcher.group());
822
823
824
825 trimmed = StringUtil.replace(trimmed, "$", "\\$");
826
827 matcher.appendReplacement(sb, trimmed);
828 }
829
830 matcher.appendTail(sb);
831
832 cdata = sb.toString();
833
834 return cdata.trim();
835 }
836
837 private String _formatInlines(String text) {
838
839
840
841 text = text.replaceAll("[?@param id](?i)\\bid(s)?\\b", " ID$1");
842
843
844
845 text = text.replaceAll(
846 "(?i)(?<!<code>|\\w)(null|false|true)(?!\\w)", "<code>$1</code>");
847
848 return text;
849 }
850
851 private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
852 return _getCDATA(abstractJavaEntity.getComment());
853 }
854
855 private String _getCDATA(String cdata) {
856 StringBundler sb = new StringBundler();
857
858 if ((cdata == null) || cdata.isEmpty()) {
859 return StringPool.BLANK;
860 }
861
862 int cdataBeginIndex = 0;
863
864 while (!cdata.isEmpty()) {
865 int preTagIndex = cdata.indexOf("<pre>");
866 int tableTagIndex = cdata.indexOf("<table>");
867
868 boolean hasPreTag = (preTagIndex != -1) ? true : false;
869 boolean hasTableTag = (tableTagIndex != -1) ? true : false;
870
871 if (!hasPreTag && !hasTableTag) {
872 sb.append(_formatCDATA(cdata));
873
874 break;
875 }
876
877 boolean startsWithPreTag = (preTagIndex == 0) ? true : false;
878 boolean startsWithTableTag = (tableTagIndex == 0) ? true : false;
879
880 if (startsWithPreTag || startsWithTableTag) {
881 sb.append("\n");
882
883 String tagName = null;
884
885 if (preTagIndex == 0) {
886 tagName = "pre";
887 }
888 else {
889 tagName = "table";
890 }
891
892 String startTag = "<" + tagName + ">";
893 String endTag = "</" + tagName + ">";
894
895 int startTagLength = startTag.length();
896 int endTagLength = endTag.length();
897
898 int endTagIndex = cdata.indexOf(endTag, startTagLength - 1);
899
900 sb.append(cdata.substring(0, endTagIndex + endTagLength));
901
902 sb.append("\n");
903
904 cdataBeginIndex = endTagIndex + endTagLength;
905 }
906 else {
907
908
909
910 int startTagIndex = 0;
911
912 if (hasPreTag && hasTableTag) {
913 if (preTagIndex < tableTagIndex) {
914 startTagIndex = preTagIndex;
915 }
916 else {
917 startTagIndex = tableTagIndex;
918 }
919 }
920 else if (hasPreTag && !hasTableTag) {
921 startTagIndex = preTagIndex;
922 }
923 else {
924
925
926
927 startTagIndex = tableTagIndex;
928 }
929
930 sb.append(_formatCDATA(cdata.substring(0, startTagIndex)));
931
932 cdataBeginIndex = startTagIndex;
933 }
934
935 cdata = cdata.substring(cdataBeginIndex);
936 }
937
938 cdata = sb.toString();
939
940 return cdata.trim();
941 }
942
943 private String _getClassName(String fileName) {
944 int pos = fileName.indexOf("src/");
945
946 if (pos == -1) {
947 pos = fileName.indexOf("test/integration/");
948
949 if (pos != -1) {
950 pos = fileName.indexOf("integration/", pos);
951 }
952 }
953
954 if (pos == -1) {
955 pos = fileName.indexOf("test/unit/");
956
957 if (pos != -1) {
958 pos = fileName.indexOf("unit/", pos);
959 }
960 }
961
962 if (pos == -1) {
963 pos = fileName.indexOf("test/");
964 }
965
966 if (pos == -1) {
967 pos = fileName.indexOf("service/");
968 }
969
970 if (pos == -1) {
971 throw new RuntimeException(fileName);
972 }
973
974 pos = fileName.indexOf("/", pos);
975
976 String srcFile = fileName.substring(pos + 1, fileName.length());
977
978 return StringUtil.replace(
979 srcFile.substring(0, srcFile.length() - 5), "/", ".");
980 }
981
982 private String _getFieldKey(Element fieldElement) {
983 return fieldElement.elementText("name");
984 }
985
986 private String _getFieldKey(JavaField javaField) {
987 return javaField.getName();
988 }
989
990 private String _getIndent(
991 String[] lines, AbstractBaseJavaEntity abstractBaseJavaEntity) {
992
993 String line = lines[abstractBaseJavaEntity.getLineNumber() - 1];
994
995 String indent = StringPool.BLANK;
996
997 for (char c : line.toCharArray()) {
998 if (Character.isWhitespace(c)) {
999 indent += c;
1000 }
1001 else {
1002 break;
1003 }
1004 }
1005
1006 return indent;
1007 }
1008
1009 private int _getIndentLength(String indent) {
1010 int indentLength = 0;
1011
1012 for (char c : indent.toCharArray()) {
1013 if (c == '\t') {
1014 indentLength = indentLength + 4;
1015 }
1016 else {
1017 indentLength++;
1018 }
1019 }
1020
1021 return indentLength;
1022 }
1023
1024 private JavaClass _getJavaClass(String fileName, Reader reader)
1025 throws Exception {
1026
1027 String className = _getClassName(fileName);
1028
1029 JavaDocBuilder javadocBuilder = new JavaDocBuilder();
1030
1031 if (reader == null) {
1032 File file = new File(fileName);
1033
1034 if (!file.exists()) {
1035 return null;
1036 }
1037
1038 javadocBuilder.addSource(file);
1039 }
1040 else {
1041 javadocBuilder.addSource(reader);
1042 }
1043
1044 return javadocBuilder.getClassByName(className);
1045 }
1046
1047 private String _getJavaClassComment(
1048 Element rootElement, JavaClass javaClass) {
1049
1050 StringBundler sb = new StringBundler();
1051
1052 String indent = StringPool.BLANK;
1053
1054 sb.append("\n");
1078
1079 return sb.toString();
1080 }
1081
1082 private int _getJavaClassLineNumber(JavaClass javaClass) {
1083 int lineNumber = javaClass.getLineNumber();
1084
1085 Annotation[] annotations = javaClass.getAnnotations();
1086
1087 if (annotations.length == 0) {
1088 return lineNumber;
1089 }
1090
1091 for (Annotation annotation : annotations) {
1092 int annotationLineNumber = annotation.getLineNumber();
1093
1094 Map<String, String> propertyMap = annotation.getPropertyMap();
1095
1096 if (propertyMap.isEmpty()) {
1097 annotationLineNumber--;
1098 }
1099
1100 if (annotationLineNumber < lineNumber) {
1101 lineNumber = annotationLineNumber;
1102 }
1103 }
1104
1105 return lineNumber;
1106 }
1107
1108 private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
1109 Element rootElement = _saxReaderUtil.createElement("javadoc");
1110
1111 Document document = _saxReaderUtil.createDocument(rootElement);
1112
1113 DocUtil.add(rootElement, "name", javaClass.getName());
1114 DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
1115
1116 _addClassCommentElement(rootElement, javaClass);
1117 _addDocletElements(rootElement, javaClass, "author");
1118 _addDocletElements(rootElement, javaClass, "version");
1119 _addDocletElements(rootElement, javaClass, "see");
1120 _addDocletElements(rootElement, javaClass, "since");
1121 _addDocletElements(rootElement, javaClass, "serial");
1122 _addDocletElements(rootElement, javaClass, "deprecated");
1123
1124 JavaMethod[] javaMethods = javaClass.getMethods();
1125
1126 for (JavaMethod javaMethod : javaMethods) {
1127 _addMethodElement(rootElement, javaMethod);
1128 }
1129
1130 JavaField[] javaFields = javaClass.getFields();
1131
1132 for (JavaField javaField : javaFields) {
1133 _addFieldElement(rootElement, javaField);
1134 }
1135
1136 return document;
1137 }
1138
1139 private Tuple _getJavadocsXmlTuple(String fileName) throws Exception {
1140 File file = new File(_inputDir + fileName);
1141
1142 String absolutePath = file.getAbsolutePath();
1143
1144 absolutePath = StringUtil.replace(absolutePath, "\\", "/");
1145 absolutePath = StringUtil.replace(absolutePath, "/./", "/");
1146
1147 int pos = absolutePath.indexOf("/portal-impl/src/");
1148
1149 String srcDirName = null;
1150
1151 if (pos != -1) {
1152 srcDirName = absolutePath.substring(0, pos + 17);
1153 }
1154
1155 if (srcDirName == null) {
1156 pos = absolutePath.indexOf("/portal-kernel/src/");
1157
1158 if (pos == -1) {
1159 pos = absolutePath.indexOf("/portal-service/src/");
1160 }
1161
1162 if (pos == -1) {
1163 pos = absolutePath.indexOf("/util-bridges/src/");
1164 }
1165
1166 if (pos == -1) {
1167 pos = absolutePath.indexOf("/util-java/src/");
1168 }
1169
1170 if (pos == -1) {
1171 pos = absolutePath.indexOf("/util-taglib/src/");
1172 }
1173
1174 if (pos != -1) {
1175 srcDirName =
1176 absolutePath.substring(0, pos) + "/portal-impl/src/";
1177 }
1178 }
1179
1180 if (srcDirName == null) {
1181 pos = absolutePath.indexOf("/WEB-INF/src/");
1182
1183 if (pos != -1) {
1184 srcDirName = absolutePath.substring(0, pos + 13);
1185 }
1186 }
1187
1188 if (srcDirName == null) {
1189 return null;
1190 }
1191
1192 Tuple tuple = _javadocxXmlTuples.get(srcDirName);
1193
1194 if (tuple != null) {
1195 return tuple;
1196 }
1197
1198 File javadocsXmlFile = new File(
1199 srcDirName, "META-INF/" + _outputFilePrefix + "-all.xml");
1200
1201 if (!javadocsXmlFile.exists()) {
1202 _fileUtil.write(
1203 javadocsXmlFile,
1204 "<?xml version=\"1.0\"?>\n\n<javadocs>\n</javadocs>");
1205 }
1206
1207 String javadocsXmlContent = _fileUtil.read(javadocsXmlFile);
1208
1209 Document javadocsXmlDocument = _saxReaderUtil.read(javadocsXmlContent);
1210
1211 tuple = new Tuple(
1212 srcDirName, javadocsXmlFile, javadocsXmlContent,
1213 javadocsXmlDocument);
1214
1215 _javadocxXmlTuples.put(srcDirName, tuple);
1216
1217 return tuple;
1218 }
1219
1220 private String _getJavaFieldComment(
1221 Map<String, Element> fieldElementsMap, JavaField javaField,
1222 String indent) {
1223
1224 String fieldKey = _getFieldKey(javaField);
1225
1226 Element fieldElement = fieldElementsMap.get(fieldKey);
1227
1228 if (fieldElement == null) {
1229 return null;
1230 }
1231
1232 StringBundler sb = new StringBundler();
1233
1234 sb.append(indent);
1235 sb.append("\n");
1259
1260 if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1261 Validator.isNull(docletTags)) {
1262
1263 return null;
1264 }
1265
1266 if (!_hasPublicModifier(javaField) && Validator.isNull(comment) &&
1267 Validator.isNull(docletTags)) {
1268
1269 return null;
1270 }
1271
1272 return sb.toString();
1273 }
1274
1275 private String _getJavaMethodComment(
1276 Map<String, Element> methodElementsMap, JavaMethod javaMethod,
1277 String indent) {
1278
1279 String methodKey = _getMethodKey(javaMethod);
1280
1281 Element methodElement = methodElementsMap.get(methodKey);
1282
1283 if (methodElement == null) {
1284 return null;
1285 }
1286
1287 StringBundler sb = new StringBundler();
1288
1289 sb.append(indent);
1290 sb.append("\n");
1317
1318 if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1319 Validator.isNull(docletTags)) {
1320
1321 return null;
1322 }
1323
1324 if (!_hasPublicModifier(javaMethod) && Validator.isNull(comment) &&
1325 Validator.isNull(docletTags)) {
1326
1327 return null;
1328 }
1329
1330 return sb.toString();
1331 }
1332
1333 private String _getMethodKey(Element methodElement) {
1334 StringBundler sb = new StringBundler();
1335
1336 sb.append(methodElement.elementText("name"));
1337 sb.append(StringPool.OPEN_PARENTHESIS);
1338
1339 List<Element> paramElements = methodElement.elements("param");
1340
1341 for (Element paramElement : paramElements) {
1342 sb.append(paramElement.elementText("name"));
1343 sb.append("|");
1344 sb.append(paramElement.elementText("type"));
1345 sb.append(",");
1346 }
1347
1348 sb.append(StringPool.CLOSE_PARENTHESIS);
1349
1350 return sb.toString();
1351 }
1352
1353 private String _getMethodKey(JavaMethod javaMethod) {
1354 StringBundler sb = new StringBundler();
1355
1356 sb.append(javaMethod.getName());
1357 sb.append(StringPool.OPEN_PARENTHESIS);
1358
1359 JavaParameter[] javaParameters = javaMethod.getParameters();
1360
1361 for (JavaParameter javaParameter : javaParameters) {
1362 sb.append(javaParameter.getName());
1363 sb.append("|");
1364 sb.append(_getTypeValue(javaParameter));
1365 sb.append(",");
1366 }
1367
1368 sb.append(StringPool.CLOSE_PARENTHESIS);
1369
1370 return sb.toString();
1371 }
1372
1373 private String _getSpacesIndent(int length) {
1374 String indent = StringPool.BLANK;
1375
1376 for (int i = 0; i < length; i++) {
1377 indent += StringPool.SPACE;
1378 }
1379
1380 return indent;
1381 }
1382
1383 private String _getTypeValue(JavaParameter javaParameter) {
1384 Type type = javaParameter.getType();
1385
1386 String typeValue = type.getValue();
1387
1388 if (type.isArray()) {
1389 typeValue += "[]";
1390 }
1391
1392 return typeValue;
1393 }
1394
1395 private boolean _hasGeneratedTag(String content) {
1396 if (content.contains("* @generated") || content.contains("$ANTLR")) {
1397 return true;
1398 }
1399 else {
1400 return false;
1401 }
1402 }
1403
1404 private boolean _hasPublicModifier(AbstractJavaEntity abstractJavaEntity) {
1405 String[] modifiers = abstractJavaEntity.getModifiers();
1406
1407 if (modifiers == null) {
1408 return false;
1409 }
1410
1411 for (String modifier : modifiers) {
1412 if (modifier.equals("public")) {
1413 return true;
1414 }
1415 }
1416
1417 return false;
1418 }
1419
1420 private boolean _isOverrideMethod(
1421 JavaClass javaClass, JavaMethod javaMethod,
1422 Collection<Tuple> ancestorJavaClassTuples) {
1423
1424 if (javaMethod.isConstructor() || javaMethod.isPrivate() ||
1425 javaMethod.isStatic() ||
1426 _overridesHigherJavaAPIVersion(javaMethod)) {
1427
1428 return false;
1429 }
1430
1431 String methodName = javaMethod.getName();
1432
1433 JavaParameter[] javaParameters = javaMethod.getParameters();
1434
1435 Type[] types = new Type[javaParameters.length];
1436
1437 for (int i = 0; i < javaParameters.length; i++) {
1438 types[i] = javaParameters[i].getType();
1439 }
1440
1441
1442
1443 for (Tuple ancestorJavaClassTuple : ancestorJavaClassTuples) {
1444 JavaClass ancestorJavaClass =
1445 (JavaClass)ancestorJavaClassTuple.getObject(0);
1446
1447 JavaMethod ancestorJavaMethod = null;
1448
1449 if (ancestorJavaClassTuple.getSize() > 1) {
1450
1451
1452
1453 Type[] ancestorActualTypeArguments =
1454 (Type[])ancestorJavaClassTuple.getObject(1);
1455
1456 Type[] genericTypes = new Type[types.length];
1457
1458 for (int i = 0; i < types.length; i++) {
1459 Type type = types[i];
1460
1461 String typeValue = type.getValue();
1462
1463 boolean useGenericType = false;
1464
1465 for (int j = 0; j < ancestorActualTypeArguments.length;
1466 j++) {
1467
1468 if (typeValue.equals(
1469 ancestorActualTypeArguments[j].getValue())) {
1470
1471 useGenericType = true;
1472
1473 break;
1474 }
1475 }
1476
1477 if (useGenericType) {
1478 genericTypes[i] = new Type("java.lang.Object");
1479 }
1480 else {
1481 genericTypes[i] = type;
1482 }
1483 }
1484
1485 ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1486 methodName, genericTypes);
1487 }
1488 else {
1489 ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1490 methodName, types);
1491 }
1492
1493 if (ancestorJavaMethod == null) {
1494 continue;
1495 }
1496
1497 boolean samePackage = false;
1498
1499 JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage();
1500
1501 if (ancestorJavaPackage != null) {
1502 samePackage = ancestorJavaPackage.equals(
1503 javaClass.getPackage());
1504 }
1505
1506
1507
1508 if (samePackage) {
1509 return !ancestorJavaMethod.isPrivate();
1510 }
1511
1512 if (ancestorJavaMethod.isProtected() ||
1513 ancestorJavaMethod.isPublic()) {
1514
1515 return true;
1516 }
1517 else {
1518 return false;
1519 }
1520 }
1521
1522 return false;
1523 }
1524
1525 private boolean _overridesHigherJavaAPIVersion(JavaMethod javaMethod) {
1526 Annotation[] annotations = javaMethod.getAnnotations();
1527
1528 if (annotations == null) {
1529 return false;
1530 }
1531
1532 for (Annotation annotation : annotations) {
1533 Type type = annotation.getType();
1534
1535 JavaClass javaClass = type.getJavaClass();
1536
1537 String javaClassName = javaClass.getFullyQualifiedName();
1538
1539 if (javaClassName.equals(SinceJava.class.getName())) {
1540 AnnotationValue annotationValue = annotation.getProperty(
1541 "value");
1542
1543 double sinceJava = GetterUtil.getDouble(
1544 annotationValue.getParameterValue());
1545
1546 if (sinceJava > _LOWEST_SUPPORTED_JAVA_VERSION) {
1547 return true;
1548 }
1549 }
1550 }
1551
1552 return false;
1553 }
1554
1555 private String _removeJavadocFromJava(JavaClass javaClass, String content) {
1556 Set<Integer> lineNumbers = new HashSet<Integer>();
1557
1558 lineNumbers.add(_getJavaClassLineNumber(javaClass));
1559
1560 JavaMethod[] javaMethods = javaClass.getMethods();
1561
1562 for (JavaMethod javaMethod : javaMethods) {
1563 lineNumbers.add(javaMethod.getLineNumber());
1564 }
1565
1566 JavaField[] javaFields = javaClass.getFields();
1567
1568 for (JavaField javaField : javaFields) {
1569 lineNumbers.add(javaField.getLineNumber());
1570 }
1571
1572 String[] lines = StringUtil.splitLines(content);
1573
1574 for (int lineNumber : lineNumbers) {
1575 if (lineNumber == 0) {
1576 continue;
1577 }
1578
1579 int pos = lineNumber - 2;
1580
1581 String line = lines[pos];
1582
1583 if (line == null) {
1584 continue;
1585 }
1586
1587 int blankLines = 0;
1588
1589 while (line.equals(StringPool.BLANK)) {
1590 line = lines[--pos];
1591
1592 blankLines++;
1593 }
1594
1595 line = line.trim();
1596
1597 if (line.endsWith("*/")) {
1598 while (true) {
1599 lines[pos] = null;
1600
1601 if (line.startsWith("