FileDocCategorySizeDatePackage
RootDocToXML.javaAPI DocAndroid 1.5 API49386Wed May 06 22:41:22 BST 2009jdiff

RootDocToXML

public class RootDocToXML extends Object
Converts a Javadoc RootDoc object into a representation in an XML file. See the file LICENSE.txt for copyright details.
author
Matthew Doar, mdoar@pobox.com

Fields Summary
public static String
outputFileName
The name of the file where the XML representing the API will be stored.
public static String
apiIdentifier
The identifier of the API being written out in XML, e.g. "SuperProduct 1.3".
private static PrintWriter
outputFile
The file where the XML representing the API will be stored.
public static String
outputDirectory
The name of the directory where the XML representing the API will be stored.
public static String
classVisibilityLevel
Do not display a class with a lower level of visibility than this. Default is to display all public and protected classes.
public static String
memberVisibilityLevel
Do not display a member with a lower level of visibility than this. Default is to display all public and protected members (constructors, methods, fields).
public static boolean
saveAllDocs
If set, then save the entire contents of a doc block comment in the API file. If not set, then just save the first sentence. Default is that this is set.
public static boolean
doExclude
If set, exclude program elements marked with whatever the exclude tag is specified as, e.g. "@exclude".
public static String
excludeTag
Exclude program elements marked with this String, e.g. "@exclude".
public static String
baseURI
The base URI for locating necessary DTDs and Schemas. By default, this is "http://www.w3.org". A typical value to use local copies of DTD files might be "file:///C:/jdiff/lib"
static boolean
stripNonPrintables
If set, then strip out non-printing characters from documentation. Default is that this is set.
static boolean
addSrcInfo
If set, then add the information about the source file and line number which is available in J2SE1.4. Default is that this is not set.
static boolean
packagesOnly
If set, scan classes with no packages. If the source is a jar file this may duplicates classes, so disable it using the -packagesonly option. Default is that this is not set.
private static boolean
trace
Set to enable increased logging verbosity for debugging.
Constructors Summary
public RootDocToXML()
Default constructor.

    
Methods Summary
public voidaddCommonModifiers(ProgramElementDoc ped, int indent)
Add qualifiers for the program element as attributes.

param
ped The given program element.

        addSourcePosition(ped, indent);
        // Static and final and visibility on one line
        for (int i = 0; i < indent; i++) outputFile.print(" ");
        outputFile.print("static=\"" + ped.isStatic() + "\"");
        outputFile.print(" final=\"" + ped.isFinal() + "\"");
        // Visibility
        String visibility = null;
        if (ped.isPublic())
            visibility = "public";
        else if (ped.isProtected())
            visibility = "protected";
        else if (ped.isPackagePrivate())
            visibility = "package";
        else if (ped.isPrivate())
            visibility = "private";
        outputFile.println(" visibility=\"" + visibility + "\"");

        // Deprecation on its own line
        for (int i = 0; i < indent; i++) outputFile.print(" ");
        boolean isDeprecated = false;
        Tag[] ta = ((Doc)ped).tags("deprecated");
        if (ta.length != 0) {
            isDeprecated = true;
        }
        if (ta.length > 1) {
            System.out.println("JDiff: warning: multiple @deprecated tags found in comments for " + ped.name() + ". Using the first one only.");
            System.out.println("Text is: " + ((Doc)ped).getRawCommentText());
        }
        if (isDeprecated) {
            String text = ta[0].text(); // Use only one @deprecated tag
            if (text != null && text.compareTo("") != 0) {
                int idx = endOfFirstSentence(text);
                if (idx == 0) {
                    // No useful comment
                    outputFile.print("deprecated=\"deprecated, no comment\"");
                } else {
                    String fs = null;
                    if (idx == -1)
                        fs = text;
                    else
                        fs = text.substring(0, idx+1);
                    String st = API.hideHTMLTags(fs);
                    outputFile.print("deprecated=\"" + st + "\"");
                }
            } else {
                outputFile.print("deprecated=\"deprecated, no comment\"");
            }
        } else {
            outputFile.print("deprecated=\"not deprecated\"");
        }

    
