<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<article id="collab">
  <articleinfo>
    <title>Using Ant, JavaDoc, LOG4J, JUnit, and DocBook together</title>
    <author>
      <firstname>Ashley</firstname>
      <othername>J.S</othername>
      <surname>Mills</surname>
      <affiliation><address><email>ashley@ashleymills.com</email></address></affiliation>
    </author>

    <copyright>
      <year>2005</year>
      <holder role="mailto:ashley@ashleymills.com">The University Of Birmingham</holder>
    </copyright>
  </articleinfo>

  <sect1 id="collab-introduction"><title>Introduction</title>
    <para>
      This document is an attempt to unite the various programmer tools documented <ulink url="../tutorialshome.html">here</ulink>. The specific tools that will be used in the development of the program in this tutorial, will be:
    </para>

    <itemizedlist>
      <listitem><para><ulink url="../ant/anthome.html">Ant</ulink></para></listitem>
      <listitem><para><ulink url="../javadoc/javadochome.html">JavaDoc</ulink></para></listitem>
      <listitem><para><ulink url="../log4j/log4jhome.html">LOG4J</ulink></para></listitem>
      <listitem><para><ulink url="../junit/junithome.html">JUnit</ulink></para></listitem>
      <listitem><para><ulink url="../docbooksys/docbooksyshome.html">DocBook</ulink></para></listitem>
    </itemizedlist>

    <para>
      It will be assumed that you have read these documents. The program itself will be a little game called &quot;Identify&quot; that I created based on my memories of a program on the Acorn BBC micros we had at my middle school. More information about this computer can be found at <ulink url="http://home.wanadoo.nl/jarod/museum/bbc.htm">http://home.wanadoo.nl/jarod/museum/bbc.htm</ulink>. The program constructs a binary tree which contains a <literal>String</literal> as it's root. It can have left and right sub-trees which are the same type of binary tree.
    </para>

    <para>
      Each root (apart from the leaves of the tree) contains a yes/no question such as &quot;Is it a bird?&quot;, this is presented to the user and the users response is received and stored. If the user responds with yes then the left subtree is evaluated, if the user responds with no then the right subtree is evaluated. Eventually the user will hit a leaf node, a tree with no children. This is an identification node which specifies an object in the form of a question such as &quot;Is it a Vesper sparrow (Pooecetes gramineus)?&quot;. The answer to this question is special and if the user answers yes, the program will ask the user if they want to refine the identification. If the user answers no, the program will ask the user to specify what the object was that they were trying to identify, it will then ask them to specify a question that distinguishes between the object in the leaf node that failed to identify the object they were trying to identify and the object they were trying to identify, a transcript from use of the program should make this clearer:
    </para>

    <sect2 id="collab-theprogram-transcript"><title>An example run of the program</title>
      <screen>
        Is it living?
        <userinput>y</userinput>
        Is it a Tree?
        <userinput>n</userinput>
        What is your Object? (be as specific as possible)

        <userinput>a tiger</userinput>

        Please enter an question that could be used to distinguish between:

        &quot;Is it a Tree?&quot;
        and
        &quot;Is it a tiger?&quot;

        Try to make the distinction as high-level as possible.
        Phrase the question so that answering yes to it will display:

        &quot;Is it a tiger?&quot;

        <userinput>Is it an animal?</userinput>

        The computer will ask:
        &quot;Is it an animal?&quot;

        Responding yes will produce the question:
        &quot;Is it a Tiger&quot;
        Responding no will produce the question:
        &quot;Is it a Tree&quot;

        Is this behaviour satisfactory? y/n
        <userinput>y</userinput> 

        Would you like to play again? y/n
        <userinput>y</userinput> 

        Is it living?
        <userinput>y</userinput> 
        Is it an animal?
        <userinput>y</userinput>
        Is it a tiger?
        <userinput>y</userinput>
        Is the question:

         &quot;Is it a tiger?&quot;

        specific enough to pinpoint your object? y/n
        <userinput>n</userinput> 

        Please enter a question that will be displayed after
        the user answers yes to:

        Is it a tiger?

        For example, if the old question was &quot;Is it fictional literature?&quot;
        and your object is a copy of &quot;Romeo and Juliet&quot; then
        you could enter the question &quot;Is it a Shakespeare play?&quot;

        <userinput>Is it white with chocolate stripes and icy blue eyes?</userinput>
        What is your object?

        <userinput>a rare White Bengal Tiger (Panthera tigris tigris)</userinput>

        Give me an object I can use if somebody answers yes to
        &quot;Is it a tiger?&quot;
        but no to
        &quot;Is it white with chocolate stripes and icy blue eyes?&quot;

        <userinput>a Siberian (Amur) tiger (Panthera tigris altaica)</userinput>

        Would you like to play again? y/n
        <userinput>y</userinput>

        Is it living?
        <userinput>y</userinput>
        Is it a tiger?
        <userinput>y</userinput>
        Is it white with chocolate stripes and icy blue eyes?
        <userinput>y</userinput>
        Is it a rare White Bengal Tiger (Panthera tigris tigris)?
        <userinput>y</userinput>
        Is the question:

          &quot;Is it a rare White Bengal Tiger (Panthera tigris tigris)?&quot;

        specific enough to pinpoint your object? y/n
        <userinput>y</userinput>

        Correct identification!

        Would you like to play again? y/n
        <userinput>n</userinput>
      </screen>

      <para>
        How it does this is pretty straightforward, when it encounters a tree with empty children (a leaf) it knows that either the user said yes to the last identification question or said no. If the user said yes then the identification is correct and the program goes on to ask whether or not the definition was sufficiently accurate or not. If the user said no then the identification is incorrect and the program asks the user to define the object and provide a new, distinguishing question.
      </para>
    </sect2>
  </sect1>

  <sect1 id="collab-theprogram"><title>The Program</title>
    <para>The program is composed of two components:</para>

    <itemizedlist>
      <listitem>
        <para>
          <filename>QuestionTree.java</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Identify.java</filename>
        </para>
      </listitem>
    </itemizedlist>

    <sect2 id="collab-theprogram-questiontree"><title><filename>QuestionTree.java</filename></title>
      <para>
        <filename>QuestionTree.java</filename> is an implementation of a binary tree that provides the underlying structure for the <filename>Identify.java</filename> program.  The class is shown below and it can be downloaded here: <ulink url="files/src/QuestionTree.java">QuestionTree.java</ulink>.
      </para>

      <programlisting>
import org.apache.log4j.Logger; 
/**
 * A question tree for a hierarchical identification model.
 *
 * Implemented as a binary tree, the root node is a &lt;code&gt;String&lt;/code&gt;
 * representing a question.
 *
 * &lt;p&gt;
 * The left subtree is the tree that should be evaluated if the user
 * answers yes to the question held in the root of the parent tree.
 * &lt;/p&gt;<co id="collab-theprogram-questiontree-javadoc-intro"/>
 *
 * &lt;p&gt;
 * The right subtree is the tree that should be evaluated if the user
 * answers no to the question held in the root of the parent tree.
 * &lt;/p&gt;
 *
 * @author  Ashley Mills
 * @version 0.1
 *
 */
public class QuestionTree {
   private Logger logger = Logger.getLogger(QuestionTree.class);
   private QuestionTree left, right;
   private String root;

   /**
    * Creates a new, empty &lt;code&gt;QuestionTree&lt;/code&gt;.<co id="collab-theprogram-questiontree-logger"/>
    */
   public QuestionTree() {
      logger.debug(&quot;QuestionTree() called&quot;);
      root = null;
      left = null;
      right = null;
   }

   /**
    * Creates a new &lt;code&gt;QuestionTree&lt;/code&gt; with a root question.
    *
    * @param String The root question.
    */
   public QuestionTree(String root) {
      logger.debug(&quot;QuestionTree(String root) called&quot;);
      this.root = root;
      left = new QuestionTree();
      right = new QuestionTree();
   }

