You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by bd...@apache.org on 2003/05/06 10:50:00 UTC

cvs commit: cocoon-2.1/src/blocks/qdox/samples/stylesheets qdox2html.xsl

bdelacretaz    2003/05/06 01:50:00

  Modified:    .        blocks.properties gump.xml
               lib      jars.xml
  Added:       src/blocks/qdox/conf qdox.xconf qdox.xsamples
               src/blocks/qdox/java/org/apache/cocoon/components/source/impl
                        QDoxSource.java QDoxSourceFactory.java
               src/blocks/qdox/lib qdox-1.1.jar
               src/blocks/qdox/samples samples.xml sitemap.xmap
               src/blocks/qdox/samples/stylesheets qdox2html.xsl
  Log:
  qdox block added, thanks to b.guijt1@chello.nl (Bart Guijt)
  
  Revision  Changes    Path
  1.11      +1 -0      cocoon-2.1/blocks.properties
  
  Index: blocks.properties
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/blocks.properties,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- blocks.properties	29 Apr 2003 08:41:08 -0000	1.10
  +++ blocks.properties	6 May 2003 08:49:59 -0000	1.11
  @@ -61,3 +61,4 @@
   #exclude.block.mail=true
   #exclude.block.axis=true
   #exclude.block.woody=true
  +#exclude.block.qdox=true
  
  
  
  1.56      +19 -1     cocoon-2.1/gump.xml
  
  Index: gump.xml
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/gump.xml,v
  retrieving revision 1.55
  retrieving revision 1.56
  diff -u -r1.55 -r1.56
  --- gump.xml	1 May 2003 12:49:34 -0000	1.55
  +++ gump.xml	6 May 2003 08:49:59 -0000	1.56
  @@ -759,6 +759,24 @@
       <nag from="Gump" to="cocoon-dev@xml.apache.org"/>
     </project>
   
  +  <project name="cocoon-block-qdox" status="unstable">
  +    <package>org.apache.cocoon</package>
  +
  +    <ant target="gump-block">
  +      <property name="block-name" value="qdox"/>
  +      <property name="version" value="@@DATE@@"/>
  +    </ant>
  +
  +    <depend project="cocoon" inherit="all"/>
  +
  +    <work nested="tools/anttasks"/>
  +    <home nested="build/cocoon-@@DATE@@"/>
  +
  +    <jar name="blocks/qdox-block.jar"/>
  +
  +    <nag from="Gump" to="cocoon-dev@xml.apache.org"/>
  +    </project>
  +
     <project name="cocoon-block-xmlform">
       <package>org.apache.cocoon</package>
   
  
  
  
  1.38      +12 -1     cocoon-2.1/lib/jars.xml
  
  Index: jars.xml
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/lib/jars.xml,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- jars.xml	3 May 2003 13:51:41 -0000	1.37
  +++ jars.xml	6 May 2003 08:49:59 -0000	1.38
  @@ -767,4 +767,15 @@
     <homepage>http://xreporter.cocoondev.org</homepage>
    </file>
   
  +  <file>
  +    <title>QDox - Quick JavaDoc Scanner</title>
  +    <description>
  +        QDox is a high speed, small footprint parser for extracting class/interface/method
  +        definitions from source files complete with JavaDoc @tags.
  +    </description>
  +    <used-by>QDoxSource (qdox block)</used-by>
  +    <lib>qdox/lib/qdox-1.1.jar</lib>
  +    <homepage>http://qdox.codehaus.org</homepage>
  +   </file>
  +
   </jars>
  
  
  
  1.1                  cocoon-2.1/src/blocks/qdox/conf/qdox.xconf
  
  Index: qdox.xconf
  ===================================================================
  <?xml version="1.0"?>
  
  <xconf xpath="/cocoon/source-factories" unless="component-instance[@name='qodx']">
      <component-instance
          class="org.apache.cocoon.components.source.impl.QDoxSourceFactory"
          logger="core.sources.qdox"
          name="qdox">
        <include-inheritance value="yes" />
  
        <!-- these source-roots must be configured for your system! -->
        <source-roots group="test-source">
          <!-- test source-root as mentioned in the qdox block samples.xml file -->
            <source-root uri="file:///tmp/qdox-test"/>
        </source-roots>
  
        <!-- examples of other source-roots
        <source-roots group="JDK">
          <source-root uri="jar:file:///tmp/jdk-src.zip!" />
        </source-roots>
        <source-roots group="Avalon">
          <source-root uri="file://D:/cvs-workspaces/apache/jakarta-avalon/src/java" />
          <source-root uri="file://D:/cvs-workspaces/apache/jakarta-avalon-logkit/src/java" />
          <source-root uri="file://D:/cvs-workspaces/apache/jakarta-avalon-excalibur/component/src/java" />
          <source-root uri="file://D:/cvs-workspaces/apache/jakarta-avalon-excalibur/sourceresolve/src/java" />
          <source-root uri="file://D:/cvs-workspaces/apache/jakarta-avalon-excalibur/pool/src/java" />
          <source-root uri="file://D:/cvs-workspaces/apache/jakarta-avalon-excalibur/xmlutil/src/java" />
        </source-roots>
        <source-roots group="Cocoon">
          <source-root uri="file://D:/cvs-workspaces/apache/xml-cocoon2/src/java" />
          <source-root uri="file://D:/cvs-workspaces/apache/xml-cocoon2/src/deprecated/java" />
        </source-roots>
        -->
  
      </component-instance>
  
  </xconf>
  
  
  1.1                  cocoon-2.1/src/blocks/qdox/conf/qdox.xsamples
  
  Index: qdox.xsamples
  ===================================================================
  <?xml version="1.0"?>
  
  <xsamples xpath="/samples" unless="group[@name='QDox']">
    <group name="QDox">
      <sample name="Samples" href="qdox/samples">Javadoc-like parsing of Java code using QDox.</sample>
    </group>
  </xsamples>
  
  
  
  1.1                  cocoon-2.1/src/blocks/qdox/java/org/apache/cocoon/components/source/impl/QDoxSource.java
  
  Index: QDoxSource.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.source.impl;
  
  
  import java.io.BufferedReader;
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.net.MalformedURLException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import com.thoughtworks.qdox.JavaDocBuilder;
  import com.thoughtworks.qdox.model.AbstractJavaEntity;
  import com.thoughtworks.qdox.model.DocletTag;
  import com.thoughtworks.qdox.model.JavaClass;
  import com.thoughtworks.qdox.model.JavaField;
  import com.thoughtworks.qdox.model.JavaMethod;
  import com.thoughtworks.qdox.model.JavaParameter;
  import com.thoughtworks.qdox.model.JavaSource;
  import com.thoughtworks.qdox.model.Type;
  
  //import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.excalibur.pool.Recyclable;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  //import org.apache.avalon.framework.component.ComponentSelector;
  import org.apache.avalon.framework.logger.Logger;
  //import org.apache.cocoon.serialization.Serializer;
  import org.apache.cocoon.serialization.XMLSerializer;
  import org.apache.excalibur.source.Source;
  import org.apache.excalibur.source.SourceException;
  import org.apache.excalibur.source.SourceResolver;
  import org.apache.excalibur.source.SourceValidity;
  import org.apache.excalibur.source.impl.AbstractSource;
  import org.apache.excalibur.xml.sax.XMLizable;
  import org.apache.regexp.RE;
  import org.apache.regexp.RESyntaxException;
  import org.xml.sax.Attributes;
  import org.xml.sax.ContentHandler;
  import org.xml.sax.SAXException;
  import org.xml.sax.helpers.AttributesImpl;
  
  
  /**
   * Source implementation for XML Javadoc.
   * 
   * @author <a href="mailto:b.guijt1@chello.nl">Bart Guijt</a>
   * @version CVS $Revision: 1.1 $ $Date: 2003/05/06 08:49:59 $
   */
  public final class QDoxSource
      extends AbstractSource
      implements XMLizable, Recyclable {
      
      protected final static String ROOT_CLASSNAME = "java.lang.Object";
      
      protected final static String EMPTY = "";
      protected final static String NS_URI = "http://apache.org/cocoon/javadoc/1.0";
      protected final static String NS_PREFIX = "jd";
      protected final static String ATTR_TYPE = "NMTOKEN";
      protected final static Attributes EMPTY_ATTRS = new AttributesImpl();
      
      protected final static String CLASS_ELEMENT = "class";
      protected final static String CLASSNAME_ATTRIBUTE = "name";
      protected final static String PACKAGE_ATTRIBUTE = "package";
      protected final static String QNAME_ATTRIBUTE = "qname";
      protected final static String INHERIT_ELEMENT = "inherit";
      protected final static String INNERCLASSES_ELEMENT = "innerclasses";
      protected final static String NESTED_IN_ELEMENT = "nested-in";
      protected final static String IMPORTS_ELEMENT = "imports";
      protected final static String IMPORT_ELEMENT = "import";
      protected final static String IMPORT_ATTRIBUTE = "type";
      protected final static String IMPLEMENTS_ELEMENT = "implements";
      protected final static String INTERFACE_ELEMENT = "interface";
      protected final static String MODIFIERS_ELEMENT = "modifiers";
      protected final static String COMMENT_ELEMENT = "comment";
      protected final static String LINK_ELEMENT = "link";
      protected final static String LINK_CLASS_ATTRIBUTE = "class";
      protected final static String LINK_MEMBER_ATTRIBUTE = "member";
      protected final static String HREF_ATTRIBUTE = "uri";
      protected final static String TAGS_ELEMENT = "tags";
      protected final static String FIELDS_ELEMENT = "fields";
      protected final static String FIELD_ELEMENT = "field";
      protected final static String CONSTRUCTORS_ELEMENT = "constructors";
      protected final static String CONSTRUCTOR_ELEMENT = "constructor";
      protected final static String METHODS_ELEMENT = "methods";
      protected final static String METHOD_ELEMENT = "method";
      protected final static String NAME_ATTRIBUTE = "name";
      protected final static String TYPE_ATTRIBUTE = "type";
      protected final static String DIMENSIONS_ATTRIBUTE = "dimensions";
      protected final static String SIGNATURE_ATTRIBUTE = "signature";
      protected final static String PARAMETERS_ELEMENT = "parameters";
      protected final static String PARAMETER_ELEMENT = "parameter";
      protected final static String THROWS_ELEMENT = "throws";
      protected final static String EXCEPTION_ELEMENT = "exception";
      
      protected final static int CONSTRUCTOR_MODE = 1;
      protected final static int METHOD_MODE = 2;
      
      protected final static int CLASS_INHERITANCE = 1;
      protected final static int INTERFACE_INHERITANCE = 2;
      protected final static int INNERCLASS_INHERITANCE = 3;
      protected final static int FIELD_INHERITANCE = 4;
      protected final static int CONSTRUCTOR_INHERITANCE = 5;
      protected final static int METHOD_INHERITANCE = 6;
      
      protected ComponentManager manager;
      protected Logger logger;
      
      protected Source javaSource;
      protected String javadocUri;
      protected String javadocClassName;
      protected JavaClass javadocClass;
      protected JavaClass containingJavadocClass;  // in case javadocClass is an inner class
      protected Map classMap;
      
      /**
       * This RegExp matches the <code>{</code><code>@link &hellip;}</code> occurrances in
       * Javadoc comments.
       */
      protected RE reLink;
      
      /**
       * Contains a regular expression to match the <code>{</code><code>@link &hellip;}</code> occurrances.
       * 
       * <p>The following <code>{</code><code>@link &hellip;}</code> literals are recognized:</p>
       * 
       * <ul>
       * <li><code>{</code><code>@link HashMap}</code> - returns 'Hashmap' with <code>reLink.getParen(6)</code>;</li>
       * <li><code>{</code><code>@link #equals(java.lang.Object) equals(&hellip;)}</code> - returns '#equals(java.lang.Object)' with <code>reLink.getParen(2)</code>
       *   and 'equals(&hellip;)' with <code>reLink.getParen(5)</code>;</li>
       * <li><code>{</code><code>@link #indexOf(char, int) indexOf(&hellip;)}</code> - returns '#indexOf(char, int)' with <code>reLink.getParen(2)</code>
       *   and 'indexOf(&hellip;)' with <code>reLink.getParen(5)</code>.</li>
       * </ul>
       * <p>The regexp is as follows:</p>
       * <code>\{@link\s+((([\w.#,$&amp;;\s]+)|([\w.#,$&amp;;(\s]+[\w.#,$&amp;;)\s]+))\s+([\w()#.,$&amp;;\s]+)|([\w.#,$&amp;;\s()]+))\s*\}</code>
       * 
       * @see #reLink
       */
      protected final static String RE_LINK = "\\{@link\\s+((([\\w.#,$&;\\s]+)|([\\w.#,$&;(\\s]+[\\w.#,$&;)\\s]+))\\s+([\\w()#.,$&;\\s]+)|([\\w.#,$&;\\s()]+))\\s*\\}";
      
      /**
       * Constructor for QDoxSource.
       * 
       * @param location
       * @param javaSource
       * @param logger
       * @param manager
       */
      public QDoxSource(String location, Source javaSource, Logger logger, ComponentManager manager) {
          this.javadocUri = location;
          this.javaSource = javaSource;
          this.logger = logger;
          this.manager = manager;
          
          this.javadocClassName = javadocUri.substring(javadocUri.indexOf(':') + 1);
          
          try {
              createJavadocXml();
          } catch (SourceException se) {
              logger.error("Error reading source!", se);
          } catch (IOException ioe) {
              logger.error("Error reading source!", ioe);
          }
          
          // Initialize regular expression:
          try {
              reLink = new RE(RE_LINK);
          } catch (RESyntaxException rse) {
              logger.error("Regular Expression syntax error!", rse);
          }
      }
      
      /**
       * Returns the parsed Java class.
       * 
       * @return JavaClass
       */
      public JavaClass getJavadocClass() {
          return javadocClass;
      }
      
      /**
       * @see org.apache.avalon.excalibur.xml.XMLizable#toSAX(org.xml.sax.ContentHandler)
       * @throws SAXException if any error occurs during SAX outputting.
       */
      public void toSAX(ContentHandler handler) throws SAXException {
          if (javadocClass == null) {
              logger.error("No classfile loaded! Cannot output SAX events.");
              
              return;
          }
          
          if (logger.isDebugEnabled()) {
              logger.debug("Outputting SAX events for class " + javadocClass.getFullyQualifiedName());
              logger.debug("  #fields: " + javadocClass.getFields().length);
              logger.debug("  #methods and constructors: " + javadocClass.getMethods().length);
          }
          
          // Output SAX 'header':
          handler.startDocument();
          handler.startPrefixMapping(NS_PREFIX, NS_URI);
          
          // Output class-level element:
          outputClassStartElement(handler, javadocClass);
          
          // Modifiers:
          outputModifiers(handler, javadocClass);
          
          // Imports:
          JavaSource parent = javadocClass.getParentSource();
          // Add two implicit imports:
          parent.addImport("java.lang.*");
          if (parent.getPackage().length() > 0) {
              parent.addImport(parent.getPackage() + ".*");
          } else {
              parent.addImport("*");
          }
          String[] imports = parent.getImports();
          
          saxStartElement(handler, IMPORTS_ELEMENT);
          for (int i=0; i<imports.length; i++) {
              if (imports[i].endsWith("*")) {
                  // package import:
                  saxStartElement(handler, IMPORT_ELEMENT, new String[][] {{IMPORT_ATTRIBUTE, "package"}});
                  String imp = imports[i];
                  while (imp.endsWith("*") || imp.endsWith(".")) {
                      imp = imp.substring(0, imp.length() - 1);
                  }
                  saxCharacters(handler, imp);
              } else {
                  saxStartElement(handler, IMPORT_ELEMENT, new String[][] {{IMPORT_ATTRIBUTE, "class"}});
                  saxCharacters(handler, imports[i]);
              }
              saxEndElement(handler, IMPORT_ELEMENT);
          }
          saxEndElement(handler, IMPORTS_ELEMENT);
          
          // Superclass:
          if (!javadocClass.isInterface()) {
              outputSuperClassInheritance(handler, javadocClass, CLASS_INHERITANCE);
          }
          
          // Implements:
          outputImplements(handler, javadocClass, true);
          
          // Containing class in case this is an inner class:
          if (containingJavadocClass != null) {
              saxStartElement(handler, NESTED_IN_ELEMENT);
              outputClassStartElement(handler, containingJavadocClass);
              outputModifiers(handler, containingJavadocClass);
              outputComment(handler, containingJavadocClass.getComment());
              outputTags(handler, containingJavadocClass);
              outputClassEndElement(handler, containingJavadocClass);
              saxEndElement(handler, NESTED_IN_ELEMENT);
          }
          
          // Comment:
          outputComment(handler, javadocClass.getComment());
          
          // Tags:
          outputTags(handler, javadocClass);
          
          // Inner classes:
          outputInnerClasses(handler, javadocClass, true);
          
          // Fields:
          outputFields(handler, javadocClass, true);
          
          // Constructors:
          outputMethods(handler, javadocClass, CONSTRUCTOR_MODE);
          
          // Methods:
          outputMethods(handler, javadocClass, METHOD_MODE);
  
          // Close class-level element:
          outputClassEndElement(handler, javadocClass);
          
          // Output SAX 'footer':
          handler.endPrefixMapping(NS_PREFIX);
          handler.endDocument();
      }
      
      /**
       * @see org.apache.excalibur.source.Recyclable#recycle()
       */
      public void recycle() {
          if (logger != null && logger.isDebugEnabled()) {
              logger.debug("Recycling QDoxSource '" + javadocClassName + "'...");
          }
          
          manager = null;
          javaSource = null;
          javadocUri = null;
          javadocClassName = null;
          javadocClass = null;
          containingJavadocClass = null;
          classMap = null;
          logger = null;
      }
      
      /**
       * Get the content length of the source or -1 if it
       * is not possible to determine the length.
       */
      public long getContentLength() {
          return -1L;
      }
  
      /**
       * @see org.apache.excalibur.source.Source#getLastModified()
       */
      public long getLastModified() {
          return javaSource.getLastModified();
      }
  
      /**
       * @see org.apache.excalibur.source.Source#getMimeType()
       */
      public String getMimeType() {
          return "text/xml";
      }
  
      /**
       * Return the unique identifer for this source
       */
      public String getURI() {
          return javadocUri;
      }
  
      /**
       * @see org.apache.excalibur.source.Source#getValidity()
       */
      public SourceValidity getValidity() {
          return javaSource.getValidity();
      }
      
      /**
       * @see org.apache.excalibur.source.Source#getInputStream()
       */
      public InputStream getInputStream() throws IOException, SourceException {
          if (logger.isDebugEnabled()) {
              logger.debug("Getting InputStream for class " + javadocClass.getFullyQualifiedName());
          }
          
          // Serialize the SAX events to the XMLSerializer:
          
          XMLSerializer serializer = new XMLSerializer();
          //ComponentSelector serializerSelector = null;
          ByteArrayInputStream inputStream = null;
          
          try {
              //serializerSelector = (ComponentSelector) manager.lookup(Serializer.ROLE + "Selector");
              //logger.debug("serializer selector: " + serializerSelector.toString());
              //serializer = (XMLSerializer) serializerSelector.select(XMLSerializer.class);
              ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2048);
              serializer.setOutputStream(outputStream);
              toSAX(serializer);
              inputStream = new ByteArrayInputStream(outputStream.toByteArray());
          //} catch (ComponentException ce) {
          //    logger.error("Component not found: " + XMLSerializer.ROLE, ce);
          //    throw new SourceException("Component lookup of XMLSerializer failed!", ce);
          } catch (SAXException se) {
              logger.error("SAX exception!", se);
              throw new SourceException("Serializing SAX to a ByteArray failed!", se);
          //} finally {
              //serializerSelector.release(serializer);
              //manager.release(serializerSelector);
          }
          
          return inputStream;
      }
  
      protected void createJavadocXml() throws SourceException, IOException {
          if (logger.isDebugEnabled()) {
              logger.debug("Reading Java source " + javaSource.getURI());
          }
          
          JavaDocBuilder builder = new JavaDocBuilder();
          builder.addSource(new BufferedReader(new InputStreamReader(javaSource.getInputStream())));
          
          javadocClass = builder.getClassByName(javadocClassName);
          if (javadocClass == null) {
              // An inner class is specified - let's find it:
              int index = javadocUri.lastIndexOf('.');
              String containingClassName = javadocUri.substring(javadocUri.indexOf(':') + 1, index);
              String innerClassName = javadocUri.substring(index + 1);
              containingJavadocClass = builder.getClassByName(containingClassName);
              javadocClass = getJavadocInnerClass(containingJavadocClass, innerClassName);
          }
      }
      
      /**
       * Method resolveMemberNameFromLink.
       * 
       * @param ref
       * @return String
       */
      private String resolveMemberNameFromLink(String ref) {
          int hashIndex = ref.indexOf('#');
          if (hashIndex < 0) {
              return "";
          } else {
              return ref.substring(hashIndex + 1);
          }
      }
      
      /**
       * Method resolveClassNameFromLink.
       * 
       * @param ref
       * @return String
       */
      private String resolveClassNameFromLink(String ref) {
          String classPart = null;
          int hashIndex = ref.indexOf('#');
          if (hashIndex < 0) {
              classPart = ref;
          } else {
              classPart = ref.substring(0, hashIndex);
          }
          return getQualifiedClassName(classPart);
      }
      
      private String getQualifiedClassName(String classPart) {
          if (classPart.length() == 0) {
              // No classname specified:
              classPart = javadocClass.getFullyQualifiedName();
          } else if (classPart.equals("Object")) {
              // Fastest way to identify the root object - otherwise the next, *expensive* 'if' block is executed!
              classPart = "java.lang.Object";
          } else if (classPart.indexOf('.') < 0) {
              // No qualified name specified:
              String[] imports = javadocClass.getParentSource().getImports();
              List classImports = new ArrayList();
              List packageImports = new ArrayList();
              packageImports.add(javadocClass.getPackage());  // Most likely to find sources here, I guess...
              packageImports.add("java.lang");  // 2nd most likely place to find sources?
              for (int i=0; i<imports.length; i++) {
                  if (imports[i].endsWith(".*")) {
                      packageImports.add(imports[i].substring(0, imports[i].length() - 2));
                  } else if (imports[i].endsWith("*")) {
                      packageImports.add(imports[i].substring(0, imports[i].length() - 1));
                  } else {
                      classImports.add(imports[i]);
                  }
              }
                      
              boolean found = false;
              for (int i=0; !found && i<classImports.size(); i++) {
                  String name = (String) classImports.get(i);
                  if (name.endsWith(classPart)) {
                      classPart = name;
                      found = true;
                  }
              }
                      
              if (!found) {
                  SourceResolver resolver = null;
                  try {
                      resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
                      for (int i=0; !found && i<packageImports.size(); i++) {
                          String name = (String) packageImports.get(i);
                          if (name.length() == 0) {
                              name = classPart;
                          } else {
                              name += '.' + classPart;
                          }
                                  
                          // Test whether the classname 'name' is valid:
                          Source source = resolver.resolveURI("javadoc:" + name);
                          found = source != null && source instanceof QDoxSource;
                          if (found) {
                              classPart = name;
                          }
                          
                          resolver.release(source);
                      }
                  } catch (ComponentException e) {
                      logger.error("Could not find a SourceResolver!", e);
                  } catch (MalformedURLException e) {
                      // ignore - invalid URI (is subject of test)
                  } catch (SourceException e) {
                      // ignore
                  } catch (IOException e) {
                      // ignore
                  } finally {
                      if (resolver != null) {
                          manager.release(resolver);
                      }
                  }
              }
          }
          
          return classPart;
      }
      
      /**
       * Method outputClassInheritance.
       * 
       * @param handler
       * @param jClass
       */
      private void outputSuperClassInheritance(ContentHandler handler, JavaClass jClass, int mode) throws SAXException {
          JavaClass superClass = getJavadocSuperClass(jClass);
          if (superClass != null && hasInheritance(jClass, mode)) {
              outputClassInheritance(handler, superClass, mode);
          }
      }
      
      private void outputClassInheritance(ContentHandler handler, JavaClass jClass, int mode) throws SAXException {
          outputInheritStartElement(handler, jClass);
          
          switch (mode) {
              case CLASS_INHERITANCE :
                  // Already there!
                  outputSuperClassInheritance(handler, jClass, mode);
                  break;
                  
              case INTERFACE_INHERITANCE :
                  // Output interface inheritance summary:
                  outputImplements(handler, jClass, false);
                  break;
                  
              case INNERCLASS_INHERITANCE :
                  // Output nested inheritance summary:
                  outputInnerClasses(handler, jClass, false);
                  break;
                  
              case FIELD_INHERITANCE :
                  // Output field inheritance summary:
                  outputFields(handler, jClass, false);
                  break;
                  
              case METHOD_INHERITANCE :
                  // Output method inheritance summary from implemented interfaces:
                  Type[] interfaces = jClass.getImplements();
                  for (int i=0; i<interfaces.length; i++) {
                      logger.debug("inherit from " + interfaces[i].getValue());
                      outputClassInheritance(handler, getJavaClass(interfaces[i].getValue()), mode);
                  }
                  
              case CONSTRUCTOR_INHERITANCE :
                  // Output method/constructor inheritance summary from superclass:
                  if (!(mode == METHOD_INHERITANCE && jClass.isInterface())) {
                      outputSuperClassInheritance(handler, jClass, mode);
                  }
                  JavaMethod[] methods = jClass.getMethods();
                  for (int i=0; i<methods.length; i++) {
                      if ((mode == METHOD_INHERITANCE && methods[i].getReturns() != null) ||
                          (mode == CONSTRUCTOR_INHERITANCE && methods[i].getReturns() == null)) {
                          outputMethodStartElement(handler, methods[i]);
                          outputMethodEndElement(handler, methods[i]);
                      }
                  }
                  break;
                  
              default :
                  break;
          }
          
          saxEndElement(handler, INHERIT_ELEMENT);
      }
      
      private boolean hasInheritance(JavaClass jClass, int mode) {
          JavaClass superClass = getJavadocSuperClass(jClass);
          boolean result = false;
          
          if (superClass != null) {
              switch (mode) {
                  case CLASS_INHERITANCE :
                      // Already there!
                      result = true;
                      break;
                      
                  case INTERFACE_INHERITANCE :
                      result = superClass.getImplements().length > 0;
                      break;
                      
                  case INNERCLASS_INHERITANCE :
                      result = superClass.getClasses().length > 0;
                      break;
                      
                  case FIELD_INHERITANCE :
                      result = superClass.getFields().length > 0;
                      break;
                      
                  case METHOD_INHERITANCE :
                      Type[] interfaces = jClass.getImplements();
                      for (int i=0; i<interfaces.length && !result; i++) {
                          JavaClass iface = getJavaClass(interfaces[i].getValue());
                          result = iface != null && iface.getMethods().length > 0;
                      }
                      
                  case CONSTRUCTOR_INHERITANCE :
                      JavaMethod[] methods = superClass.getMethods();
                      for (int i=0; i<methods.length && !result; i++) {
                          result = ((mode == METHOD_INHERITANCE && methods[i].getReturns() != null) ||
                              (mode == CONSTRUCTOR_INHERITANCE && methods[i].getReturns() == null));
                      }
                      break;
                      
                  default :
                      break;
              }
              
              if (!result) {
                  result = hasInheritance(superClass, mode);
              }
          }
          
          return result;
      }
      
      /**
       * Method getJavadocSuperClass.
       * 
       * @param jClass
       * @return JavaClass
       */
      private JavaClass getJavadocSuperClass(JavaClass jClass) {
          if (jClass == null) {
              // May not happen, of course ;-)
              throw new IllegalArgumentException("Argument 'jClass' must not be <null>!");
          }
          
          if (jClass.getFullyQualifiedName().equals(ROOT_CLASSNAME)) {
              // jClass is root class:
              return null;
          }
          
          JavaClass superClass = null;
          
          if (!jClass.isInterface()) {
              try {
                  // Use QDocx operation to retrieve class:
                  superClass = jClass.getSuperJavaClass();
              } catch (UnsupportedOperationException uoe) {
                  // No Cache built (yet)... ignore!
              }
          }
          
          if (superClass == null) {
              String superJavadocClassName = null;
              
              if (jClass.isInterface()) {
                  Type[] interfaces = jClass.getImplements();
                  if (interfaces.length == 1) {
                      superJavadocClassName = interfaces[0].getValue();
                  }
              } else {
                  superJavadocClassName = jClass.getSuperClass().getValue();
                  
                  // Is the superClass itself an inner class?
                  if (superJavadocClassName.indexOf('.') == -1 && getJavadocInnerClass(containingJavadocClass, superJavadocClassName) != null) {
                      superJavadocClassName = containingJavadocClass.getFullyQualifiedName() + '.' + superJavadocClassName;
                  }
              }
              
              if (superJavadocClassName != null) {
                  superClass = getJavaClass(superJavadocClassName);
              }
          }
          
          return superClass;
      }
      
      /**
       * Method getInnerClass.
       * 
       * @param jClass
       * @param superJavadocClassName
       * @return JavaClass
       */
      private JavaClass getJavadocInnerClass(JavaClass jClass, String className) {
          if (jClass != null) {
              JavaClass[] classes = jClass.getClasses();
              
              for (int i=0; i<classes.length; i++) {
                  if (classes[i].getName().equals(className)) {
                      return classes[i];
                  }
              }
          }
          
          return null;
      }
      
      /**
       * Get the meta class for the specified classname. The result is cached internally.
       * 
       * @param className
       * @return JavaClass
       */
      private JavaClass getJavaClass(String className) {
          if (classMap != null && classMap.containsKey(className)) {
              return (JavaClass) classMap.get(className);
          }
          
          JavaClass jClass = null;
          SourceResolver resolver = null;
          
          try {
              resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
              Source source = resolver.resolveURI("javadoc:" + className);
              if (source instanceof QDoxSource) {
                  QDoxSource javadocSource = (QDoxSource) source;
                  jClass = javadocSource.getJavadocClass();
                  if (classMap == null) {
                      classMap = new HashMap();
                  }
                  classMap.put(className, jClass);
              }
              resolver.release(source);
          } catch (ComponentException ce) {
              logger.error("Couldn't return JavaClass!", ce);
          } catch (MalformedURLException mue) {
              logger.error("Couldn't return JavaClass!", mue);
          } catch (SourceException se) {
              logger.error("Couldn't return JavaClass!", se);
          } catch (IOException ioe) {
              logger.error("Couldn't return JavaClass!", ioe);
          } finally {
              if (resolver != null) {
                  manager.release(resolver);
              }
          }
          
          return jClass;
      }
      
      /**
       * Method outputModifiers.
       * 
       * @param handler
       * @param strings
       */
      private void outputModifiers(ContentHandler handler, AbstractJavaEntity entity) throws SAXException {
          String[] modifiers = entity.getModifiers();
          if (modifiers.length > 0) {
              saxStartElement(handler, MODIFIERS_ELEMENT);
              for (int i=0; i<modifiers.length; i++) {
                  saxStartElement(handler, modifiers[i]);
                  saxEndElement(handler, modifiers[i]);
              }
              saxEndElement(handler, MODIFIERS_ELEMENT);
          }
      }
      
      /**
       * Method outputCommentAndTags.
       * 
       * @param handler
       * @param javadocClass
       */
      private void outputTags(ContentHandler handler, AbstractJavaEntity entity) throws SAXException {
          DocletTag[] tags = entity.getTags();
          
          boolean tagElementPassed = false;
          for (int i=0; i<tags.length; i++) {
              String tagName = tags[i].getName();
              String value = tags[i].getValue();
              if (!tagElementPassed && !tagName.equals("throws") && !tagName.equals("param")) {
                  saxStartElement(handler, TAGS_ELEMENT);
                  tagElementPassed = true;
              }
              
              if (tagName.equals("see")) {
                  saxStartElement(handler, tagName);
                  outputLink(handler, value, null);
                  saxEndElement(handler, tagName);
              } else if (!tagName.equals("throws") && !tagName.equals("param")) {
                  // the 'throws' and 'param' tags are handled at method exception and method parameter level:
                  saxStartElement(handler, tagName);
                  outputComment(handler, value);
                  saxEndElement(handler, tagName);
              }
          }
          
          if (tagElementPassed) {
              saxEndElement(handler, TAGS_ELEMENT);
          }
      }
      
      /**
       * Outputs a Javadoc comment.
       * 
       * @param handler SAX ContentHandler
       * @param comment The Javadoc comment
       * @throws SAXException if something goes wrong
       */
      private void outputComment(ContentHandler handler, String comment) throws SAXException {
          if (comment != null && comment.length() > 0) {
              // When newlines are recognized in QDox, uncomment these lines:
              //if (comment.indexOf("<pre>") >= 0) {
                  //saxStartElement(handler, COMMENT_ELEMENT, new String[][] {{"http://www.w3.org/XML/1998/namespace",
                  //                "space", "xml:space", "NMTOKEN", "preserve"}});
                  //saxStartElement(handler, COMMENT_ELEMENT, new String[][] {{"xml:space", "preserve"}});
              //} else {
                  saxStartElement(handler, COMMENT_ELEMENT);
              //}
              
              while (reLink.match(comment)) {
                  String ref = null;
                  String display = null;
                  if (reLink.getParen(6) == null) {
                      // {@link xxx yyy}
                      ref = reLink.getParen(2);
                      display = reLink.getParen(5);
                  } else {
                      // {@link xxx}
                      ref = reLink.getParen(6);
                      display = EMPTY;
                  }
                  
                  // Output SAX:
                  saxCharacters(handler, comment.substring(0, reLink.getParenStart(0)));
                  
                  outputLink(handler, ref, display);
                  
                  // Cut from doc:
                  comment = comment.substring(reLink.getParenEnd(0));
              }
              
              saxCharacters(handler, comment);
              
              saxEndElement(handler, COMMENT_ELEMENT);
          }
      }
      
      /**
       * Method outputLink.
       * 
       * @param handler
       * @param ref
       * @param display
       */
      private void outputLink(ContentHandler handler, String ref, String display) throws SAXException {
          String classPart = resolveClassNameFromLink(ref);
          String memberPart = resolveMemberNameFromLink(ref);
          String displayPart = display;
          
          List attrs = new ArrayList();
          
          if (classPart != null && classPart.length() > 0) {
              attrs.add(new String[] {LINK_CLASS_ATTRIBUTE, classPart});
          }
          
          if (memberPart != null && memberPart.length() > 0) {
              attrs.add(new String[] {LINK_MEMBER_ATTRIBUTE, memberPart});
          }
          
          if (display == null || display.length() == 0 && !ref.equals(classPart + "#" + memberPart)) {
              displayPart = ref.replace('#', '.');
          }
          
          saxStartElement(handler, LINK_ELEMENT, (String[][]) attrs.toArray(new String[][]{{}}));
          saxCharacters(handler, displayPart);
          saxEndElement(handler, LINK_ELEMENT);
      }
      
      /**
       * Method outputInnerClasses.
       * 
       * @param handler
       * @param jClass
       * @param detailed
       */
      private void outputInnerClasses(ContentHandler handler, JavaClass jClass, boolean detailed) throws SAXException {
          JavaClass[] innerClasses = jClass.getClasses();
          if (innerClasses.length > 0 || hasInheritance(jClass, INNERCLASS_INHERITANCE)) {
              if (detailed) {
                  saxStartElement(handler, INNERCLASSES_ELEMENT);
              }
              
              // Output inheritance:
              outputSuperClassInheritance(handler, jClass, INNERCLASS_INHERITANCE);
              
              for (int i=0; i<innerClasses.length; i++) {
                  outputClassStartElement(handler, innerClasses[i]);
                  if (detailed) {
                      outputModifiers(handler, innerClasses[i]);
                      outputComment(handler, innerClasses[i].getComment());
                      outputTags(handler, innerClasses[i]);
                  }
                  outputClassEndElement(handler, innerClasses[i]);
              }
              
              if (detailed) {
                  saxEndElement(handler, INNERCLASSES_ELEMENT);
              }
          }
      }
      
      /**
       * Method outputImplements.
       * 
       * @param handler
       * @param jClass
       */
      private void outputImplements(ContentHandler handler, JavaClass jClass, boolean detailed) throws SAXException {
          Type[] interfaces = jClass.getImplements();
          if (interfaces.length > 0 || hasInheritance(jClass, INTERFACE_INHERITANCE)) {
              if (detailed) {
                  saxStartElement(handler, IMPLEMENTS_ELEMENT);
              }
              
              // Output inheritance:
              outputSuperClassInheritance(handler, jClass, INTERFACE_INHERITANCE);
              
              for (int i=0; i<interfaces.length; i++) {
                  String name = interfaces[i].getValue().toString();
                  String pckg = name.substring(0, name.lastIndexOf('.'));
                  name = name.substring(pckg.length() + 1);
                  
                  saxStartElement(handler, INTERFACE_ELEMENT,
                      new String[][] {{CLASSNAME_ATTRIBUTE, name},
                                      {PACKAGE_ATTRIBUTE, pckg},
                                      {QNAME_ATTRIBUTE, pckg + '.' + name}});
                  saxEndElement(handler, INTERFACE_ELEMENT);
              }
              
              if (detailed) {
                  saxEndElement(handler, IMPLEMENTS_ELEMENT);
              }
          }
      }
      
      /**
       * Method outputFields.
       * 
       * @param handler
       * @param jClass
       * @param detailed
       */
      private void outputFields(ContentHandler handler, JavaClass jClass, boolean detailed) throws SAXException {
          JavaField[] fields = jClass.getFields();
          
          if (fields.length > 0 || hasInheritance(jClass, FIELD_INHERITANCE)) {
              if (detailed) {
                  saxStartElement(handler, FIELDS_ELEMENT);
              }
              
              // Output inheritance:
              outputSuperClassInheritance(handler, jClass, FIELD_INHERITANCE);
              
              for (int i=0; i<fields.length; i++) {
                  saxStartElement(handler, FIELD_ELEMENT,
                      new String[][] {{NAME_ATTRIBUTE, fields[i].getName()},
                                      {TYPE_ATTRIBUTE, fields[i].getType().getValue()},
                                      {DIMENSIONS_ATTRIBUTE, Integer.toString(fields[i].getType().getDimensions())}});
                  if (detailed) {
                      outputModifiers(handler, fields[i]);
                      outputComment(handler, fields[i].getComment());
                      outputTags(handler, fields[i]);
                  }
                  saxEndElement(handler, FIELD_ELEMENT);
              }
              
              if (detailed) {
                  saxEndElement(handler, FIELDS_ELEMENT);
              }
          }
      }
      
      /**
       * Method outputClassStartElement.
       * 
       * @param handler
       * @param superClass
       */
      private void outputInheritStartElement(ContentHandler handler, JavaClass jClass) throws SAXException {
          saxStartElement(handler, INHERIT_ELEMENT,
              new String[][] {{TYPE_ATTRIBUTE, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT},
                              {CLASSNAME_ATTRIBUTE, jClass.getName()},
                              {PACKAGE_ATTRIBUTE, jClass.getPackage()},
                              {QNAME_ATTRIBUTE, jClass.getFullyQualifiedName()}});
      }
      
      /**
       * Method outputClassStartElement.
       * 
       * @param handler
       * @param superClass
       */
      private void outputClassStartElement(ContentHandler handler, JavaClass jClass) throws SAXException {
          saxStartElement(handler, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT,
              new String[][] {{CLASSNAME_ATTRIBUTE, jClass.getName()},
                              {PACKAGE_ATTRIBUTE, jClass.getPackage()},
                              {QNAME_ATTRIBUTE, jClass.getFullyQualifiedName()}});
      }
      
      /**
       * Method outputClassEndElement.
       * 
       * @param handler
       * @param jClass
       */
      private void outputClassEndElement(ContentHandler handler, JavaClass jClass) throws SAXException {
          saxEndElement(handler, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT);
      }
      
      /**
       * Method outputMethods.
       * 
       * @param handler
       * @param methods
       * @param mode
       */
      private void outputMethods(ContentHandler handler, JavaClass jClass, int mode) throws SAXException {
          // Are there any methods in <mode>?
          int size = 0;
          String elementGroup, element;
          JavaMethod[] methods = jClass.getMethods();
          
          if (mode == CONSTRUCTOR_MODE) {
              elementGroup = CONSTRUCTORS_ELEMENT;
              element = CONSTRUCTOR_ELEMENT;
              for (int i=0; i<methods.length; i++) {
                  if (methods[i].getReturns() == null) {
                      size++;
                  }
              }
          } else {
              elementGroup = METHODS_ELEMENT;
              element = METHOD_ELEMENT;
              for (int i=0; i<methods.length; i++) {
                  if (methods[i].getReturns() != null) {
                      size++;
                  }
              }
          }
          
          if (size > 0 || (mode == METHOD_MODE && hasInheritance(jClass, METHOD_INHERITANCE)) ||
              (mode == CONSTRUCTOR_MODE && hasInheritance(jClass, CONSTRUCTOR_INHERITANCE))) {
              saxStartElement(handler, elementGroup);
              
              // Output inheritance:
              if (mode == METHOD_MODE) {
                  outputSuperClassInheritance(handler, jClass, METHOD_INHERITANCE);
              } else {
                  outputSuperClassInheritance(handler, jClass, CONSTRUCTOR_INHERITANCE);
              }
          
              for (int i=0; i<methods.length; i++) {
                  if (mode == METHOD_MODE && methods[i].getReturns() != null) {
                      outputMethodStartElement(handler, methods[i]);
                  } else if (mode == CONSTRUCTOR_MODE && methods[i].getReturns() == null) {
                      saxStartElement(handler, CONSTRUCTOR_ELEMENT,
                          new String[][] {{NAME_ATTRIBUTE, methods[i].getName()},
                                          {SIGNATURE_ATTRIBUTE, getSignature(methods[i])}});
                  } else {
                      // Do not process this method or constructor:
                      continue;
                  }
                  
                  JavaParameter[] params = methods[i].getParameters();
                  DocletTag[] paramTags = methods[i].getTagsByName("param");
                  DocletTag[] throwsTags = methods[i].getTagsByName("throws");
                  
                  // Modifiers, comment, tags:
                  outputModifiers(handler, methods[i]);
                  outputComment(handler, methods[i].getComment());
                  outputTags(handler, methods[i]);
                  
                  // Parameters:
                  if (params.length > 0) {
                      saxStartElement(handler, PARAMETERS_ELEMENT);
                      for (int j=0; j<params.length; j++) {
                          String paramName = params[j].getName();
                          saxStartElement(handler, PARAMETER_ELEMENT,
                              new String[][] {{NAME_ATTRIBUTE, paramName},
                                              {TYPE_ATTRIBUTE, params[j].getType().getValue()},
                                              {DIMENSIONS_ATTRIBUTE, Integer.toString(params[j].getType().getDimensions())}});
                          
                          // Is there any doc for this parameter?
                          for (int k=0; k<paramTags.length; k++) {
                              String paramValue = paramTags[k].getValue();
                              int splitIndex = paramValue.indexOf(' ');
                              String paramValueName = splitIndex > 0 ? paramValue.substring(0, splitIndex) : paramValue;
                              if (paramName.equals(paramValueName)) {
                                  outputComment(handler, splitIndex > 0 ? paramValue.substring(splitIndex + 1) : "");
                              }
                          }
                          
                          saxEndElement(handler, PARAMETER_ELEMENT);
                      }
                      saxEndElement(handler, PARAMETERS_ELEMENT);
                  }
                  
                  // Exceptions:
                  Type[] exceptions = methods[i].getExceptions();
                  if (exceptions.length + throwsTags.length > 0) {
                      saxStartElement(handler, THROWS_ELEMENT);
                      for (int j=0; j<exceptions.length; j++) {
                          // Iterate each exception which is declared in the throws clause:
                          String exceptionName = exceptions[j].getValue();
                          saxStartElement(handler, EXCEPTION_ELEMENT, new String[][] {{NAME_ATTRIBUTE, exceptionName}});
                          
                          // Is there any doc for this exception?
                          if (throwsTags.length > 0) {
                              String exceptionClassName = exceptionName.substring(exceptionName.lastIndexOf('.'));
                              for (int k=0; k<throwsTags.length; k++) {
                                  String excValue = throwsTags[k].getValue();
                                  int splitIndex = excValue.indexOf(' ');
                                  String excValueName = splitIndex > 0 ? excValue.substring(0, splitIndex) : excValue;
                                  if (exceptionClassName.equals(excValueName)) {
                                      outputComment(handler, splitIndex > 0 ? excValue.substring(splitIndex + 1) : "");
                                  }
                              }
                          }
                          
                          saxEndElement(handler, EXCEPTION_ELEMENT);
                      }
                      
                      for (int j=0; j<throwsTags.length; j++) {
                          // Iterate each exception which is not declared in the throws clause but documented in javadoc:
                          String content = throwsTags[j].getValue();
                          int splitIndex = content.indexOf(' ');
                          String exceptionName = content.substring(0, splitIndex);
                          String qualifiedExceptionName = getQualifiedClassName(exceptionName);
                          
                          // Does the exception *not* exist in the throws clause?
                          boolean found = false;
                          for (int k=0; !found && k<exceptions.length; k++) {
                              found = qualifiedExceptionName.equals(exceptions[k].getValue());
                          }
                          
                          if (!found) {
                              saxStartElement(handler, EXCEPTION_ELEMENT, new String[][] {{NAME_ATTRIBUTE, qualifiedExceptionName}});
                              outputComment(handler, splitIndex > 0 ? content.substring(splitIndex + 1) : "");
                              saxEndElement(handler, EXCEPTION_ELEMENT);
                          }
                      }
                      
                      saxEndElement(handler, THROWS_ELEMENT);
                  }
                  
                  saxEndElement(handler, element);
              }
              
              saxEndElement(handler, elementGroup);
          }
      }
      
      /**
       * Method getSignature.
       * 
       * @param javaMethod
       * @return String
       */
      private String getSignature(JavaMethod javaMethod) {
          StringBuffer sb = new StringBuffer(javaMethod.getName());
          sb.append('(');
          JavaParameter[] params = javaMethod.getParameters();
          for (int j=0; j<params.length; j++) {
              if (j > 0) {
                  sb.append(", ");
              }
              sb.append(params[j].getType().getValue());
              int dims = params[j].getType().getDimensions();
              for (int k=0; k<dims; k++) {
                  sb.append("[]");
              }
          }
          sb.append(')');
          
          return sb.toString();
      }
      
      /**
       * Method outputMethodStartElement.
       * 
       * @param handler
       * @param javaMethod
       */
      private void outputMethodStartElement(ContentHandler handler, JavaMethod javaMethod) throws SAXException {
          if (javaMethod.getReturns() != null) {
              saxStartElement(handler, METHOD_ELEMENT,
                  new String[][] {{NAME_ATTRIBUTE, javaMethod.getName()},
                                  {TYPE_ATTRIBUTE, javaMethod.getReturns().getValue()},
                                  {DIMENSIONS_ATTRIBUTE, Integer.toString(javaMethod.getReturns().getDimensions())},
                                  {SIGNATURE_ATTRIBUTE, getSignature(javaMethod)}});
          } else {
              saxStartElement(handler, CONSTRUCTOR_ELEMENT,
                  new String[][] {{NAME_ATTRIBUTE, javaMethod.getName()},
                                  {SIGNATURE_ATTRIBUTE, getSignature(javaMethod)}});
          }
      }
      
      /**
       * Method outputMethodEndElement.
       * 
       * @param handler
       */
      private void outputMethodEndElement(ContentHandler handler, JavaMethod javaMethod) throws SAXException {
          if (javaMethod.getReturns() != null) {
              saxEndElement(handler, METHOD_ELEMENT);
          } else {
              saxEndElement(handler, CONSTRUCTOR_ELEMENT);
          }
      }
      
      /**
       * Method saxStartElement.
       * 
       * @param handler
       * @param localName
       */
      private void saxStartElement(ContentHandler handler, String localName) throws SAXException {
          handler.startElement(NS_URI, localName, NS_PREFIX + ':' + localName, EMPTY_ATTRS);
      }
      
      /**
       * Method saxStartElement.
       *
       * @param handler
       * @param localName
       * @param attrs
       */
      private void saxStartElement(ContentHandler handler, String localName, String[][] attrs) throws SAXException {
          AttributesImpl saxAttrs = new AttributesImpl();
          for (int i=0; i<attrs.length; i++) {
              if (attrs[i].length == 2) {
                  saxAttrs.addAttribute(EMPTY, attrs[i][0], attrs[i][0], ATTR_TYPE, attrs[i][1]);
              } else if (attrs[i].length == 5) {
                  saxAttrs.addAttribute(attrs[i][0], attrs[i][1], attrs[i][2], attrs[i][3], attrs[i][4]);
              }
          }
          
          handler.startElement(NS_URI, localName, NS_PREFIX + ':' + localName, saxAttrs);
      }
      
      /**
       * Method saxEndElement.
       * 
       * @param handler
       * @param localName
       */
      private void saxEndElement(ContentHandler handler, String localName) throws SAXException {
          handler.endElement(NS_URI, localName, NS_PREFIX + ':' + localName);
      }
      
      /**
       * Method saxCharacters.
       * 
       * @param handler
       * @param string
       */
      private void saxCharacters(ContentHandler handler, String text) throws SAXException {
          if (text != null && text.length() > 0) {
              handler.characters(text.toCharArray(), 0, text.length());
          }
      }
  
      /**
        * @see org.apache.excalibur.source.Source#exists()
        */
       public boolean exists() {
           return true;
       }
  }
  
  
  
  1.1                  cocoon-2.1/src/blocks/qdox/java/org/apache/cocoon/components/source/impl/QDoxSourceFactory.java
  
  Index: QDoxSourceFactory.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.source.impl;
  
  
  import java.io.File;
  import java.io.IOException;
  import java.net.MalformedURLException;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.Composable;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.excalibur.source.Source;
  import org.apache.excalibur.source.SourceException;
  import org.apache.excalibur.source.SourceFactory;
  import org.apache.excalibur.source.SourceResolver;
  import org.apache.regexp.RE;
  import org.apache.regexp.RESyntaxException;
  
  
  /**
   * This {@link org.apache.excalibur.source.SourceFactory SourceFactory} creates {@link
   * org.apache.excalibur.source.Source Source}s for the <code>javadoc:</code> URI scheme.
   * 
   * <p>The goal for this <code>SourceFactory</code> is to provide a <code>Source</code>
   * for a Java sourcefile containing as much information as possible to mimic the
   * standard Javadoc output.</p>
   * 
   * <p>The Source provides the following content:
   * <ul>
   *   <li>Classname</li>
   *   <li>Superclass</li>
   *   <li>Imports, including <code>java.lang</code> and the class' package</li>
   *   <li>Implemented interfaces</li>
   *   <li>Inner classes/interfaces, including superclass, implemented interfaces and
   * Javadoc (inner classes can be requested separately)</li>
   *   <li>Fields, including type, name and Javadoc</li>
   *   <li>Constructors, including parameters with their types and names, signature,
   * Javadoc and thrown exceptions</li>
   *   <li>Methods, including returntype, parameters, signature, Javadoc and thrown
   * exceptions</li>
   *   <li>Inheritance tree for each Class member, if needed</li>
   *   <li>Private members, if needed</li>
   * </ul>
   * </p>
   * 
   * <p>With this <code>SourceFactory</code>, you create Doclets with XSLT stylesheets
   * instead of Java code.</p>
   * 
   * <p>The <code>QDoxSourceFactory</code> uses <a href="http://qdox.sf.net/">QDox</a>
   * to parse the Java sourcefiles.
   * </p>
   * 
   * @author <a href="mailto:b.guijt1@chello.nl">Bart Guijt</a>
   * @version CVS $Revision: 1.1 $ $Date: 2003/05/06 08:49:59 $
   */
  public final class QDoxSourceFactory
      extends AbstractLogEnabled
      implements SourceFactory, Composable, Configurable, ThreadSafe {
      
      protected final static String INCLUDE_INHERITANCE_ELEMENT = "include-inheritance";
      protected final static String VALUE_ATTRIBUTE = "value";
      protected final static String SOURCE_GROUP_ELEMENT = "source-roots";
      protected final static String GROUP_ATTRIBUTE = "group";
      protected final static String SOURCE_ROOT_ELEMENT = "source-root";
      protected final static String URI_ATTRIBUTE = "uri";
      
      protected ComponentManager manager;
      protected List sourceRootUris;
      
      /**
       * RegExp matcher for Java classnames: distinguishes package and classname.
       */
      protected RE rePackageClass;
      
      /**
       * RegExp matcher for Java classnames: distinguishes package, classname and innerclassname.
       */
      protected RE rePackageClassInnerclass;
      
      
      /**
       * Represents an URI and which packages it contains.
       * 
       * <p>Using this class, the QDoxSourceFactory can quickly find the right SourceRoot URI given a specified
       * package.</p>
       */
      protected final class SourceRoot {
          private List packages;
          private String sourceRootUri;
          
          protected SourceRoot(String uri) {
              if (!uri.endsWith(File.separator)) {
                  uri += '/';
              }
              sourceRootUri = uri;
              packages = new ArrayList();
          }
          
          protected void addPackage(String packageName) {
              packages.add(packageName);
          }
          
          protected boolean hasPackage(String packageName) {
              return packages.contains(packageName);
          }
          
          protected String getUri() {
              return sourceRootUri;
          }
      }
      
      
      /**
       * @see org.apache.excalibur.source.SourceFactory#getSource(java.lang.String, java.util.Map)
       */
      public Source getSource(String location, Map parameters) throws MalformedURLException, IOException, SourceException {
          String className = location.substring(location.indexOf(':') + 1);
          Source javaSource = null;
          if (className.length() > 0) {
              try {
                  if(getLogger().isDebugEnabled()) {
                      getLogger().debug("getSource called with className=" + className);
                  }
                  javaSource = getSource(className);
              } catch (ComponentException ce) {
                  throw new SourceException("SourceResolver not found", ce);
              }
          } else {
              throw new MalformedURLException();
          }
  
          QDoxSource result = null;
          if (javaSource != null) {
              return new QDoxSource(location, javaSource, getLogger(), manager);
          }
  
          if(getLogger().isDebugEnabled()) {
              getLogger().debug("returning source=" + result + " for className=" + className);
          }
  
          return result;
      }
      
      /**
       * @see org.apache.avalon.framework.component.Composable#compose(org.apache.avalon.framework.component.ComponentManager)
       */
      public void compose(ComponentManager manager) throws ComponentException {
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("Composing the QDoxSourceFactory...");
          }
          this.manager = manager;
          
          try {
              rePackageClass = new RE("([$\\w.]+)\\.([$\\w]+)");
              rePackageClassInnerclass = new RE("([$\\w.]+)\\.([$\\w]+)\\.([$\\w]+)");
          } catch (RESyntaxException e) {
              getLogger().error("RegExp syntax error!", e);
          }
      }
      
      /**
       * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
       */
      public void configure(Configuration config) throws ConfigurationException {
          Configuration[] sourceRootGroups = config.getChildren(SOURCE_GROUP_ELEMENT);
          sourceRootUris = new ArrayList();
          
          for (int i=0; i<sourceRootGroups.length; i++) {
              Configuration[] sourceRootConfigs = sourceRootGroups[i].getChildren(SOURCE_ROOT_ELEMENT);
              
              for (int j=0; j<sourceRootConfigs.length; j++) {
                  String uri = sourceRootConfigs[j].getAttribute(URI_ATTRIBUTE);
                  sourceRootUris.add(new SourceRoot(uri));
              }
          }
          
          if (sourceRootUris.size() == 0 && getLogger().isErrorEnabled()) {
              getLogger().error("No source roots configured!");
          }
      }
      
      /**
       * Releases the specified Source.
       * 
       * @see org.apache.excalibur.source.SourceFactory#release(org.apache.excalibur.source.Source)
       */
      public void release(Source source) {
          // ??? What to do here?
      }
      
      /**
       * Method getSource.
       * 
       * @param className
       * @return File
       */
      private Source getSource(String className) throws ComponentException {
          String classFileName = className;
          String packageName;
          
          if (rePackageClass.match(className)) {
              packageName = rePackageClass.getParen(1);
          } else {
              packageName = "";
          }
          
          classFileName = classFileName.replace('.', '/') + ".java";
          SourceResolver resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
          
          Source source = getSource(classFileName, packageName, resolver); 
          if (source == null && rePackageClassInnerclass.match(className)) {
              // Inner class?
              
              packageName = rePackageClassInnerclass.getParen(1);
              classFileName = className.substring(0, className.lastIndexOf('.')).replace('.', '/') + ".java";
              source = getSource(classFileName, packageName, resolver);
          }
          manager.release(resolver);
              
          if (source == null && getLogger().isWarnEnabled()) {
              getLogger().warn("No source found for class '" + className + "'!");
          }
  
          return source;
      }
      
      private Source getSource(String classFileName, String packageName, SourceResolver resolver) {
          // First, test whether there are configured packages to speed things up:
          for (Iterator i = sourceRootUris.iterator(); i.hasNext();) {
              SourceRoot sourceRoot = (SourceRoot) i.next();
              
              if (sourceRoot.hasPackage(packageName)) {
                  String uri = sourceRoot.getUri() + classFileName;
                  Source source = getSource(uri, resolver);
                  if (source != null) {
                      return source;
                  }
              }
          }
          
          // No suitable package found, iterate all source roots:
          for (Iterator i = sourceRootUris.iterator(); i.hasNext();) {
              SourceRoot sourceRoot = (SourceRoot) i.next();
              String uri = sourceRoot.getUri() + classFileName;
              
              Source source = getSource(uri, resolver);
              if (source != null) {
                  sourceRoot.addPackage(packageName);
                  return source;
              }
          }
          
          return null;
      }
      
      /**
       * Method getSource.
       * 
       * @param uri
       * @param resolver
       * @return Source
       */
      private Source getSource(String uri, SourceResolver resolver) {
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("Testing uri <" + uri + ">...");
          }
              
          try {
              Source source = resolver.resolveURI(uri);
                  
              if (source != null && source.getInputStream() != null) {
                  return source;
              } else {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("uri <" + uri + "> is invalid.");
                  }
              }
          } catch (Exception e) {
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("uri <" + uri + "> is invalid: " + e.getClass().getName() + " says " + e.getMessage());
              }
          }
          
          return null;
      }
  }
  
  
  1.1                  cocoon-2.1/src/blocks/qdox/lib/qdox-1.1.jar
  
  	<<Binary file>>
  
  
  1.1                  cocoon-2.1/src/blocks/qdox/samples/samples.xml
  
  Index: samples.xml
  ===================================================================
  <?xml version="1.0" encoding="iso-8859-1"?>
  
  <!-- CVS: $Id: samples.xml,v 1.1 2003/05/06 08:50:00 bdelacretaz Exp $ -->
  
  <samples xmlns:xlink="http://www.w3.org/1999/xlink" name="QDoxSource">
    <group name="Class: java.util.HashMap">
      <sample name="HTML" href="javadoc/java.util.HashMap">
        Shows the Javadoc page of the class <code>java.util.HashMap</code>
      </sample>
      <sample name="XML" href="javadoc-xml/java.util.HashMap">
        Shows the Javadoc XML source of the class <code>java.util.HashMap</code>
      </sample>
      <sample name="J2SE" href="http://java.sun.com/j2se/1.4.1/docs/api/java/util/HashMap.html">
        Shows the original J2SE API document of the class <code>java.util.HashMap</code>
      </sample>
        <note>
            NOTE: for these samples to work, the &lt;source-roots&gt; of the QDoxSource must be configured
            correctly in cocoon.xconf. The QDox block provides an initial configuration that reads source code from
            file:///tmp/qdox-test, so unless you reconfigure source-roots in cocoon.xconf you need to copy source files
            there for these tests to work (for example /tmp/qdox-test//java/util/HashMap.java).
        </note>
    </group>
    <group name="Interface: java.util.SortedSet">
      <sample name="HTML" href="javadoc/java.util.SortedSet">
        Shows the Javadoc page of the interface <code>java.util.SortedSet</code>
      </sample>
      <sample name="XML" href="javadoc-xml/java.util.SortedSet">
        Shows the Javadoc XML source of the interface <code>java.util.SortedSet</code>
      </sample>
      <sample name="J2SE" href="http://java.sun.com/j2se/1.4.1/docs/api/java/util/SortedSet.html">
        Shows the original J2SE API document of the interface <code>java.util.SortedSet</code>
      </sample>
    </group>
    <group name="BIG class: javax.swing.JComponent">
      <sample name="HTML" href="javadoc/javax.swing.JComponent">
        Shows the Javadoc page of the class <code>javax.swing.JComponent</code>
      </sample>
      <sample name="XML" href="javadoc-xml/javax.swing.JComponent">
        Shows the Javadoc XML source of the class <code>javax.swing.JComponent</code>
      </sample>
      <sample name="J2SE" href="http://java.sun.com/j2se/1.4.1/docs/api/javax/swing/JComponent.html">
        Shows the original J2SE API document of the class <code>javax.swing.JComponent</code>
      </sample>
    </group>
    <group name="Inner class: java.awt.geom.Arc2D.Double">
      <sample name="HTML" href="javadoc/java.awt.geom.Arc2D.Double">
        Shows the Javadoc page of the class <code>java.awt.geom.Arc2D.Double</code>
      </sample>
      <sample name="XML" href="javadoc-xml/java.awt.geom.Arc2D.Double">
        Shows the Javadoc XML source of the class <code>java.awt.geom.Arc2D.Double</code>
      </sample>
      <sample name="J2SE" href="http://java.sun.com/j2se/1.4.1/docs/api/java/awt/geom/Arc2D.Double.html">
        Shows the original J2SE API document of the class <code>java.awt.geom.Arc2D.Double</code>
      </sample>
    </group>
  
    <group name="Resources">
      <sample name="QDox web site" href="http://qdox.codehaus.org/">
         Links and reference information
      </sample>
     </group>
  
  </samples>
  
  
  
  1.1                  cocoon-2.1/src/blocks/qdox/samples/sitemap.xmap
  
  Index: sitemap.xmap
  ===================================================================
  <?xml version="1.0"?>
  
  <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
    <!-- =========================== Components ================================ -->
  
    <map:components>
      <map:generators default="file" />
      <map:transformers default="xslt" />
      <map:readers default="resource" />
      <map:serializers default="html" />
      <map:matchers default="wildcard" />
      <map:selectors default="browser" />
    </map:components>
  
  
    <!-- =========================== Pipelines ================================= -->
  
    <map:pipelines>
      <map:pipeline>
        
        <map:match pattern="">
          <map:redirect-to uri="samples"/>
        </map:match>
        
        <map:match pattern="samples">
          <map:generate src="samples.xml"/>
          <map:transform type="xalan" src="context://samples/common/style/xsl/html/simple-samples2html.xsl"/>
          <map:serialize/>
        </map:match>
  
        <!-- Output Javadoc XML: -->
        <map:match pattern="javadoc-xml/*">
          <map:generate src="qdox:{1}" />
          <map:serialize type="xml" />
        </map:match>
        
        <!-- Output Javadoc HTML: -->
        <map:match pattern="javadoc/*">
          <map:generate src="qdox:{1}" />
          <map:transform src="stylesheets/qdox2html.xsl" />
          <map:serialize type="html" />
        </map:match>
      </map:pipeline>
    </map:pipelines>
  
  </map:sitemap>
  
  
  
  1.1                  cocoon-2.1/src/blocks/qdox/samples/stylesheets/qdox2html.xsl
  
  Index: qdox2html.xsl
  ===================================================================
  <?xml version="1.0"?>
  
  <!-- $Id: qdox2html.xsl,v 1.1 2003/05/06 08:50:00 bdelacretaz Exp $ -->
  
  <!DOCTYPE xsl:stylesheet [
    <!ENTITY nbsp "&#160;">
    <!ENTITY lt   "&#60;">
    <!ENTITY gt   "&#62;">
    ]>
  
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                  xmlns:jd="http://apache.org/cocoon/javadoc/1.0">
    
    
    <xsl:output method="html" />
    
    
    <xsl:template match="/">
      <html>
        <head>
          <title>API specs of <xsl:value-of select="@qname" /></title>
        </head>
        <body bcolor="white">
          <font size="-1" color="grey">This Javadoc has been produced by Cocoon using the QDoxSource component</font>
          <xsl:comment> ======== START OF CLASS DATA ======== </xsl:comment>
          <h2>
            <font size="-1"><xsl:value-of select="*/@package" /></font>
            <br />
            <xsl:choose>
              <xsl:when test="jd:class">
                <xsl:text>Class </xsl:text>
              </xsl:when>
              <xsl:otherwise>
                <xsl:text>Interface </xsl:text>
              </xsl:otherwise>
            </xsl:choose>
            <xsl:if test="*/jd:nested-in">
              <xsl:value-of select="concat(*/jd:nested-in/*/@name, '.')" />
            </xsl:if>
            <xsl:value-of select="*/@name" />
          </h2>
          <xsl:apply-templates select="*" />
        </body>
      </html>
    </xsl:template>
    
    
    <xsl:template match="/jd:class">
      <pre>
        <xsl:apply-templates select="jd:inherit" mode="tree" />
      </pre>
      <xsl:if test="jd:implements/descendant::jd:interface">
        <dl>
          <dt>
            <b>All Implemented Interfaces:</b>
          </dt>
          <dd>
            <xsl:apply-templates select="jd:implements" mode="implemented_interfaces" />
          </dd>
        </dl>
      </xsl:if>
      <xsl:apply-templates select="jd:nested-in" />
      <hr />
      
      <dl>
        <dt>
          <xsl:for-each select="jd:modifiers/*">
            <xsl:value-of select="concat(local-name(), ' ')" />
          </xsl:for-each>
          <xsl:text>class </xsl:text>
          <b><xsl:value-of select="@name" /></b>
        </dt>
        <dt>
          <xsl:text>extends </xsl:text>
          <a href="{jd:inherit/@qname}">
            <xsl:value-of select="jd:inherit/@name" />
          </a>
        </dt>
        <xsl:if test="jd:implements/*">
          <dt>
            <xsl:text>implements </xsl:text>
            <xsl:for-each select="jd:implements/jd:interface">
              <a href="{@qname}">
                <xsl:value-of select="@name" />
              </a>
              <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
              </xsl:if>
            </xsl:for-each>
          </dt>
        </xsl:if>
      </dl>
      <p>
        <xsl:apply-templates select="jd:comment" mode="detail" />
      </p>
      <p>
        <xsl:apply-templates select="jd:tags" />
      </p>
      <hr />
      
      <xsl:apply-templates select="jd:innerclasses" mode="summary" />
      <xsl:apply-templates select="jd:fields"       mode="summary" />
      <xsl:apply-templates select="jd:constructors" mode="summary" />
      <xsl:apply-templates select="jd:methods"      mode="summary" />
      
      <p />
      
      <xsl:apply-templates select="jd:fields[jd:field]"             mode="detail" />
      <xsl:apply-templates select="jd:constructors[jd:constructor]" mode="detail" />
      <xsl:apply-templates select="jd:methods[jd:method]"           mode="detail" />
    </xsl:template>
    
    
    <xsl:template match="/jd:interface">
      <pre>
        <xsl:apply-templates select="jd:inherit" mode="tree" />
      </pre>
      <xsl:if test="jd:implements">
        <dl>
          <dt>
            <b>All Superinterfaces:</b>
          </dt>
          <dd>
            <xsl:for-each select="jd:implements//jd:interface">
              <a href="{@qname}">
                <xsl:value-of select="@name" />
              </a>
              <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
              </xsl:if>
            </xsl:for-each>
          </dd>
        </dl>
      </xsl:if>
      <xsl:apply-templates select="jd:nested-in" />
      <hr />
      
      <dl>
        <dt>
          <xsl:for-each select="jd:modifiers/*">
            <xsl:value-of select="concat(local-name(), ' ')" />
          </xsl:for-each>
          <xsl:text>interface </xsl:text>
          <b>
            <xsl:if test="jd:nested-in">
              <xsl:value-of select="concat(jd:nested-in/*/@name, '.')" />
            </xsl:if>
            <xsl:value-of select="@name" />
          </b>
        </dt>
        <xsl:if test="jd:implements/*">
          <dt>
            <xsl:text>extends </xsl:text>
            <xsl:for-each select="jd:implements/jd:interface">
              <a href="{@qname}">
                <xsl:value-of select="@name" />
              </a>
              <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
              </xsl:if>
            </xsl:for-each>
          </dt>
        </xsl:if>
      </dl>
      <p>
        <xsl:apply-templates select="jd:comment" mode="detail" />
      </p>
      <p>
        <xsl:apply-templates select="jd:tags" />
      </p>
      <hr />
      
      <xsl:apply-templates select="jd:innerclasses" mode="summary" />
      <xsl:apply-templates select="jd:fields"       mode="summary" />
      <xsl:apply-templates select="jd:methods"      mode="summary" />
      
      <p />
      
      <xsl:apply-templates select="jd:fields[jd:field]"   mode="detail" />
      <xsl:apply-templates select="jd:methods[jd:method]" mode="detail" />
    </xsl:template>
    
    
    <xsl:template match="jd:inherit" mode="tree">
      <xsl:for-each select="descendant-or-self::jd:inherit">
        <xsl:sort select="position()" data-type="number" order="descending" />
        
        <xsl:variable name="spaces">
          <xsl:call-template name="repeat">
            <xsl:with-param name="cnt" select="count(descendant::jd:inherit) * 6 - 2" />
            <xsl:with-param name="text" select="' '" />
          </xsl:call-template>
        </xsl:variable>
        
        <xsl:if test="position() != 1">
          <xsl:value-of select="concat($spaces, '|&#xA;', $spaces, '+-')" />
        </xsl:if>
        <a href="{@qname}"><xsl:value-of select="@qname" /></a>
        <xsl:text>&#xA;</xsl:text>
      </xsl:for-each>
      
      <xsl:variable name="spaces">
        <xsl:call-template name="repeat">
          <xsl:with-param name="cnt" select="count(descendant::jd:inherit) * 6 + 4" />
          <xsl:with-param name="text" select="' '" />
        </xsl:call-template>
      </xsl:variable>
      
      <xsl:value-of select="concat($spaces, '|&#xA;', $spaces, '+-')" />
      <b><xsl:value-of select="/jd:class/@qname" /></b>
    </xsl:template>
    
    
    <xsl:template match="jd:implements" mode="implemented_interfaces">
      <xsl:for-each select="//jd:interface">
        <xsl:sort select="@name" data-type="text" />
        <xsl:if test="1=1"> <!-- TODO: refine condition ;-) -->
          <xsl:if test="position() != 1">
            <xsl:text>, </xsl:text>
          </xsl:if>
          <a href="{@qname}">
            <xsl:value-of select="@name" />
          </a>
        </xsl:if>
      </xsl:for-each>
    </xsl:template>
    
    
    <xsl:template match="jd:tags">
      <dl>
        <xsl:if test="jd:since">
          <dt>
            <b>Since:</b>
          </dt>
          <dd><xsl:value-of select="jd:since" /></dd>
        </xsl:if>
        <xsl:if test="jd:version">
          <dt>
            <b>Version:</b>
          </dt>
          <dd><xsl:value-of select="jd:version" disable-output-escaping="yes" /></dd>
        </xsl:if>
        <xsl:if test="jd:author">
          <dt>
            <b>Author:</b>
          </dt>
          <dd>
            <xsl:for-each select="jd:author">
              <xsl:value-of select="text()" disable-output-escaping="yes" />
              <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
              </xsl:if>
            </xsl:for-each>
          </dd>
        </xsl:if>
        <xsl:if test="jd:see">
          <dt>
            <b>See Also:</b>
          </dt>
          <dd>
            <xsl:for-each select="jd:see">
              <xsl:apply-templates select="jd:link" mode="comment" />
              <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
              </xsl:if>
            </xsl:for-each>
          </dd>
        </xsl:if>
      </dl>
    </xsl:template>
    
    
    <xsl:template match="jd:innerclasses" mode="summary">
      <xsl:comment> =========== NESTED CLASS SUMMARY =========== </xsl:comment>
      <a name="nested_class_summary" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#CCCCFF" class="TableHeadingColor">
          <td colspan="2">
            <font size="+2">
              <b>Nested Class Summary</b>
            </font>
          </td>
        </tr>
        <xsl:for-each select="jd:class | jd:interface">
          <xsl:sort select="@name" />
          <tr bgcolor="white" class="TableRowColor">
            <td align="right" valign="top" width="1%">
              <font size="-1">
                <code>
                  <xsl:text>&nbsp;</xsl:text>
                  <xsl:for-each select="jd:modifiers/*">
                    <xsl:value-of select="local-name()" />
                    <xsl:text> </xsl:text>
                  </xsl:for-each>
                  <xsl:value-of select="local-name()" />
                </code>
              </font>
            </td>
            <td>
              <code>
                <b>
                  <a href="{concat(/*/@qname, '.', @name)}">
                    <xsl:value-of select="concat(/*/@name, '.', @name)" />
                  </a>
                </b>
              </code>
              <br />
              <xsl:apply-templates select="jd:comment" mode="summary" />
            </td>
          </tr>
        </xsl:for-each>
      </table>
      <xsl:text>&nbsp;</xsl:text>
      <xsl:apply-templates select="descendant::jd:inherit" mode="innerclass-summary" />
    </xsl:template>
    
    
    <xsl:template match="jd:inherit" mode="innerclass-summary">
      <a name="{concat('nested_classes_inherited_from_class_', @qname)}" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#EEEEFF" class="TableSubHeadingColor">
          <td>
            <b>
              <xsl:value-of select="concat('Nested classes inherited from ', local-name(/*), ' ', @package, '.')" />
              <a href="{@qname}"><xsl:value-of select="@name" /></a>
            </b>
          </td>
        </tr>
        <tr bgcolor="white" class="TableRowColor">
          <td>
            <code>
              <xsl:for-each select="*">
                <xsl:sort select="@name" data-type="text" />
                <a href="{concat(parent::*/@qname, '.', @name)}">
                  <xsl:value-of select="concat(parent::*/@name, '.', @name)" />
                </a>
                <xsl:if test="position() != last()">
                  <xsl:text>, </xsl:text>
                </xsl:if>
              </xsl:for-each>
            </code>
          </td>
        </tr>
      </table>
      <xsl:text>&nbsp;</xsl:text>
    </xsl:template>
    
    
    <xsl:template match="jd:fields" mode="summary">
      <xsl:comment> =========== FIELD SUMMARY =========== </xsl:comment>
      <a name="field_summary" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#CCCCFF" class="TableHeadingColor">
          <td colspan="2">
            <font size="+2">
              <b>Field Summary</b>
            </font>
          </td>
        </tr>
        <xsl:for-each select="jd:field">
          <xsl:sort select="@name" data-type="text" />
          <tr bgcolor="white" class="TableRowColor">
            <td align="right" valign="top" width="1%">
              <font size="-1">
                <code>
                  <xsl:text>&nbsp;</xsl:text>
                  <xsl:for-each select="jd:modifiers/*">
                    <xsl:value-of select="local-name()" />
                    <xsl:text> </xsl:text>
                  </xsl:for-each>
                  <xsl:call-template name="output-type">
                    <xsl:with-param name="type" select="current()" />
                  </xsl:call-template>
                </code>
              </font>
            </td>
            <td>
              <code>
                <b>
                  <a href="{concat('#', @name)}"><xsl:value-of select="@name" /></a>
                </b>
              </code>
              <br />
              <xsl:apply-templates select="jd:comment" mode="summary" />
            </td>
          </tr>
        </xsl:for-each>
      </table>
      <xsl:text>&nbsp;</xsl:text>
      <xsl:apply-templates select="descendant::jd:inherit" mode="field-summary" />
    </xsl:template>
  
    
    <xsl:template match="jd:inherit" mode="field-summary">
      <a name="{concat('fields_inherited_from_class_', @qname)}" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#EEEEFF" class="TableSubHeadingColor">
          <td>
            <b>
              <xsl:value-of select="concat('Fields inherited from ', local-name(/*), ' ', @package, '.')" />
              <a href="{@qname}"><xsl:value-of select="@name" /></a>
            </b>
          </td>
        </tr>
        <tr bgcolor="white" class="TableRowColor">
          <td>
            <code>
              <xsl:for-each select="jd:field">
                <xsl:sort select="@name" data-type="text" />
                <a href="{concat(parent::*/@qname, '#', @name)}"><xsl:value-of select="@name" /></a>
                <xsl:if test="position() != last()">
                  <xsl:text>, </xsl:text>
                </xsl:if>
              </xsl:for-each>
            </code>
          </td>
        </tr>
      </table>
      <xsl:text>&nbsp;</xsl:text>
    </xsl:template>
    
    
    <xsl:template match="jd:fields" mode="detail">
      <xsl:comment> =========== FIELD DETAIL =========== </xsl:comment>
      <a name="field_detail" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#CCCCFF" class="TableHeadingColor">
          <td>
            <font size="+2">
              <b>Field Detail</b>
            </font>
          </td>
        </tr>
      </table>
      <xsl:for-each select="jd:field">
        <xsl:sort select="@name" data-type="text" />
        <a name="{@name}" />
        <h3><xsl:value-of select="@name" /></h3>
        <pre>
          <xsl:for-each select="jd:modifiers/*">
            <xsl:value-of select="local-name()" />
            <xsl:text> </xsl:text>
          </xsl:for-each>
          <xsl:call-template name="output-type">
            <xsl:with-param name="type" select="current()" />
          </xsl:call-template>
          <xsl:text> </xsl:text>
          <b><xsl:value-of select="@name" /></b>
        </pre>
        <dl>
          <xsl:if test="jd:comment">
            <dd>
              <xsl:apply-templates select="jd:comment" mode="detail" />
            </dd>
          </xsl:if>
        </dl>
        <xsl:if test="position() != last()">
          <hr />
        </xsl:if>
      </xsl:for-each>
    </xsl:template>
    
    
    <xsl:template match="jd:constructors" mode="summary">
      <xsl:comment> =========== CONSTRUCTOR SUMMARY =========== </xsl:comment>
      <a name="constructor_summary" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#CCCCFF" class="TableHeadingColor">
          <td colspan="2">
            <font size="+2">
              <b>Constructor Summary</b>
            </font>
          </td>
        </tr>
        <xsl:for-each select="jd:constructor">
          <xsl:sort select="jd:parameters/jd:parameter[1]/@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[2]/@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[3]/@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[4]/@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[5]/@name" data-type="text" />
          <tr bgcolor="white" class="TableRowColor">
            <td align="right" valign="top" width="1%">
              <font size="-1">
                <code>
                  <xsl:text>&nbsp;</xsl:text>
                  <xsl:for-each select="jd:modifiers/*">
                    <xsl:value-of select="local-name()" />
                    <xsl:if test="position() != last()">
                      <xsl:text> </xsl:text>
                    </xsl:if>
                  </xsl:for-each>
                </code>
              </font>
            </td>
            <td>
              <code>
                <b>
                  <a href="{concat('#', @signature)}"><xsl:value-of select="@name" /></a>
                </b>
                <!-- Parameters: -->
                <xsl:text>(</xsl:text>
                <xsl:for-each select="jd:parameters/jd:parameter">
                  <xsl:call-template name="output-type">
                    <xsl:with-param name="type" select="current()" />
                  </xsl:call-template>
                  <xsl:value-of select="concat('&nbsp;', @name)" />
                  <xsl:if test="position() != last()">
                    <xsl:text>, </xsl:text>
                  </xsl:if>
                </xsl:for-each>
                <xsl:text>)</xsl:text>
              </code>
              <br />
              <xsl:apply-templates select="jd:comment" mode="summary" />
            </td>
          </tr>
        </xsl:for-each>
      </table>
      <xsl:text>&nbsp;</xsl:text>
    </xsl:template>
    
    
    <xsl:template match="jd:constructors" mode="detail">
      <xsl:comment> =========== CONSTRUCTOR DETAIL =========== </xsl:comment>
      <a name="constructor_detail" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#CCCCFF" class="TableHeadingColor">
          <td>
            <font size="+2">
              <b>Constructor Detail</b>
            </font>
          </td>
        </tr>
      </table>
      <xsl:for-each select="jd:constructor">
        <xsl:sort select="jd:parameters/jd:parameter[1]/@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[2]/@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[3]/@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[4]/@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[5]/@name" data-type="text" />
        
        <a name="{@signature}" />
        <h3><xsl:value-of select="@name" /></h3>
        <xsl:variable name="mod">
          <xsl:for-each select="jd:modifiers/*">
            <xsl:value-of select="local-name()" />
            <xsl:text> </xsl:text>
          </xsl:for-each>
        </xsl:variable>
        <xsl:variable name="spaces">
          <xsl:call-template name="repeat">
            <xsl:with-param name="text" select="' '" />
            <xsl:with-param name="cnt" select="string-length($mod) + string-length(@name) + 1" />
          </xsl:call-template>
        </xsl:variable>
        <pre>
          <xsl:value-of select="$mod" />
          <b><xsl:value-of select="@name" /></b>
          <xsl:text>(</xsl:text>
          <xsl:for-each select="jd:parameters/jd:parameter">
            <xsl:call-template name="output-type">
              <xsl:with-param name="type" select="current()" />
            </xsl:call-template>
            <xsl:value-of select="concat('&nbsp;', @name)" />
            <xsl:if test="position() != last()">
              <xsl:value-of select="concat(',&#xA;', $spaces)" />
            </xsl:if>
          </xsl:for-each>
          <xsl:text>)</xsl:text>
          <xsl:if test="jd:throws/jd:exception">
            <xsl:text>&#xA;</xsl:text>
            <xsl:call-template name="repeat">
              <xsl:with-param name="text" select="' '" />
              <xsl:with-param name="cnt" select="string-length($mod) + string-length(@name) - 6" />
            </xsl:call-template>
            <xsl:text>throws </xsl:text>
            <xsl:for-each select="jd:throws/jd:exception">
              <a href="{@name}">
                <xsl:call-template name="class-part">
                  <xsl:with-param name="classname" select="@name" />
                </xsl:call-template>
              </a>
              <xsl:if test="position() != last()">
                <xsl:value-of select="concat(',&#xA;', $spaces)" />
              </xsl:if>
            </xsl:for-each>
          </xsl:if>
        </pre>
        <dl>
          <xsl:if test="jd:comment">
            <dd>
              <xsl:apply-templates select="jd:comment" mode="detail" />
            </dd>
          </xsl:if>
          <p />
          <xsl:apply-templates select="jd:parameters" mode="list_comment" />
          <xsl:if test="jd:throws/jd:exception">
            <dt>
              <b>Throws:</b>
            </dt>
            <xsl:apply-templates select="jd:throws/jd:exception" mode="list_comment" />
          </xsl:if>
        </dl>
        <xsl:if test="position() != last()">
          <hr />
        </xsl:if>
      </xsl:for-each>
    </xsl:template>
    
    
    <xsl:template match="jd:methods" mode="summary">
      <xsl:comment> =========== METHOD SUMMARY =========== </xsl:comment>
      <a name="method_summary" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#CCCCFF" class="TableHeadingColor">
          <td colspan="2">
            <font size="+2">
              <b>Method Summary</b>
            </font>
          </td>
        </tr>
        <xsl:apply-templates select="jd:method" mode="summary">
          <xsl:sort select="@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[1]/@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[2]/@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[3]/@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[4]/@name" data-type="text" />
          <xsl:sort select="jd:parameters/jd:parameter[5]/@name" data-type="text" />
        </xsl:apply-templates>
      </table>
      <xsl:text>&nbsp;</xsl:text>
      <xsl:apply-templates select="descendant::jd:inherit[@type=local-name(/*)]" mode="method-summary" />
    </xsl:template>
    
    
    <xsl:template match="jd:method" mode="summary">
      <tr bgcolor="white" class="TableRowColor">
        <td align="right" valign="top" width="1%">
          <font size="-1">
            <code>
              <xsl:text>&nbsp;</xsl:text>
              <xsl:for-each select="jd:modifiers/*">
                <xsl:value-of select="local-name()" />
                <xsl:text> </xsl:text>
              </xsl:for-each>
              <xsl:call-template name="output-type">
                <xsl:with-param name="type" select="current()" />
              </xsl:call-template>
            </code>
          </font>
        </td>
        <td>
          <code>
            <b>
              <a href="{concat('#', @signature)}"><xsl:value-of select="@name" /></a>
            </b>
            <!-- Parameters: -->
            <xsl:text>(</xsl:text>
            <xsl:for-each select="jd:parameters/jd:parameter">
              <xsl:call-template name="output-type">
                <xsl:with-param name="type" select="current()" />
              </xsl:call-template>
              <xsl:value-of select="concat('&nbsp;', @name)" />
              <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
              </xsl:if>
            </xsl:for-each>
            <xsl:text>)</xsl:text>
          </code>
          <br />
          <xsl:apply-templates select="jd:comment" mode="summary" />
        </td>
      </tr>
    </xsl:template>
    
    
    <xsl:template match="jd:inherit" mode="method-summary">
      <xsl:variable name="signatures" select="ancestor::*[local-name()='inherit' or local-name()='methods']/jd:method/@signature" />
      <xsl:if test="jd:method[not(@signature = $signatures)]">
        <a name="{concat('methods_inherited_from_class_', @qname)}" />
        <table border="1" cellpadding="3" cellspacing="0" width="100%">
          <tr bgcolor="#EEEEFF" class="TableSubHeadingColor">
            <td>
              <b>
                <xsl:value-of select="concat('Methods inherited from ', local-name(/*), ' ', @package, '.')" />
                <a href="{@qname}"><xsl:value-of select="@name" /></a>
              </b>
            </td>
          </tr>
          <tr bgcolor="white" class="TableRowColor">
            <td>
              <code>
                <xsl:for-each select="jd:method[not(@signature = $signatures)]">
                  <xsl:sort select="@name" data-type="text" />
                  <a href="{concat(parent::*/@qname, '#', @signature)}"><xsl:value-of select="@name" /></a>
                  <xsl:if test="position() != last()">
                    <xsl:text>, </xsl:text>
                  </xsl:if>
                </xsl:for-each>
              </code>
            </td>
          </tr>
        </table>
        <xsl:text>&nbsp;</xsl:text>
      </xsl:if>
    </xsl:template>
    
    
    <xsl:template match="jd:methods" mode="detail">
      <xsl:comment> =========== METHOD DETAIL =========== </xsl:comment>
      <a name="method_detail" />
      <table border="1" cellpadding="3" cellspacing="0" width="100%">
        <tr bgcolor="#CCCCFF" class="TableHeadingColor">
          <td>
            <font size="+2">
              <b>Method Detail</b>
            </font>
          </td>
        </tr>
      </table>
      <xsl:for-each select="jd:method">
        <xsl:sort select="@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[1]/@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[2]/@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[3]/@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[4]/@name" data-type="text" />
        <xsl:sort select="jd:parameters/jd:parameter[5]/@name" data-type="text" />
        
        <a name="{@signature}" />
        <h3><xsl:value-of select="@name" /></h3>
        <xsl:variable name="mod-type">
          <xsl:for-each select="jd:modifiers/*">
            <xsl:value-of select="local-name()" />
            <xsl:text> </xsl:text>
          </xsl:for-each>
          <xsl:call-template name="output-type">
            <xsl:with-param name="type" select="current()" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="spaces">
          <xsl:call-template name="repeat">
            <xsl:with-param name="text" select="' '" />
            <xsl:with-param name="cnt" select="string-length($mod-type) + string-length(@name) + 2" />
          </xsl:call-template>
        </xsl:variable>
        <pre>
          <xsl:value-of select="$mod-type" />
          <xsl:text> </xsl:text>
          <b><xsl:value-of select="@name" /></b>
          <xsl:text>(</xsl:text>
          <xsl:for-each select="jd:parameters/jd:parameter">
            <xsl:call-template name="output-type">
              <xsl:with-param name="type" select="current()" />
            </xsl:call-template>
            <xsl:value-of select="concat('&nbsp;', @name)" />
            <xsl:if test="position() != last()">
              <xsl:value-of select="concat(',&#xA;', $spaces)" />
            </xsl:if>
          </xsl:for-each>
          <xsl:text>)</xsl:text>
          <xsl:if test="jd:throws/jd:exception">
            <xsl:text>&#xA;</xsl:text>
            <xsl:call-template name="repeat">
              <xsl:with-param name="text" select="' '" />
              <xsl:with-param name="cnt" select="string-length($mod-type) + string-length(@name) - 5" />
            </xsl:call-template>
            <xsl:text>throws </xsl:text>
            <xsl:for-each select="jd:throws/jd:exception">
              <a href="{@name}">
                <xsl:call-template name="class-part">
                  <xsl:with-param name="classname" select="@name" />
                </xsl:call-template>
              </a>
              <xsl:if test="position() != last()">
                <xsl:value-of select="concat(',&#xA;', $spaces)" />
              </xsl:if>
            </xsl:for-each>
          </xsl:if>
        </pre>
        <dl>
          <xsl:if test="jd:comment">
            <dd>
              <xsl:apply-templates select="jd:comment" mode="detail" />
            </dd>
          </xsl:if>
          <p />
          <!-- Circumvention for Xalan bug - Xalan does not understand braces in xpath expressions! -->
          <xsl:variable name="m-specifies" select="ancestor::jd:methods/descendant::jd:inherit[@type='interface']/jd:method[@signature = current()/@signature]" />
          <xsl:variable name="specifies" select="$m-specifies[1]" />
          <xsl:if test="$specifies">
            <dt>
              <b>Specified by:</b>
            </dt>
            <dd>
              <a href="{concat($specifies/../@qname, '#', $specifies/@signature)}">
                <xsl:value-of select="$specifies/@name" />
              </a>
              <xsl:text> in interface </xsl:text>
              <a href="{$specifies/../@qname}">
                <xsl:value-of select="$specifies/../@name" />
              </a>
            </dd>
          </xsl:if>
          <!-- Circumvention for Xalan bug - Xalan does not understand braces in xpath expressions! -->
          <xsl:variable name="m-overrides" select="ancestor::jd:methods/descendant::jd:inherit[@type='class']/jd:method[@signature = current()/@signature]" />
          <xsl:variable name="overrides" select="$m-overrides[last()]" />
          <xsl:if test="$overrides">
            <dt>
              <b>Overrides:</b>
            </dt>
            <dd>
              <a href="{concat($overrides/../@qname, '#', $overrides/@signature)}">
                <xsl:value-of select="$overrides/@name" />
              </a>
              <xsl:value-of select="concat(' in ', local-name(/*), ' ')" />
              <a href="{$overrides/../@qname}">
                <xsl:value-of select="$overrides/../@name" />
              </a>
            </dd>
          </xsl:if>
          <xsl:apply-templates select="jd:parameters" mode="list_comment" />
          <xsl:if test="jd:tags/jd:return">
            <dt>
              <b>Returns:</b>
            </dt>
            <dd>
              <xsl:value-of select="jd:tags/jd:return" disable-output-escaping="yes" />
            </dd>
          </xsl:if>
          <xsl:if test="jd:throws/jd:exception">
            <dt>
              <b>Throws:</b>
            </dt>
            <xsl:apply-templates select="jd:throws/jd:exception" mode="list_comment" />
          </xsl:if>
        </dl>
        <xsl:if test="position() != last()">
          <hr />
        </xsl:if>
      </xsl:for-each>
    </xsl:template>
    
    
    <xsl:template match="jd:nested-in">
      <dl>
        <dt>
          <b><xsl:value-of select="concat('Enclosing ', local-name(*), ':')" /></b>
        </dt>
        <dd>
          <a href="{concat(*/@package, '.', */@name)}">
            <xsl:value-of select="*/@name" />
          </a>
        </dd>
      </dl>
    </xsl:template>
    
    
    <xsl:template match="jd:comment" mode="summary">
      <xsl:text>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</xsl:text>
      <xsl:variable name="before-dotspace">
        <xsl:choose>
          <xsl:when test="contains(text(), '. ')">
            <xsl:value-of select="concat(substring-before(text(), '. '), '.')" disable-output-escaping="yes" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="text()" disable-output-escaping="yes" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="contains($before-dotspace, '.&lt;')">
          <xsl:value-of select="concat(substring-before($before-dotspace, '.&lt;'), '.')" disable-output-escaping="yes" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$before-dotspace" disable-output-escaping="yes" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
    
    
    <xsl:template match="jd:comment" mode="detail">
      <xsl:apply-templates select="text()|jd:link" mode="comment" />
    </xsl:template>
    
    
    <xsl:template match="text()" mode="comment">
      <xsl:value-of select="." disable-output-escaping="yes" />
    </xsl:template>
    
    
    <xsl:template match="jd:link" mode="comment">
      <a>
        <xsl:attribute name="href">
          <xsl:value-of select="@class" />
          <xsl:if test="@member">
            <xsl:value-of select="concat('#', @member)" />
          </xsl:if>
        </xsl:attribute>
        <code>
          <xsl:choose>
            <xsl:when test="text()">
              <xsl:value-of select="text()" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="@class" />
              <xsl:if test="@member">
                <xsl:value-of select="concat('.', @member)" />
              </xsl:if>
            </xsl:otherwise>
          </xsl:choose>
        </code>
      </a>
    </xsl:template>
    
    
    <xsl:template match="jd:parameters" mode="list_comment">
      <dt>
        <b>Parameters:</b>
      </dt>
      <xsl:for-each select="jd:parameter">
        <dd>
          <code><xsl:value-of select="@name" /></code>
          <xsl:if test="jd:comment">
            <xsl:text> - </xsl:text>
            <xsl:apply-templates select="jd:comment" mode="detail" />
          </xsl:if>
        </dd>
      </xsl:for-each>
    </xsl:template>
  
  
    <xsl:template match="jd:exception" mode="list_comment">
      <dd>
        <a href="{@name}">
          <code>
            <xsl:call-template name="class-part">
              <xsl:with-param name="classname" select="@name" />
            </xsl:call-template>
          </code>
        </a>
        <xsl:text> - </xsl:text>
        <xsl:apply-templates select="jd:comment" mode="detail" />
      </dd>
    </xsl:template>
  
    
    <xsl:template name="output-type">
      <xsl:param name="type" />
      
      <xsl:choose>
        <xsl:when test="contains($type/@type, '.')">
          <!-- Class type: -->
          <a href="{$type/@type}">
            <xsl:call-template name="class-part">
              <xsl:with-param name="classname" select="$type/@type" />
            </xsl:call-template>
          </a>
        </xsl:when>
        <xsl:otherwise>
          <!-- Primitive type: -->
          <xsl:value-of select="$type/@type" />
        </xsl:otherwise>
      </xsl:choose>
      <xsl:call-template name="repeat">
        <xsl:with-param name="text" select="'[]'" />
        <xsl:with-param name="cnt" select="$type/@dimensions" />
      </xsl:call-template>
    </xsl:template>
    
    
    <xsl:template name="repeat">
      <xsl:param name="cnt" />
      <xsl:param name="text" />
      
      <xsl:if test="$cnt &gt; 0">
        <xsl:value-of select="$text" />
        <xsl:call-template name="repeat">
          <xsl:with-param name="cnt" select="$cnt - 1" />
          <xsl:with-param name="text" select="$text" />
        </xsl:call-template>
      </xsl:if>
    </xsl:template>
    
    
    <xsl:template name="class-part">
      <xsl:param name="classname" />
      
      <xsl:choose>
        <xsl:when test="contains($classname, '.')">
          <xsl:call-template name="class-part">
            <xsl:with-param name="classname" select="substring-after($classname, '.')" />
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$classname" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
    
  </xsl:stylesheet>