1 16 package org.apache.cocoon.components.source.impl; 17 18 import java.io.BufferedReader ; 19 import java.io.ByteArrayInputStream ; 20 import java.io.ByteArrayOutputStream ; 21 import java.io.IOException ; 22 import java.io.InputStream ; 23 import java.io.InputStreamReader ; 24 import java.net.MalformedURLException ; 25 import java.util.ArrayList ; 26 import java.util.HashMap ; 27 import java.util.List ; 28 import java.util.Map ; 29 30 import com.thoughtworks.qdox.JavaDocBuilder; 31 import com.thoughtworks.qdox.model.AbstractJavaEntity; 32 import com.thoughtworks.qdox.model.DocletTag; 33 import com.thoughtworks.qdox.model.JavaClass; 34 import com.thoughtworks.qdox.model.JavaField; 35 import com.thoughtworks.qdox.model.JavaMethod; 36 import com.thoughtworks.qdox.model.JavaParameter; 37 import com.thoughtworks.qdox.model.JavaSource; 38 import com.thoughtworks.qdox.model.Type; 39 40 import org.apache.avalon.excalibur.pool.Recyclable; 41 import org.apache.avalon.framework.logger.Logger; 42 import org.apache.avalon.framework.service.ServiceException; 43 import org.apache.avalon.framework.service.ServiceManager; 44 import org.apache.cocoon.serialization.XMLSerializer; 45 import org.apache.cocoon.xml.XMLUtils; 46 47 import org.apache.commons.lang.StringUtils; 48 import org.apache.excalibur.source.Source; 49 import org.apache.excalibur.source.SourceException; 50 import org.apache.excalibur.source.SourceResolver; 51 import org.apache.excalibur.source.SourceValidity; 52 import org.apache.excalibur.source.impl.AbstractSource; 53 import org.apache.excalibur.xml.sax.XMLizable; 54 import org.apache.regexp.RE; 55 import org.apache.regexp.RESyntaxException; 56 import org.xml.sax.ContentHandler ; 57 import org.xml.sax.SAXException ; 58 import org.xml.sax.helpers.AttributesImpl ; 59 60 66 public final class QDoxSource extends AbstractSource 67 implements XMLizable, Recyclable { 68 69 protected final static String ROOT_CLASSNAME = "java.lang.Object"; 70 71 protected final static String PROTOCOL = "qdox:"; 72 protected final static String NS_URI = "http://apache.org/cocoon/javadoc/1.0"; 73 protected final static String NS_PREFIX = "jd"; 74 protected final static String ATTR_TYPE = "NMTOKEN"; 75 76 protected final static String CLASS_ELEMENT = "class"; 77 protected final static String CLASSNAME_ATTRIBUTE = "name"; 78 protected final static String PACKAGE_ATTRIBUTE = "package"; 79 protected final static String QNAME_ATTRIBUTE = "qname"; 80 protected final static String INHERIT_ELEMENT = "inherit"; 81 protected final static String INNERCLASSES_ELEMENT = "innerclasses"; 82 protected final static String NESTED_IN_ELEMENT = "nested-in"; 83 protected final static String IMPORTS_ELEMENT = "imports"; 84 protected final static String IMPORT_ELEMENT = "import"; 85 protected final static String IMPORT_ATTRIBUTE = "type"; 86 protected final static String IMPLEMENTS_ELEMENT = "implements"; 87 protected final static String INTERFACE_ELEMENT = "interface"; 88 protected final static String MODIFIERS_ELEMENT = "modifiers"; 89 protected final static String COMMENT_ELEMENT = "comment"; 90 protected final static String LINK_ELEMENT = "link"; 91 protected final static String LINK_CLASS_ATTRIBUTE = "class"; 92 protected final static String LINK_MEMBER_ATTRIBUTE = "member"; 93 protected final static String HREF_ATTRIBUTE = "uri"; 94 protected final static String TAGS_ELEMENT = "tags"; 95 protected final static String FIELDS_ELEMENT = "fields"; 96 protected final static String FIELD_ELEMENT = "field"; 97 protected final static String CONSTRUCTORS_ELEMENT = "constructors"; 98 protected final static String CONSTRUCTOR_ELEMENT = "constructor"; 99 protected final static String METHODS_ELEMENT = "methods"; 100 protected final static String METHOD_ELEMENT = "method"; 101 protected final static String NAME_ATTRIBUTE = "name"; 102 protected final static String TYPE_ATTRIBUTE = "type"; 103 protected final static String DIMENSIONS_ATTRIBUTE = "dimensions"; 104 protected final static String SIGNATURE_ATTRIBUTE = "signature"; 105 protected final static String PARAMETERS_ELEMENT = "parameters"; 106 protected final static String PARAMETER_ELEMENT = "parameter"; 107 protected final static String THROWS_ELEMENT = "throws"; 108 protected final static String EXCEPTION_ELEMENT = "exception"; 109 110 protected final static int CONSTRUCTOR_MODE = 1; 111 protected final static int METHOD_MODE = 2; 112 113 protected final static int CLASS_INHERITANCE = 1; 114 protected final static int INTERFACE_INHERITANCE = 2; 115 protected final static int INNERCLASS_INHERITANCE = 3; 116 protected final static int FIELD_INHERITANCE = 4; 117 protected final static int CONSTRUCTOR_INHERITANCE = 5; 118 protected final static int METHOD_INHERITANCE = 6; 119 120 protected ServiceManager manager; 121 protected Logger logger; 122 123 protected Source javaSource; 124 protected String javadocUri; 125 protected String javadocClassName; 126 protected JavaClass javadocClass; 127 protected JavaClass containingJavadocClass; protected Map classMap; 129 130 134 protected RE reLink; 135 136 153 protected final static String RE_LINK = "\\{@link\\s+((([\\w.#,$&;\\s]+)|([\\w.#,$&;(\\s]+[\\w.#,$&;)\\s]+))\\s+([\\w()#.,$&;\\s]+)|([\\w.#,$&;\\s()]+))\\s*\\}"; 154 155 163 public QDoxSource(String location, Source javaSource, Logger logger, ServiceManager manager) { 164 this.javadocUri = location; 165 this.javaSource = javaSource; 166 this.logger = logger; 167 this.manager = manager; 168 this.javadocClassName = javadocUri.substring(javadocUri.indexOf(':') + 1); 169 try { 170 createJavadocXml(); 171 } catch (SourceException se) { 172 logger.error("Error reading source!", se); 173 } catch (IOException ioe) { 174 logger.error("Error reading source!", ioe); 175 } 176 try { 178 reLink = new RE(RE_LINK); 179 } catch (RESyntaxException rse) { 180 logger.error("Regular Expression syntax error!", rse); 181 } 182 } 183 184 189 public JavaClass getJavadocClass() { 190 return javadocClass; 191 } 192 193 197 public void toSAX(ContentHandler handler) throws SAXException { 198 if (javadocClass == null) { 199 logger.error("No classfile loaded! Cannot output SAX events."); 200 return; 201 } 202 203 if (logger.isDebugEnabled()) { 204 logger.debug("Outputting SAX events for class " + javadocClass.getFullyQualifiedName()); 205 logger.debug(" #fields: " + javadocClass.getFields().length); 206 logger.debug(" #methods and constructors: " + javadocClass.getMethods().length); 207 } 208 209 handler.startDocument(); 211 handler.startPrefixMapping(NS_PREFIX, NS_URI); 212 213 outputClassStartElement(handler, javadocClass); 215 216 outputModifiers(handler, javadocClass); 218 219 JavaSource parent = javadocClass.getParentSource(); 221 parent.addImport("java.lang.*"); 223 if (parent.getPackage() != null) { 224 parent.addImport(parent.getPackage() + ".*"); 225 } else { 226 parent.addImport("*"); 227 } 228 String [] imports = parent.getImports(); 229 230 saxStartElement(handler, IMPORTS_ELEMENT); 231 for (int i = 0; i < imports.length; i++) { 232 if (imports[i].endsWith("*")) { 233 saxStartElement(handler, IMPORT_ELEMENT, new String [][] {{IMPORT_ATTRIBUTE, "package"}}); 235 String imp = StringUtils.substringBeforeLast(imports[i], ".*"); 236 saxCharacters(handler, imp); 237 } else { 238 saxStartElement(handler, IMPORT_ELEMENT, new String [][] {{IMPORT_ATTRIBUTE, "class"}}); 239 saxCharacters(handler, imports[i]); 240 } 241 saxEndElement(handler, IMPORT_ELEMENT); 242 } 243 saxEndElement(handler, IMPORTS_ELEMENT); 244 245 if (!javadocClass.isInterface()) { 247 outputSuperClassInheritance(handler, javadocClass, CLASS_INHERITANCE); 248 } 249 250 outputImplements(handler, javadocClass, true); 252 253 if (containingJavadocClass != null) { 255 saxStartElement(handler, NESTED_IN_ELEMENT); 256 outputClassStartElement(handler, containingJavadocClass); 257 outputModifiers(handler, containingJavadocClass); 258 outputComment(handler, containingJavadocClass.getComment()); 259 outputTags(handler, containingJavadocClass); 260 outputClassEndElement(handler, containingJavadocClass); 261 saxEndElement(handler, NESTED_IN_ELEMENT); 262 } 263 264 outputComment(handler, javadocClass.getComment()); 266 267 outputTags(handler, javadocClass); 269 270 outputInnerClasses(handler, javadocClass, true); 272 273 outputFields(handler, javadocClass, true); 275 276 outputMethods(handler, javadocClass, CONSTRUCTOR_MODE); 278 279 outputMethods(handler, javadocClass, METHOD_MODE); 281 282 outputClassEndElement(handler, javadocClass); 284 285 handler.endPrefixMapping(NS_PREFIX); 287 handler.endDocument(); 288 } 289 290 293 public void recycle() { 294 if (logger != null && logger.isDebugEnabled()) { 295 logger.debug("Recycling QDoxSource '" + javadocClassName + "'..."); 296 } 297 298 manager = null; 299 javaSource = null; 300 javadocUri = null; 301 javadocClassName = null; 302 javadocClass = null; 303 containingJavadocClass = null; 304 classMap = null; 305 logger = null; 306 } 307 308 312 public long getContentLength() { 313 return -1L; 314 } 315 316 319 public long getLastModified() { 320 return javaSource.getLastModified(); 321 } 322 323 326 public String getMimeType() { 327 return "text/xml"; 328 } 329 330 333 public String getURI() { 334 return javadocUri; 335 } 336 337 340 public SourceValidity getValidity() { 341 return javaSource.getValidity(); 342 } 343 344 347 public InputStream getInputStream() throws IOException , SourceException { 348 if (logger.isDebugEnabled()) { 349 logger.debug("Getting InputStream for class " + javadocClass.getFullyQualifiedName()); 350 } 351 XMLSerializer serializer = new XMLSerializer(); 352 ByteArrayInputStream inputStream = null; 353 354 try { 355 ByteArrayOutputStream outputStream = new ByteArrayOutputStream (2048); 356 serializer.setOutputStream(outputStream); 357 toSAX(serializer); 358 inputStream = new ByteArrayInputStream (outputStream.toByteArray()); 359 } catch (SAXException se) { 360 logger.error("SAX exception!", se); 361 throw new SourceException("Serializing SAX to a ByteArray failed!", se); 362 } 363 return inputStream; 364 } 365 366 protected void createJavadocXml() throws SourceException, IOException { 367 if (logger.isDebugEnabled()) { 368 logger.debug("Reading Java source " + javaSource.getURI()); 369 } 370 JavaDocBuilder builder = new JavaDocBuilder(); 371 builder.addSource(new BufferedReader (new InputStreamReader (javaSource.getInputStream()))); 372 373 javadocClass = builder.getClassByName(javadocClassName); 374 if (javadocClass.getPackage() == null) { 375 int index = javadocClassName.lastIndexOf('.'); 377 String containingClassName = javadocClassName.substring(0, index); 378 String innerClassName = javadocClassName.substring(index + 1); 379 containingJavadocClass = builder.getClassByName(containingClassName); 380 javadocClass = containingJavadocClass.getInnerClassByName(innerClassName); 381 } 382 } 383 384 390 private String resolveClassNameFromLink(String ref) { 391 String classPart = null; 392 int hashIndex = ref.indexOf('#'); 393 if (hashIndex < 0) { 394 classPart = ref; 395 } else { 396 classPart = ref.substring(0, hashIndex); 397 } 398 return getQualifiedClassName(classPart); 399 } 400 401 private String getQualifiedClassName(String classPart) { 402 if (classPart.length() == 0) { 403 classPart = javadocClass.getFullyQualifiedName(); 405 } else if (classPart.equals("Object")) { 406 classPart = ROOT_CLASSNAME; 408 } else if (classPart.indexOf('.') < 0) { 409 String [] imports = javadocClass.getParentSource().getImports(); 411 List classImports = new ArrayList (); 412 List packageImports = new ArrayList (); 413 packageImports.add(javadocClass.getPackage()); packageImports.add("java.lang"); for (int i=0; i<imports.length; i++) { 416 if (imports[i].endsWith(".*")) { 417 packageImports.add(imports[i].substring(0, imports[i].length() - 2)); 418 } else if (imports[i].endsWith("*")) { 419 packageImports.add(imports[i].substring(0, imports[i].length() - 1)); 420 } else { 421 classImports.add(imports[i]); 422 } 423 } 424 425 boolean found = false; 426 for (int i = 0; !found && i < classImports.size(); i++) { 427 String name = (String ) classImports.get(i); 428 if (name.endsWith(classPart)) { 429 classPart = name; 430 found = true; 431 } 432 } 433 434 if (!found) { 435 SourceResolver resolver = null; 436 try { 437 resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 438 for (int i=0; !found && i<packageImports.size(); i++) { 439 String name = (String ) packageImports.get(i); 440 if (name.length() == 0) { 441 name = classPart; 442 } else { 443 name += '.' + classPart; 444 } 445 446 Source source = resolver.resolveURI(PROTOCOL + name); 448 found = source != null && source instanceof QDoxSource; 449 if (found) { 450 classPart = name; 451 } 452 453 resolver.release(source); 454 } 455 } catch (ServiceException se) { 456 logger.error("Could not find a SourceResolver!", se); 457 } catch (MalformedURLException e) { 458 } catch (SourceException e) { 460 } catch (IOException e) { 462 } finally { 464 if (resolver != null) { 465 manager.release(resolver); 466 } 467 } 468 } 469 } 470 return classPart; 471 } 472 473 479 private void outputSuperClassInheritance(ContentHandler handler, JavaClass jClass, int mode) throws SAXException { 480 JavaClass superClass = getJavadocSuperClass(jClass); 481 if (superClass != null && hasInheritance(jClass, mode)) { 482 outputClassInheritance(handler, superClass, mode); 483 } 484 } 485 486 private void outputClassInheritance(ContentHandler handler, JavaClass jClass, int mode) throws SAXException { 487 outputInheritStartElement(handler, jClass); 488 489 switch (mode) { 490 case CLASS_INHERITANCE : 491 outputSuperClassInheritance(handler, jClass, mode); 493 break; 494 495 case INTERFACE_INHERITANCE : 496 outputImplements(handler, jClass, false); 498 break; 499 500 case INNERCLASS_INHERITANCE : 501 outputInnerClasses(handler, jClass, false); 503 break; 504 505 case FIELD_INHERITANCE : 506 outputFields(handler, jClass, false); 508 break; 509 510 case METHOD_INHERITANCE : 511 Type[] interfaces = jClass.getImplements(); 513 for (int i=0; i<interfaces.length; i++) { 514 logger.debug("inherit from " + interfaces[i].getValue()); 515 outputClassInheritance(handler, getJavaClass(interfaces[i].getValue()), mode); 516 } 517 518 case CONSTRUCTOR_INHERITANCE : 519 if (!(mode == METHOD_INHERITANCE && jClass.isInterface())) { 521 outputSuperClassInheritance(handler, jClass, mode); 522 } 523 JavaMethod[] methods = jClass.getMethods(); 524 for (int i = 0; i < methods.length; i++) { 525 if ((mode == METHOD_INHERITANCE && methods[i].getReturns() != null) || 526 (mode == CONSTRUCTOR_INHERITANCE && methods[i].getReturns() == null)) { 527 outputMethodStartElement(handler, methods[i]); 528 outputMethodEndElement(handler, methods[i]); 529 } 530 } 531 break; 532 default : 533 break; 534 } 535 saxEndElement(handler, INHERIT_ELEMENT); 536 } 537 538 private boolean hasInheritance(JavaClass jClass, int mode) { 539 JavaClass superClass = getJavadocSuperClass(jClass); 540 boolean result = false; 541 542 if (superClass != null) { 543 switch (mode) { 544 case CLASS_INHERITANCE : 545 result = true; 547 break; 548 549 case INTERFACE_INHERITANCE : 550 result = superClass.getImplements().length > 0; 551 break; 552 553 case INNERCLASS_INHERITANCE : 554 result = superClass.getInnerClasses().length > 0; 555 break; 556 557 case FIELD_INHERITANCE : 558 result = superClass.getFields().length > 0; 559 break; 560 561 case METHOD_INHERITANCE : 562 Type[] interfaces = jClass.getImplements(); 563 for (int i=0; i<interfaces.length && !result; i++) { 564 JavaClass iface = getJavaClass(interfaces[i].getValue()); 565 result = iface != null && iface.getMethods().length > 0; 566 } 567 568 case CONSTRUCTOR_INHERITANCE : 569 JavaMethod[] methods = superClass.getMethods(); 570 for (int i=0; i<methods.length && !result; i++) { 571 result = ((mode == METHOD_INHERITANCE && methods[i].getReturns() != null) || 572 (mode == CONSTRUCTOR_INHERITANCE && methods[i].getReturns() == null)); 573 } 574 break; 575 576 default : 577 break; 578 } 579 580 if (!result) { 581 result = hasInheritance(superClass, mode); 582 } 583 } 584 585 return result; 586 } 587 588 594 private JavaClass getJavadocSuperClass(JavaClass jClass) { 595 if (jClass == null) { 596 throw new IllegalArgumentException ("Argument 'jClass' must not be <null>!"); 598 } 599 600 if (jClass.getFullyQualifiedName().equals(ROOT_CLASSNAME)) { 601 return null; 603 } 604 605 JavaClass superClass = null; 606 607 if (!jClass.isInterface()) { 608 try { 609 superClass = jClass.getSuperJavaClass(); 611 } catch (UnsupportedOperationException uoe) { 612 } 614 } 615 616 if (superClass == null) { 617 String superJavadocClassName = null; 618 619 if (jClass.isInterface()) { 620 Type[] interfaces = jClass.getImplements(); 621 if (interfaces.length == 1) { 622 superJavadocClassName = interfaces[0].getValue(); 623 } 624 } else { 625 superJavadocClassName = jClass.getSuperClass().getValue(); 626 627 if (superJavadocClassName.indexOf('.') == -1 && containingJavadocClass.getInnerClassByName(superJavadocClassName) != null) { 629 superJavadocClassName = containingJavadocClass.getFullyQualifiedName() + '.' + superJavadocClassName; 630 } 631 } 632 633 if (superJavadocClassName != null) { 634 superClass = getJavaClass(superJavadocClassName); 635 } 636 } 637 638 return superClass; 639 } 640 641 648 660 661 667 private JavaClass getJavaClass(String className) { 668 if (classMap != null && classMap.containsKey(className)) { 669 return (JavaClass) classMap.get(className); 670 } 671 672 JavaClass jClass = null; 673 SourceResolver resolver = null; 674 675 try { 676 resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 677 Source source = resolver.resolveURI(PROTOCOL + className); 678 if (source instanceof QDoxSource) { 679 QDoxSource javadocSource = (QDoxSource) source; 680 jClass = javadocSource.getJavadocClass(); 681 if (classMap == null) { 682 classMap = new HashMap (); 683 } 684 classMap.put(className, jClass); 685 } 686 resolver.release(source); 687 } catch (ServiceException se) { 688 logger.error("Couldn't return JavaClass!", se); 689 } catch (MalformedURLException mue) { 690 logger.error("Couldn't return JavaClass!", mue); 691 } catch (SourceException se) { 692 logger.error("Couldn't return JavaClass!", se); 693 } catch (IOException ioe) { 694 logger.error("Couldn't return JavaClass!", ioe); 695 } finally { 696 if (resolver != null) { 697 manager.release(resolver); 698 } 699 } 700 701 return jClass; 702 } 703 704 710 private void outputModifiers(ContentHandler handler, AbstractJavaEntity entity) throws SAXException { 711 String [] modifiers = entity.getModifiers(); 712 if (modifiers.length > 0) { 713 saxStartElement(handler, MODIFIERS_ELEMENT); 714 for (int i=0; i<modifiers.length; i++) { 715 saxStartElement(handler, modifiers[i]); 716 saxEndElement(handler, modifiers[i]); 717 } 718 saxEndElement(handler, MODIFIERS_ELEMENT); 719 } 720 } 721 722 728 private void outputTags(ContentHandler handler, AbstractJavaEntity entity) throws SAXException { 729 DocletTag[] tags = entity.getTags(); 730 731 boolean tagElementPassed = false; 732 for (int i=0; i<tags.length; i++) { 733 String tagName = tags[i].getName(); 734 String value = tags[i].getValue(); 735 if (!tagElementPassed && !tagName.equals("throws") && !tagName.equals("param")) { 736 saxStartElement(handler, TAGS_ELEMENT); 737 tagElementPassed = true; 738 } 739 740 if (tagName.equals("see")) { 741 saxStartElement(handler, tagName); 742 outputLink(handler, value, null); 743 saxEndElement(handler, tagName); 744 } else if (!tagName.equals("throws") && !tagName.equals("param")) { 745 saxStartElement(handler, tagName); 747 outputComment(handler, value); 748 saxEndElement(handler, tagName); 749 } 750 } 751 752 if (tagElementPassed) { 753 saxEndElement(handler, TAGS_ELEMENT); 754 } 755 } 756 757 764 private void outputComment(ContentHandler handler, String comment) throws SAXException { 765 if (comment != null && comment.length() > 0) { 766 saxStartElement(handler, COMMENT_ELEMENT); 767 while (reLink.match(comment)) { 768 String ref = null; 769 String display = null; 770 if (reLink.getParen(6) == null) { 771 ref = reLink.getParen(2); 773 display = reLink.getParen(5); 774 } else { 775 ref = reLink.getParen(6); 777 display = ""; 778 } 779 saxCharacters(handler, comment.substring(0, reLink.getParenStart(0))); 781 outputLink(handler, ref, display); 782 comment = comment.substring(reLink.getParenEnd(0)); 784 } 785 saxCharacters(handler, comment); 786 saxEndElement(handler, COMMENT_ELEMENT); 787 } 788 } 789 790 797 private void outputLink(ContentHandler handler, String ref, String display) throws SAXException { 798 String classPart = resolveClassNameFromLink(ref); 799 String memberPart = StringUtils.substringAfter(ref, "#"); 800 String displayPart = display; 801 802 List attrs = new ArrayList (); 803 804 if (StringUtils.isNotEmpty(classPart)) { 805 attrs.add(new String [] {LINK_CLASS_ATTRIBUTE, classPart}); 806 } 807 808 if (StringUtils.isNotEmpty(memberPart)) { 809 attrs.add(new String [] {LINK_MEMBER_ATTRIBUTE, memberPart}); 810 } 811 812 if (StringUtils.isEmpty(display) && !ref.equals(classPart + "#" + memberPart)) { 813 displayPart = ref.replace('#', '.'); 814 } 815 816 saxStartElement(handler, LINK_ELEMENT, (String [][]) attrs.toArray(new String [][]{{}})); 817 saxCharacters(handler, displayPart); 818 saxEndElement(handler, LINK_ELEMENT); 819 } 820 821 828 private void outputInnerClasses(ContentHandler handler, JavaClass jClass, boolean detailed) throws SAXException { 829 JavaClass[] innerClasses = jClass.getInnerClasses(); 830 if (innerClasses.length > 0 || hasInheritance(jClass, INNERCLASS_INHERITANCE)) { 831 if (detailed) { 832 saxStartElement(handler, INNERCLASSES_ELEMENT); 833 } 834 835 outputSuperClassInheritance(handler, jClass, INNERCLASS_INHERITANCE); 837 838 for (int i=0; i<innerClasses.length; i++) { 839 outputClassStartElement(handler, innerClasses[i]); 840 if (detailed) { 841 outputModifiers(handler, innerClasses[i]); 842 outputComment(handler, innerClasses[i].getComment()); 843 outputTags(handler, innerClasses[i]); 844 } 845 outputClassEndElement(handler, innerClasses[i]); 846 } 847 848 if (detailed) { 849 saxEndElement(handler, INNERCLASSES_ELEMENT); 850 } 851 } 852 } 853 854 860 private void outputImplements(ContentHandler handler, JavaClass jClass, boolean detailed) throws SAXException { 861 Type[] interfaces = jClass.getImplements(); 862 if (interfaces.length > 0 || hasInheritance(jClass, INTERFACE_INHERITANCE)) { 863 if (detailed) { 864 saxStartElement(handler, IMPLEMENTS_ELEMENT); 865 } 866 867 outputSuperClassInheritance(handler, jClass, INTERFACE_INHERITANCE); 869 870 for (int i=0; i<interfaces.length; i++) { 871 String name = interfaces[i].getValue(); 872 String pckg = name.substring(0, name.lastIndexOf('.')); 873 name = name.substring(pckg.length() + 1); 874 875 saxStartElement(handler, INTERFACE_ELEMENT, 876 new String [][] {{CLASSNAME_ATTRIBUTE, name}, 877 {PACKAGE_ATTRIBUTE, pckg}, 878 {QNAME_ATTRIBUTE, pckg + '.' + name}}); 879 saxEndElement(handler, INTERFACE_ELEMENT); 880 } 881 882 if (detailed) { 883 saxEndElement(handler, IMPLEMENTS_ELEMENT); 884 } 885 } 886 } 887 888 895 private void outputFields(ContentHandler handler, JavaClass jClass, boolean detailed) throws SAXException { 896 JavaField[] fields = jClass.getFields(); 897 898 if (fields.length > 0 || hasInheritance(jClass, FIELD_INHERITANCE)) { 899 if (detailed) { 900 saxStartElement(handler, FIELDS_ELEMENT); 901 } 902 903 outputSuperClassInheritance(handler, jClass, FIELD_INHERITANCE); 905 906 for (int i=0; i<fields.length; i++) { 907 saxStartElement(handler, FIELD_ELEMENT, 908 new String [][] {{NAME_ATTRIBUTE, fields[i].getName()}, 909 {TYPE_ATTRIBUTE, fields[i].getType().getValue()}, 910 {DIMENSIONS_ATTRIBUTE, Integer.toString(fields[i].getType().getDimensions())}}); 911 if (detailed) { 912 outputModifiers(handler, fields[i]); 913 outputComment(handler, fields[i].getComment()); 914 outputTags(handler, fields[i]); 915 } 916 saxEndElement(handler, FIELD_ELEMENT); 917 } 918 919 if (detailed) { 920 saxEndElement(handler, FIELDS_ELEMENT); 921 } 922 } 923 } 924 925 931 private void outputInheritStartElement(ContentHandler handler, JavaClass jClass) throws SAXException { 932 saxStartElement(handler, INHERIT_ELEMENT, 933 new String [][] {{TYPE_ATTRIBUTE, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT}, 934 {CLASSNAME_ATTRIBUTE, jClass.getName()}, 935 {PACKAGE_ATTRIBUTE, jClass.getPackage()}, 936 {QNAME_ATTRIBUTE, jClass.getFullyQualifiedName()}}); 937 } 938 939 945 private void outputClassStartElement(ContentHandler handler, JavaClass jClass) throws SAXException { 946 saxStartElement(handler, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT, 947 new String [][] {{CLASSNAME_ATTRIBUTE, jClass.getName()}, 948 {PACKAGE_ATTRIBUTE, jClass.getPackage()}, 949 {QNAME_ATTRIBUTE, jClass.getFullyQualifiedName()}}); 950 } 951 952 958 private void outputClassEndElement(ContentHandler handler, JavaClass jClass) throws SAXException { 959 saxEndElement(handler, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT); 960 } 961 962 969 private void outputMethods(ContentHandler handler, JavaClass jClass, int mode) throws SAXException { 970 int size = 0; 972 String elementGroup, element; 973 JavaMethod[] methods = jClass.getMethods(); 974 975 if (mode == CONSTRUCTOR_MODE) { 976 elementGroup = CONSTRUCTORS_ELEMENT; 977 element = CONSTRUCTOR_ELEMENT; 978 for (int i=0; i<methods.length; i++) { 979 if (methods[i].getReturns() == null) { 980 size++; 981 } 982 } 983 } else { 984 elementGroup = METHODS_ELEMENT; 985 element = METHOD_ELEMENT; 986 for (int i=0; i<methods.length; i++) { 987 if (methods[i].getReturns() != null) { 988 size++; 989 } 990 } 991 } 992 993 if (size > 0 || (mode == METHOD_MODE && hasInheritance(jClass, METHOD_INHERITANCE)) || 994 (mode == CONSTRUCTOR_MODE && hasInheritance(jClass, CONSTRUCTOR_INHERITANCE))) { 995 saxStartElement(handler, elementGroup); 996 997 if (mode == METHOD_MODE) { 999 outputSuperClassInheritance(handler, jClass, METHOD_INHERITANCE); 1000 } else { 1001 outputSuperClassInheritance(handler, jClass, CONSTRUCTOR_INHERITANCE); 1002 } 1003 1004 for (int i=0; i<methods.length; i++) { 1005 if (mode == METHOD_MODE && methods[i].getReturns() != null) { 1006 outputMethodStartElement(handler, methods[i]); 1007 } else if (mode == CONSTRUCTOR_MODE && methods[i].getReturns() == null) { 1008 saxStartElement(handler, CONSTRUCTOR_ELEMENT, 1009 new String [][] {{NAME_ATTRIBUTE, methods[i].getName()}, 1010 {SIGNATURE_ATTRIBUTE, getSignature(methods[i])}}); 1011 } else { 1012 continue; 1014 } 1015 1016 JavaParameter[] params = methods[i].getParameters(); 1017 DocletTag[] paramTags = methods[i].getTagsByName("param"); 1018 DocletTag[] throwsTags = methods[i].getTagsByName("throws"); 1019 1020 outputModifiers(handler, methods[i]); 1022 outputComment(handler, methods[i].getComment()); 1023 outputTags(handler, methods[i]); 1024 1025 if (params.length > 0) { 1027 saxStartElement(handler, PARAMETERS_ELEMENT); 1028 for (int j=0; j<params.length; j++) { 1029 String paramName = params[j].getName(); 1030 saxStartElement(handler, PARAMETER_ELEMENT, 1031 new String [][] {{NAME_ATTRIBUTE, paramName}, 1032 {TYPE_ATTRIBUTE, params[j].getType().getValue()}, 1033 {DIMENSIONS_ATTRIBUTE, Integer.toString(params[j].getType().getDimensions())}}); 1034 1035 for (int k=0; k<paramTags.length; k++) { 1037 String paramValue = paramTags[k].getValue(); 1038 int splitIndex = paramValue.indexOf(' '); 1039 String paramValueName = splitIndex > 0 ? paramValue.substring(0, splitIndex) : paramValue; 1040 if (paramName.equals(paramValueName)) { 1041 outputComment(handler, splitIndex > 0 ? paramValue.substring(splitIndex + 1) : ""); 1042 } 1043 } 1044 1045 saxEndElement(handler, PARAMETER_ELEMENT); 1046 } 1047 saxEndElement(handler, PARAMETERS_ELEMENT); 1048 } 1049 1050 Type[] exceptions = methods[i].getExceptions(); 1052 if (exceptions.length + throwsTags.length > 0) { 1053 saxStartElement(handler, THROWS_ELEMENT); 1054 for (int j=0; j<exceptions.length; j++) { 1055 String exceptionName = exceptions[j].getValue(); 1057 saxStartElement(handler, EXCEPTION_ELEMENT, new String [][] {{NAME_ATTRIBUTE, exceptionName}}); 1058 1059 if (throwsTags.length > 0) { 1061 String exceptionClassName = exceptionName.substring(exceptionName.lastIndexOf('.')); 1062 for (int k=0; k<throwsTags.length; k++) { 1063 String excValue = throwsTags[k].getValue(); 1064 int splitIndex = excValue.indexOf(' '); 1065 String excValueName = splitIndex > 0 ? excValue.substring(0, splitIndex) : excValue; 1066 if (exceptionClassName.equals(excValueName)) { 1067 outputComment(handler, splitIndex > 0 ? excValue.substring(splitIndex + 1) : ""); 1068 } 1069 } 1070 } 1071 1072 saxEndElement(handler, EXCEPTION_ELEMENT); 1073 } 1074 1075 for (int j=0; j<throwsTags.length; j++) { 1076 String content = throwsTags[j].getValue(); 1078 int splitIndex = content.indexOf(' '); 1079 String exceptionName = content.substring(0, splitIndex); 1080 String qualifiedExceptionName = getQualifiedClassName(exceptionName); 1081 1082 boolean found = false; 1084 for (int k=0; !found && k<exceptions.length; k++) { 1085 found = qualifiedExceptionName.equals(exceptions[k].getValue()); 1086 } 1087 1088 if (!found) { 1089 saxStartElement(handler, EXCEPTION_ELEMENT, new String [][] {{NAME_ATTRIBUTE, qualifiedExceptionName}}); 1090 outputComment(handler, splitIndex > 0 ? content.substring(splitIndex + 1) : ""); 1091 saxEndElement(handler, EXCEPTION_ELEMENT); 1092 } 1093 } 1094 1095 saxEndElement(handler, THROWS_ELEMENT); 1096 } 1097 1098 saxEndElement(handler, element); 1099 } 1100 1101 saxEndElement(handler, elementGroup); 1102 } 1103 } 1104 1105 1111 private String getSignature(JavaMethod javaMethod) { 1112 StringBuffer sb = new StringBuffer (javaMethod.getName()); 1113 sb.append('('); 1114 JavaParameter[] params = javaMethod.getParameters(); 1115 for (int j=0; j<params.length; j++) { 1116 if (j > 0) { 1117 sb.append(", "); 1118 } 1119 sb.append(params[j].getType().getValue()); 1120 int dims = params[j].getType().getDimensions(); 1121 for (int k=0; k<dims; k++) { 1122 sb.append("[]"); 1123 } 1124 } 1125 sb.append(')'); 1126 1127 return sb.toString(); 1128 } 1129 1130 1136 private void outputMethodStartElement(ContentHandler handler, JavaMethod javaMethod) throws SAXException { 1137 if (javaMethod.getReturns() != null) { 1138 saxStartElement(handler, METHOD_ELEMENT, 1139 new String [][] {{NAME_ATTRIBUTE, javaMethod.getName()}, 1140 {TYPE_ATTRIBUTE, javaMethod.getReturns().getValue()}, 1141 {DIMENSIONS_ATTRIBUTE, Integer.toString(javaMethod.getReturns().getDimensions())}, 1142 {SIGNATURE_ATTRIBUTE, getSignature(javaMethod)}}); 1143 } else { 1144 saxStartElement(handler, CONSTRUCTOR_ELEMENT, 1145 new String [][] {{NAME_ATTRIBUTE, javaMethod.getName()}, 1146 {SIGNATURE_ATTRIBUTE, getSignature(javaMethod)}}); 1147 } 1148 } 1149 1150 1155 private void outputMethodEndElement(ContentHandler handler, JavaMethod javaMethod) throws SAXException { 1156 if (javaMethod.getReturns() != null) { 1157 saxEndElement(handler, METHOD_ELEMENT); 1158 } else { 1159 saxEndElement(handler, CONSTRUCTOR_ELEMENT); 1160 } 1161 } 1162 1163 1169 private void saxStartElement(ContentHandler handler, String localName) throws SAXException { 1170 handler.startElement(NS_URI, localName, NS_PREFIX + ':' + localName, XMLUtils.EMPTY_ATTRIBUTES); 1171 } 1172 1173 1180 private void saxStartElement(ContentHandler handler, String localName, String [][] attrs) throws SAXException { 1181 AttributesImpl saxAttrs = new AttributesImpl (); 1182 for (int i=0; i<attrs.length; i++) { 1183 if (attrs[i].length == 2) { 1184 saxAttrs.addAttribute("", attrs[i][0], attrs[i][0], ATTR_TYPE, attrs[i][1]); 1185 } else if (attrs[i].length == 5) { 1186 saxAttrs.addAttribute(attrs[i][0], attrs[i][1], attrs[i][2], attrs[i][3], attrs[i][4]); 1187 } 1188 } 1189 1190 handler.startElement(NS_URI, localName, NS_PREFIX + ':' + localName, saxAttrs); 1191 } 1192 1193 1199 private void saxEndElement(ContentHandler handler, String localName) throws SAXException { 1200 handler.endElement(NS_URI, localName, NS_PREFIX + ':' + localName); 1201 } 1202 1203 1209 private void saxCharacters(ContentHandler handler, String text) throws SAXException { 1210 if (text != null && text.length() > 0) { 1211 handler.characters(text.toCharArray(), 0, text.length()); 1212 } 1213 } 1214 1215 1218 public boolean exists() { 1219 return true; 1220 } 1221} 1222 | Popular Tags |