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.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
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
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
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
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
442
443 comment = _assembleTagComment(
444 tagName, elementName, comment, indent,
445 tagNameIndent);
446
447 sb.append(comment);
448 }
449 else if (!requiredTagNames.isEmpty()) {
450
451
452
453 comment = _assembleTagComment(
454 tagName, elementName, comment, indent,
455 tagNameIndent);
456
457 sb.append(comment);
458 }
459 else {
460
461
462
463 }
464 }
465 else {
466 if (!tagName.equals("param") &&
467 !tagName.equals("return") &&
468 !tagName.equals("throws")) {
469
470
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
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
704
705 comment = _wrapText(comment, indent + tagNameIndent);
706
707
708
709 comment =
710 indentAndTagName + comment.substring(indentAndTagName.length());
711 }
712 else {
713 if (Validator.isNotNull(comment)) {
714
715
716
717 comment = _wrapText(comment, indent + tagNameIndent);
718
719
720
721 comment =
722 indentAndTagName +
723 comment.substring(indentAndTagName.length());
724 }
725 else {
726
727
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
791
792 Pattern pattern = Pattern.compile(
793 "(^.*?(?=\n\n|$)+|(?<=<p>\n).*?(?=\n</p>))", Pattern.DOTALL);
794
795 Matcher matcher = pattern.matcher(cdata);
796
797 StringBuffer sb = new StringBuffer();
798
799 while (matcher.find()) {
800 String trimmed = _trimMultilineText(matcher.group());
801
802
803
804 trimmed = trimmed.replaceAll("\\$", "\\\\\\$");
805
806 matcher.appendReplacement(sb, trimmed);
807 }
808
809 matcher.appendTail(sb);
810
811 cdata = sb.toString();
812
813 return cdata.trim();
814 }
815
816 private String _formatInlines(String text) {
817
818
819
820 text = text.replaceAll("[?@param id](?i)\\bid(s)?\\b", " ID$1");
821
822
823
824 text = text.replaceAll(
825 "(?i)(?<!<code>|\\w)(null|false|true)(?!\\w)", "<code>$1</code>");
826
827 return text;
828 }
829
830 private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
831 return _getCDATA(abstractJavaEntity.getComment());
832 }
833
834 private String _getCDATA(String cdata) {
835 StringBundler sb = new StringBundler();
836
837 if ((cdata == null) || cdata.isEmpty()) {
838 return StringPool.BLANK;
839 }
840
841 int cdataBeginIndex = 0;
842
843 while (!cdata.isEmpty()) {
844 int preTagIndex = cdata.indexOf("<pre>");
845 int tableTagIndex = cdata.indexOf("<table>");
846
847 boolean hasPreTag = (preTagIndex != -1) ? true : false;
848 boolean hasTableTag = (tableTagIndex != -1) ? true : false;
849
850 if (!hasPreTag && !hasTableTag) {
851 sb.append(_formatCDATA(cdata));
852
853 break;
854 }
855
856 boolean startsWithPreTag = (preTagIndex == 0) ? true : false;
857 boolean startsWithTableTag = (tableTagIndex == 0) ? true : false;
858
859 if (startsWithPreTag || startsWithTableTag) {
860 sb.append("\n");
861
862 String tagName = null;
863
864 if (preTagIndex == 0) {
865 tagName = "pre";
866 }
867 else {
868 tagName = "table";
869 }
870
871 String startTag = "<" + tagName + ">";
872 String endTag = "</" + tagName + ">";
873
874 int startTagLength = startTag.length();
875 int endTagLength = endTag.length();
876
877 int endTagIndex = cdata.indexOf(endTag, startTagLength - 1);
878
879 sb.append(cdata.substring(0, endTagIndex + endTagLength));
880
881 sb.append("\n");
882
883 cdataBeginIndex = endTagIndex + endTagLength;
884 }
885 else {
886
887
888
889 int startTagIndex = 0;
890
891 if (hasPreTag && hasTableTag) {
892 if (preTagIndex < tableTagIndex) {
893 startTagIndex = preTagIndex;
894 }
895 else {
896 startTagIndex = tableTagIndex;
897 }
898 }
899 else if (hasPreTag && !hasTableTag) {
900 startTagIndex = preTagIndex;
901 }
902 else {
903
904
905
906 startTagIndex = tableTagIndex;
907 }
908
909 sb.append(_formatCDATA(cdata.substring(0, startTagIndex)));
910
911 cdataBeginIndex = startTagIndex;
912 }
913
914 cdata = cdata.substring(cdataBeginIndex);
915 }
916
917 cdata = sb.toString();
918
919 return cdata.trim();
920 }
921
922 private String _getClassName(String fileName) {
923 int pos = fileName.indexOf("src/");
924
925 if (pos == -1) {
926 pos = fileName.indexOf("test/integration/");
927
928 if (pos != -1) {
929 pos = fileName.indexOf("integration/", pos);
930 }
931 }
932
933 if (pos == -1) {
934 pos = fileName.indexOf("test/unit/");
935
936 if (pos != -1) {
937 pos = fileName.indexOf("unit/", pos);
938 }
939 }
940
941 if (pos == -1) {
942 pos = fileName.indexOf("test/");
943 }
944
945 if (pos == -1) {
946 pos = fileName.indexOf("service/");
947 }
948
949 if (pos == -1) {
950 throw new RuntimeException(fileName);
951 }
952
953 pos = fileName.indexOf("/", pos);
954
955 String srcFile = fileName.substring(pos + 1, fileName.length());
956
957 return StringUtil.replace(
958 srcFile.substring(0, srcFile.length() - 5), "/", ".");
959 }
960
961 private String _getFieldKey(Element fieldElement) {
962 return fieldElement.elementText("name");
963 }
964
965 private String _getFieldKey(JavaField javaField) {
966 return javaField.getName();
967 }
968
969 private String _getIndent(
970 String[] lines, AbstractBaseJavaEntity abstractBaseJavaEntity) {
971
972 String line = lines[abstractBaseJavaEntity.getLineNumber() - 1];
973
974 String indent = StringPool.BLANK;
975
976 for (char c : line.toCharArray()) {
977 if (Character.isWhitespace(c)) {
978 indent += c;
979 }
980 else {
981 break;
982 }
983 }
984
985 return indent;
986 }
987
988 private int _getIndentLength(String indent) {
989 int indentLength = 0;
990
991 for (char c : indent.toCharArray()) {
992 if (c == '\t') {
993 indentLength = indentLength + 4;
994 }
995 else {
996 indentLength++;
997 }
998 }
999
1000 return indentLength;
1001 }
1002
1003 private JavaClass _getJavaClass(String fileName, Reader reader)
1004 throws Exception {
1005
1006 String className = _getClassName(fileName);
1007
1008 JavaDocBuilder javadocBuilder = new JavaDocBuilder();
1009
1010 if (reader == null) {
1011 File file = new File(fileName);
1012
1013 if (!file.exists()) {
1014 return null;
1015 }
1016
1017 javadocBuilder.addSource(file);
1018 }
1019 else {
1020 javadocBuilder.addSource(reader);
1021 }
1022
1023 return javadocBuilder.getClassByName(className);
1024 }
1025
1026 private String _getJavaClassComment(
1027 Element rootElement, JavaClass javaClass) {
1028
1029 StringBundler sb = new StringBundler();
1030
1031 String indent = StringPool.BLANK;
1032
1033 sb.append("\n");
1057
1058 return sb.toString();
1059 }
1060
1061 private int _getJavaClassLineNumber(JavaClass javaClass) {
1062 int lineNumber = javaClass.getLineNumber();
1063
1064 Annotation[] annotations = javaClass.getAnnotations();
1065
1066 if (annotations.length == 0) {
1067 return lineNumber;
1068 }
1069
1070 for (Annotation annotation : annotations) {
1071 int annotationLineNumber = annotation.getLineNumber();
1072
1073 Map<String, String> propertyMap = annotation.getPropertyMap();
1074
1075 if (propertyMap.isEmpty()) {
1076 annotationLineNumber--;
1077 }
1078
1079 if (annotationLineNumber < lineNumber) {
1080 lineNumber = annotationLineNumber;
1081 }
1082 }
1083
1084 return lineNumber;
1085 }
1086
1087 private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
1088 Element rootElement = _saxReaderUtil.createElement("javadoc");
1089
1090 Document document = _saxReaderUtil.createDocument(rootElement);
1091
1092 DocUtil.add(rootElement, "name", javaClass.getName());
1093 DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
1094
1095 _addClassCommentElement(rootElement, javaClass);
1096 _addDocletElements(rootElement, javaClass, "author");
1097 _addDocletElements(rootElement, javaClass, "version");
1098 _addDocletElements(rootElement, javaClass, "see");
1099 _addDocletElements(rootElement, javaClass, "since");
1100 _addDocletElements(rootElement, javaClass, "serial");
1101 _addDocletElements(rootElement, javaClass, "deprecated");
1102
1103 JavaMethod[] javaMethods = javaClass.getMethods();
1104
1105 for (JavaMethod javaMethod : javaMethods) {
1106 _addMethodElement(rootElement, javaMethod);
1107 }
1108
1109 JavaField[] javaFields = javaClass.getFields();
1110
1111 for (JavaField javaField : javaFields) {
1112 _addFieldElement(rootElement, javaField);
1113 }
1114
1115 return document;
1116 }
1117
1118 private Tuple _getJavadocsXmlTuple(String fileName) throws Exception {
1119 File file = new File(_inputDir + fileName);
1120
1121 String absolutePath = file.getAbsolutePath();
1122
1123 absolutePath = StringUtil.replace(absolutePath, "\\", "/");
1124 absolutePath = StringUtil.replace(absolutePath, "/./", "/");
1125
1126 int pos = absolutePath.indexOf("/portal-impl/src/");
1127
1128 String srcDirName = null;
1129
1130 if (pos != -1) {
1131 srcDirName = absolutePath.substring(0, pos + 17);
1132 }
1133
1134 if (srcDirName == null) {
1135 pos = absolutePath.indexOf("/portal-kernel/src/");
1136
1137 if (pos == -1) {
1138 pos = absolutePath.indexOf("/portal-service/src/");
1139 }
1140
1141 if (pos == -1) {
1142 pos = absolutePath.indexOf("/util-bridges/src/");
1143 }
1144
1145 if (pos == -1) {
1146 pos = absolutePath.indexOf("/util-java/src/");
1147 }
1148
1149 if (pos == -1) {
1150 pos = absolutePath.indexOf("/util-taglib/src/");
1151 }
1152
1153 if (pos != -1) {
1154 srcDirName =
1155 absolutePath.substring(0, pos) + "/portal-impl/src/";
1156 }
1157 }
1158
1159 if (srcDirName == null) {
1160 pos = absolutePath.indexOf("/WEB-INF/src/");
1161
1162 if (pos != -1) {
1163 srcDirName = absolutePath.substring(0, pos + 13);
1164 }
1165 }
1166
1167 if (srcDirName == null) {
1168 return null;
1169 }
1170
1171 Tuple tuple = _javadocxXmlTuples.get(srcDirName);
1172
1173 if (tuple != null) {
1174 return tuple;
1175 }
1176
1177 File javadocsXmlFile = new File(
1178 srcDirName, "META-INF/" + _outputFilePrefix + "-all.xml");
1179
1180 if (!javadocsXmlFile.exists()) {
1181 _fileUtil.write(
1182 javadocsXmlFile,
1183 "<?xml version=\"1.0\"?>\n\n<javadocs>\n</javadocs>");
1184 }
1185
1186 String javadocsXmlContent = _fileUtil.read(javadocsXmlFile);
1187
1188 Document javadocsXmlDocument = _saxReaderUtil.read(javadocsXmlContent);
1189
1190 tuple = new Tuple(
1191 srcDirName, javadocsXmlFile, javadocsXmlContent,
1192 javadocsXmlDocument);
1193
1194 _javadocxXmlTuples.put(srcDirName, tuple);
1195
1196 return tuple;
1197 }
1198
1199 private String _getJavaFieldComment(
1200 String[] lines, Map<String, Element> fieldElementsMap,
1201 JavaField javaField) {
1202
1203 String fieldKey = _getFieldKey(javaField);
1204
1205 Element fieldElement = fieldElementsMap.get(fieldKey);
1206
1207 if (fieldElement == null) {
1208 return null;
1209 }
1210
1211 String indent = _getIndent(lines, javaField);
1212
1213 StringBundler sb = new StringBundler();
1214
1215 sb.append(indent);
1216 sb.append("\n");
1240
1241 if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1242 Validator.isNull(docletTags)) {
1243
1244 return null;
1245 }
1246
1247 if (!_hasPublicModifier(javaField) && Validator.isNull(comment) &&
1248 Validator.isNull(docletTags)) {
1249
1250 return null;
1251 }
1252
1253 return sb.toString();
1254 }
1255
1256 private String _getJavaMethodComment(
1257 String[] lines, Map<String, Element> methodElementsMap,
1258 JavaMethod javaMethod) {
1259
1260 String methodKey = _getMethodKey(javaMethod);
1261
1262 Element methodElement = methodElementsMap.get(methodKey);
1263
1264 if (methodElement == null) {
1265 return null;
1266 }
1267
1268 String indent = _getIndent(lines, javaMethod);
1269
1270 StringBundler sb = new StringBundler();
1271
1272 sb.append(indent);
1273 sb.append("\n");
1300
1301 if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1302 Validator.isNull(docletTags)) {
1303
1304 return null;
1305 }
1306
1307 if (!_hasPublicModifier(javaMethod) && Validator.isNull(comment) &&
1308 Validator.isNull(docletTags)) {
1309
1310 return null;
1311 }
1312
1313 return sb.toString();
1314 }
1315
1316 private String _getMethodKey(Element methodElement) {
1317 StringBundler sb = new StringBundler();
1318
1319 sb.append(methodElement.elementText("name"));
1320 sb.append(StringPool.OPEN_PARENTHESIS);
1321
1322 List<Element> paramElements = methodElement.elements("param");
1323
1324 for (Element paramElement : paramElements) {
1325 sb.append(paramElement.elementText("name"));
1326 sb.append("|");
1327 sb.append(paramElement.elementText("type"));
1328 sb.append(",");
1329 }
1330
1331 sb.append(StringPool.CLOSE_PARENTHESIS);
1332
1333 return sb.toString();
1334 }
1335
1336 private String _getMethodKey(JavaMethod javaMethod) {
1337 StringBundler sb = new StringBundler();
1338
1339 sb.append(javaMethod.getName());
1340 sb.append(StringPool.OPEN_PARENTHESIS);
1341
1342 JavaParameter[] javaParameters = javaMethod.getParameters();
1343
1344 for (JavaParameter javaParameter : javaParameters) {
1345 sb.append(javaParameter.getName());
1346 sb.append("|");
1347 sb.append(_getTypeValue(javaParameter));
1348 sb.append(",");
1349 }
1350
1351 sb.append(StringPool.CLOSE_PARENTHESIS);
1352
1353 return sb.toString();
1354 }
1355
1356 private String _getSpacesIndent(int length) {
1357 String indent = StringPool.BLANK;
1358
1359 for (int i = 0; i < length; i++) {
1360 indent += StringPool.SPACE;
1361 }
1362
1363 return indent;
1364 }
1365
1366 private String _getTypeValue(JavaParameter javaParameter) {
1367 Type type = javaParameter.getType();
1368
1369 String typeValue = type.getValue();
1370
1371 if (type.isArray()) {
1372 typeValue += "[]";
1373 }
1374
1375 return typeValue;
1376 }
1377
1378 private boolean _hasAnnotation(
1379 AbstractBaseJavaEntity abstractBaseJavaEntity, String annotationName) {
1380
1381 Annotation[] annotations = abstractBaseJavaEntity.getAnnotations();
1382
1383 if (annotations == null) {
1384 return false;
1385 }
1386
1387 for (int i = 0; i < annotations.length; i++) {
1388 Type type = annotations[i].getType();
1389
1390 JavaClass javaClass = type.getJavaClass();
1391
1392 if (annotationName.equals(javaClass.getName())) {
1393 return true;
1394 }
1395 }
1396
1397 return false;
1398 }
1399
1400 private boolean _hasGeneratedTag(String content) {
1401 if (content.contains("* @generated") || content.contains("$ANTLR")) {
1402 return true;
1403 }
1404 else {
1405 return false;
1406 }
1407 }
1408
1409 private boolean _hasPublicModifier(AbstractJavaEntity abstractJavaEntity) {
1410 String[] modifiers = abstractJavaEntity.getModifiers();
1411
1412 if (modifiers == null) {
1413 return false;
1414 }
1415
1416 for (String modifier : modifiers) {
1417 if (modifier.equals("public")) {
1418 return true;
1419 }
1420 }
1421
1422 return false;
1423 }
1424
1425 private boolean _isOverrideMethod(
1426 JavaClass javaClass, JavaMethod javaMethod,
1427 Collection<Tuple> ancestorJavaClassTuples) {
1428
1429 if (javaMethod.isConstructor() || javaMethod.isPrivate() ||
1430 javaMethod.isStatic() ||
1431 _overridesHigherJavaAPIVersion(javaMethod)) {
1432
1433 return false;
1434 }
1435
1436 String methodName = javaMethod.getName();
1437
1438 JavaParameter[] javaParameters = javaMethod.getParameters();
1439
1440 Type[] types = new Type[javaParameters.length];
1441
1442 for (int i = 0; i < javaParameters.length; i++) {
1443 types[i] = javaParameters[i].getType();
1444 }
1445
1446
1447
1448 for (Tuple ancestorJavaClassTuple : ancestorJavaClassTuples) {
1449 JavaClass ancestorJavaClass =
1450 (JavaClass)ancestorJavaClassTuple.getObject(0);
1451
1452 JavaMethod ancestorJavaMethod = null;
1453
1454 if (ancestorJavaClassTuple.getSize() > 1) {
1455
1456
1457
1458 Type[] ancestorActualTypeArguments =
1459 (Type[])ancestorJavaClassTuple.getObject(1);
1460
1461 Type[] genericTypes = new Type[types.length];
1462
1463 for (int i = 0; i < types.length; i++) {
1464 Type type = types[i];
1465
1466 String typeValue = type.getValue();
1467
1468 boolean useGenericType = false;
1469
1470 for (int j = 0; j < ancestorActualTypeArguments.length;
1471 j++) {
1472
1473 if (typeValue.equals(
1474 ancestorActualTypeArguments[j].getValue())) {
1475
1476 useGenericType = true;
1477
1478 break;
1479 }
1480 }
1481
1482 if (useGenericType) {
1483 genericTypes[i] = new Type("java.lang.Object");
1484 }
1485 else {
1486 genericTypes[i] = type;
1487 }
1488 }
1489
1490 ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1491 methodName, genericTypes);
1492 }
1493 else {
1494 ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1495 methodName, types);
1496 }
1497
1498 if (ancestorJavaMethod == null) {
1499 continue;
1500 }
1501
1502 boolean samePackage = false;
1503
1504 JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage();
1505
1506 if (ancestorJavaPackage != null) {
1507 samePackage = ancestorJavaPackage.equals(
1508 javaClass.getPackage());
1509 }
1510
1511
1512
1513 if (samePackage) {
1514 return !ancestorJavaMethod.isPrivate();
1515 }
1516
1517 if (ancestorJavaMethod.isProtected() ||
1518 ancestorJavaMethod.isPublic()) {
1519
1520 return true;
1521 }
1522 else {
1523 return false;
1524 }
1525
1526 }
1527
1528 return false;
1529 }
1530
1531 private boolean _overridesHigherJavaAPIVersion(JavaMethod javaMethod) {
1532 Annotation[] annotations = javaMethod.getAnnotations();
1533
1534 if (annotations == null) {
1535 return false;
1536 }
1537
1538 for (Annotation annotation : annotations) {
1539 Type type = annotation.getType();
1540
1541 JavaClass javaClass = type.getJavaClass();
1542
1543 String javaClassName = javaClass.getFullyQualifiedName();
1544
1545 if (javaClassName.equals(SinceJava.class.getName())) {
1546 AnnotationValue value = annotation.getProperty("value");
1547
1548 double sinceJava = GetterUtil.getDouble(
1549 value.getParameterValue());
1550
1551 if (sinceJava > _LOWEST_SUPPORTED_JAVA_VERSION) {
1552 return true;
1553 }
1554 }
1555 }
1556
1557 return false;
1558 }
1559
1560 private String _removeJavadocFromJava(JavaClass javaClass, String content) {
1561 Set<Integer> lineNumbers = new HashSet<Integer>();
1562
1563 lineNumbers.add(_getJavaClassLineNumber(javaClass));
1564
1565 JavaMethod[] javaMethods = javaClass.getMethods();
1566
1567 for (JavaMethod javaMethod : javaMethods) {
1568 lineNumbers.add(javaMethod.getLineNumber());
1569 }
1570
1571 JavaField[] javaFields = javaClass.getFields();
1572
1573 for (JavaField javaField : javaFields) {
1574 lineNumbers.add(javaField.getLineNumber());
1575 }
1576
1577 String[] lines = StringUtil.splitLines(content);
1578
1579 for (int lineNumber : lineNumbers) {
1580 if (lineNumber == 0) {
1581 continue;
1582 }
1583
1584 int pos = lineNumber - 2;
1585
1586 String line = lines[pos];
1587
1588 if (line == null) {
1589 continue;
1590 }
1591
1592 line = line.trim();
1593
1594 if (line.endsWith("*/")) {
1595 while (true) {
1596 lines[pos] = null;
1597
1598 if (line.startsWith("