001
014
015 package com.liferay.portal.tools;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
018 import com.liferay.portal.kernel.util.StringPool;
019 import com.liferay.portal.kernel.util.StringUtil;
020 import com.liferay.portal.kernel.util.Validator;
021 import com.liferay.portal.kernel.xml.Document;
022 import com.liferay.portal.kernel.xml.Element;
023 import com.liferay.portal.kernel.xml.SAXReader;
024 import com.liferay.portal.util.FileImpl;
025 import com.liferay.portal.xml.SAXReaderImpl;
026 import com.liferay.util.xml.DocUtil;
027
028 import com.thoughtworks.qdox.JavaDocBuilder;
029 import com.thoughtworks.qdox.model.AbstractJavaEntity;
030 import com.thoughtworks.qdox.model.DocletTag;
031 import com.thoughtworks.qdox.model.JavaClass;
032 import com.thoughtworks.qdox.model.JavaField;
033 import com.thoughtworks.qdox.model.JavaMethod;
034 import com.thoughtworks.qdox.model.JavaParameter;
035 import com.thoughtworks.qdox.model.Type;
036
037 import jargs.gnu.CmdLineParser;
038
039 import java.io.File;
040 import java.io.Reader;
041
042 import java.util.ArrayList;
043 import java.util.HashMap;
044 import java.util.HashSet;
045 import java.util.List;
046 import java.util.Map;
047 import java.util.Set;
048 import java.util.TreeMap;
049
050 import org.apache.tools.ant.DirectoryScanner;
051
052
055 public class JavadocBuilder {
056
057 public static void main(String[] args) {
058 try {
059 new JavadocBuilder(args);
060 }
061 catch (Exception e) {
062 e.printStackTrace();
063 }
064 }
065
066 public JavadocBuilder(String[] args) throws Exception {
067 CmdLineParser cmdLineParser = new CmdLineParser();
068
069 cmdLineParser.parse(args);
070
071 CmdLineParser.Option commandOption = cmdLineParser.addStringOption(
072 "command");
073
074 String command = (String)cmdLineParser.getOptionValue(commandOption);
075
076 CmdLineParser.Option limitOption = cmdLineParser.addStringOption(
077 "limit");
078
079 String limit = (String)cmdLineParser.getOptionValue(limitOption);
080
081 CmdLineParser.Option ignoreAutogeneratedOption =
082 cmdLineParser.addBooleanOption("ignoreAutogenerated");
083
084 Boolean ignoreAutogenerated = (Boolean)cmdLineParser.getOptionValue(
085 ignoreAutogeneratedOption);
086
087 _process(command, limit, ignoreAutogenerated);
088 }
089
090 private void _addClassCommentElement(
091 Element rootElement, JavaClass javaClass) {
092
093 Element commentElement = rootElement.addElement("comment");
094
095 String comment = _getCDATA(javaClass);
096
097 if (comment.startsWith("Copyright (c) 2000-present Liferay, Inc.")) {
098 comment = StringPool.BLANK;
099 }
100
101 if (comment.startsWith(
102 "<a href=\"" + javaClass.getName() + ".java.html\">")) {
103
104 int pos = comment.indexOf("</a>");
105
106 comment = comment.substring(pos + 4).trim();
107 }
108
109 commentElement.addCDATA(comment);
110 }
111
112 private void _addDocletElements(
113 Element parentElement, AbstractJavaEntity abstractJavaEntity,
114 String name) {
115
116 DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name);
117
118 for (DocletTag docletTag : docletTags) {
119 String value = docletTag.getValue();
120
121 if (name.equals("author") || name.equals("see") ||
122 name.equals("since") || name.equals("version")) {
123
124
127
128 DocUtil.add(parentElement, name, value);
129 }
130 else {
131 Element element = parentElement.addElement(name);
132
133 element.addCDATA(value);
134 }
135 }
136 }
137
138 private void _addDocletTags(
139 Element parentElement, String name, String indent, StringBuilder sb) {
140
141 List<Element> elements = parentElement.elements(name);
142
143 for (Element element : elements) {
144 sb.append(indent);
145 sb.append(" * @");
146 sb.append(name);
147 sb.append(" ");
148
149 Element commentElement = element.element("comment");
150
151 if (commentElement != null) {
152 sb.append(element.elementText("name"));
153 sb.append(" ");
154 sb.append(_getCDATA(element.elementText("comment")));
155 }
156 else {
157 sb.append(_getCDATA(element.getText()));
158 }
159
160 sb.append("\n");
161 }
162 }
163
164 private void _addFieldElement(Element rootElement, JavaField javaField) {
165 Element fieldElement = rootElement.addElement("field");
166
167 DocUtil.add(fieldElement, "name", javaField.getName());
168
169 Element commentElement = fieldElement.addElement("comment");
170
171 commentElement.addCDATA(_getCDATA(javaField));
172
173 _addDocletElements(fieldElement, javaField, "deprecated");
174 _addDocletElements(fieldElement, javaField, "see");
175 _addDocletElements(fieldElement, javaField, "since");
176 _addDocletElements(fieldElement, javaField, "version");
177 }
178
179 private void _addMethodElement(Element rootElement, JavaMethod javaMethod) {
180 Element methodElement = rootElement.addElement("method");
181
182 DocUtil.add(methodElement, "name", javaMethod.getName());
183
184 Element commentElement = methodElement.addElement("comment");
185
186 commentElement.addCDATA(_getCDATA(javaMethod));
187
188 _addDocletElements(methodElement, javaMethod, "deprecated");
189 _addParamElements(methodElement, javaMethod);
190 _addReturnElement(methodElement, javaMethod);
191 _addDocletElements(methodElement, javaMethod, "see");
192 _addDocletElements(methodElement, javaMethod, "since");
193 _addThrowsElements(methodElement, javaMethod);
194 _addDocletElements(methodElement, javaMethod, "version");
195 }
196
197 private void _addParamElement(
198 Element methodElement, JavaParameter javaParameter,
199 DocletTag[] paramDocletTags) {
200
201 String name = javaParameter.getName();
202 String type = javaParameter.getType().getValue();
203 String value = null;
204
205 for (DocletTag paramDocletTag : paramDocletTags) {
206 String curValue = paramDocletTag.getValue();
207
208 if (!curValue.startsWith(name)) {
209 continue;
210 }
211 else {
212 curValue = value;
213
214 break;
215 }
216 }
217
218 Element paramElement = methodElement.addElement("param");
219
220 DocUtil.add(paramElement, "name", name);
221 DocUtil.add(paramElement, "type", type);
222
223 if (value != null) {
224 value = value.substring(name.length());
225 }
226
227 Element commentElement = paramElement.addElement("comment");
228
229 commentElement.addCDATA(_getCDATA(value));
230 }
231
232 private void _addParamElements(
233 Element methodElement, JavaMethod javaMethod) {
234
235 JavaParameter[] javaParameters = javaMethod.getParameters();
236
237 DocletTag[] paramDocletTags = javaMethod.getTagsByName("param");
238
239 for (JavaParameter javaParameter : javaParameters) {
240 _addParamElement(methodElement, javaParameter, paramDocletTags);
241 }
242 }
243
244 private void _addReturnElement(
245 Element methodElement, JavaMethod javaMethod) {
246
247 Type returnType = javaMethod.getReturnType();
248
249 if ((returnType == null) || returnType.getValue().equals("void")) {
250 return;
251 }
252
253 _addDocletElements(methodElement, javaMethod, "return");
254 }
255
256 private void _addThrowsElement(
257 Element methodElement, Type exception, DocletTag[] throwsDocletTags) {
258
259 String name = exception.getJavaClass().getName();
260 String value = null;
261
262 for (DocletTag throwsDocletTag : throwsDocletTags) {
263 String curValue = throwsDocletTag.getValue();
264
265 if (!curValue.startsWith(name)) {
266 continue;
267 }
268 else {
269 curValue = value;
270
271 break;
272 }
273 }
274
275 Element throwsElement = methodElement.addElement("throws");
276
277 DocUtil.add(throwsElement, "name", name);
278 DocUtil.add(throwsElement, "type", exception.getValue());
279
280 if (value != null) {
281 value = value.substring(name.length());
282 }
283
284 Element commentElement = throwsElement.addElement("comment");
285
286 commentElement.addCDATA(_getCDATA(value));
287 }
288
289 private void _addThrowsElements(
290 Element methodElement, JavaMethod javaMethod) {
291
292 Type[] exceptions = javaMethod.getExceptions();
293
294 DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws");
295
296 for (Type exception : exceptions) {
297 _addThrowsElement(methodElement, exception, throwsDocletTags);
298 }
299 }
300
301 private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
302 return _getCDATA(abstractJavaEntity.getComment());
303 }
304
305 private String _getCDATA(String cdata) {
306 if (cdata == null) {
307 return StringPool.BLANK;
308 }
309
310 cdata = StringUtil.replace(
311 cdata, new String[] {"\n", "<p>", "</p>"},
312 new String[] {" ", " <p> ", " </p> "});
313
314 while (cdata.contains(" ")) {
315 cdata = StringUtil.replace(cdata, " ", " ");
316 }
317
318 return cdata.trim();
319 }
320
321 private String _getFieldKey(Element fieldElement) {
322 return fieldElement.elementText("name");
323 }
324
325 private String _getFieldKey(JavaField javaField) {
326 return javaField.getName();
327 }
328
329 private JavaClass _getJavaClass(String fileName) throws Exception {
330 return _getJavaClass(fileName, null);
331 }
332
333 private JavaClass _getJavaClass(String fileName, Reader reader)
334 throws Exception {
335
336 int pos = fileName.indexOf("src/");
337
338 if (pos == -1) {
339 pos = fileName.indexOf("test/");
340 }
341
342 if (pos == -1) {
343 throw new RuntimeException(fileName);
344 }
345
346 pos = fileName.indexOf("/", pos);
347
348 String srcFile = fileName.substring(pos + 1);
349 String className = StringUtil.replace(
350 srcFile.substring(0, srcFile.length() - 5), "/", ".");
351
352 JavaDocBuilder builder = new JavaDocBuilder();
353
354 if (reader == null) {
355 File file = new File(fileName);
356
357 if (!file.exists()) {
358 return null;
359 }
360
361 builder.addSource(file);
362 }
363 else {
364 builder.addSource(reader);
365 }
366
367 return builder.getClassByName(className);
368 }
369
370 private String _getJavaClassComment(Element rootElement) {
371 StringBuilder sb = new StringBuilder();
372
373 sb.append("\n");
389
390 return sb.toString();
391 }
392
393 private String _getJavadocXml(JavaClass javaClass) throws Exception {
394 Element rootElement = _saxReader.createElement("javadoc");
395
396 Document document = _saxReader.createDocument(rootElement);
397
398 DocUtil.add(rootElement, "name", javaClass.getName());
399 DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
400
401 _addClassCommentElement(rootElement, javaClass);
402 _addDocletElements(rootElement, javaClass, "author");
403 _addDocletElements(rootElement, javaClass, "deprecated");
404 _addDocletElements(rootElement, javaClass, "see");
405 _addDocletElements(rootElement, javaClass, "serial");
406 _addDocletElements(rootElement, javaClass, "since");
407 _addDocletElements(rootElement, javaClass, "version");
408
409 JavaMethod[] javaMethods = javaClass.getMethods();
410
411 for (JavaMethod javaMethod : javaMethods) {
412 _addMethodElement(rootElement, javaMethod);
413 }
414
415 JavaField[] javaFields = javaClass.getFields();
416
417 for (JavaField javaField : javaFields) {
418 _addFieldElement(rootElement, javaField);
419 }
420
421 return document.formattedString();
422 }
423
424 private String _getJavaFieldComment(
425 String[] lines, Map<String, Element> fieldElementsMap,
426 JavaField javaField) {
427
428 String fieldKey = _getFieldKey(javaField);
429
430 Element fieldElement = fieldElementsMap.get(fieldKey);
431
432 if (fieldElement == null) {
433 return null;
434 }
435
436 String line = lines[javaField.getLineNumber() - 1];
437
438 String indent = StringPool.BLANK;
439
440 for (char c : line.toCharArray()) {
441 if (Character.isWhitespace(c)) {
442 indent += c;
443 }
444 else {
445 break;
446 }
447 }
448
449 StringBuilder sb = new StringBuilder();
450
451 sb.append(indent);
452 sb.append("\n");
467
468 return sb.toString();
469 }
470
471 private String _getJavaMethodComment(
472 String[] lines, Map<String, Element> methodElementsMap,
473 JavaMethod javaMethod) {
474
475 String methodKey = _getMethodKey(javaMethod);
476
477 Element methodElement = methodElementsMap.get(methodKey);
478
479 if (methodElement == null) {
480 return null;
481 }
482
483 String line = lines[javaMethod.getLineNumber() - 1];
484
485 String indent = StringPool.BLANK;
486
487 for (char c : line.toCharArray()) {
488 if (Character.isWhitespace(c)) {
489 indent += c;
490 }
491 else {
492 break;
493 }
494 }
495
496 StringBuilder sb = new StringBuilder();
497
498 sb.append(indent);
499 sb.append("\n");
517
518 return sb.toString();
519 }
520
521 private String _getMethodKey(Element methodElement) {
522 StringBuilder sb = new StringBuilder();
523
524 sb.append(methodElement.elementText("name"));
525 sb.append(StringPool.OPEN_PARENTHESIS);
526
527 List<Element> paramElements = methodElement.elements("param");
528
529 for (Element paramElement : paramElements) {
530 sb.append(paramElement.elementText("name"));
531 sb.append("|");
532 sb.append(paramElement.elementText("type"));
533 sb.append(",");
534 }
535
536 sb.append(StringPool.CLOSE_PARENTHESIS);
537
538 return sb.toString();
539 }
540
541 private String _getMethodKey(JavaMethod javaMethod) {
542 StringBuilder sb = new StringBuilder();
543
544 sb.append(javaMethod.getName());
545 sb.append(StringPool.OPEN_PARENTHESIS);
546
547 JavaParameter[] javaParameters = javaMethod.getParameters();
548
549 for (JavaParameter javaParameter : javaParameters) {
550 sb.append(javaParameter.getName());
551 sb.append("|");
552 sb.append(javaParameter.getType().getValue());
553 sb.append(",");
554 }
555
556 sb.append(StringPool.CLOSE_PARENTHESIS);
557
558 return sb.toString();
559 }
560
561 private boolean _isGenerated(String content) {
562 if (content.contains("<javadoc autogenerated=\"true\">")) {
563 return true;
564 }
565 else {
566 return false;
567 }
568 }
569
570 private void _process(
571 String command, String limit, Boolean ignoreAutogenerated)
572 throws Exception {
573
574 DirectoryScanner ds = new DirectoryScanner();
575
576 ds.setBasedir(_BASEDIR);
577 ds.setExcludes(
578 new String[] {
579 "**\\classes\\**", "**\\portal-client\\**", "**\\portal-web\\**"
580 });
581
582 List<String> includes = new ArrayList<>();
583
584 if (Validator.isNotNull(limit) && !limit.startsWith("$")) {
585 String[] limitArray = StringUtil.split(limit, '/');
586
587 for (String curLimit : limitArray) {
588 includes.add(
589 "**\\" + StringUtil.replace(curLimit, ".", "\\") +
590 "\\**\\*.java");
591 includes.add("**\\" + curLimit + ".java");
592 }
593 }
594 else {
595 includes.add("**\\*.java");
596 }
597
598 ds.setIncludes(includes.toArray(new String[includes.size()]));
599
600 ds.scan();
601
602 String[] fileNames = ds.getIncludedFiles();
603
604 for (String fileName : fileNames) {
605 fileName = StringUtil.replace(fileName, "\\", "/");
606
607
610
611 if ((ignoreAutogenerated != null) &&
612 ignoreAutogenerated.booleanValue()) {
613
614 File file = new File(_BASEDIR + fileName);
615
616 if (file.exists()) {
617 String oldContent = _fileUtil.read(
618 _BASEDIR + fileName + "doc");
619
620 if (_isGenerated(oldContent)) {
621 continue;
622 }
623 }
624 }
625
626 if (command.equals("cleanup")) {
627 _processGet(fileName);
628 _processSave(fileName);
629 _processDelete(fileName);
630 }
631 else if (command.equals("commit")) {
632 _processSave(fileName);
633 _processDelete(fileName);
634 }
635 else if (command.equals("delete")) {
636 _processDelete(fileName);
637 }
638 else if (command.equals("get")) {
639 _processGet(fileName);
640 }
641 else if (command.equals("save")) {
642 _processSave(fileName);
643 }
644 }
645 }
646
647 private void _processDelete(String fileName) throws Exception {
648 _removeJavadocFromJava(fileName, true);
649 }
650
651 private void _processGet(String fileName) throws Exception {
652 File javadocFile = new File(_BASEDIR + fileName + "doc");
653
654 if (!javadocFile.exists()) {
655 _updateJavadocFromJava(fileName);
656 }
657
658 String javaWithoutJavadoc = _removeJavadocFromJava(fileName, false);
659
660 _updateJavaFromJavadoc(fileName, javaWithoutJavadoc);
661 }
662
663 private void _processSave(String fileName) throws Exception {
664 _updateJavadocFromJava(fileName);
665 }
666
667 private String _removeJavadocFromJava(String fileName, boolean log)
668 throws Exception {
669
670 File file = new File(_BASEDIR + fileName);
671
672 String oldContent = _fileUtil.read(file);
673
674 String[] lines = StringUtil.splitLines(oldContent);
675
676 JavaClass javaClass = _getJavaClass(
677 fileName, new UnsyncStringReader(oldContent));
678
679 Set<Integer> lineNumbers = new HashSet<>();
680
681 lineNumbers.add(javaClass.getLineNumber());
682
683 JavaMethod[] javaMethods = javaClass.getMethods();
684
685 for (JavaMethod javaMethod : javaMethods) {
686 lineNumbers.add(javaMethod.getLineNumber());
687 }
688
689 JavaField[] javaFields = javaClass.getFields();
690
691 for (JavaField javaField : javaFields) {
692 lineNumbers.add(javaField.getLineNumber());
693 }
694
695 for (int lineNumber : lineNumbers) {
696 int pos = lineNumber - 2;
697
698 String line = lines[pos].trim();
699
700 if (line.endsWith("*/")) {
701 while (true) {
702 lines[pos] = null;
703
704 if (line.startsWith("