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.parse(args);
069
070 CmdLineParser.Option commandOption = cmdLineParser.addStringOption(
071 "command");
072
073 String command = (String)cmdLineParser.getOptionValue(commandOption);
074
075 CmdLineParser.Option limitOption = cmdLineParser.addStringOption(
076 "limit");
077
078 String limit = (String)cmdLineParser.getOptionValue(limitOption);
079
080 CmdLineParser.Option ignoreAutogeneratedOption =
081 cmdLineParser.addBooleanOption("ignoreAutogenerated");
082
083 Boolean ignoreAutogenerated = (Boolean)cmdLineParser.getOptionValue(
084 ignoreAutogeneratedOption);
085
086 _process(command, limit, ignoreAutogenerated);
087 }
088
089 private void _addClassCommentElement(
090 Element rootElement, JavaClass javaClass) {
091
092 Element commentElement = rootElement.addElement("comment");
093
094 String comment = _getCDATA(javaClass);
095
096 if (comment.startsWith("Copyright (c) 2000-2010 Liferay, Inc.")) {
097 comment = StringPool.BLANK;
098 }
099
100 if (comment.startsWith(
101 "<a href=\"" + javaClass.getName() + ".java.html\">")) {
102
103 int pos = comment.indexOf("</a>");
104
105 comment = comment.substring(pos + 4).trim();
106 }
107
108 commentElement.addCDATA(comment);
109 }
110
111 private void _addDocletElements(
112 Element parentElement, AbstractJavaEntity abstractJavaEntity,
113 String name) {
114
115 DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name);
116
117 for (DocletTag docletTag : docletTags) {
118 String value = docletTag.getValue();
119
120 if (name.equals("author") || name.equals("see") ||
121 name.equals("since") || name.equals("version")) {
122
123
126
127 DocUtil.add(parentElement, name, value);
128 }
129 else {
130 Element element = parentElement.addElement(name);
131
132 element.addCDATA(value);
133 }
134 }
135 }
136
137 private void _addDocletTags(
138 Element parentElement, String name, String indent, StringBuilder sb) {
139
140 List<Element> elements = parentElement.elements(name);
141
142 for (Element element : elements) {
143 sb.append(indent);
144 sb.append(" * @");
145 sb.append(name);
146 sb.append(" ");
147
148 Element commentElement = element.element("comment");
149
150 if (commentElement != null) {
151 sb.append(element.elementText("name"));
152 sb.append(" ");
153 sb.append(_getCDATA(element.elementText("comment")));
154 }
155 else {
156 sb.append(_getCDATA(element.getText()));
157 }
158
159 sb.append("\n");
160 }
161 }
162
163 private void _addFieldElement(Element rootElement, JavaField javaField) {
164 Element fieldElement = rootElement.addElement("field");
165
166 DocUtil.add(fieldElement, "name", javaField.getName());
167
168 Element commentElement = fieldElement.addElement("comment");
169
170 commentElement.addCDATA(_getCDATA(javaField));
171
172 _addDocletElements(fieldElement, javaField, "deprecated");
173 _addDocletElements(fieldElement, javaField, "see");
174 _addDocletElements(fieldElement, javaField, "since");
175 _addDocletElements(fieldElement, javaField, "version");
176 }
177
178 private void _addMethodElement(Element rootElement, JavaMethod javaMethod) {
179 Element methodElement = rootElement.addElement("method");
180
181 DocUtil.add(methodElement, "name", javaMethod.getName());
182
183 Element commentElement = methodElement.addElement("comment");
184
185 commentElement.addCDATA(_getCDATA(javaMethod));
186
187 _addDocletElements(methodElement, javaMethod, "deprecated");
188 _addParamElements(methodElement, javaMethod);
189 _addReturnElement(methodElement, javaMethod);
190 _addDocletElements(methodElement, javaMethod, "see");
191 _addDocletElements(methodElement, javaMethod, "since");
192 _addThrowsElements(methodElement, javaMethod);
193 _addDocletElements(methodElement, javaMethod, "version");
194 }
195
196 private void _addParamElement(
197 Element methodElement, JavaParameter javaParameter,
198 DocletTag[] paramDocletTags) {
199
200 String name = javaParameter.getName();
201 String type = javaParameter.getType().getValue();
202 String value = null;
203
204 for (DocletTag paramDocletTag : paramDocletTags) {
205 String curValue = paramDocletTag.getValue();
206
207 if (!curValue.startsWith(name)) {
208 continue;
209 }
210 else {
211 curValue = value;
212
213 break;
214 }
215 }
216
217 Element paramElement = methodElement.addElement("param");
218
219 DocUtil.add(paramElement, "name", name);
220 DocUtil.add(paramElement, "type", type);
221
222 if (value != null) {
223 value = value.substring(name.length());
224 }
225
226 Element commentElement = paramElement.addElement("comment");
227
228 commentElement.addCDATA(_getCDATA(value));
229 }
230
231 private void _addParamElements(
232 Element methodElement, JavaMethod javaMethod) {
233
234 JavaParameter[] javaParameters = javaMethod.getParameters();
235
236 DocletTag[] paramDocletTags = javaMethod.getTagsByName("param");
237
238 for (JavaParameter javaParameter : javaParameters) {
239 _addParamElement(methodElement, javaParameter, paramDocletTags);
240 }
241 }
242
243 private void _addReturnElement(
244 Element methodElement, JavaMethod javaMethod) {
245
246 Type returns = javaMethod.getReturns();
247
248 if ((returns == null) || returns.getValue().equals("void")) {
249 return;
250 }
251
252 _addDocletElements(methodElement, javaMethod, "return");
253 }
254
255 private void _addThrowsElement(
256 Element methodElement, Type exception, DocletTag[] throwsDocletTags) {
257
258 String name = exception.getJavaClass().getName();
259 String value = null;
260
261 for (DocletTag throwsDocletTag : throwsDocletTags) {
262 String curValue = throwsDocletTag.getValue();
263
264 if (!curValue.startsWith(name)) {
265 continue;
266 }
267 else {
268 curValue = value;
269
270 break;
271 }
272 }
273
274 Element throwsElement = methodElement.addElement("throws");
275
276 DocUtil.add(throwsElement, "name", name);
277 DocUtil.add(throwsElement, "type", exception.getValue());
278
279 if (value != null) {
280 value = value.substring(name.length());
281 }
282
283 Element commentElement = throwsElement.addElement("comment");
284
285 commentElement.addCDATA(_getCDATA(value));
286
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(
371 Element rootElement, JavaClass javaClass) {
372
373 StringBuilder sb = new StringBuilder();
374
375 sb.append("\n");
391
392 return sb.toString();
393 }
394
395 private String _getJavadocXml(JavaClass javaClass) throws Exception {
396 Element rootElement = _saxReaderUtil.createElement("javadoc");
397
398 Document document = _saxReaderUtil.createDocument(rootElement);
399
400 DocUtil.add(rootElement, "name", javaClass.getName());
401 DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
402
403 _addClassCommentElement(rootElement, javaClass);
404 _addDocletElements(rootElement, javaClass, "author");
405 _addDocletElements(rootElement, javaClass, "deprecated");
406 _addDocletElements(rootElement, javaClass, "see");
407 _addDocletElements(rootElement, javaClass, "serial");
408 _addDocletElements(rootElement, javaClass, "since");
409 _addDocletElements(rootElement, javaClass, "version");
410
411 JavaMethod[] javaMethods = javaClass.getMethods();
412
413 for (JavaMethod javaMethod : javaMethods) {
414 _addMethodElement(rootElement, javaMethod);
415 }
416
417 JavaField[] javaFields = javaClass.getFields();
418
419 for (JavaField javaField : javaFields) {
420 _addFieldElement(rootElement, javaField);
421 }
422
423 return document.formattedString();
424 }
425
426 private String _getJavaFieldComment(
427 String[] lines, Map<String, Element> fieldElementsMap,
428 JavaField javaField) {
429
430 String fieldKey = _getFieldKey(javaField);
431
432 Element fieldElement = fieldElementsMap.get(fieldKey);
433
434 if (fieldElement == null) {
435 return null;
436 }
437
438 String line = lines[javaField.getLineNumber() - 1];
439
440 String indent = StringPool.BLANK;
441
442 for (char c : line.toCharArray()) {
443 if (Character.isWhitespace(c)) {
444 indent += c;
445 }
446 else {
447 break;
448 }
449 }
450
451 StringBuilder sb = new StringBuilder();
452
453 sb.append(indent);
454 sb.append("\n");
469
470 return sb.toString();
471 }
472
473 private String _getJavaMethodComment(
474 String[] lines, Map<String, Element> methodElementsMap,
475 JavaMethod javaMethod) {
476
477 String methodKey = _getMethodKey(javaMethod);
478
479 Element methodElement = methodElementsMap.get(methodKey);
480
481 if (methodElement == null) {
482 return null;
483 }
484
485 String line = lines[javaMethod.getLineNumber() - 1];
486
487 String indent = StringPool.BLANK;
488
489 for (char c : line.toCharArray()) {
490 if (Character.isWhitespace(c)) {
491 indent += c;
492 }
493 else {
494 break;
495 }
496 }
497
498 StringBuilder sb = new StringBuilder();
499
500 sb.append(indent);
501 sb.append("\n");
519
520 return sb.toString();
521 }
522
523 private String _getMethodKey(Element methodElement) {
524 StringBuilder sb = new StringBuilder();
525
526 sb.append(methodElement.elementText("name"));
527 sb.append(StringPool.OPEN_PARENTHESIS);
528
529 List<Element> paramElements = methodElement.elements("param");
530
531 for (Element paramElement : paramElements) {
532 sb.append(paramElement.elementText("name"));
533 sb.append("|");
534 sb.append(paramElement.elementText("type"));
535 sb.append(",");
536 }
537
538 sb.append(StringPool.CLOSE_PARENTHESIS);
539
540 return sb.toString();
541 }
542
543 private String _getMethodKey(JavaMethod javaMethod) {
544 StringBuilder sb = new StringBuilder();
545
546 sb.append(javaMethod.getName());
547 sb.append(StringPool.OPEN_PARENTHESIS);
548
549 JavaParameter[] javaParameters = javaMethod.getParameters();
550
551 for (JavaParameter javaParameter : javaParameters) {
552 sb.append(javaParameter.getName());
553 sb.append("|");
554 sb.append(javaParameter.getType().getValue());
555 sb.append(",");
556 }
557
558 sb.append(StringPool.CLOSE_PARENTHESIS);
559
560 return sb.toString();
561 }
562
563 private boolean _isGenerated(String content) {
564 if (content.contains("<javadoc autogenerated=\"true\">")) {
565 return true;
566 }
567 else {
568 return false;
569 }
570 }
571
572 private void _process(
573 String command, String limit, Boolean ignoreAutogenerated)
574 throws Exception {
575
576 DirectoryScanner ds = new DirectoryScanner();
577
578 ds.setBasedir(_basedir);
579 ds.setExcludes(
580 new String[] {
581 "**\\classes\\**", "**\\portal-client\\**", "**\\portal-web\\**"
582 });
583
584 List<String> includes = new ArrayList<String>();
585
586 if (Validator.isNotNull(limit) && !limit.startsWith("$")) {
587 String[] limitArray = StringUtil.split(limit, '/');
588
589 for (String curLimit : limitArray) {
590 includes.add(
591 "**\\" + StringUtil.replace(curLimit, ".", "\\") +
592 "\\**\\*.java");
593 includes.add("**\\" + curLimit + ".java");
594 }
595 }
596 else {
597 includes.add("**\\*.java");
598 }
599
600 ds.setIncludes(includes.toArray(new String[includes.size()]));
601
602 ds.scan();
603
604 String[] fileNames = ds.getIncludedFiles();
605
606 for (String fileName : fileNames) {
607 fileName = StringUtil.replace(fileName, "\\", "/");
608
609
612
613 if ((ignoreAutogenerated != null) &&
614 ignoreAutogenerated.booleanValue()) {
615
616 File file = new File(_basedir + fileName);
617
618 if (file.exists()) {
619 String oldContent = _fileUtil.read(
620 _basedir + fileName + "doc");
621
622 if (_isGenerated(oldContent)) {
623 continue;
624 }
625 }
626 }
627
628 if (command.equals("cleanup")) {
629 _processGet(fileName);
630 _processSave(fileName);
631 _processDelete(fileName);
632 }
633 else if (command.equals("commit")) {
634 _processSave(fileName);
635 _processDelete(fileName);
636 }
637 else if (command.equals("delete")) {
638 _processDelete(fileName);
639 }
640 else if (command.equals("get")) {
641 _processGet(fileName);
642 }
643 else if (command.equals("save")) {
644 _processSave(fileName);
645 }
646 }
647 }
648
649 private void _processDelete(String fileName) throws Exception {
650 _removeJavadocFromJava(fileName, true);
651 }
652
653 private void _processGet(String fileName) throws Exception {
654 File javadocFile = new File(_basedir + fileName + "doc");
655
656 if (!javadocFile.exists()) {
657 _updateJavadocFromJava(fileName);
658 }
659
660 String javaWithoutJavadoc = _removeJavadocFromJava(fileName, false);
661
662 _updateJavaFromJavadoc(fileName, javaWithoutJavadoc);
663 }
664
665 private void _processSave(String fileName) throws Exception {
666 _updateJavadocFromJava(fileName);
667 }
668
669 private String _removeJavadocFromJava(String fileName, boolean log)
670 throws Exception {
671
672 File file = new File(_basedir + fileName);
673
674 String oldContent = _fileUtil.read(file);
675
676 String[] lines = StringUtil.splitLines(oldContent);
677
678 JavaClass javaClass = _getJavaClass(
679 fileName, new UnsyncStringReader(oldContent));
680
681 Set<Integer> lineNumbers = new HashSet<Integer>();
682
683 lineNumbers.add(javaClass.getLineNumber());
684
685 JavaMethod[] javaMethods = javaClass.getMethods();
686
687 for (JavaMethod javaMethod : javaMethods) {
688 lineNumbers.add(javaMethod.getLineNumber());
689 }
690
691 JavaField[] javaFields = javaClass.getFields();
692
693 for (JavaField javaField : javaFields) {
694 lineNumbers.add(javaField.getLineNumber());
695 }
696
697 for (int lineNumber : lineNumbers) {
698 int pos = lineNumber - 2;
699
700 String line = lines[pos].trim();
701
702 if (line.endsWith("*/")) {
703 while (true) {
704 lines[pos] = null;
705
706 if (line.startsWith("