   /**
    * Creates a new &lt;code&gt;QuestionTree&lt;/code&gt; with a root question, a left
    * sub-&lt;code&gt;QuestionTree&lt;/code&gt; and a right sub-&lt;code&gt;QuestionTree&lt;/code&gt;.
    *
    * @param String The root question.
    * @param QuestionTree The &lt;code&gt;QuestionTree&lt;/code&gt; that should become the left,
    * &quot;yes branch&quot; of the &lt;code&gt;QuestionTree&lt;/code&gt;.
    *
    * @param QuestionTree The &lt;code&gt;QuestionTree&lt;/code&gt; that should become the right,
    * &quot;no branch&quot; of the &lt;code&gt;QuestionTree&lt;/code&gt;. 
    */
   public QuestionTree(String root, QuestionTree left, QuestionTree right) {
      logger.debug(&quot;QuestionTree(String root, QuestionTree left, QuestionTree right) called&quot;);
      this.root = root;
      this.left = left;
      this.right = right;
   }

   /**
    * Sets the root question of the &lt;code&gt;QuestionTree&lt;/code&gt; that the
    * method was called from.
    *
    * @param String The question that should become this &lt;code&gt;QuestionTree&lt;/code&gt;s root question.
    */
   public void setRoot(String root) {
      logger.debug(&quot;setRoot(String root) called&quot;);
      this.root = root;
   }

   /**
    * Sets the left sub-&lt;code&gt;QuestionTree&lt;/code&gt; of the &lt;code&gt;QuestionTree&lt;/code&gt;.
    *
    * @param QuestionTree The &lt;code&gt;QuestionTree&lt;/code&gt; that should become the left subtree.
    */
   public void setLeft(QuestionTree left) {
      logger.debug(&quot;setLeft(QuestionTree left) called&quot;);
      this.left = left;
   }

   /**
    * Sets the right sub-&lt;code&gt;QuestionTree&lt;/code&gt; of the &lt;code&gt;QuestionTree&lt;/code&gt;.
    *
    * @param QuestionTree The &lt;code&gt;QuestionTree&lt;/code&gt; that should become the right subtree.
    */
   public void setRight(QuestionTree right) {
      logger.debug(&quot;setRight(QuestionTree right) called&quot;);
      this.right = right;
   }

   /**
    * Returns the &lt;code&gt;QuestionTree&lt;/code&gt;s root question.
    *
    * @return String The question defined in the root of this tree.
    */
   public String getRoot() {
      logger.debug(&quot;getRoot() called&quot;);
      return root;
   }

   /**
    * Returns the left sub-&lt;code&gt;QuestionTree&lt;/code&gt; of the &lt;code&gt;QuestionTree&lt;/code&gt;.
    *
    * @return QuestionTree The left sub-&lt;code&gt;QuestionTree&lt;/code&gt;.
    */
   public QuestionTree getLeft() {
      logger.debug(&quot;getLeft() called&quot;);
      return left;
   }

   /**
    * Returns the right sub-&lt;code&gt;QuestionTree&lt;/code&gt; of the &lt;code&gt;QuestionTree&lt;/code&gt;.
    *
    * @return QuestionTree The right sub-&lt;code&gt;QuestionTree&lt;/code&gt;.
    */
   public QuestionTree getRight() {
      logger.debug(&quot;getRight() called&quot;);
      return right;
   }

   /**
    * Determines whether or not the &lt;code&gt;QuestionTree&lt;/code&gt; is empty.
    *
    * @return boolean &lt;code&gt;true&lt;/code&gt; if the &lt;code&gt;QuestionTree&lt;/code&gt; is empty
    * and &lt;code&gt;false&lt;/code&gt; otherwise.
    */
   public boolean isEmpty() {
      logger.debug(&quot;isEmpty() called&quot;);
      return root==null;
   }
}
      </programlisting>

      <calloutlist>
        <callout arearefs="collab-theprogram-questiontree-javadoc-intro">
          <para/>
          <programlisting>
/**
 * A question tree for a hierarchical identification model.
 *
 * &lt;p&gt; 
 * Implemented as a binary tree, the root node is a &lt;code&gt;String&lt;/code&gt;
 * representing a question.
 * &lt;/p&gt;
 *
 * &lt;p&gt;
 * The left subtree is the tree that should be evaluated if the user
 * answers yes to the question held in the root of the parent tree.
 * &lt;/p&gt;
 *
 * &lt;p&gt;
 * The right subtree is the tree that should be evaluated if the user
 * answers no to the question held in the root of the parent tree.
 * &lt;/p&gt;
 *
 * @author  Ashley Mills
 * @version 0.1
 *
 */
          </programlisting>
          <para>
            <filename>QuestionTree.java</filename> contains JavaDoc for every method and constructor, this is the JavaDoc for the entire class, notice the use of <acronym>HTML</acronym> and the one line summary to start with. The author specified is &quot;Ashley Mills&quot; and the version is &quot;0.1&quot;. The JavaDoc output for this section can be seen below:
          </para>

          <figure><title>The JavaDoc output for the listing above</title>
            <mediaobject>
              <imageobject><imagedata fileref="files/images/javadoc-intro.png" format="PNG"/></imageobject>
            </mediaobject>
          </figure>
        </callout>

        <callout arearefs="collab-theprogram-questiontree-logger">
          <para/>
          <programlisting>
public class QuestionTree {
   private Logger logger = Logger.getLogger(QuestionTree.class);
   private QuestionTree left, right;
   private String root;

   /**
    * Creates a new, empty &lt;code&gt;QuestionTree&lt;/code&gt;.
    */
   public QuestionTree() {
      logger.debug(&quot;QuestionTree() called&quot;);
      root = null;
      left = null;
      right = null;
   }
          </programlisting>
          <para>
            Notice that the logger is instantiated using the name of the class <filename>QuestionTree.class</filename>. It would be inefficient to create a new logger every time the constructors were called so <filename>QuestionTree.java</filename> inherits its logger from whichever class instantiates it. A logger statement can be seen in the QuestionTree constructor:
          </para>

          <programlisting>
      logger.debug(&quot;QuestionTree() called&quot;);            
          </programlisting>

          <para>
            The QuestionTree contains many logger statements, one for every method and constructor. The methods and constructors are called many times during the execution of <filename>Identify.class</filename> so the <emphasis>Level</emphasis> <emphasis role="strong">DEBUG</emphasis> was chosen instead of <emphasis role="strong">INFO</emphasis>, which is usually used to produce messages indicating the entering and/or leaving of methods, to reduce the number of messages being produced. The logger level is set to <emphasis role="strong">INFO</emphasis> in the configuration file.
          </para>
        </callout>
      </calloutlist>

      <para>
        It is assumed that a basic knowledge of computer data structures is known so the program code should be self-documenting. For those that need the relevant background information on binary trees, I suggest you read the binary tree handouts produced by Martin Escardo for the <citetitle>Introduction To Computer Science - B</citetitle> first year course at The University Of Birmingham, they can be found at <ulink url="http://www.cs.bham.ac.uk/~mhe/introductionb.html#ref:lectures">http://www.cs.bham.ac.uk/~mhe/introductionb.html#ref:lectures</ulink>.
      </para>
    </sect2>

    <sect2 id="collab-theprogram-Identify"><title><filename>Identify.java</filename></title>
      <para>
        <filename>Identify.java</filename> provides the part of the program that gets input from the user and constructs the QuestionTree, it is too big to be shown in it's entirety here so only the <emphasis>main</emphasis> method is shown, the auxiliary functions will be shown and discussed separately later. The program can be downloaded here: <ulink url="files/src/Identify.java">Identify.java</ulink>.
      </para>