public voidaddDocumentation(ProgramElementDoc ped, int indent)
Add at least the first sentence from a doc block to the API. This is used by the report generator if no comment is provided. Need to make sure that HTML tags are not confused with XML tags. This could be done by stuffing the < character to another string or by handling HTML in the parser. This second option seems neater. Note that XML expects all element tags to have either a closing "/>" or a matching end element tag. Due to the difficulties of converting incorrect HTML to XHTML, the first option is used.

        String rct = ((Doc)ped).getRawCommentText();
        if (rct != null) {
            rct = stripNonPrintingChars(rct, (Doc)ped);
            rct = rct.trim();
            if (rct.compareTo("") != 0 && 
                rct.indexOf(Comments.placeHolderText) == -1 &&
                rct.indexOf("InsertOtherCommentsHere") == -1) {
                int idx = endOfFirstSentence(rct);
                if (idx == 0)
                    return;
                for (int i = 0; i < indent; i++) outputFile.print(" ");
                outputFile.println("<doc>");
                for (int i = 0; i < indent; i++) outputFile.print(" ");
                String firstSentence = null;
                if (idx == -1)
                    firstSentence = rct;
                else
                    firstSentence = rct.substring(0, idx+1);
                boolean checkForAts = false;
                if (checkForAts && firstSentence.indexOf("@") != -1 && 
                    firstSentence.indexOf("@link") == -1) {
                    System.out.println("Warning: @ tag seen in comment: " + 
                                       firstSentence);
                }
                String firstSentenceNoTags = API.stuffHTMLTags(firstSentence);
                outputFile.println(firstSentenceNoTags);
                for (int i = 0; i < indent; i++) outputFile.print(" ");
                outputFile.println("</doc>");
            }
        }
    
