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