      <programlisting>
/** A program which models a hierarchical question tree which is
 * extensible, it's purpose is to identify objects through a series
 * of yes/no questions.
 *
 * @author  Ashley Mills
 * @version 0.1
 */
import java.io.*;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
public class Identify {
   private static BufferedReader reader;
   private static Logger logger = Logger.getLogger(Identify.class);
   private static QuestionTree tree;
   public static void main(String[] args) {<co id="collab-theprogram-Identify-init"/>
      DOMConfigurator.configure(&quot;log4jconfig.xml&quot;);
      logger.info(&quot;Entering main&quot;);
      reader = new BufferedReader(new InputStreamReader(System.in));

      logger.info(&quot;Constructing initial QuestionTree&quot;);
      tree = new QuestionTree(&quot;Is it living?&quot;, 
                new QuestionTree(&quot;Is it a tree?&quot;),<co id="collab-theprogram-Identify-Qtreeinit"/>
                new QuestionTree(&quot;Is it a computer?&quot;)
             );

      QuestionTree currentTree = tree;
      boolean correctIdentification = false,
      finished = false, stopped = false, yes;
      
      logger.debug(&quot;Starting outer while loop...&quot;);
      while(!stopped) {

         output(&quot;&quot;);
         logger.debug(&quot;Transversing tree...&quot;);
         while(!finished) {
            output(currentTree.getRoot());
            yes = yesOrNo();
            logger.debug(&quot;yes = &quot; + yes);

            correctIdentification = false;
            if(yes) {
               correctIdentification = true; 
               if(currentTree.getLeft().isEmpty()) finished=true;
               else currentTree = currentTree.getLeft();
               logger.debug(&quot;finished: &quot;+finished);
            } else {
               if(currentTree.getRight().isEmpty()) finished=true;
               else currentTree = currentTree.getRight();<co id="collab-theprogram-Identify-mainloop"/>
            }
         }

         if(correctIdentification) {
            output(&quot;Is the question:\n&quot;);
            output(&quot;  \&quot;&quot;+currentTree.getRoot()+&quot;\&quot;\n&quot;);
            output(&quot;specific enough to pinpoint your object? y/n&quot;);

            yes = yesOrNo();
            if(yes) { 
               output(&quot;\nCorrect identification!&quot;);
            } else {
               refineLeafQuestion(currentTree);
            }
         } else {
            addNewObjectToTree(currentTree);
         }

         output(&quot;\nWould you like to play again? y/n&quot;);
         yes = yesOrNo();
         if(yes) {
            currentTree  = tree;
            correctIdentification = false;
            finished     = false;
         } else stopped  = true;
      }
      logger.info(&quot;Leaving main&quot;);
   }
      </programlisting>

      <calloutlist>
        <callout arearefs="collab-theprogram-Identify-init">
          <para/>
          <programlisting>
/** A program which models a hierarchical question tree which is
 * extensible, it's purpose is to identify objects through a series
 * of yes/no questions.
 *
 * @author  Ashley Mills
 * @version 0.1
 */
import java.io.*;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
public class Identify {
   private static BufferedReader reader;
   private static Logger logger = Logger.getLogger(Identify.class);
   private static QuestionTree tree;
   public static void main(String[] args) {
      DOMConfigurator.configure(&quot;log4jconfig.xml&quot;);
      logger.info(&quot;Entering main&quot;);
      reader = new BufferedReader(new InputStreamReader(System.in));
          </programlisting>

          <para>
            Some JavaDoc is present at the top of the program, this will not be used by any external programs as JavaDoc will not be generated for this class since it contains no public methods. The JavaDoc shown is just for persons inspecting the program code. The <emphasis>import</emphasis> statements import the classes used in the program. A BufferedReader is declared, this will be used to get input from the user. A logger is created with the name of the class and the QuestionTree is declared so it can be accessed by the whole class. The <emphasis>main</emphasis> method sees the configuration of the logger via a <emphasis>DOMConfigurator</emphasis>, this allows the use of an external configuration file for the logger, marked up in XML. There are also a couple of logger statements present.
          </para>
        </callout>

        <callout arearefs="collab-theprogram-Identify-Qtreeinit">
          <para/>
          <programlisting>
      logger.info(&quot;Constructing initial QuestionTree&quot;);
      tree = new QuestionTree(&quot;Is it living?&quot;,
                new QuestionTree(&quot;Is it a tree?&quot;),
                new QuestionTree(&quot;Is it a computer?&quot;)
             );
          </programlisting>

          <para>
            There is a log message, followed by the construction of a QuestionTree, this is the QuestionTree that will always point to the root tree of the whole QuestionTree. The tree construction section defines a QuestionTree with the root question &quot;Is it living?&quot; When this is used later on,  if the user answers yes to the question &quot;Is it living?&quot;, the user will be asked the question &quot;Is it a Tree&quot;, if the user answers no to the question &quot;Is it living?&quot;, the user will be asked the question &quot;Is it a Computer?&quot;. Here is a diagram, which illustrating this:
          </para>

          <figure><title>The initial QuestionTree</title>
            <mediaobject>
              <imageobject><imagedata fileref="files/images/qtreeinit.png" format="PNG"/></imageobject>
            </mediaobject>
          </figure>
        </callout>

        <callout arearefs="collab-theprogram-Identify-mainloop">
          <para/>
          <programlisting>
      QuestionTree currentTree = tree;
      boolean correctIdentification = false,
      finished = false, stopped = false, yes;
      
      logger.debug(&quot;Starting outer while loop...&quot;);
      while(!stopped) {

         output(&quot;&quot;);
         logger.debug(&quot;Transversing tree...&quot;);
         while(!finished) {
            output(currentTree.getRoot());
            yes = yesOrNo();
            logger.debug(&quot;yes = &quot; + yes);

            correctIdentification = false;
            if(yes) {
               correctIdentification = true; 
               if(currentTree.getLeft().isEmpty()) finished=true;
               else currentTree = currentTree.getLeft();
               logger.debug(&quot;finished: &quot;+finished);
            } else {
               if(currentTree.getRight().isEmpty()) finished=true;
               else currentTree = currentTree.getRight();
            }
         }

         if(correctIdentification) {
            output(&quot;Is the question:\n&quot;);
            output(&quot;  \&quot;&quot;+currentTree.getRoot()+&quot;\&quot;\n&quot;);
            output(&quot;specific enough to pinpoint your object? y/n&quot;);

            yes = yesOrNo();
            if(yes) { 
               output(&quot;\nCorrect identification!&quot;);
            } else {
               refineLeafQuestion(currentTree);
            }
         } else {
            addNewObjectToTree(currentTree);
         }

         output(&quot;\nWould you like to play again? y/n&quot;);
         yes = yesOrNo();
         if(yes) {
            currentTree  = tree;
            correctIdentification = false;
            finished     = false;
         } else stopped  = true;
      }
          </programlisting>

          <para>
            This is where the construction and modification of the QuestionTree occurs the first thing that happens is some variables are initialised:
          </para>

          <programlisting>
      QuestionTree currentTree = tree;
      boolean correctIdentification = false,
      finished = false, stopped = false, yes;
          </programlisting>

          <para>
            A new QuestionTree is created that is a pointer to the root node of the overall tree, it is called <emphasis>currentTree</emphasis>, <emphasis>currentTree</emphasis> will vary as the tree is transversed so that <emphasis>currentTree</emphasis> always points to the last question asked. The other variables initialised are <emphasis>boolean</emphasis>, and control things like loops and whether certain paths of the program are executed. Below the initialisation section is a large loop controlled via the <emphasis>stopped</emphasis> variable:
          </para>

          <programlisting>
      while(!stopped) {
         .
         .
         .
         output(&quot;\nWould you like to play again? y/n&quot;);
         yes = yesOrNo();
         if(yes) {
            currentTree  = tree;
            correctIdentification = false;
            finished     = false;
         } else stopped  = true;
      }
   
          </programlisting>

          <para>
            When the user enters no to the question &quot;Would you like to play again?&quot;, <emphasis>stopped</emphasis> is set to <emphasis role="strong">true</emphasis> causing the outer loop to be be broken and subsequently, the program to terminate. The contents of this outer loop can be broken up into two sections, the first controls the transversal of the QuestionTree and the second controls the modification of the tree upon reaching a leaf, here is the first section:
          </para>

          <programlisting>
         output(&quot;&quot;);
         logger.debug(&quot;Transversing tree...&quot;);
         while(!finished) {
            output(currentTree.getRoot());
            yes = yesOrNo();
            logger.debug(&quot;yes = &quot; + yes);

            correctIdentification = false;
            if(yes) {
               correctIdentification = true; 
               if(currentTree.getLeft().isEmpty()) finished=true;
               else currentTree = currentTree.getLeft();
               logger.debug(&quot;finished: &quot;+finished);
            } else {
               if(currentTree.getRight().isEmpty()) finished=true;
               else currentTree = currentTree.getRight();
            }
         }
          </programlisting>

          <para>
            The first line outputs an empty line for formatting reasons. The while loop is controlled by the variable <emphasis>finished</emphasis> which was set to <emphasis role="strong">false</emphasis> in the initialisation section described above. The loop prints out the root of the current tree, which is a question, and gets the users response to this question via the <emphasis role="strong">yesOrNo()</emphasis> method. The boolean variable <emphasis>correctIdentification</emphasis> is set to <emphasis role="strong">false</emphasis> and the users response to the printed question is evaluated.
          </para>
            
          <para>
            If the user said yes to the printed question then <emphasis>correctIdentification</emphasis> is set to <emphasis role="strong">true</emphasis>, this is incase <emphasis>currentTree</emphasis> happens to be a leaf, whereupon if the user says yes then the object they are looking for has been correctly identified (as much as is possible anyway). A &quot;yes&quot; answer requires that the transversal of the tree continues at the left subtree but first the left subtree is checked for emptiness. If the left subtree is empty then <emphasis>currentTree</emphasis> is a leaf node and transversal must stop, so <emphasis>finished</emphasis> is set to <emphasis role="strong">true</emphasis>. If the left subtree it is not empty then <emphasis>currentTree</emphasis> is set to the left subtree.
          </para>

          <para>
            If the user said no to the printed question then the right subtree must be evaluated, but first the right subtree is checked for emptiness, because if it is empty it is a leaf node and transversal of the tree must stop, <emphasis role="strong">finished</emphasis> is set to <emphasis role="strong">true</emphasis> to accomplish this. If the right subtree is not empty then <emphasis>currentTree</emphasis> is set to the left subtree.
          </para>

          <para>
            The loop goes round and round (that is generally what loops do ;)), transversing the question tree in response to the users answers to the questions printed. Eventually a leaf node is encountered, transversal of the tree terminates and program control flows to the next section:
          </para>

