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