public voidaddPkgDocumentation(RootDoc root, PackageDoc pd, int indent)
Add at least the first sentence from a doc block for a package to the API. This is used by the report generator if no comment is provided. The default source tree may not include the package.html files, so this may be unavailable in many cases. Need to make sure that HTML tags are not confused with XML tags. This could be done by stuffing the < character to another string or by handling HTML in the parser. This second option is neater. Note that XML expects all element tags to have either a closing "/>" or a matching end element tag. Due to the difficulties of converting incorrect HTML to XHTML, the first option is used.

        String rct = null;
        String filename = pd.name();
        try {
            // See if the source path was specified as part of the
            // options and prepend it if it was.
            String srcLocation = null;
            String[][] options = root.options();
            for (int opt = 0; opt < options.length; opt++) {
                if ((options[opt][0]).compareTo("-sourcepath") == 0) {
                    srcLocation = options[opt][1];
                    break;
                }
            }
            filename = filename.replace('.", JDiff.DIR_SEP.charAt(0));
            if (srcLocation != null) {
                // Make a relative location absolute 
                if (srcLocation.startsWith("..")) {
                    String curDir = System.getProperty("user.dir");
                    while (srcLocation.startsWith("..")) {
                        srcLocation = srcLocation.substring(3);
                        int idx = curDir.lastIndexOf(JDiff.DIR_SEP);
                        curDir = curDir.substring(0, idx+1);
                    }
                    srcLocation = curDir + srcLocation;
                }
                filename = srcLocation + JDiff.DIR_SEP + filename;
            }
            // Try both ".htm" and ".html"
            filename += JDiff.DIR_SEP + "package.htm";
            File f2 = new File(filename);
            if (!f2.exists()) {
                filename += "l";
            }
            FileInputStream f = new FileInputStream(filename);
            BufferedReader d = new BufferedReader(new InputStreamReader(f));
            String str = d.readLine();
 	    // Ignore everything except the lines between <body> elements
	    boolean inBody = false;
	    while(str != null) {
                if (!inBody) {
		    if (str.toLowerCase().trim().startsWith("<body")) {
			inBody = true;
		    }
		    str = d.readLine(); // Get the next line
		    continue; // Ignore the line
		} else {
		    if (str.toLowerCase().trim().startsWith("</body")) {
			inBody = false;
			continue; // Ignore the line
		    }
		}
                if (rct == null)
                    rct = str + "\n";
                else
                    rct += str + "\n";
                str = d.readLine();
            }
        }  catch(java.io.FileNotFoundException e) {
            // If it doesn't exist, that's fine
            if (trace)
                System.out.println("No package level documentation file at '" + filename + "'");
        } catch(java.io.IOException e) {
            System.out.println("Error reading file \"" + filename + "\": " + e.getMessage());
            System.exit(5);
        }     
        if (rct != null) {
            rct = stripNonPrintingChars(rct, (Doc)pd);
            rct = rct.trim();
            if (rct.compareTo("") != 0 &&
                rct.indexOf(Comments.placeHolderText) == -1 &&
                rct.indexOf("InsertOtherCommentsHere") == -1) {
                int idx = endOfFirstSentence(rct);
                if (idx == 0)
                    return;
                for (int i = 0; i < indent; i++) outputFile.print(" ");
                outputFile.println("<doc>");
                for (int i = 0; i < indent; i++) outputFile.print(" ");
                String firstSentence = null;
                if (idx == -1)
                    firstSentence = rct;
                else
                    firstSentence = rct.substring(0, idx+1);
                String firstSentenceNoTags = API.stuffHTMLTags(firstSentence);
                outputFile.println(firstSentenceNoTags);
                for (int i = 0; i < indent; i++) outputFile.print(" ");
                outputFile.println("</doc>");
            }
        }
    
public voidaddSourcePosition(ProgramElementDoc ped, int indent)
Insert the source code details, if available.

param
ped The given program element.

        if (!addSrcInfo)
            return;
        if (JDiff.javaVersion.startsWith("1.1") || 
            JDiff.javaVersion.startsWith("1.2") || 
            JDiff.javaVersion.startsWith("1.3")) {
            return; // position() only appeared in J2SE1.4
        }
        try {
            // Could cache the method for improved performance
            Class c = ProgramElementDoc.class;
            Method m = c.getMethod("position", (Class[]) null);
            Object sp = m.invoke(ped, (Object[]) null);
            if (sp != null) {
                for (int i = 0; i < indent; i++) outputFile.print(" ");
                outputFile.println("src=\"" + sp + "\"");
            }
        } catch (NoSuchMethodException e2) {
            System.err.println("Error: method \"position\" not found");
            e2.printStackTrace();
        } catch (IllegalAccessException e4) {
            System.err.println("Error: class not permitted to be instantiated");
            e4.printStackTrace();
        } catch (InvocationTargetException e5) {
            System.err.println("Error: method \"position\" could not be invoked");
            e5.printStackTrace();
        } catch (Exception e6) {
            System.err.println("Error: ");
            e6.printStackTrace();
        }
    
private java.lang.StringbuildEmittableTypeString(com.sun.javadoc.Type type)
Build the emittable type name. The type may be an array and/or a generic type.

param
type A Type object
return
The emittable type name

        if (type == null) {
    	    return null;
        }
      // type.toString() returns the fully qualified name of the type
      // including the dimension and the parameters we just need to
      // escape the generic parameters brackets so that the XML
      // generated is correct
      String name = type.toString().replaceAll("<", "<").replaceAll(">", ">");
      if (name.startsWith("<<ambiguous>>")) {
          name = name.substring(13);
      }
      return name;
    
public voidemitType(com.sun.javadoc.Type type)
Emit the type name. Removed any prefixed warnings about ambiguity. The type maybe an array.

param
type A Type object.

        String name = buildEmittableTypeString(type);
        if (name == null)
            return;
        outputFile.print(name);
    
public voidemitXMLFooter()
Emit the XML footer.

        outputFile.println();
        outputFile.println("</api>");
    
public voidemitXMLHeader()
Emit the XML header.

        outputFile.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>");
        outputFile.println("<!-- Generated by the JDiff Javadoc doclet -->");
        outputFile.println("<!-- (" + JDiff.jDiffLocation + ") -->");
        outputFile.println("<!-- on " + new Date() + " -->");
        outputFile.println();
/* No need for this any longer, since doc block text is in an CDATA element
        outputFile.println("<!-- XML Schema is used, but XHTML transitional DTD is needed for nbsp -->");
        outputFile.println("<!-- entity definitions etc.-->");
        outputFile.println("<!DOCTYPE api");
        outputFile.println("     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
        outputFile.println("     \"" + baseURI + "/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
*/
        outputFile.println("<api");
        outputFile.println("  xmlns:xsi='" + baseURI + "/2001/XMLSchema-instance'");
        outputFile.println("  xsi:noNamespaceSchemaLocation='api.xsd'");
        outputFile.println("  name=\"" + apiIdentifier + "\"");
        outputFile.println("  jdversion=\"" + JDiff.version + "\">");
        outputFile.println();
    
public static intendOfFirstSentence(java.lang.String text)
Find the index of the end of the first sentence in the given text, when writing out to an XML file. This is an extended version of the algorithm used by the DocCheck Javadoc doclet. It checks for @tags too.

param
text The text to be searched.
return
The index of the end of the first sentence. If there is no end, return -1. If there is no useful text, return 0. If the whole doc block comment is wanted (default), return -1.

        return endOfFirstSentence(text, true);
    
public static intendOfFirstSentence(java.lang.String text, boolean writingToXML)
Find the index of the end of the first sentence in the given text. This is an extended version of the algorithm used by the DocCheck Javadoc doclet. It checks for @tags too.

param
text The text to be searched.
param
writingToXML Set to true when writing out XML.
return
The index of the end of the first sentence. If there is no end, return -1. If there is no useful text, return 0. If the whole doc block comment is wanted (default), return -1.

        if (saveAllDocs && writingToXML)
            return -1;
	int textLen = text.length();
	if (textLen == 0)
	    return 0;
        int index = -1;
        // Handle some special cases
        int fromindex = 0;
        int ellipsis = text.indexOf(". . ."); // Handles one instance of this
        if (ellipsis != -1)
            fromindex = ellipsis + 5;
        // If the first non-whitespace character is an @, go beyond it
        int i = 0;
        while (i < textLen && text.charAt(i) == ' ") {
            i++;
        }
        if (text.charAt(i) == '@" && fromindex < textLen-1)
            fromindex = i + 1;
        // Use the brute force approach.
        index = minIndex(index, text.indexOf("? ", fromindex));
        index = minIndex(index, text.indexOf("?\t", fromindex));
        index = minIndex(index, text.indexOf("?\n", fromindex));
        index = minIndex(index, text.indexOf("?\r", fromindex));
        index = minIndex(index, text.indexOf("?\f", fromindex));
        index = minIndex(index, text.indexOf("! ", fromindex));
        index = minIndex(index, text.indexOf("!\t", fromindex));
        index = minIndex(index, text.indexOf("!\n", fromindex));
        index = minIndex(index, text.indexOf("!\r", fromindex));
        index = minIndex(index, text.indexOf("!\f", fromindex));
        index = minIndex(index, text.indexOf(". ", fromindex));
        index = minIndex(index, text.indexOf(".\t", fromindex));
        index = minIndex(index, text.indexOf(".\n", fromindex));
        index = minIndex(index, text.indexOf(".\r", fromindex));
        index = minIndex(index, text.indexOf(".\f", fromindex));
        index = minIndex(index, text.indexOf("@param", fromindex));
        index = minIndex(index, text.indexOf("@return", fromindex));
        index = minIndex(index, text.indexOf("@throw", fromindex));
        index = minIndex(index, text.indexOf("@serial", fromindex));
        index = minIndex(index, text.indexOf("@exception", fromindex));
        index = minIndex(index, text.indexOf("@deprecate", fromindex));
        index = minIndex(index, text.indexOf("@author", fromindex));
        index = minIndex(index, text.indexOf("@since", fromindex));
        index = minIndex(index, text.indexOf("@see", fromindex));
        index = minIndex(index, text.indexOf("@version", fromindex));
        if (doExclude && excludeTag != null)
            index = minIndex(index, text.indexOf(excludeTag));
        index = minIndex(index, text.indexOf("@vtexclude", fromindex));
        index = minIndex(index, text.indexOf("@vtinclude", fromindex));
        index = minIndex(index, text.indexOf("<p>", 2)); // Not at start
        index = minIndex(index, text.indexOf("<P>", 2)); // Not at start
        index = minIndex(index, text.indexOf("<blockquote", 2));  // Not at start
        index = minIndex(index, text.indexOf("<pre", fromindex)); // May contain anything!
        // Avoid the char at the start of a tag in some cases
        if (index != -1 &&  
            (text.charAt(index) == '@" || text.charAt(index) == '<")) {
            if (index != 0)
                index--;
        }
        
/* Not used for jdiff, since tags are explicitly checked for above.
        // Look for a sentence terminated by an HTML tag.
        index = minIndex(index, text.indexOf(".<", fromindex));
        if (index == -1) {
            // If period-whitespace etc was not found, check to see if
            // last character is a period,
            int endIndex = text.length()-1;
            if (text.charAt(endIndex) == '.' ||
                text.charAt(endIndex) == '?' ||
                text.charAt(endIndex) == '!') 
                index = endIndex;
        }
*/
        return index;
    
public booleaninRange(int val, int min, int max)
Return true if val is in the range [min|max], inclusive.

        if (val < min)
            return false;
        if (val > max)
            return false;
        return true;
    
public voidlogOptions()
Write the options which were used to generate this XML file out as XML comments.

        outputFile.print("<!-- ");
        outputFile.print(" Command line arguments = " + Options.cmdOptions);
        outputFile.println(" -->");
    
public static intminIndex(int i, int j)
Return the minimum of two indexes if > -1, and return -1 only if both indexes = -1.

param
i an int index
param
j an int index
return
an int equal to the minimum index > -1, or -1

        if (i == -1) return j;
        if (j == -1) return i;
        return Math.min(i,j);
    
public voidprocessClasses(ClassDoc[] cd, java.lang.String pkgName)
Process classes and interfaces.

param
cd An array of ClassDoc objects.

        if (cd.length == 0)
            return;
        if (trace) System.out.println("PROCESSING CLASSES, number=" + cd.length);
        for (int i = 0; i < cd.length; i++) {
            String className = cd[i].name();
            if (trace) System.out.println("PROCESSING CLASS/IFC: " + className);
            // Only save the shown elements
            if (!shownElement(cd[i], classVisibilityLevel))
                continue;
            boolean isInterface = false;
            if (cd[i].isInterface())
                isInterface = true;
            if (isInterface) {
                outputFile.println("  <!-- start interface " + pkgName + "." + className + " -->");
                outputFile.print("  <interface name=\"" + className + "\"");
            } else {
                outputFile.println("  <!-- start class " + pkgName + "." + className + " -->");
                outputFile.print("  <class name=\"" + className + "\"");
            }
            // Add attributes to the class element
            Type parent = cd[i].superclassType();
            if (parent != null)
                outputFile.println(" extends=\"" + buildEmittableTypeString(parent) + "\"");
            outputFile.println("    abstract=\"" + cd[i].isAbstract() + "\"");
            addCommonModifiers(cd[i], 4);
            outputFile.println(">");
            // Process class members. (Treat inner classes as members.)
            processInterfaces(cd[i].interfaceTypes());
            processConstructors(cd[i].constructors());
            processMethods(cd[i], cd[i].methods());
            processFields(cd[i].fields());

            addDocumentation(cd[i], 4);

            if (isInterface) {
                outputFile.println("  </interface>");
                outputFile.println("  <!-- end interface " + pkgName + "." + className + " -->");
            } else {
                outputFile.println("  </class>");
                outputFile.println("  <!-- end class " + pkgName + "." + className + " -->");
            }
            // Inner classes have already been added.
            /*
              ClassDoc[] ic = cd[i].innerClasses();
              for (int k = 0; k < ic.length; k++) {
              System.out.println("Inner class " + k + ", name = " + ic[k].name());
              } 
            */
        }//for
    
public voidprocessConstructors(ConstructorDoc[] ct)
Process the constructors in the class.

param
ct An array of ConstructorDoc objects

        if (trace) System.out.println("PROCESSING CONSTRUCTORS, number=" + ct.length);
        for (int i = 0; i < ct.length; i++) {
            String ctorName = ct[i].name();
            if (trace) System.out.println("PROCESSING CONSTRUCTOR: " + ctorName);
            // Only save the shown elements
            if (!shownElement(ct[i], memberVisibilityLevel))
                continue;
            outputFile.print("    <constructor name=\"" + ctorName + "\"");

            Parameter[] params = ct[i].parameters();
            boolean first = true;
            if (params.length != 0) {
                outputFile.print(" type=\"");
                for (int j = 0; j < params.length; j++) {
                    if (!first)
                        outputFile.print(", ");
                    emitType(params[j].type());
                    first = false;
                }
                outputFile.println("\"");
            } else
                outputFile.println();
            addCommonModifiers(ct[i], 6);
            outputFile.println(">");
            
            // Generate the exception elements if any exceptions are thrown
            processExceptions(ct[i].thrownExceptions());

            addDocumentation(ct[i], 6);

            outputFile.println("    </constructor>");
        }//for
    
public voidprocessExceptions(ClassDoc[] cd)
Process all exceptions thrown by a constructor or method.

param
cd An array of ClassDoc objects

        if (trace) System.out.println("PROCESSING EXCEPTIONS, number=" + cd.length);
        for (int i = 0; i < cd.length; i++) {
            String exceptionName = cd[i].name();
            if (trace) System.out.println("PROCESSING EXCEPTION: " + exceptionName);
            outputFile.print("      <exception name=\"" + exceptionName + "\" type=\"");
            emitType(cd[i]);
            outputFile.println("\"/>");
        }//for
    
public voidprocessFields(FieldDoc[] fd)
Process the fields in the class.

param
fd An array of FieldDoc objects

        if (trace) System.out.println("PROCESSING FIELDS, number=" + fd.length);
        for (int i = 0; i < fd.length; i++) {
            String fieldName = fd[i].name();
            if (trace) System.out.println("PROCESSING FIELD: " + fieldName);
            // Only save the shown elements
            if (!shownElement(fd[i], memberVisibilityLevel))
                continue;
            outputFile.print("    <field name=\"" + fieldName + "\"");
            outputFile.print(" type=\"");
            emitType(fd[i].type());
            outputFile.println("\"");
            outputFile.print("      transient=\"" + fd[i].isTransient() + "\"");
            outputFile.println(" volatile=\"" + fd[i].isVolatile() + "\"");
/* JDK 1.4 and later */
/*
            String value = fd[i].constantValueExpression();
            if (value != null)
                outputFile.println(" value=\"" + value + "\"");
*/
            addCommonModifiers(fd[i], 6);
            outputFile.println(">");

            addDocumentation(fd[i], 6);

            outputFile.println("    </field>");

        }//for
    
public voidprocessInterfaces(com.sun.javadoc.Type[] ifaces)
Process the interfaces implemented by the class.

param
ifaces An array of ClassDoc objects

        if (trace) System.out.println("PROCESSING INTERFACES, number=" + ifaces.length);
        for (int i = 0; i < ifaces.length; i++) {
            String ifaceName = buildEmittableTypeString(ifaces[i]);
            if (trace) System.out.println("PROCESSING INTERFACE: " + ifaceName);
            outputFile.println("    <implements name=\"" + ifaceName + "\"/>");
        }//for
    
public voidprocessMethods(ClassDoc cd, MethodDoc[] md)
Process the methods in the class.

param
md An array of MethodDoc objects

        if (trace) System.out.println("PROCESSING " +cd.name()+" METHODS, number = " + md.length);
        for (int i = 0; i < md.length; i++) {
            String methodName = md[i].name();
            if (trace) System.out.println("PROCESSING METHOD: " + methodName);
            // Skip <init> and <clinit>
            if (methodName.startsWith("<"))
                continue;
            // Only save the shown elements
            if (!shownElement(md[i], memberVisibilityLevel))
                continue;
            outputFile.print("    <method name=\"" + methodName + "\"");
            com.sun.javadoc.Type retType = md[i].returnType();
            if (retType.qualifiedTypeName().compareTo("void") == 0) {
                // Don't add a return attribute if the return type is void
                outputFile.println();
            } else {
                outputFile.print(" return=\"");
                emitType(retType);
                outputFile.println("\"");
            }
            outputFile.print("      abstract=\"" + md[i].isAbstract() + "\"");
            outputFile.print(" native=\"" + md[i].isNative() + "\"");
            outputFile.println(" synchronized=\"" + md[i].isSynchronized() + "\"");
            addCommonModifiers(md[i], 6);
            outputFile.println(">");
            // Generate the parameter elements, if any
            Parameter[] params = md[i].parameters();
            for (int j = 0; j < params.length; j++) {
                outputFile.print("      <param name=\"" + params[j].name() + "\"");
                outputFile.print(" type=\"");
                emitType(params[j].type());
                outputFile.println("\"/>");
            }

            // Generate the exception elements if any exceptions are thrown
            processExceptions(md[i].thrownExceptions());

            addDocumentation(md[i], 6);

            outputFile.println("    </method>");
        }//for
    
public voidprocessPackages(RootDoc root)
Process each package and the classes/interfaces within it.

param
pd an array of PackageDoc objects

        PackageDoc[] specified_pd = root.specifiedPackages();
	Map pdl = new TreeMap();
        for (int i = 0; specified_pd != null && i < specified_pd.length; i++) {
	    pdl.put(specified_pd[i].name(), specified_pd[i]);
	}

	// Classes may be specified separately, so merge their packages into the
	// list of specified packages.
        ClassDoc[] cd = root.specifiedClasses();
	// This is lists of the specific classes to document
	Map classesToUse = new HashMap();
        for (int i = 0; cd != null && i < cd.length; i++) {
	    PackageDoc cpd = cd[i].containingPackage();
	    if (cpd == null && !packagesOnly) {
		// If the RootDoc object has been created from a jar file
		// this duplicates classes, so we have to be able to disable it.
		// TODO this is still null?
		cpd = root.packageNamed("anonymous");
	    }
            String pkgName = cpd.name();
            String className = cd[i].name();
	    if (trace) System.out.println("Found package " + pkgName + " for class " + className);
	    if (!pdl.containsKey(pkgName)) {
		if (trace) System.out.println("Adding new package " + pkgName);
		pdl.put(pkgName, cpd);
	    }

	    // Keep track of the specific classes to be used for this package
	    List classes;
	    if (classesToUse.containsKey(pkgName)) {
		classes = (ArrayList) classesToUse.get(pkgName);
	    } else {
		classes = new ArrayList();
	    }
	    classes.add(cd[i]);
	    classesToUse.put(pkgName, classes);
	}

	PackageDoc[] pd = (PackageDoc[]) pdl.values().toArray(new PackageDoc[0]);
        for (int i = 0; pd != null && i < pd.length; i++) {
            String pkgName = pd[i].name();
            
            // Check for an exclude tag in the package doc block, but not
	    // in the package.htm[l] file.
            if (!shownElement(pd[i], null))
                continue;

            if (trace) System.out.println("PROCESSING PACKAGE: " + pkgName);
            outputFile.println("<package name=\"" + pkgName + "\">");

            int tagCount = pd[i].tags().length;
            if (trace) System.out.println("#tags: " + tagCount);
            
            List classList;
	    if (classesToUse.containsKey(pkgName)) {
		// Use only the specified classes in the package
		System.out.println("Using the specified classes");
		classList = (ArrayList) classesToUse.get(pkgName);
	    } else {
		// Use all classes in the package
		classList = new LinkedList(Arrays.asList(pd[i].allClasses()));
	    }
            Collections.sort(classList);
            ClassDoc[] classes = new ClassDoc[classList.size()];
            classes = (ClassDoc[])classList.toArray(classes);
            processClasses(classes, pkgName);

            addPkgDocumentation(root, pd[i], 2);

            outputFile.println("</package>");
        }
    
public booleanshownElement(Doc doc, java.lang.String visLevel)
Determine if the program element is shown, according to the given level of visibility.

param
ped The given program element.
param
visLevel The desired visibility level; "public", "protected", "package" or "private". If null, only check for an exclude tag.
return
boolean Set if this element is shown.

        // If a doc block contains @exclude or a similar such tag, 
        // then don't display it.
	if (doExclude && excludeTag != null && doc != null) {
            String rct = doc.getRawCommentText();
            if (rct != null && rct.indexOf(excludeTag) != -1) {
                return false;
	    }
	}  
	if (visLevel == null) {
	    return true;
	}
	ProgramElementDoc ped = null;
	if (doc instanceof ProgramElementDoc) {
	    ped = (ProgramElementDoc)doc;
	}
        if (visLevel.compareTo("private") == 0)
            return true;
        // Show all that is not private 
        if (visLevel.compareTo("package") == 0)
            return !ped.isPrivate();
        // Show all that is not private or package
        if (visLevel.compareTo("protected") == 0)
            return !(ped.isPrivate() || ped.isPackagePrivate());
        // Show all that is not private or package or protected,
        // i.e. all that is public
        if (visLevel.compareTo("public") == 0)
            return ped.isPublic();
        return false;
    
public java.lang.StringstripNonPrintingChars(java.lang.String s, Doc doc)
Strip out non-printing characters, replacing them with a character which will not change where the end of the first sentence is found. This character is the hash mark, '#'.

        if (!stripNonPrintables)
            return s;
        char[] sa = s.toCharArray();
        for (int i = 0; i < sa.length; i++) {
            char c = sa[i];
            // TODO still have an issue with Unicode: 0xfc in java.lang.String.toUpperCase comments
//            if (Character.isDefined(c))
            if (Character.isLetterOrDigit(c))
                continue;
            // There must be a better way that is still platform independent!
            if (c == ' " ||
                c == '." ||
                c == '," ||
                c == '\r" ||
                c == '\t" ||
                c == '\n" ||
                c == '!" ||
                c == '?" ||
                c == ';" ||
                c == ':" ||
                c == '[" ||
                c == ']" ||
                c == '(" ||
                c == ')" ||
                c == '~" ||
                c == '@" ||
                c == '#" ||
                c == '$" ||
                c == '%" ||
                c == '^" ||
                c == '&" ||
                c == '*" ||
                c == '-" ||
                c == '=" ||
                c == '+" ||
                c == '_" ||
                c == '|" ||
                c == '\\" ||
                c == '/" ||
                c == '\'" ||
                c == '}" ||
                c == '{" ||
                c == '"" ||
                c == '<" ||
                c == '>" ||
                c == '`"
                )
                continue;
/* Doesn't seem to return the expected values?
            int val = Character.getNumericValue(c);
//            if (s.indexOf("which is also a test for non-printable") != -1)
//                System.out.println("** Char " + i + "[" + c + "], val =" + val); //DEBUG
            // Ranges from http://www.unicode.org/unicode/reports/tr20/
            // Should really replace 0x2028 and  0x2029 with <br/>
            if (val == 0x0 ||
                inRange(val, 0x2028, 0x2029) || 
                inRange(val, 0x202A, 0x202E) || 
                inRange(val, 0x206A, 0x206F) || 
                inRange(val, 0xFFF9, 0xFFFC) || 
                inRange(val, 0xE0000, 0xE007F)) {
                if (trace) {
                    System.out.println("Warning: changed non-printing character  " + sa[i] + " in " + doc.name()); 
                }
                sa[i] = '#';
            }
*/
            // Replace the non-printable character with a printable character
            // which does not change the end of the first sentence
            sa[i] = '#";
        }
        return new String(sa);
    
public static booleanwriteXML(RootDoc root)
Write the XML representation of the API to a file.

param
root the RootDoc object passed by Javadoc
return
true if no problems encountered

    	String tempFileName = outputFileName;
    	if (outputDirectory != null) {
	    tempFileName = outputDirectory;
	    if (!tempFileName.endsWith(JDiff.DIR_SEP)) 
		tempFileName += JDiff.DIR_SEP;
	    tempFileName += outputFileName;
    	}

        try {
            FileOutputStream fos = new FileOutputStream(tempFileName);
            outputFile = new PrintWriter(fos);
            System.out.println("JDiff: writing the API to file '" + tempFileName + "'...");
            if (root.specifiedPackages().length != 0 || root.specifiedClasses().length != 0) {
                RootDocToXML apiWriter = new RootDocToXML();
                apiWriter.emitXMLHeader();
                apiWriter.logOptions();
                apiWriter.processPackages(root);
                apiWriter.emitXMLFooter();
            }
            outputFile.close();
        } catch(IOException e) {
            System.out.println("IO Error while attempting to create " + tempFileName);
            System.out.println("Error: " +  e.getMessage());
            System.exit(1);
        }
        // If validation is desired, write out the appropriate api.xsd file
        // in the same directory as the XML file.
        if (XMLToAPI.validateXML) {
            writeXSD();
        }
        return true;
    
public static voidwriteXSD()
Write the XML Schema file used for validation.

        String xsdFileName = outputFileName;
        if (outputDirectory == null) {
	    int idx = xsdFileName.lastIndexOf('\\");
	    int idx2 = xsdFileName.lastIndexOf('/");
	    if (idx == -1 && idx2 == -1) {
		xsdFileName = "";
	    } else if (idx == -1 && idx2 != -1) {
		xsdFileName = xsdFileName.substring(0, idx2);
	    } else if (idx != -1  && idx2 == -1) {
		xsdFileName = xsdFileName.substring(0, idx);
	    } else if (idx != -1  && idx2 != -1) {
		int max = idx2 > idx ? idx2 : idx;
		xsdFileName = xsdFileName.substring(0, max);
	    }
	} else {
	    xsdFileName = outputDirectory;
	    if (!xsdFileName.endsWith(JDiff.DIR_SEP)) 
		 xsdFileName += JDiff.DIR_SEP;
	}
        xsdFileName += "api.xsd";
        try {
            FileOutputStream fos = new FileOutputStream(xsdFileName);
            PrintWriter xsdFile = new PrintWriter(fos);
            // The contents of the api.xsd file
            xsdFile.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>");
            xsdFile.println("<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
            xsdFile.println("");
            xsdFile.println("<xsd:annotation>");
            xsdFile.println("  <xsd:documentation>");
            xsdFile.println("  Schema for JDiff API representation.");
            xsdFile.println("  </xsd:documentation>");
            xsdFile.println("</xsd:annotation>");
            xsdFile.println();
            xsdFile.println("<xsd:element name=\"api\" type=\"apiType\"/>");
            xsdFile.println("");
            xsdFile.println("<xsd:complexType name=\"apiType\">");
            xsdFile.println("  <xsd:sequence>");
            xsdFile.println("    <xsd:element name=\"package\" type=\"packageType\" minOccurs='1' maxOccurs='unbounded'/>");
            xsdFile.println("  </xsd:sequence>");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"jdversion\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("<xsd:complexType name=\"packageType\">");
            xsdFile.println("  <xsd:sequence>");
            xsdFile.println("    <xsd:choice maxOccurs='unbounded'>");
            xsdFile.println("      <xsd:element name=\"class\" type=\"classType\"/>");
            xsdFile.println("      <xsd:element name=\"interface\" type=\"classType\"/>");
            xsdFile.println("    </xsd:choice>");
            xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
            xsdFile.println("  </xsd:sequence>");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("<xsd:complexType name=\"classType\">");
            xsdFile.println("  <xsd:sequence>");
            xsdFile.println("    <xsd:element name=\"implements\" type=\"interfaceTypeName\" minOccurs='0' maxOccurs='unbounded'/>");
            xsdFile.println("    <xsd:element name=\"constructor\" type=\"constructorType\" minOccurs='0' maxOccurs='unbounded'/>");
            xsdFile.println("    <xsd:element name=\"method\" type=\"methodType\" minOccurs='0' maxOccurs='unbounded'/>");
            xsdFile.println("    <xsd:element name=\"field\" type=\"fieldType\" minOccurs='0' maxOccurs='unbounded'/>");
            xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
            xsdFile.println("  </xsd:sequence>");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"extends\" type=\"xsd:string\" use='optional'/>");
            xsdFile.println("  <xsd:attribute name=\"abstract\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>");
            xsdFile.println("  <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("<xsd:complexType name=\"interfaceTypeName\">");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("<xsd:complexType name=\"constructorType\">");
            xsdFile.println("  <xsd:sequence>");
            xsdFile.println("    <xsd:element name=\"exception\" type=\"exceptionType\" minOccurs='0' maxOccurs='unbounded'/>");
            xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
            xsdFile.println("  </xsd:sequence>");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"type\" type=\"xsd:string\" use='optional'/>");
            xsdFile.println("  <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>");
            xsdFile.println("  <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("<xsd:complexType name=\"paramsType\">");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"type\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("<xsd:complexType name=\"exceptionType\">");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"type\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("<xsd:complexType name=\"methodType\">");
            xsdFile.println("  <xsd:sequence>");
            xsdFile.println("    <xsd:element name=\"param\" type=\"paramsType\" minOccurs='0' maxOccurs='unbounded'/>");
            xsdFile.println("    <xsd:element name=\"exception\" type=\"exceptionType\" minOccurs='0' maxOccurs='unbounded'/>");
            xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
            xsdFile.println("  </xsd:sequence>");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"return\" type=\"xsd:string\" use='optional'/>");
            xsdFile.println("  <xsd:attribute name=\"abstract\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"native\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"synchronized\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>");
            xsdFile.println("  <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("<xsd:complexType name=\"fieldType\">");
            xsdFile.println("  <xsd:sequence>");
            xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
            xsdFile.println("  </xsd:sequence>");
            xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"type\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"transient\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"volatile\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"value\" type=\"xsd:string\" use='optional'/>");
            xsdFile.println("  <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>");
            xsdFile.println("  <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>");
            xsdFile.println("  <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>");
            xsdFile.println("  <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>");
            xsdFile.println("</xsd:complexType>");
            xsdFile.println();
            xsdFile.println("</xsd:schema>");
            xsdFile.close();
        } catch(IOException e) {
            System.out.println("IO Error while attempting to create " + xsdFileName);
            System.out.println("Error: " +  e.getMessage());
            System.exit(1);
        }