          <programlisting>
          if(correctIdentification) {
            output(&quot;Is the question:\n&quot;);
            output(&quot;  \&quot;&quot;+currentTree.getRoot()+&quot;\&quot;\n&quot;);
            output(&quot;specific enough to pinpoint your object? y/n&quot;);

            yes = yesOrNo();
            if(yes) { 
               output(&quot;\nCorrect identification!&quot;);
            } else {
               refineLeafQuestion(currentTree);
            }
         } else {
            addNewObjectToTree(currentTree);
         }            
          </programlisting>

          <para>
            If the item was correctly identified (if the user said yes to a question that was leaf), <emphasis>correctIdentification</emphasis> will be <emphasis role="strong">true</emphasis>. The user is asked whether the question they answered yes to was specific enough to pinpoint the object they were trying to identify. If the user says that it was specific enough, by answering yes, the program outputs &quot;Correct identification!&quot;, if the user says no then <emphasis>refineLeafQuestion(currentTree)</emphasis> is called to refine the question. For an example of this see the section entitled <link linkend="collab-theprogram-transcript">An example run of the program</link>.
          </para>

          <para>
            If the item was not correctly identified (if the user said no to a question that was a leaf) <emphasis>correctIdentification</emphasis> will be <emphasis role="strong">false</emphasis> and the alternative of the if..then..else structure will be executed. The method <emphasis>addNewObjectToTre(currentTree)</emphasis> is called to add a new object to the tree since the object the user was trying to identify was not found.
          </para>
        </callout>
      </calloutlist>

      <para>
        Let's take a look at the <emphasis>refineLeafQuestion</emphasis> method which is called when an object has been identified as much as possible (down to a leaf node) but the identification is not specific enough:
      </para>

      <programlisting>
   private static void refineLeafQuestion(QuestionTree currentTree) {
      logger.info(&quot;Entering refineLeafQuestion(QuestionTree currentTree)&quot;);
      output(&quot;\nPlease enter a question that will be displayed after&quot;);
      output(&quot;the user answers yes to:\n&quot;);

      output(currentTree.getRoot()+&quot;\n&quot;);

      output(&quot;For example, if the old question was \&quot;Is it fictional literature?\&quot;&quot;);
      output(&quot;and your object is a copy of \&quot;Romeo and Juliet\&quot; then you&quot;);
      output(&quot;could enter the question \&quot;Is it a Shakespeare play?\&quot;\n&quot;); 

      String usersQuestion = getString();

      output(&quot;\nWhat is your object?\n&quot;);

      String usersYesObject = getString(); 

      output(&quot;\nGive me an object I can use if somebody answers yes to&quot;);
      output(&quot;\&quot;&quot;+currentTree.getRoot()+&quot;\&quot;&quot;);
      output(&quot;but no to&quot;);
      output(&quot;\&quot;&quot;+usersQuestion+&quot;\&quot;\n&quot;);

      String usersNoObject = getString();

      currentTree.setLeft(
         new QuestionTree(usersQuestion,
            new QuestionTree(&quot;Is it &quot;+usersYesObject+&quot;?&quot;),
            new QuestionTree(&quot;Is it &quot;+usersNoObject+&quot;?&quot;)
         )
      );
      logger.info(&quot;Leaving refineLeafQuestion(QuestionTree currentTree)&quot;);
   }
      </programlisting>

      <para>
        The output statements make it pretty clear what is going on, essentially this method can be summarised to:
      </para>

      <programlisting>
      String usersQuestion  = getString();
      String usersYesObject = getString();
      String usersNoObject  = getString();
      currentTree.setLeft(
         new QuestionTree(usersQuestion,
            new QuestionTree(&quot;Is it &quot;+usersYesObject+&quot;?&quot;),
            new QuestionTree(&quot;Is it &quot;+usersNoObject+&quot;?&quot;)
         )
      );
      </programlisting>

      <para>
        A new question is got from the user which will become the left subtree of the question that was not specific enough to identify the object the user was looking for. So if the not-specific-enough question was &quot;Is it a book?&quot;, and the users object is &quot;Rowan-Robinson Cosmology SECOND EDITION&quot; the user might specify the new question &quot;Is it a scientific book?&quot;, the user is then asked to specify the object, assume that the user specifies  &quot;Rowan-Robinson Cosmology SECOND EDITION&quot;. The user is then asked to specify an alternative to the object they just specified that could be used as the no-branch for the question they just specified. The object has to be in context, since this tree will become the left subtree of the tree with the question &quot;Is it a book?&quot;. In this case the user would want to specify some kind of non-scientific book, for example the children's book &quot;Enid Blyton - The Enchanted Wood&quot;. After the user has provided the necessary details, the left subtree is set to a new QuestionTree with the users question as root, the users object as the yes-branch and the users alternative object as the no-branch, the diagrams below illustrate this:
      </para>

      <figure><title>Part of the QuestionTree before refinement</title>
        <mediaobject>
          <imageobject><imagedata fileref="files/images/refineqtreebefore.png" format="PNG"/></imageobject>
        </mediaobject>
      </figure>

      <figure><title>The same part of the QuestionTree after refinement</title>
        <mediaobject>
          <imageobject><imagedata fileref="files/images/refineqtreeafter.png" format="PNG"/></imageobject>
        </mediaobject>
      </figure>

      <para>
        Let's take a look at the <emphasis>addNewObjectToTree</emphasis> method which is called when the tree has been transversed to a leaf node but the identification of the users object has failed. (the user said no to a question in a leaf node):
      </para>

      <programlisting>
   private static void addNewObjectToTree(QuestionTree currentTree) {
      logger.info(&quot;Entering addNewObjectToTree(QuestionTree currentTree)&quot;);

      String newQuestion = &quot;&quot;; boolean goodAnswer = false;

      output(&quot;What is your object?\n&quot;);

      String usersObject = getString();

      while(!goodAnswer) {
         output(&quot;\nPlease enter a question that could be used to distinguish between:\n&quot;);

         output(&quot;\&quot;&quot; + currentTree.getRoot() + &quot;\&quot;&quot;);
         output(&quot;and&quot;);
         output(&quot;\&quot;Is it &quot; + usersObject + &quot;?\&quot;\n&quot; );

         output(&quot;Try to make the distinction as high-level as possible.&quot;);
         output(&quot;Phrase the question so that answering yes to it will display:\n&quot;);

         output(&quot;\&quot;Is it &quot; + usersObject + &quot;?\&quot;\n&quot;);

         newQuestion = getString();

         output(&quot;\nThe computer will ask:&quot;);
         output(&quot;\&quot;&quot;+newQuestion+&quot;\&quot;\n&quot;);

         output(&quot;Responding yes will produce the question:&quot;);
         output(&quot;\&quot;Is it &quot; + usersObject + &quot;\&quot;&quot;);
         output(&quot;Responding no will produce the question:&quot;);
         output(&quot;\&quot;&quot; + currentTree.getRoot() + &quot;\&quot;\n&quot;);

         output(&quot;Is this behaviour satisfactory? y/n&quot;);

         goodAnswer = yesOrNo();
      }

      String temp = currentTree.getRoot();
      currentTree.setRoot(newQuestion);
      currentTree.setLeft(new QuestionTree(&quot;Is it &quot;+usersObject+&quot;?&quot;));
      currentTree.setRight(new QuestionTree(temp));
      logger.info(&quot;Leaving addNewObjectToTree(QuestionTree currentTree)&quot;);
   }
      </programlisting>

      <para>This can be summarised to:</para>

      <programlisting>
      boolean goodAnswer = false;
      String usersObject = getString();
      while(!goodAnswer) {
         newQuestion = getString();
         output(&quot;Is this behaviour satisfactory? y/n&quot;);
         goodAnswer = yesOrNo();
      }

      String temp = currentTree.getRoot();
      currentTree.setRoot(newQuestion);
      currentTree.setLeft(new QuestionTree(&quot;Is it &quot;+usersObject+&quot;?&quot;));
      currentTree.setRight(new QuestionTree(temp));
      </programlisting>

      <para>
        <emphasis>goodAnswer</emphasis> is set to <emphasis role="strong">false</emphasis> so that the while loop will be processed, the user is asked to specify the object they are trying to identify and this is stored in the variable <emphasis>usersObject</emphasis>. The loop is entered, which asks the user for a question that should distinguish between the object the user is trying to identify and the false identification that the QuestionTree provided. The new state of the tree is displayed and the user is asked if the behaviour is satisfactory, the users response to this question is used to set the <emphasis>goodAnswer</emphasis> variable which controls the loop.
      </para>

      <para>
        After the user enters and confirms a question the question that failed to identify the object is replaced with the new question the user provided and the object the user provided becomes the left subtree of this question, the right subtree is set to the original question which failed to identify the object the user was trying to identify. For example, the original question could have been &quot;Is it a cat?&quot; and perhaps the user was trying to identify &quot;a dog&quot;, the user could provide the new question &quot;Is it known as mans best friend?&quot; this would replace &quot;Is it a cat?&quot;, the yes-branch would become &quot;Is it a dog?&quot; and the no-branch would become &quot;Is it a cat?&quot;, the diagrams below illustrate this:
      </para>

      <figure><title>Part of the QuestionTree before adding a new question</title>
        <mediaobject>
          <imageobject><imagedata fileref="files/images/addtoqtreebefore.png" format="PNG"/></imageobject>
        </mediaobject>
      </figure>

      <figure><title>The same part of the QuestionTree after adding a new question</title>
        <mediaobject>
          <imageobject><imagedata fileref="files/images/addtoqtreeafter.png" format="PNG"/></imageobject>
        </mediaobject>
      </figure>

      <para>
        The rest of the methods in the program are auxiliary methods like <emphasis>output</emphasis> which outputs strings and <emphasis>getString</emphasis> which gets a string from the user, these need no explaining, examine the source code for more information.
      </para>
    </sect2>
  </sect1>

  <sect1 id="collab-thetestharness"><title>The Test Harness</title>
    <para>
      Since the QuestionTree is the underlying data structure that the program works with, it is essential that this part works exactly as is desired hence a test harness was created for it using JUnit. The test program is shown below: 
    </para>

    <programlisting>
import junit.framework.*;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
public class QuestionTreeTest extends TestCase {
   private Logger logger = Logger.getLogger(QuestionTreeTest.class);
   private QuestionTree tree1, tree2, tree3;

   public QuestionTreeTest(String name) {
      super(name);
      DOMConfigurator.configure(&quot;log4jconfig2.xml&quot;);
   }

   protected void setUp() { 
      logger.info(&quot;Entering setUp()&quot;);
      tree1 = new QuestionTree(&quot;Is it living?&quot;,
                 new QuestionTree(&quot;Is it a Wolf?&quot;),
                 new QuestionTree(&quot;Is it a brick?&quot;)
              );
      tree2 = new QuestionTree(&quot;Is it living?&quot;);
      logger.info(&quot;Leaving setUp()&quot;);
   }

   public void testConstructor() {
      logger.info(&quot;Entering testConstructor()&quot;);
      QuestionTree tree3 = new QuestionTree(&quot;Is it living?&quot;);
      assertEquals(&quot;Is it living?&quot;, tree3.getRoot());
      logger.info(&quot;Leaving testConstructor()&quot;);
   }

   public void testGetRoot() {
      logger.info(&quot;Entering testGetRoot()&quot;);
      assertEquals(&quot;Is it living?&quot;, tree2.getRoot());
      logger.info(&quot;Leaving testGetRoot()&quot;);
   }

   public void testGetLeft() {
      logger.info(&quot;Entering testGetLeft()&quot;);
      assertEquals(&quot;Is it a Wolf?&quot;, tree1.getLeft().getRoot());
      logger.info(&quot;Leaving testGetLeft()&quot;);
   }

   public void testGetRight() {
      logger.info(&quot;Entering testGetRight()&quot;);
      assertEquals(&quot;Is it a brick?&quot;, tree1.getRight().getRoot());
      logger.info(&quot;Leaving testGetRight()&quot;);
   }

   public void testSetRoot() {
      logger.info(&quot;Entering testSetRoot()&quot;);
      tree1.setRoot(&quot;Is it alive?&quot;); 
      assertEquals(&quot;Is it alive?&quot;, tree1.getRoot()); 
      logger.info(&quot;Leaving testSetRoot()&quot;);
   }

   public void testSetLeft() {
      logger.info(&quot;Entering testSetLeft()&quot;);
      tree1.setLeft(new QuestionTree(&quot;Is it a Dog?&quot;));
      assertEquals(&quot;Is it a Dog?&quot;, tree1.getLeft().getRoot());
      logger.info(&quot;Leaving testSetLeft()&quot;);
   }

   public void testSetRight() {
      logger.info(&quot;Entering testSetRight()&quot;);
      tree1.setRight(new QuestionTree(&quot;Is it a concrete block?&quot;));
      assertEquals(&quot;Is it a concrete block?&quot;, tree1.getRight().getRoot());
      logger.info(&quot;Leaving testSetRight()&quot;);
   }

   public void testIsEmpty() {
      logger.info(&quot;Entering testIsEmpty()&quot;);
      assertEquals(true, tree2.getLeft().isEmpty());
      assertEquals(true, tree2.getRight().isEmpty());
      logger.info(&quot;Leaving testIsEmpty()&quot;);
   }
}
    </programlisting>

    <para>
      <emphasis>junit.framework.*</emphasis> is imported so that the class can extend <emphasis>TestCase</emphasis>. <emphasis>org.apache.log4j.Logger</emphasis> and <emphasis>org.apache.log4j.xml.DOMConfigurator</emphasis> are imported so that a logger can be setup. The logger is setup in the <emphasis>QuestionTreeTest</emphasis> constructor of the class. A different logfile is used for logging than the one used for the logging from <filename>Identify.java</filename>. The configuration file for the logger is <filename>log4jconfig2.xml</filename>. The logger has a priority of <emphasis role="strong">DEBUG</emphasis>.
    </para>

    <para>
      All the methods of <filename>QuestionTree.java</filename> are tested, they appear to be tested in a particular order but JUnit uses reflection and cannot guarantee the order that tests are executed in hence the program just displays logical grouping. The constructors are tested first (implicitly in the <emphasis>setUp</emphasis> method, and via <emphasis>constructorTest</emphasis>) followed by the <emphasis role="strong">get</emphasis> methods, the <emphasis role="strong">set</emphasis> methods and finally the <emphasis>isEmpty</emphasis> method is tested.  The following <emphasis>junit.framework.assert</emphasis> methods are used:
    </para>

    <itemizedlist>
      <listitem>
        <para>
          public static void assertEquals(boolean expected, boolean actual)
        </para>
        <para>To test the <emphasis>isEmpty()</emphasis> method.</para>
      </listitem>
      <listitem>
        <para>
         public static void assertEquals(java.lang.Object expected, java.lang.Object actual)
        </para>
        <para>To test all the rest of the methods</para>
      </listitem>
    </itemizedlist>

    <para>
      It is possible to use <emphasis>assertTrue(boolean condition)</emphasis> to test the strings for equality in the program's tests instead of <emphasis>assertEquals(java.lang.Object expected, java.lang.Object actual)</emphasis>. The latter can be used to compare any two objects that implement the <emphasis>equals</emphasis> method.  The former does exactly the same thing as the latter since it actually uses the <emphasis>equals</emphasis> method itself.
    </para>

    <para>
      The tests will be integrated into an Ant script later but one can manually run the tests by issuing these commands: 
    </para>

    <screen>
      <userinput><command>java</command> junit.textui.TestRunner <filename>QuestionTreeTest</filename></userinput>
    </screen>

    <para>The output produced from this is:</para>

    <screen>
........
Time: 0.2

OK (8 tests)
    </screen>

    <para>
      It is interesting to note here that before the logging statements and code were implemented into this class, the output from running the test was:
    </para>

    <screen>
.log4j:WARN No appenders could be found for logger (QuestionTree.class).
log4j:WARN Please initialize the log4j system properly.
.......
Time: 0.14

OK (8 tests)
    </screen>

    <para>
      The log4j warnings occur because there was no logger for <filename>QuestionTree.java</filename> to inherit. Usually <filename>QuestionTree.java</filename> inherits and uses the logger created by QuestionTreeTest. The time for the log-free test is about (it varies slightly) 0.06 seconds less than it is with loggers added.  This is an indication of the kind of performance hit one gets when using the kind of logger described in <filename>log4jconfig2.xml</filename> and the kind of logging system used here. For more information about the loggers used by the test harness, including description of the output, see <link linkend="collab-theloggers-qtreetestlogger"><citetitle><filename>QuestionTreeTest.java</filename>'s Logger Configuration File</citetitle></link>.
    </para>
  </sect1>

  <sect1 id="collab-theloggers"><title>The LOG4J Loggers</title>
    <para>
      There are two Log4J loggers used in this program, one is used by the program <filename>Identify.java</filename> and the other is used by the program  <filename>QuestionTreeTest.java</filename>. <filename>QuestionTree.java</filename> inherits the logger from the class it is instantiated from. Both loggers are instantiated in the same manner; the logger is declared globally in the class and named after the class it is called from then the logger is configured via an external XML file, referenced by <emphasis>DOMConfigurator</emphasis>.
    </para>

    <sect2 id="collab-theloggers-identifylogger"><title><filename>Identify.java</filename>'s Logger Configuration File</title>
      <para>
        The configuration file used by <filename>Identify.java</filename> can be downloaded here: <ulink url="files/src/log4jconfig.xml">log4jconfig.xml</ulink>, it is shown below:
      </para>

      <programlisting>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;!DOCTYPE log4j:configuration SYSTEM &quot;log4j.dtd&quot;&gt;

&lt;log4j:configuration xmlns:log4j=&quot;http://jakarta.apache.org/log4j/&quot;&gt;
        
  &lt;appender name=&quot;appender&quot; class=&quot;org.apache.log4j.FileAppender&quot;&gt;
    &lt;param name=&quot;File&quot; value=&quot;Identify.log&quot;/&gt;
    &lt;param name=&quot;Append&quot; value=&quot;false&quot;/&gt;
    &lt;layout class=&quot;org.apache.log4j.PatternLayout&quot;&gt;
      &lt;param name=&quot;ConversionPattern&quot; value=&quot;[%d{HH:mm:ss}] [%-12C] [%p] - %m%n&quot;/&gt;
    &lt;/layout&gt;
  &lt;/appender&gt;

  &lt;root&gt;
    &lt;priority value =&quot;info&quot;/&gt;
    &lt;appender-ref ref=&quot;appender&quot;/&gt;
  &lt;/root&gt;

&lt;/log4j:configuration&gt;
      </programlisting>

      <para>
        A <emphasis>FileAppender</emphasis> is created that outputs directly (non-appending) to the file <filename>Identify.log</filename>. The <emphasis>Layout</emphasis> is set as <emphasis>PatternLayout</emphasis> and the <emphasis>ConversionPattern</emphasis> is setup so that messages are output like this:
      </para>

      <screen>
[13:07:15] [Identify    ] [INFO] - Constructing initial QuestionTree
      </screen>

      <para>
        The fields are &quot;%d{HH:mm:ss}&quot; for the date in the format shown above, &quot;%-12C&quot; to output the fully qualified classname, right-padded to 12 characters, &quot;%p&quot; outputs the logger priority (Level), &quot;%m&quot; outputs the logging message and &quot;%n&quot; outputs a newline. The priority is set to <emphasis role="strong">INFO</emphasis>
      </para>

      <para>A typical log of running the <emphasis>Identify</emphasis> program is shown below:</para>

      <programlisting>
[13:36:05] [Identify    ] [INFO] - Entering main
[13:36:05] [Identify    ] [INFO] - Constructing initial QuestionTree
[13:36:10] [Identify    ] [INFO] - Entering refineLeafQuestion(QuestionTree currentTree)
[13:36:38] [Identify    ] [INFO] - Leaving refineLeafQuestion(QuestionTree currentTree)
[13:37:02] [Identify    ] [INFO] - Entering addNewObjectToTree(QuestionTree currentTree)
[13:37:57] [Identify    ] [INFO] - Leaving addNewObjectToTree(QuestionTree currentTree)
[13:38:06] [Identify    ] [INFO] - Leaving main
      </programlisting>

      <para>
        If the <emphasis>Level</emphasis> is set to <emphasis role="strong">DEBUG</emphasis>, the amount of messages quickly becomes large so an example will not be shown here, instead, one may be downloaded from here <ulink url="files/IdentifyDebug.log">IdentifyDebug.log</ulink>.
      </para>
    </sect2>

    <sect2 id="collab-theloggers-qtreetestlogger"><title><filename>QuestionTreeTest.java</filename>'s Logger Configuration File</title>
      <para>
        The configuration file used by <filename>Identify.java</filename> can be downloaded here: <ulink url="files/src/log4jconfig2.xml">log4jconfig2.xml</ulink>, it is shown below:
      </para>

      <programlisting>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;!DOCTYPE log4j:configuration SYSTEM &quot;log4j.dtd&quot;&gt;

&lt;log4j:configuration xmlns:log4j=&quot;http://jakarta.apache.org/log4j/&quot;&gt;
        
  &lt;appender name=&quot;appender&quot; class=&quot;org.apache.log4j.FileAppender&quot;&gt;
    &lt;param name=&quot;File&quot; value=&quot;qtreetest.log&quot;/&gt;
    &lt;param name=&quot;Append&quot; value=&quot;false&quot;/&gt;
    &lt;layout class=&quot;org.apache.log4j.PatternLayout&quot;&gt;
      &lt;param name=&quot;ConversionPattern&quot; value=&quot;[%d{HH:mm:ss}] [%-16C] [%-5p] - %m%n&quot;/&gt;
    &lt;/layout&gt;
  &lt;/appender&gt;

  &lt;root&gt;
    &lt;priority value =&quot;debug&quot;/&gt;
    &lt;appender-ref ref=&quot;appender&quot;/&gt;
  &lt;/root&gt;

&lt;/log4j:configuration&gt;
      </programlisting>

      <para>
        A <emphasis>FileAppender</emphasis> is created that outputs directly (non-appending) to the file <filename>qtreetest.log</filename>. The <emphasis>Layout</emphasis> is set as <emphasis>PatternLayout</emphasis> and the <emphasis>ConversionPattern</emphasis> is setup so that messages are output like this:
      </para>

      <programlisting>
[13:56:49] [QuestionTreeTest] [INFO ] - Entering setUp()
      </programlisting>

      <para>
        At first sight, it looks identical to the output produced using <filename>log4jconfig.xml</filename>, but there is one difference, instead of using &quot;%-14C&quot; to output the fully qualified classname right-padded to 12 characters, &quot;%-16C&quot; is used to output the fully qualified classname right-padded to 16 characters because the classnames in use are a little bit longer. The output log produced when running <filename>QuestionTreeTest.java</filename> as a JUnit set of tests is quite long so will not be shown in this document, instead, it can be downloaded here: <ulink url="files/qtreetest.log">qtreetest.log</ulink>.
      </para>

      <para>
        The output produced if the <emphasis>Level</emphasis> is changed to <emphasis role="strong">INFO</emphasis> is not that long and is shown below:
      </para>

      <programlisting>
[14:10:36] [QuestionTreeTest] [INFO ] - Entering setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering testConstructor()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving testConstructor()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering testGetRoot()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving testGetRoot()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering testGetLeft()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving testGetLeft()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering testGetRight()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving testGetRight()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering testSetRoot()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving testSetRoot()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering testSetLeft()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving testSetLeft()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering testSetRight()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving testSetRight()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving setUp()
[14:10:36] [QuestionTreeTest] [INFO ] - Entering testIsEmpty()
[14:10:36] [QuestionTreeTest] [INFO ] - Leaving testIsEmpty()
      </programlisting>

      <para>
        Notice that the method <emphasis>setUp</emphasis> in <filename>QuestionTreeTest.java</filename> is called before every test, if <emphasis>tearDown</emphasis> had been used, this would be called after every test.
      </para>
    </sect2>
  </sect1>

  <sect1 id="collab-thejavadoc"><title>The JavaDoc</title>
    <para>
      The JavaDoc is produced by the Ant buildfile discussed in the section entitled <link linkend="collab-thebuildfile"><citetitle>The Ant Buildfile</citetitle></link>. The JavaDoc can be viewed online at <ulink url="files/build/javadoc/index.html">index.html</ulink>.
    </para>
  </sect1>

  <sect1 id="collab-thedocumentation"><title>The Documentation in <acronym>XML </acronym>DocBook</title>
    <para>
      The DocBook documentation for the Identify program can be found here: <ulink url="files/identifyhome.html">Identify Documentation</ulink>. The <acronym>XML</acronym> file from which the <acronym>HTML</acronym> and <acronym>PDF</acronym> versions are created from is shown below:
    </para>

    <programlisting>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE article PUBLIC &quot;-//OASIS//DTD DocBook XML V4.2//EN&quot;
&quot;http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd&quot;&gt;
&lt;article id=&quot;Identify&quot;&gt;
  &lt;articleinfo&gt;
    &lt;title&gt;Identify&lt;/title&gt;
    &lt;author&gt;
      &lt;firstname&gt;Ashley&lt;/firstname&gt;
      &lt;surname&gt;Mills&lt;/surname&gt;
      &lt;affiliation&gt;
        &lt;address&gt;&lt;email&gt;ug55axm@cs.bham.ac.uk&lt;/email&gt;&lt;/address&gt;
      &lt;/affiliation&gt;
    &lt;/author&gt;

    &lt;copyright&gt;
      &lt;year&gt;2002&lt;/year&gt;
      &lt;holder role=&quot;mailto:ug55axm@cs.bham.ac.uk&quot;&gt;The University Of Birmingham&lt;/holder&gt;
    &lt;/copyright&gt;
  &lt;/articleinfo&gt;

  &lt;sect1 id=&quot;Identify-Description&quot;&gt;&lt;title&gt;Think Of An Object!&lt;/title&gt;
    &lt;para&gt;
      The Identify program builds a binary tree of questions that is transversed according to a users response to each question encountered. A successful transversal will result in a correct identification of the object that the user is describing by interacting with the program, additionally, the user may refine the correct identification if it is considered to be too unspecific. An unsuccessful transversal will result in the addition of the unfound object to the tree according to the users ideas about how the addition should be made.
    &lt;/para&gt;

    &lt;para&gt;
      The implementation consists of a separate class to provide the special binary tree, called &lt;filename&gt;QuestionTree.class&lt;/filename&gt;, and a class which builds and transverses the tree, called &lt;filename&gt;Identify.class&lt;/filename&gt;. An example of a QuestionTree is shown below:
    &lt;/para&gt;

    &lt;figure&gt;&lt;title&gt;An example of a QuestionTree&lt;/title&gt;
      &lt;mediaobject&gt;
        &lt;imageobject&gt;&lt;imagedata fileref=&quot;qtreeexample.png&quot; format=&quot;PNG&quot;/&gt;&lt;/imageobject&gt;
      &lt;/mediaobject&gt;
    &lt;/figure&gt;

    &lt;para&gt;It can be constructed like this:&lt;/para&gt;

    &lt;programlisting&gt;
      QuestionTree tree = new QuestionTree(
            
         &quot;Is it living?&quot;,

         new QuestionTree(&quot;Does it live in the sea?&quot;,
            new QuestionTree(&quot;Is it a whale?&quot;),
            new QuestionTree(&quot;Is it a tiger?&quot;)
         ),

         new QuestionTree(&quot;Is it electrical hardware?&quot;,
            new QuestionTree(&quot;Is it a computer?&quot;),
            new QuestionTree(&quot;Is it a diamond?&quot;)
         )
      );
    &lt;/programlisting&gt;

    &lt;para&gt;
      The &lt;acronym&gt;API&lt;/acronym&gt; for QuestionTree is available from here: &lt;ulink url=&quot;../javadoc/index.html&quot;&gt;QuestionTree API&lt;/ulink&gt;. To run &lt;emphasis&gt;Identify&lt;/emphasis&gt;, &lt;command&gt;cd&lt;/command&gt; to the &lt;filename&gt;build/bin/&lt;/filename&gt; directory and type:
    &lt;/para&gt;

    &lt;screen&gt;
      &lt;userinput&gt;&lt;command&gt;java&lt;/command&gt; Identify&lt;/userinput&gt;
    &lt;/screen&gt;
  &lt;/sect1&gt;
&lt;/article&gt;</programlisting>

    <para>
      The file starts with an <emphasis>articleinfo</emphasis> section which declares whom the author is, the copyright and contact information. The article only has one section, which comes next and contains a little bit of information about the Identify program including an example QuestionTree in pictorial form and the source code used to create the QuestionTree. The document ends by illustrating how the program is executed.
    </para>
  </sect1>

  <sect1 id="collab-thebuildfile"><title>The Ant Buildfile</title>
    <para>
      The Ant buildfile used to build the whole project can be downloaded here: <ulink url="files/build.xml">build.xml</ulink>. The buildfile is also shown below:
    </para>

    <programlisting>
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;project name=&quot;Identify&quot; default=&quot;all&quot; basedir=&quot;.&quot;&gt;
  &lt;property name=&quot;src&quot;   value=&quot;src&quot;/&gt;
  &lt;property name=&quot;build&quot; value=&quot;build&quot;/&gt;

  &lt;target name=&quot;all&quot; depends=&quot;clean, mkdir, program, javadoc, docbook&quot;/&gt;

  &lt;target name=&quot;program&quot; description=&quot;Compiles the program source&quot;&gt;
    &lt;javac srcdir=&quot;${src}&quot; destdir=&quot;${build}/bin&quot;/&gt;
  &lt;/target&gt;

  &lt;target name=&quot;javadoc&quot; description=&quot;Creates the JavaDoc output&quot;&gt;
    &lt;javadoc sourcefiles=&quot;${src}/QuestionTree.java&quot; destdir=&quot;${build}/javadoc&quot;/&gt;
  &lt;/target&gt;

  &lt;target name=&quot;docbook&quot; description=&quot;Creates the documentation&quot;&gt;

    &lt;exec executable=&quot;xsltproc&quot;&gt;
      &lt;arg line=&quot;-o ${build}/documentation/Identify.html&quot;/&gt;
      &lt;arg line=&quot;--stringparam generate.toc 'article nop'&quot;/&gt;
      &lt;arg line=&quot;file:///c:/lib/stylesheets/xhtml/customxhtml.xsl&quot;/&gt;
      &lt;arg line=&quot;${src}/Identify.xml&quot;/&gt;
    &lt;/exec&gt;

    &lt;exec executable=&quot;xsltproc&quot;&gt;
      &lt;arg line=&quot;-o ${src}/Identify.fo&quot;/&gt;
      &lt;arg line=&quot;--stringparam generate.toc 'article nop'&quot;/&gt;
      &lt;arg line=&quot;file:///c:/lib/stylesheets/fo/customfo.xsl&quot;/&gt;
      &lt;arg line=&quot;${src}/Identify.xml&quot;/&gt;
    &lt;/exec&gt;

    &lt;exec executable=&quot;fop&quot;&gt;
      &lt;arg line=&quot;${src}/Identify.fo&quot;/&gt;
      &lt;arg line=&quot;${build}/documentation/Identify.pdf&quot;/&gt;
    &lt;/exec&gt;

    &lt;delete file=&quot;${src}/Identify.fo&quot;/&gt;
    &lt;copy file=&quot;${src}/Identify.xml&quot;
          tofile=&quot;${build}/documentation/Identify.xml&quot;/&gt;
    &lt;copy file=&quot;${src}/qtreeexample.png&quot;
          tofile=&quot;${build}/documentation/qtreeexample.png&quot;/&gt;
  &lt;/target&gt;

  &lt;target name=&quot;clean&quot; description=&quot;Cleans the whole project&quot;&gt;
    &lt;delete dir=&quot;${build}&quot;/&gt;
  &lt;/target&gt;

  &lt;target name=&quot;mkdir&quot; description=&quot;Creates the required output directories&quot;&gt;
    &lt;mkdir dir=&quot;${build}/bin&quot;/&gt;
    &lt;mkdir dir=&quot;${build}/javadoc&quot;/&gt;
    &lt;mkdir dir=&quot;${build}/documentation&quot;/&gt;
  &lt;/target&gt;
&lt;/project&gt;</programlisting>

    <para>The default target is all, which looks like this:</para>

    <programlisting>&lt;target name=&quot;all&quot; depends=&quot;clean, mkdir, program, javadoc, docbook&quot;/&gt;</programlisting>

    <para>First, the target, <emphasis>clean</emphasis> is called:</para>

    <programlisting>
  &lt;target name=&quot;clean&quot; description=&quot;Cleans the whole project&quot;&gt;
    &lt;delete dir=&quot;${build}&quot;/&gt;
  &lt;/target&gt;</programlisting>

    <para>
      This target cleans out the last build by deleting the build directory. Next in the list of depends for the <emphasis>all</emphasis> target is <emphasis>mkdir</emphasis>: 
    </para>

    <programlisting>
  &lt;target name=&quot;mkdir&quot; description=&quot;Creates the required output directories&quot;&gt;
    &lt;mkdir dir=&quot;${build}/bin&quot;/&gt;
    &lt;mkdir dir=&quot;${build}/javadoc&quot;/&gt;
    &lt;mkdir dir=&quot;${build}/documentation&quot;/&gt;
  &lt;/target&gt;</programlisting>

    <para>
      This creates the output directories, notice that the directory <filename>build</filename> is never explicitly created, this is because Ant will create any non-existent parent directories, for example:
    </para>

    <programlisting>&lt;mkdir dir=&quot;dir1/dir2/dir3/dir4/dir5&quot;/&gt;</programlisting>

    <para>
      Would create the first four directories before creating the 5th directory. Next in the list of depends for the <emphasis>all</emphasis> target is <emphasis>program</emphasis>:
    </para>

    <programlisting>
  &lt;target name=&quot;program&quot; description=&quot;Compiles the program source&quot;&gt;
    &lt;javac srcdir=&quot;${src}&quot; destdir=&quot;${build}/bin&quot;/&gt;
  &lt;/target&gt;
    </programlisting>

    <para>
      This compiles the program source code using the <emphasis>javac</emphasis> task. Next in the list of depends for the <emphasis>all</emphasis> target is <emphasis>javadoc</emphasis>:
    </para>

    <programlisting>
  &lt;target name=&quot;javadoc&quot; description=&quot;Creates the JavaDoc output&quot;&gt;
    &lt;javadoc sourcefiles=&quot;${src}/QuestionTree.java&quot; destdir=&quot;${build}/javadoc&quot;/&gt;
  &lt;/target&gt;
    </programlisting>

    <para>
      This creates the JavaDoc output by using Ant's builtin <emphasis>javadoc</emphasis> task.  Next, and last, in the list of depends for the <emphasis>all</emphasis> target is <emphasis>docbook</emphasis>:
    </para>

    <programlisting>
&lt;target name=&quot;docbook&quot; description=&quot;Creates the documentation&quot;&gt;

  &lt;exec executable=&quot;xsltproc&quot;&gt;
    &lt;arg line=&quot;-o ${build}/documentation/Identify.html&quot;/&gt;
    &lt;arg line=&quot;--stringparam generate.toc 'article nop'&quot;/&gt;
    &lt;arg line=&quot;file:///c:/lib/stylesheets/xhtml/customxhtml.xsl&quot;/&gt;
    &lt;arg line=&quot;${src}/Identify.xml&quot;/&gt;
  &lt;/exec&gt;

  &lt;exec executable=&quot;xsltproc&quot;&gt;
    &lt;arg line=&quot;-o ${src}/Identify.fo&quot;/&gt;
    &lt;arg line=&quot;--stringparam generate.toc 'article nop'&quot;/&gt;
    &lt;arg line=&quot;file:///c:/lib/stylesheets/fo/customfo.xsl&quot;/&gt;
    &lt;arg line=&quot;${src}/Identify.xml&quot;/&gt;
  &lt;/exec&gt;

  &lt;exec executable=&quot;fop&quot;&gt;
    &lt;arg line=&quot;${src}/Identify.fo&quot;/&gt;
    &lt;arg line=&quot;${build}/documentation/Identify.pdf&quot;/&gt;
  &lt;/exec&gt;

  &lt;delete file=&quot;${src}/Identify.fo&quot;/&gt;
  &lt;copy file=&quot;${src}/Identify.xml&quot;
        tofile=&quot;${build}/documentation/Identify.xml&quot;/&gt;
  &lt;copy file=&quot;${src}/qtreeexample.png&quot;
        tofile=&quot;${build}/documentation/qtreeexample.png&quot;/&gt;
&lt;/target&gt;</programlisting>

    <para>
      The Ant task <emphasis>exec</emphasis> is used to execute <command>xsltproc</command> which generates the <acronym>HTML</acronym> and <acronym>FO</acronym> output. The Ant task <emphasis>java</emphasis> is used to execute the Java program <acronym>FOP</acronym> which generates the <acronym>PDF</acronym> output from the <acronym>FO</acronym> output produced by xsltproc. The temporary <acronym>FO</acronym> medium is deleted and the source <acronym>XML</acronym> and image file are copied to the output directory. Notice that the creation of the <acronym>FO</acronym> and <acronym>HTML</acronym> with xsltproc uses xslproc's ability to accept <acronym>XSL</acronym> parameters on the command line:
    </para>

    <programlisting>&lt;arg line=&quot;--stringparam generate.toc 'article nop'&quot;/&gt;</programlisting>

    <para>
      The <acronym>XSL</acronym> parameter <emphasis>generate.toc</emphasis> is set to <emphasis>article nop</emphasis> so that the generation of tables of content in articles is suppressed.
    </para>
    <sect2 id="Collab-thebuildfile-directory-structure"><title>Directory Structure</title>
      <para>Directory structure of the project, after an Ant build, is shown below:</para>

      <programlisting>
<filename>build.xml</filename>
<filename>build</filename>
   <filename>bin</filename>
      <filename>Identify.class</filename>
      <filename>QuestionTree.class</filename>
      <filename>QuestionTreeTest.class</filename>
   <filename>documentation</filename>
      <filename>Identify.html</filename>
      <filename>Identify.pdf</filename>
      <filename>Indentify.xml</filename>
      <filename>qtreeexample.png</filename>
   <filename>javadoc</filename>
      <filename>allclasses-frame.html</filename>
      <filename>allclasses-noframe.html</filename>
      <filename>constant-values.html</filename>
      <filename>deprecated-list.html</filename>
      <filename>help-doc.html</filename>
      <filename>index-all.html</filename>
      <filename>index.html</filename>
      <filename>overview-tree.html</filename>
      <filename>package-list</filename>
      <filename>packages.html</filename>
      <filename>QuestionTree.html</filename>
      <filename>stylesheet.css</filename>
<filename>src</filename>
   <filename>Identify.java</filename>
   <filename>Identify.xml</filename>
   <filename>log4jconfig.xml</filename>
   <filename>log4jconfig2.xml</filename>
   <filename>qtreeexample.png</filename>
   <filename>QuestionTree.java</filename>
   <filename>QuestionTreeTest.java</filename>
      </programlisting>
    </sect2>
  </sect1>

  <sect1 id="collab-references"><title>References</title>
    <itemizedlist>
      <listitem><para><ulink url="../ant/anthome.html">Ant</ulink></para></listitem>
      <listitem><para><ulink url="../javadoc/javadochome.html">JavaDoc</ulink></para></listitem>
      <listitem><para><ulink url="../log4j/log4jhome.html">LOG4J</ulink></para></listitem>
      <listitem><para><ulink url="../junit/junithome.html">JUnit</ulink></para></listitem>
      <listitem><para><ulink url="../docbooksys/docbooksyshome.html">DocBook</ulink></para></listitem>
    </itemizedlist>
  </sect1>
</article>

