hlship      2004/05/25 15:31:41

  Modified:    common   jar-module.xml project.xml javacc.xml
                        dependency.xml common.properties common.xml
               framework/src/test/hivemind/test/rules
                        TestEnumerationTranslator.java
                        TestConfigurationTranslator.java
                        TestObjectTranslator.java
               framework build.xml
               framework/src/test/hivemind/test TestMisc.java
               framework/src/test/hivemind/test/impl
                        TestRegistryAssemblyImpl.java
               library  build.xml
  Added:       src/documentation/content/xdocs index.xml sdl.xml site.xml
                        case1.xml links.ent tabs.xml bootstrap.xml
               .        forrest.properties
               common   forrest.xml
               src/documentation/conf cli.xconf
               src/documentation/resources/images InterceptorStack.png
                        AdderExample-ProjectLayout.png jakarta-logo.gif
                        HiveMind-Logo.png
               src/documentation skinconf.xml
  Removed:     common   links.xml
               framework/src/test/hivemind/test/rules MockModule.java
  Log:
  Begin reworking documentation as Forrest xdoc.
  
  Revision  Changes    Path
  1.1                  
jakarta-hivemind/src/documentation/content/xdocs/index.xml
  
  Index: index.xml
  ===================================================================
  <?xml version="1.0"?>
  <!-- $Id: index.xml,v 1.1 2004/05/25 22:31:40 hlship Exp $ -->
  <!-- 
     Copyright 2004 The Apache Software Foundation
  
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
         http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.2//EN" 
"./dtd/document-v12.dtd"
  [
        <!ENTITY % common-links SYSTEM "links.ent">
        %common-links;
  ]>
  <document>
  
    <header>
      <title>Introduction to HiveMind</title>
        </header>
        
    <body>
  <section><title>HiveMind</title>
  
  <warning>
  Still be translated from Maven XDoc.  
  </warning>    
        
  </section>
  
      
    </body>
  </document>
  
  
  
  1.1                  jakarta-hivemind/src/documentation/content/xdocs/sdl.xml
  
  Index: sdl.xml
  ===================================================================
  <?xml version="1.0"?>
  <!-- $Id: sdl.xml,v 1.1 2004/05/25 22:31:40 hlship Exp $ -->
  <!-- 
     Copyright 2004 The Apache Software Foundation
  
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
         http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.2//EN" 
"./dtd/document-v12.dtd"
  [
        <!ENTITY % common-links SYSTEM "links.ent">
        %common-links;
  ]>
  <document>
        <header>
                <title>Simple Data Language</title>
        </header>
        <body>
                        
  <p>
  One of the frequent criticisms of J2EE is: <em>too much XML</em>. That is, 
every small aspect
  of a J2EE application requires a big XML deployment descriptor to be 
generated (by hand, or generated
  from code in some way). What's interesting is what's <em>in</em> those XML 
files: configuration
  data containing simple strings and identifiers.
  </p>
  
  <p>
  XML is overkill for these purposes: its a <em>markup</em>      language, 
designed to add 
  <em>semantic meaning</em> to documents that normally have a <em>literal</em> 
meaning (that is,
  documents that are supposed to be read primarily by persons, not other 
programs). Like many technologies,
  its intended use has been co-opted (to what degree is debatable). XML for 
real documents such as XHTML or SVG make sense.
  The complexity of SOAP mandates an industrial strength syntax to express its 
complex structure. But for the
  majority of uses of XML within the J2EE stack, it simply is vastly more 
complex than is necessary.
  </p>
  
  <p>
  The complexity comes at some cost ... XML is very verbose, a tangle of 
punctuation 
  (such as <code>&lt;</code>, <code>&gt;</code> and quotes) and repetition 
(start tags and end tags). Even 
  experienced developers often need to take a bit of time to visually and 
mentally parse an XML snippet.
  </p>
  
  <p>
  Through HiveMind release 1.0-alpha-4, HiveMind was as guilty as the next 
project in XML usage. HiveMind
  module deployment descriptors would, at least, centralize the XML concerning 
a service, and enforce
  some amount of uniformity.    
  </p>
  
  <p>
  Release 1.0-alpha-5 introduces <strong>Simple Data Language</strong>, an 
<em>alternative</em> to the use
        of XML in HiveMind.  XML will continue to be supported as a first class 
citizen, but in HiveMind,
        there is not such a compelling reason to use it!
  </p>
  
  
  <section><title>Goals</title>
        
  <p>
  The goals of SDL are to provide the bare essentials needed for a hierachical 
data language, but
  keep is spare and readable. Unecessary typing is to be avoided, so the use of 
quotes is made
  optional whereever possible. SDL syntax should be reasonably obvious to an 
interested observer.       
  </p>
        
        
  </section>
  
  <section><title>Examples</title>
  
  <p>
  Before getting bogged down in a formal specification for SDL, a few simple 
examples will explain just
  about everything.     Compare the following two HiveMind module deployment 
descriptors, which express
  identical information:
  </p>
  
  <p>
  <strong>Traditional XML Format:</strong>
  </p>
  <source><![CDATA[
  <?xml version="1.0"?>
  
  <module id="some.module" version="1.0.0">
    <configuration id="ControlPipeline">
      <schema>
        <element name="processor">
         
           <attribute name="name" required="true"/>
           <attribute name="service-id" required="true" translator="service"/>
           <attribute name="before"/>
           <attribute name="after"/>
           
           <conversion class="some.module.PipelineContribution">
             <map property="controlService" attribute="service-id"/>
           </conversion>
        
        </element>
      </schema>
    </configuration>
  </module>     
  ]]>
  </source>
  
  <p>
  <strong>SDL format:</strong>  
  </p>
  
  <source>
  module (id=some.module version="1.0.0")
  {
    configuration (id=ControlPipeline)
    {
      schema
      {
        element (name=processor)
        {
          attribute (name=name required=true)
          attribute (name=service-id required=true)
          attribute (name=before)
          attribute (name=after)
          
          conversion (class=some.module.PipelineContribution)
          {
            map (property=controlService attribute=service-id 
translator=service)
          }
        }
      }
    }
  }   
  </source>     
  
  
  <p>
  Some observations:
  </p>
  
  <ul>
  <li>SDL uses open and close braces to denote containment of elements within 
another element</li>      
  <li>Attributes, as a list of name-value pairs, are placed in parenthesis 
following the element name</li>
  <li>Elements without attributes can omit the parenthesis (example: 
<code>schema</code>)</li>
  <li>Elements that do not contain other elements can omit the open and close 
braces denoting thier
        body (example: <code>attribute</code>)</li>
  <li>Most common strings do not have to be quoted</li>
  <li><em>All</em> whitespace not inside quotes is ignored</li>
  </ul> 
  
  </section>
  
        
  <section><title>Whitespace</title>
  
  <p>
  All whitespace (outside of literals) is ingored.  Whitespace is considered to 
be:
  </p>
  
  <ul>
        <li>Spaces</li> 
        <li>Tabs</li>
        <li>Newlines</li>
        <li>Carriage Returns</li>
  </ul> 
  
  </section>
  
  <section><title>Comments</title>
  
  <p>
  Comments are in the format traditional in Java and C: 
  </p>  
  
  <source>
  // This is a comment that extends to the end of the current line.
  
  /* This is a multiline
     comment. */        
  </source>
  
  <p>
  Comments may appear anywhere in an SDL document (except within quoted 
strings) and are always ignored.        
  </p>
  
  </section>
  
  <section><title>Element and Attribute Names</title>
  
  <p>
  Element and attribute names must be <em>simple ids</em>. They must start with 
a letter (or underscore)
  and may contain only letters, digits, underscores and dashes. They may 
<em>not</em> be enclosed in quotes.
  </p>  
  
  </section>
  
  <section><title>Literal Values</title>
        
  <p>
  Attribute values may be literal values.  Literal values are considered one of 
the following:
  </p>
        
  <ul>
  <li>simple ids</li>   
  <li>complex ids -- a sequence of simple ids seperated by periods</li>
  <li>numeric values</li>
  <li>Symbol references</li>
  <li>Quoted strings</li>
  <li>Extended literals</li>
  </ul> 
  
  <p>
  Complex ids have the same format as Java class and interface names (but can, 
additionally, contain
  dash characters which are not allowed in Java).
  </p>
  
  <p>
  Numeric values consist of an optional sign (<code>+</code>     or 
<code>-</code>) followed
  by a integer or decimal value.  In the future, a more expansive definition 
may be provided.
  </p>
  
  <p>
  Symbol references allow Ant-style symbols to be used directly in SDL.  
Example:
  </p>
  
  <source>
  . . .
    set-service (service-id=${symbol.for.service-id})
  . . . 
  </source>     
  
  
  <p>
  Support for Ant symbols is a convienience (the same syntax is used heavily 
within HiveMind).
  There is no difference between <code>${symbol.for.service-id}</code> and
  <code>"${symbol.for.service-id}"</code> ... both will be processed 
identically.
  </p>
  
  <p>
  Quoted strings are similar to Java string literals. All whitespace within the 
string is retained as-is,
  including line breaks.  A subset of the Java escape codes are currently 
supported:
  </p>
        
  <ul>
    <li>\t (tab)</li>   
    <li>\n (newline)</li>
    <li>\r (carriage return)</li>
    <li>\"  (quote)</li>
    <li>\\  (slash)</li>
  </ul> 
  
  <p>
  Any other sequence is passed through normally (unescaped).
  </p>
        
  <p>
  Extended literals have a different syntax:    
  </p>
  
  <source><![CDATA[
  . . .
    description =
  << A long, multiline string
  that may contain "quoted" sections. >>        
  . . .
  ]]></source>
  
  <p>
  Extended literals may contain any character sequence (except 
<code>&gt;&gt;</code>). Escape sequences
  in expanded literals are not interpreted. All whitespace within the 
delimiters is retained.
  </p>
  </section>
        
  
  
  <section><title>Literal Gotcha</title>
  
  <p>
  The body of an element may contain literal text data, just as with XML.  
Unlike XML, whitespace
  is completely removed.  Thus the following are equivalent:
  </p>
  
  <source><![CDATA[
  first
  { 
    "NowIsTheTime" 
  }
  second
  {
    "Now" "Is" <<The>> <<Time>>
  }
  ]]></source>  
        
  
  <p>
  This applies to all forms of literals, including numbers. The following are 
identical:
  </p>
  <source>
  pi1
  { 
    3.14159
  }
  pi2
  {
    3 .14 159
  }
  </source>     
  
  
  <p>
  Inside the body of an element, simple ids are interpreted as 
<em>elements</em>         not
  string literals.  In the following example, <code>root1</code> and 
<code>root2</code> have the
  same structure (each contains three children and no content).  
<code>leaf</code> contains no
  children, and its content is <code>child1child2child3</code>.
  </p>
        
  <source><![CDATA[
  root1 
  {
    child1 {}
    child2 {}
    child3 {}
  }
  root2
  {
    child1 child2 child3
  }
  leaf
  {
    "child1" "child2" "child3"
  }     
  ]]></source>
        
  </section>
  
  
  <section><title>TO DO</title>
  
  <ul>
  <li>Expand the definition of "character" to properly include Unicode</li>     
  <li>Add Unicode escape patterns in quoted literals</li>
  <li>Expand the definition of numeric literal to include all Java literals</li>
  </ul>
        
  </section>
  
  
  
        </body>
  </document>
  
  
  
  1.1                  jakarta-hivemind/src/documentation/content/xdocs/site.xml
  
  Index: site.xml
  ===================================================================
  <?xml version="1.0"?>
  <!-- $Id: site.xml,v 1.1 2004/05/25 22:31:40 hlship Exp $ -->
  <!DOCTYPE site>
  <site xmlns="http://apache.org/forrest/linkmap/1.0"; tab="project">
        <project label="HiveMind Project">
                <bootstrap label="Bootstrapping the Registry" 
href="bootstrap.html"/>
                <case1 label="Case Study #1: Panorama Startup" 
href="case1.html"/>
                <sdl label="Simple Data Language" href="sdl.html"/>
        </project>
        <hivemind label="Module: hivemind" href="hivemind/">
                <services label="Services">
                        <hivemind.LoggingInterceptor 
label="hivemind.LoggingInterceptor"
                                href="LoggingInterceptor.html"/>
                </services>
                <configs label="Configurations">
                        <hivemind.ApplicationDefaults 
label="hivemind.ApplicationDefaults"
                                href="ApplicationDefaults.html"/>
                        <hivemind.FactoryDefaults 
label="hivemind.FactoryDefaults"
                                        href="FactoryDefaults.html"/>
                </configs>
        </hivemind>
        <related label="Related Projects">
                <item label="Tapestry" 
href="http://jakarta.apache.org/tapestry/"/>
        </related>
  </site>
  
  
  
  1.1                  
jakarta-hivemind/src/documentation/content/xdocs/case1.xml
  
  Index: case1.xml
  ===================================================================
  <?xml version="1.0"?>
  <!-- $Id: case1.xml,v 1.1 2004/05/25 22:31:40 hlship Exp $ -->
  <!-- 
     Copyright 2004 The Apache Software Foundation
  
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
         http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.2//EN" 
"./dtd/document-v12.dtd"
  [
    <!ENTITY % common-links SYSTEM "links.ent">
    %common-links;
  ]>
  <document>
    <header>
      <title>Case Study #1: Application Startup / Shutdown</title>
    </header>
    <body>
  
  
  <note>
  This case study is based on work done for my prior employer, who has not (yet)
  given approval to mention the project by name. The package names and module
  ids have been changed, and some minor changes and simplifications have been 
made.
  The actual name of the product has been disguised as <em>Panorama</em>.
  </note>
  
    
  <p>
  The Panorama product is a fairly large J2EE web application deployed into BEA 
WebLogic.  Panorama consists
  of well over six thousand classes, divided into a large number of tools and 
services.
  Panorama has been a production project for several years, long before 
HiveMind was available. 
  HiveMind's introduction into Panorama (on something of a trial basis) was to 
cleanup the startup
  and shutdown process for the application.
  </p>  
  
  <p>
  Panorama runs inside BEA WebLogic as an enterprise application; however, it 
is still logically a 
  number of subsystems, many of which require some form of startup or shutdown 
logic.  For example,
  the Panorama Help service caches help data stored in the database; the 
Panorama Mail tool sets up
  periodic database cleanup jobs.  All told, there are over 40 startup tasks, 
and a handful of shutdown
  tasks.
  </p>
  
  <p>
  Prior to HiveMind, a single EJB was the focus of all this startup and 
shutdown activity.
  A small WebLogic startup class would invoke the EJB, and the EJB 
implementation would invoke static methods
  on many other classes (some of which would lookup other EJBs and invoke 
methods on them).  
  This approach had grown quite unwieldy, especially in light of efforts
  to improve and modularize the Panorama build process.  HiveMind was brought 
in to rationalize
  this aspect of Panorama, with the goal being to make the fewest possible 
changes
  to existing code.
  </p>
  
  <p>
  An important aspect of startup and shutdown is the order of operations; there 
are dependencies between
  different tasks that must be honored in terms of which task is executed 
first.  
  </p>
  
  
  <section><title>Overview</title>
  
  <p>
  The appropriate place to build the registry for an EAR is from the web 
application; it has
  the widest view of available classes; the web application classloader has 
visibility to the web application
  and its libraries, all the EJBs deployed in the application, and the system 
classloader.  
  </p>
  
  <p>
  The overall approach is to provide HiveMind module deployment descriptors for 
the various
  tools and services of Panorama; each module  contributes tasks to a Startup 
or Shutdown configuration point.
  </p>
  
  <p>
  A WebLogic shutdown class is still used and the original EJB still exists to 
allow an orderly shutdown.  
  Ultimately, this is required due to class loader issues; the EJB will have 
visibility to the HiveMind library,
  but the startup class may not.
  </p>
  
  </section>
  
  <section><title>Module panorama.framework.startup</title>
  
  <p>
  The <code>panorama.framework.startup</code> ("initialization and shutdown") 
module
  contains the services and configuration points for startup and shutdown.  It 
also contains
  Java classes corresponding to task contributions.
  </p>  
    
  <source>
  
  module (id=panorama.framework.startup version="1.0.0")
  {
        description { "Module for startup and shutdown code within Panorama." }
        
        schema (id=Task)
        {
                element (name=task)
                {
                        description { "A task which may be executed." }
                        
                        attribute (name=order required=true)
                        {
                                description { "Numeric value used to set the 
order of execution for tasks." }
                        }
                        
                        attribute (name=title required=true)
                        {
                                description { "Title displayed as task is 
executed." }
                        }
                        
                        attribute (name=class translator=object)
                        {
                                description { "Name of class implementing the 
Executable interface." }
                        }
                        
                        attribute (name=service-id translator=service)
                        {
                                description { "Name of service implementing the 
Executable interface." }
                        }
                        
                        conversion 
(class=com.panorama.framework.startup.service.Task)
                        {
                                map (attribute=class property=executable)
                                map (attribute=service-id property=executable)
                                
                                // Other attribute map directly
                        }
                        
                        // Nested element
                        
                        element (name=invoke-static)
                        {
                                description { "Used to invoke a public static 
method of a class." }
                        
                                attribute (name=class required=true)
                                {
                                        description { "The name of the class 
containing the method to invoke." }
                                }
                                
                                attribute (name=method)
                                {
                                        description 
                                        {
                                                "The name of the metehod to 
invoke. The default method name is "
                                                "init."
                                         }
                                }
                                
                                conversion 
(class=com.panorama.framework.startup.service.StaticTask 
                                                                                
parent-method=setExecutable)
                                {
                                        map (attribute=class property=className)
                                        map (attribute=method 
property=methodName)
                                }
                        }
                }       
        }
        
        configuration-point (id=startup schema-id=Task)
        {
                description { "Defines startup tasks." }
        }
        
        configuration-point (id=Shutdown schema-id=Task)
        {
                description { "Defines shutdown tasks." }
        }
        
        contribution (configuration-id=Startup)
        {
                task (title=Python order=50 
class=com.panorama.framework.startup.common.PythonStartup)
        }
        
        contribution (configuration-id=Shutdown)
        {
                task (title="Update Status" order=100)
                {
                        invoke-static 
(class=com.panorama.framework.startup.common.PanoramaStatus
                                                                                
        method="shutdown)
                }
        }
        
        service-point (id=Startup interface=java.lang.Runnable)
        {
                invoke-factory (service-id=hivemind.BuilderFactory)
                {
                        construct 
(class=com.panorama.framework.startup.service.TaskExecutor
                                                                        
log-property=log messages-property=messages)
                        {
                                set-configuration (property=tasks 
configuraton-id=Startup)
                                set (property=kind value="%startup")
                        }
                }
                
                interceptor (service-id=hivemind.LoggingInterceptor)
        }
          
        service-point (id=Shutdown interface=java.lang.Runnable)
        {
                invoke-factory (service-id=hivemind.BuilderFactory)
                {
                        construct 
(class=com.panorama.framework.startup.service.TaskExecutor
                                                                        
log-property=log messages-property=messages)
                        {
                                set-configuration (property=tasks 
configuraton-id=Shutdown)
                                set (property=kind value="%shutdown")
                        }
                }
                
                interceptor (service-id=hivemind.LoggingInterceptor)
        }
                  
  }
  </source>
  
  <p>
  Notes:
  </p>
  
  <ul>
  <li>
  Extension points, configurations, schemas and services can be specified in 
any order.  
  </li>
  <li>
  We use the simplest possible interface for the Startup and Shutdown services: 
<code>java.lang.Runnable</code>.  
  </li>
  </ul>  
  
  <section><title>Startup configuration point</title>
  
  <p>
  The Startup configuration point and the Startup service are closely bound 
together; the former
  contains contributions from all sorts of modules.  The service uses those 
contributions
  and executes tasks based on them.  
  </p>  
  
  <p>
  The schema for the Startup configuration point allows a 
<code>&lt;task&gt;</code>
  to be contributed.  A task always has an <code>order</code> attribute (used 
to sort
  all the contributed elements into an execution order) and a 
<code>title</code> attribute
  (used in output).
  </p>
  
  <p>
  The task to execute is specified in one of three ways:
  </p>
        
  <ul>
  <li>As a Java class implementing the
     <code>com.panorama.framework.startup.service.Executable</code> interface 
(using the <code>class</code> attribute)</li>
  <li>As a HiveMind service, implementing the service (using the 
<code>service-id</code> attribute)</li>
  <li>As a public static method of a class (using the enclosed 
<code>&lt;invoke-static&gt;</code> element)</li>
  </ul>
    
  <p>
  The <code>Executable</code> interface is similar to the 
<code>java.lang.Runnable</code> interface:
  </p>
        
  <source>
  package com.panorama.framework.startup.service;
  
  /**
   * Variation of <code>java.lang.Runnable</code> that allows for
   * the invoked method to throw an exception. 
   */
  public interface Executable
  {
      /**
       * Invoked to execute some kind of behavior and possible throw an 
exception.
       * The caller is responsible for catching and reporting the exception.
       */
      public void execute() throws Exception;
  }
  </source>
  
  <p>
  Adding <code>throws Exception</code> to the method signature allows the 
caller to be responsible
  for exception reporting, which simplifies the task implementations.
  Shortly, we'll see how the application's master servlet invokes the Startup 
service.  
  </p>
  
  <p>
  The Shutdown configuration point and service are effectively clones of the 
Startup configuration point and schema.
  </p>
  
  </section>
  
  <section><title>Task class</title>
  
  <p>
  The Task class is used to hold the information collected by the Startup 
configuration point.
  </p>  
  
  <source>
  package com.panorama.framework.startup.service;
  
  import org.apache.hivemind.Orderable;
  
  /**
   * Configuration element for the 
<code>panorama.framework.startup.Startup</code> or
   * <code>panorama.framework.startup.Shutdown</code>
   * configuration points.  Each element has a title,
   * an [EMAIL PROTECTED] com.panorama.framework.startup.service.Executable}
   * object, and an order
   * (used to sort the Tasks into an order of execution).
   */
  public class Task implements Orderable, Executable
  {
      private int _order;
      private String _title;
      private Executable _executable;
      
      public void execute() throws Exception
      {
          _executable.execute();
      }
      
      public int getOrder()
      {
          return _order;
      }
  
      public String getTitle()
      {
          return _title;
      }
  
      public void setOrder(int i)
      {
          _order = i;
      }
  
      public void setTitle(String string)
      {
          _title = string;
      }
  
      public Executable getExecutable()
      {
          return _executable;
      }
  
      public void setExecutable(Executable executable)
      {
          _executable = executable;
      }
  }  
  </source>
  
  <p>
  Task implements <code>Executable</code>, simply delegating to its 
<code>executable</code> property. In addition,
  it implements
  <link href="&apiroot;/Orderable.html">Orderable</link>, which simply defines 
the <code>order</code>
  property (but simplifies sorting of the elements).
  </p>
  </section>
  
  
  
  <section><title>Startup service</title>
  
  <p>
  The Startup and Shutdown services are very similar: similar enough that a 
single class, properly configured, can be
  the service implementation for either service.  
  </p>
    
  <source><![CDATA[
  package com.panorama.framework.startup.service;
  
  import java.util.List;
  
  import org.apache.hivemind.HiveMind;
  import org.apache.hivemind.Messages;
  import org.apache.commons.logging.Log;
  
  /**
   * Implementation for the <code>panorama.framework.startup.Startup</code> 
   * and <code>Shutdown</code> services.
   * Reads the corresponding configuration, sorts the elements,
   * and executes each. 
   */
  public class TaskExecutor implements Runnable
  {
      private Log _log;
      private Messages _messages;
      private List _tasks;
  
      private String _kind;
  
      public void run()
      {
          long startTime = System.currentTimeMillis();
  
          List sorted = null;
  
          try
          {
              sorted = HiveMind.sortOrderables(_tasks);
          }
          catch (Exception ex)
          {
              _log.error(_messages.format("initialization-failure", _kind, 
ex.getMessage()));
  
              return;
          }
  
          int count = sorted.size();
          int failureCount = 0;
  
          for (int i = 0; i < count; i++)
          {
              Task task = (Task)sorted.get(i);
  
              if (execute(task))
                  failureCount++;
          }
  
          Long elapsedTime = new Long(System.currentTimeMillis() - startTime);
  
          if (failureCount > 0)
              _log.warn(
                  _messages.format(
                      "task-failure-summary",
                      new Object[] {
                          Integer.toString(failureCount),
                          Integer.toString(count),
                          _kind,
                          elapsedTime }));
          else
              _log.info(
                  _messages.format("task-summary", Integer.toString(count), 
_kind, elapsedTime));
      }
  
      /**
       * Executes a single task.
       * @param task the task to execute.
       * @return true if the task fails (throws an exception).
       */
      private boolean execute(Task task)
      {
          if (_log.isInfoEnabled())
              _log.info(_messages.format("executing-task", _kind, 
task.getTitle()));
  
          try
          {
              task.execute();
  
              return false;
          }
          catch (Exception ex)
          {
              _log.error(_messages.format("task-failure", _kind, 
task.getTitle(), ex.getMessage()));
  
               return true;
          }
      }
  
      public void setKind(String string)
      {
          _kind = string;
      }
  
      public void setLog(Log log)
      {
          _log = log;
      }
  
      public void setMessages(Messages messages)
      {
          _messages = messages;
      }
  
      public void setTasks(List list)
      {
          _tasks = list;
      }
  
  }
  ]]>
  </source>
  
  <p>
  HiveMind has a static convienience method, <code>sortOrderables()</code>, 
used to sort a list of Orderable
  objects into order, which is used here. Remember that the contributions to 
the Startup (and Shutdown)
  configuration points are made from multiple modules and there's no way to 
predict in what order those contributions
  will show up in the <code>tasks</code> property, which is why explicit 
sorting is necessary.
  </p>
  
  <p>
  At one time, there was a discussion about using a thread pool to allow 
execution of some of the tasks in parallel.
  That's
  a premature optimization: even with over forty startup tasks, startup still 
only takes about forty seconds.  
  </p>
  
  </section>
  
  <section><title>StaticTask class</title>
    
  <p>
  The StaticTask class allows an arbitrary public static method of a class
  to be treated like an <code>Executable</code>.
  </p>
  
  <source>
  package com.panorama.framework.startup.service;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  
  import org.apache.hivemind.ApplicationRuntimeException;
  import org.apache.hivemind.impl.BaseLocatable;
  import org.apache.commons.lang.StringUtils;
  
  /**
   * Implementation of
   * [EMAIL PROTECTED] com.panorama.framework.startup.service.Executable}
   * that Invokes a static method on a public class.
   */
  public class StaticTask extends BaseLocatable implements Executable
  {
      private String _className;
      private String _methodName = "init";
  
      public void execute() throws Exception
      {
          checkNull("className", _className);
          checkNull("methodName", _methodName);
  
          Class clazz = Class.forName(_className);
          Method m = clazz.getMethod(_methodName, null);
  
          try
          {
              m.invoke(null, null);
          }
          catch (InvocationTargetException ex)
          {
              Throwable t = ex.getTargetException();
  
              if (t instanceof Exception)
                  throw (Exception)t;
  
              throw ex;
          }
      }
  
      private void checkNull(String propertyName, String value)
      {
          if (StringUtils.isBlank(value))
              throw new ApplicationRuntimeException(
                  "Property " + propertyName + " of " + this + " is null.",
                  getLocation(),
                  null);
      }
  
      public String getClassName()
      {
          return _className;
      }
  
      public String getMethodName()
      {
          return _methodName;
      }
  
      /**
       * Sets the name of a class containing a static method that will be 
executed.
       */
      public void setClassName(String string)
      {
          _className = string;
      }
  
      /**
       * Sets the name of a public static method taking no parameters.  The 
default is "init".
       * 
       */
      public void setMethodName(String string)
      {
          _methodName = string;
      }
  
  }
  </source>
  
  <p>
  The class implements
  <link href="&apiroot;/Locatable.html">Locatable</link>, which is used
  in method <code>isNull()</code> when reporting errors; the location will be 
the location
  of the &lt;invoke-static&gt; element the StaticTask instance was created from.
  </p>
  
  </section>
  
  </section>
  
  <section><title>Other Modules</title>
  
  <p>
  Other modules, in their HiveMind module deployment descriptors, make 
contributions
  into the Startup and Shutdown configuration points of the 
<code>panorama.framework.startup</code>
  module.  For example:
  </p>
  
  <source>
  module (id=panorama.coreservice.mail version="1.0.0")
  {
        contribution (configuration-id=panorama.framework.startup.Startup)
        {
                task (title=Mail order=2600 
class=com.panorama.coreservice.mail.startup.MailStartup)
        }
  }
  </source>
  
  
  <p>
  Here, the Mail service contributes an instance of class 
<code>MailStartup</code>.
  Other modules take advantage of the &lt;invoke-static&gt; element:
  </p>
  
  <source>
  module (id=panorama.coreservice.garbagecollection version="1.0.0")
  {
        contribution (configuration-id=panorama.framework.startup.Startup)
        {
                task (title="Scheduling Garbage Collection" order=3900)
                {
                        invoke-static 
(class=com.panorama.coreservice.garbagecollection.startup.GarbageCollectionStartup)
                }
        }
  }
  </source>
  
  
    
  </section>
  
  <section><title>Other Modules</title>
    
  <p>
  The master servlet for the web application is responsible for constructing 
the registry
  and storing it so that
  other code may access it.
  </p>
    
  <source><![CDATA[
      public void init() throws ServletException
      {
          LOG.info("*** Bootstrapping HiveMind Registry ***");
  
          if (PanoramaRuntime.getHiveMindRegistry() != null)
          {
              LOG.info(
                  "Registry is already initialized (the application appears to 
have been redeployed).");
              return;
          }
  
           try
           {
               RegistryBuilder builder = new RegistryBuilder(new 
RegistryBuilderErrorHandler());
  
               ClassResolver resolver = new DefaultClassResolver();
  
               builder.processModules(resolver);
  
               Registry registry = 
builder.constructRegistry(Locale.getDefault());
  
               PanoramaRuntime.setHiveMindRegistry(registry);
  
               Runnable startup =
                   
(Runnable)registry.getService("panorama.framework.startup.Startup", 
Runnable.class);
  
               LOG.info("*** Executing panorama.framework.startup.Startup 
service ***");
  
               startup.run();
           }
           catch (Exception ex)
           {
               LOG.error(
                   "Unable to execute panorama.framework.startup.Startup 
service: " + ex.getMessage());
           }
       }
  ]]></source>
    
  <p>
  After building the registry, the servlet uses the Startup service to 
indirectly
  execute all the startup tasks.
  </p>
  
  </section>
  
  <section><title>Handling Shutdown</title>
        
  <p>
  We take advantage of a WebLogic extension to know when the application server 
is being shut down.
  </p>
  
  <source>
  package com.panorama.framework.startup;
  
  import javax.naming.InitialContext;
  import javax.rmi.PortableRemoteObject;
  
  import com.panorama.framework.startup.ejb.Shutdown;
  import com.panorama.framework.startup.ejb.ShutdownHome;
  
  /**
   * Shutdown class called by the WebLogic container.
   */
  public class Shutdown
  {
      private final static String EJB_JNDI_NAME =
          "com.panorama.framework.startup.ejb.initshutHome";
  
      /** Prevent instantiation */
      private Shutdown()
      {
      }
  
      /**
       *  Gets the Shutdown EJB and invokes <code>shutdown()</code>.
       */
  
      public static void main(String args[]) throws Exception
      {
          InitialContext context = new InitialContext();
          ShutdownHome home =
              (ShutdownHome)PortableRemoteObject.narrow(
                  context.lookup(EJB_JNDI_NAME),
                  ShutdownHome.class);
                  
          Shutdown bean = (Shutdown)home.create();
          
          bean.shutdown();
      }
  
  }  
  </source>
  
  <p>
  The implementation of the initshut EJB is similarily straight-forward:
  </p>  
        
  <source><![CDATA[
  package com.panorama.framework.startup.ejb;
  
  import java.rmi.RemoteException;
  
  import javax.ejb.CreateException;
  
  import org.apache.hivemind.HiveMind;
  import org.apache.hivemind.Registry;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  import com.panorama.framework.ejb.BaseSessionBean;
  
  /**
   * Handles shutdown logic.
   *
   */
  
  public class ShutdownEJB extends BaseSessionBean
  {
      private static final Log LOG = LogFactory.getLog(ShutdownEJB.class);
  
      public void ejbCreate() throws RemoteException, CreateException
      {
      }
  
      /**
       * Called by J2EE Container shutdown class for Panorama shutdown 
processing.
       * 
       * <p>
       * Gets the <code>panorama.framework.startup.Shutdown</code> service and 
executes it.
       * 
       */
      
      public void shutdown() throws RemoteException
      {
          Registry registry = PanoramaRuntime.getHiveMindRegistry();
  
          if (registry == null)
          {
              LOG.error(
                  "No HiveMind module registry is in place, unable to execute 
an orderly shutdown.");
              return;
          }
  
          Runnable r =
              
(Runnable)registry.getService("panorama.framework.startup.Shutdown", 
Runnable.class);
  
          r.run();
  
          LOG.info("**** Panorama shutdown complete ****");
      }
  }]]>
  </source>  
  
  </section>
  
  <section><title>Summary</title> 
  
  <p>
  This case study has shown how easy it is to leverage HiveMind for a complex 
task. A monolithic EJB was broken down into
  tiny, agile contributions to a configuration point. 
  The startup and shutdown logic is kept close to the contributing
  modules, in those modules' HiveMind deployment descriptors.  Contributions 
are in expressive, easily readable XML.
  </p>
  
  <p>A single class is used to implement multiple, similar services, just by 
  configuring it as needed. Links between different aspects of the system (such 
as
  the servlet initialization code and the Startup service) are kept simple and 
agile.
  </p>
  
  <p>
  The small amount of code necessary to orchestrate all this is fully tested in 
a unit test suite.  
  </p>
  
  <p>
  The end result: an agile, easily extended system.  HiveMind has provided the 
tools and environment
  to support an elegant, data-driven solution ... replacing the old, code-heavy 
EJB implementation.  
  </p>
    
  </section>
  
  </body>
  </document>
  
  
  1.1                  
jakarta-hivemind/src/documentation/content/xdocs/links.ent
  
  Index: links.ent
  ===================================================================
  <!-- $Id: links.ent,v 1.1 2004/05/25 22:31:40 hlship Exp $ -->
  <!-- 
     Copyright 2004 The Apache Software Foundation
  
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
         http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  
  <!ENTITY projectroot ''>
  
  <!ENTITY apiroot '&projectroot;hivemind/apidocs/org/apache/hivemind'>
  <!ENTITY hivedoc '&projectroot;hivedocs'>
  
  <!-- Fuykin Maven - - if I remove the &lt; and &gt; from the entities below 
it breaks
           (doesn't render any text within the <a> and </link> tags). Why? Who 
knows, its Maven. -->
  
  <!ENTITY _module '<code>&lt;module&gt;</code>'>
  <!ENTITY module '<link 
href="&projectroot;descriptor.html#module">&_module;</link>'>
  
  <!ENTITY _implementation '<code>&lt;implementation&gt;</code>'>
  <!ENTITY implementation '<link 
href="&projectroot;descriptor.html#implementation">&_implementation;</link>'>
  
  <!ENTITY _configuration-point '<code>&lt;configuration-point&gt;</code>'>
  <!ENTITY configuration-point '<link 
href="&projectroot;descriptor.html#configuration-point">&_configuration-point;</link>'>
  
  <!ENTITY _conversion '<code>&lt;conversion&gt;</code>'>
  <!ENTITY conversion '<link 
href="&projectroot;descriptor.html#conversion">&_conversion;</link>'>
  
  <!ENTITY _map '<code>&lt;map&gt;</code>'>
  <!ENTITY map '<link href="&projectroot;descriptor.html#map">&_map;</link>'>
  
  <!ENTITY _create-instance '<code>&lt;create-instance&gt;</code>'>
  <!ENTITY create-instance '<link 
href="&projectroot;descriptor.html#create-instance">&_create-instance;</link>'>
  
  <!ENTITY _invoke-factory '<code>&lt;invoke-factory&gt;</code>'>
  <!ENTITY invoke-factory '<link 
href="&projectroot;descriptor.html#invoke-factory">&_invoke-factory;</link>'>
  
  <!ENTITY _interceptor '<code>&lt;interceptor&gt;</code>'>
  <!ENTITY interceptor '<link 
href="&projectroot;descriptor.html#interceptor">&_interceptor;</link>'>
  
  <!ENTITY _description '<code>&lt;description&gt;</code>'>
  <!ENTITY description '<link 
href="&projectroot;descriptor.html#description">&_description;</link>'>
  
  <!ENTITY _contribution '<code>&lt;contribution&gt;</code>'>
  <!ENTITY contribution '<link 
href="&projectroot;descriptor.html#contribution">&_contribution;</link>'>
  
  <!ENTITY _service-point '<code>&lt;service-point&gt;</code>'>
  <!ENTITY service-point '<link 
href="&projectroot;descriptor.html#service-point">&_service-point;</link>'>
  
  <!ENTITY _schema '<code>&lt;schema&gt;</code>'>
  <!ENTITY schema '<link 
href="&projectroot;descriptor.html#schema">&_schema;</link>'>
  
  <!ENTITY _parameters-schema '<code>&lt;parameters-schema&gt;</code>'>
  <!ENTITY parameters-schema '<link 
href="&projectroot;descriptor.html#schema">&_parameters-schema;</link>'>
  
  <!ENTITY _element '<code>&lt;element&gt;</code>'>
  <!ENTITY element '<link 
href="&projectroot;descriptor.html#element">&_element;</link>'>
  
  <!ENTITY _attribute '<code>&lt;attribute&gt;</code>'>
  <!ENTITY attribute '<link 
href="&projectroot;descriptor.html#attribute">&_attribute;</link>'>
  
  <!ENTITY _rules '<code>&lt;rules&gt;</code>'>
  <!ENTITY rules '<link 
href="&projectroot;descriptor.html#rules">&_rules;</link>'>
  
  <!ENTITY _sub-module '<code>&lt;sub-module&gt;</code>'>
  <!ENTITY sub-module '<link 
href="&projectroot;descriptor.html#sub-module">&_sub-module;</link>'>
  
  <!-- XML entities for the XML processing rules (documented seperately from 
the rest). -->
  
  <!ENTITY _create-object '<code>&lt;create-object&gt;</code>'>
  <!ENTITY create-object '<link 
href="&projectroot;rules.html#create-object">&_create-object;</link>'>
  
  <!ENTITY _invoke-parent '<code>&lt;invoke-parent&gt;</code>'>
  <!ENTITY invoke-parent '<link 
href="&projectroot;rules.html#invoke-parent">&_invoke-parent;</link>'>
  
  <!ENTITY _read-attribute '<code>&lt;read-attribute&gt;</code>'>
  <!ENTITY read-attribute '<link 
href="&projectroot;rules.html#read-attribute">&_read-attribute;</link>'>
  
  <!ENTITY _read-content '<code>&lt;read-content&gt;</code>'>
  <!ENTITY read-content '<link 
href="&projectroot;rules.html#read-content">&_read-content;</link>'>
  
  
  <!ENTITY _set-module '<code>&lt;set-module&gt;</code>'>
  <!ENTITY set-module '<link 
href="&projectroot;rules.html#set-module">&_set-module;</link>'>
  
  <!ENTITY _set-parent '<code>&lt;set-parent&gt;</code>'>
  <!ENTITY set-parent '<link 
href="&projectroot;rules.html#set-parent">&_set-parent;</link>'>
  
  <!ENTITY _set-property '<code>&lt;set-property&gt;</code>'>
  <!ENTITY set-property '<link 
href="&projectroot;rules.html#set-property">&_set-property;</link>'>
  
  <!ENTITY _custom '<code>&lt;custom&gt;</code>'>
  <!ENTITY custom '<link 
href="&projectroot;rules.html#custom">&_custom;</link>'>
  
  <!ENTITY _push-attribute '<code>&lt;push-attribute&gt;</code>'>
  <!ENTITY push-attribute '<link 
href="&projectroot;rules.html#push-attribute">&_push-attribute;</link>'>
  
  
  
  1.1                  jakarta-hivemind/src/documentation/content/xdocs/tabs.xml
  
  Index: tabs.xml
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!--
     Copyright 2004 The Apache Software Foundation
    
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
    
         http://www.apache.org/licenses/LICENSE-2.0
    
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  <!-- $Id: tabs.xml,v 1.1 2004/05/25 22:31:40 hlship Exp $ -->
  <!DOCTYPE tabs PUBLIC "-//APACHE//DTD Cocoon Documentation Tab V1.0//EN" 
"http://apache.org/forrest/dtd/tab-cocoon-v10.dtd";>
  
  <tabs software="HiveMind"
    title="HiveMind Project"
    copyright="Apache Software Foundation"
    xmlns:xlink="http://www.w3.org/1999/xlink";>
  
    <!-- The rules are:
      @dir will always have '/@indexfile' added.
      @indexfile gets appended to @dir if the tab is selected. Defaults to 
'index.html'
      @href is not modified unless it is root-relative and obviously specifies a
      directory (ends in '/'), in which case /index.html will be added
      
      HLS NOTE: I don't think the following line is accurate!
      
      If @id's are present, site.xml entries with a matching @tab will be in 
that tab.
    -->
  
    <tab id="project" label="HiveMind Project" dir="" indexfile="index.html"/>
    
    <!-- Tabs just not working right in Forrest 0.5.1 !!! -->
    
    <!-- tab id="hivemind" label="Module: hivemind" dir="hivemind" 
indexfile="index.html"/ -->
    
   </tabs>
  
  
  
  1.1                  
jakarta-hivemind/src/documentation/content/xdocs/bootstrap.xml
  
  Index: bootstrap.xml
  ===================================================================
  <?xml version="1.0"?>
  <!-- $Id: bootstrap.xml,v 1.1 2004/05/25 22:31:40 hlship Exp $ -->
  <!-- 
     Copyright 2004 The Apache Software Foundation
  
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
         http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.2//EN" 
"./dtd/document-v12.dtd"
  [
        <!ENTITY % common-links SYSTEM "links.ent">
        %common-links;
  ]>
  <document>
        
        <header>
                <title>Bootstrapping the Registry</title>
        </header>
        
        <body>
  
  
  <p>
  Before you can access the configuration points and services defined in your   
many module deployment
  descriptors, you need a registry; here we'll describe how to construct the 
registry.
  </p>
  
  <p>
  The key class here is
  <link href="&apiroot;/impl/RegistryBuilder.html">RegistryBuilder</link>, 
which contains
  code for locating and parsing the module deployment descriptors and 
constructing a registry from the combined
  data.
  </p>
  
  
  <p>
  Let's examine how all this comes together. The layout of the project is shown 
below.
  </p>
  
  <figure src="images/AdderExample-ProjectLayout.png" alt="[Project Layout]"/>
  
  
  <section> <title>Services, Interfaces, Descriptors</title> 
  
  <p>
  The first step is to define the service interface:
  </p>  
  
  <source>
  package hivemind.examples;
  
  public interface Adder
  {
      public int add(int arg0, int arg1);
  }     
  </source>
        
  <p>
  Next we need an implementation for that service:      
  </p>  
  
  <source>
  package hivemind.examples.impl;
  
  import hivemind.examples.Adder;
  
  public class AdderImpl implements Adder
  {
  
      public int add(int arg0, int arg1)
      {
          return arg0 + arg1;
      }
  
  }
  </source>
  
  <p>
  Finally, we need the HiveMind module deployment descriptor,
  <code>hivemodule.sdl</code>.  This file is in
  <link href="site:sdl">Simple Data Language</link> format (though equivalent 
XML
  is supported if the file is named <code>hivemodule.xml</code>).
  </p>
  
  <source>
  module (id=hivemind.examples version="1.0.0")
  {
    service-point (id=Adder interface=hivemind.examples.Adder)
    {
      create-instance (class=hivemind.examples.impl.AdderImpl)
     }
  }     
  </source>
  
  <p>
  Here we've chosen to have the module id, <code>hivemind.examples</code>,      
match the package name but
  that is not an absolute requirement.
  </p>
  
  </section>
  
  <section><title>Building the Registry</title>
  
  <p>
  Before your code can access any services (or configuration points), it must 
construct the registry.   
  </p>  
        
  
  <source>
  package hivemind.examples;
  
  import java.util.Locale;
  
  import org.apache.hivemind.ClassResolver;
  import org.apache.hivemind.Registry;
  import org.apache.hivemind.impl.DefaultClassResolver;
  import org.apache.hivemind.impl.RegistryBuilder;
  
  public class Main
  {
  
      public static void main(String[] args)
      {
          int arg0 = Integer.parseInt(args[0]);
          int arg1 = Integer.parseInt(args[1]);
  
          ClassResolver resolver = new DefaultClassResolver();
          RegistryBuilder builder = new RegistryBuilder();
  
          builder.processModules(resolver);
  
          Registry registry = builder.constructRegistry(Locale.getDefault());
  
          Adder adder = (Adder) registry.getService("hivemind.examples.Adder", 
Adder.class);
  
          System.out.println("Result: " + adder.add(arg0, arg1));
      }
  }
        
  </source>     
  
  <p>
  Building the registry requires four steps:
  
  </p>
  
  
  <ul>
  <li>Create a <link href="&apiroot;/ClassResolver.html">ClassResolver</link> 
instance. 
        DefaultClassResolver uses the thread's context class loader.</li>       
  <li>
  Create a <link 
href="&apiroot;/impl/RegistryBuilder.html">RegistryBuilder</link> instance.
  </li>
  <li>
  Invoke <code>processModules()</code> to find and parse all HiveMind module 
deployment descriptors visible on
  the classpath (as <code>META-INF/hivemodule.sdl</code> or
        <code>META-INF/hivemodule.xml</code>).  Here, this will be the master 
HiveMind module descriptor (for
  the <code>hivemind</code> module), and the descriptor for this example 
module. You could invoke <code>processModule()</code>
  to parse additional deployment descriptors stored in unusual locations.
  </li>
  <li>
  Invoke <code>constructRegistry()</code>       to integrate and validate all 
the information in all
  of the HiveMind module deployment descriptors and produce a 
  <link href="&apiroot;/Registry.html">Registry</link> from it.
  </li>
  
  </ul> 
  
  <p>
  Alternately, the static method 
  <link 
href="&apiroot;/impl/RegistryBuilder.html#constructDefaultRegistry()">constructDefaultRegistry()</link>
 can be invoked.  It's just those same four lines of code.
  </p>
  
  
  <p>
  Now that we have the registry, we can use the full id of the Adder service, 
<code>hivemind.examples.Adder</code>,     
  to get the service implementation. We pass in the class that we'll be casting 
the service to ... this allows HiveMind 
  to produce a more meaningful error than a ClassCastException.
  </p>
  
  <p>
  Using the reference to the Adder service, we can finally invoke the 
<code>add()</code>        method.
  </p>
  
  </section>
  
  <section><title>Building the Example</title>
  
  <p>
  Building and running the example using Ant is a snap; all the details are in 
the <code>build.xml</code>:
  </p>
  
  
  <source><![CDATA[<?xml version="1.0"?>
  
  <project name="HiveMind Adder Example" default="jar">
  
    <property name="java.src.dir" value="src/java"/>
    <property name="conf.dir" value="src/conf"/>
    <property name="meta-inf.dir" value="src/META-INF"/>
    <property name="target.dir" value="target"/>
    <property name="classes.dir" value="${target.dir}/classes"/>
    <property name="example.jar" value="${target.dir}/hivemind-examples.jar"/>
    <property name="lib.dir" value="lib"/>
  
    <path id="build.class.path">
      <fileset dir="${lib.dir}">
        <include name="*.jar"/>
      </fileset>
    </path>
    
    <path id="run.class.path">
      <path refid="build.class.path"/>
      <pathelement location="${example.jar}"/>
      <pathelement location="${conf.dir}"/>
    </path>
      
    <target name="clean" description="Delete all derived files.">
      <delete dir="${target.dir}" quiet="true"/>
    </target>
    
    <target name="compile" description="Compile all Java code.">  
      <mkdir dir="${classes.dir}"/>    
      <javac srcdir="${java.src.dir}" destdir="${classes.dir}" 
classpathref="build.class.path"/>
    </target>
    
    <target name="jar" description="Construct the JAR file." depends="compile">
      <jar destfile="${example.jar}">
        <fileset dir="${classes.dir}"/>
        <metainf dir="${meta-inf.dir}"/>
      </jar>
    </target>
    
    <target name="run" depends="jar" description="Run the Adder service.">
      <echo>Adding 11 and 23, should get 34.</echo>
    
      <java classname="hivemind.examples.Main" classpathref="run.class.path" 
fork="true">
        <arg value="11"/>
        <arg value="23"/>
      </java>
    </target>
  
  </project>]]></source>
  
  <p>
  The important part is to package both the classes and the HiveMind module 
deployment descriptor
  into the JAR.  The latter is accomplished using the &lt;metainf&gt; element.
  </p>
  
  <p>
  The only other oddity was to add <code>src/conf</code>        to the runtime 
classpath; this is to include
  the <code>log4j.properties</code> configuration file; 
  otherwise Log4J will write console errors about missing configuration.
  </p>
        
  </section>
  </body>
  </document>
  
  
  1.1                  jakarta-hivemind/forrest.properties
  
  Index: forrest.properties
  ===================================================================
  # 
  
  project.name=HiveMind
  project.build-dir=${project.home}/target/forrest
  project.site-dir=${project.home}/target/docs
  project.temp-dir=target/forrest
  
  project.content-dir=target/forrest-composite
  forrest.echo=on
  project.debuglevel=DEBUG
  
  
  1.3       +7 -6      jakarta-hivemind/common/jar-module.xml
  
  Index: jar-module.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/common/jar-module.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- jar-module.xml    21 May 2004 18:46:54 -0000      1.2
  +++ jar-module.xml    25 May 2004 22:31:41 -0000      1.3
  @@ -23,6 +23,7 @@
        
        <import file="common.xml"/>
        <import file="dependency.xml"/>
  +     <import file="forrest.xml"/>
                
        <!-- The default classpath for compilation is all external package 
JARs. -->
        
  @@ -209,9 +210,9 @@
        
        <target name="jar" depends="run-tests" description="Compile classes and 
package into a JAR.">
                
  -             <fail unless="jar.name" message="Property jar.name must be 
set."/>
  +             <fail unless="module.name" message="Property module.name must 
be set."/>
                
  -             <property name="complete-jar-path" 
value="${jar.target.dir}/${jar.name}-${project.version}.jar"/>
  +             <property name="complete-jar-path" 
value="${jar.target.dir}/${module.name}-${project.version}.jar"/>
                
                <mkdir dir="${jar.target.dir}"/>
                
  @@ -250,7 +251,7 @@
                                version="yes"
                                use="yes"
                                splitindex="yes"
  -                             windowtitle="${jar.name} - ${project.version} 
API">
  +                             windowtitle="${module.name} - 
${project.version} API">
                                <package name="${javadoc.package}"/>
                                <sourcepath>
                                        <pathelement 
location="${java.src.dir}"/>
  @@ -265,6 +266,6 @@
        </target>
        
        <target name="install" depends="jar" 
  -             description="Synonum for 'jar' invoked by the containing 
project."/>
  -     
  +             description="Synonym for 'jar' invoked by the containing 
project."/>
  +                     
   </project>
  
  
  
  1.2       +29 -1     jakarta-hivemind/common/project.xml
  
  Index: project.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/common/project.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- project.xml       21 May 2004 18:46:54 -0000      1.1
  +++ project.xml       25 May 2004 22:31:41 -0000      1.2
  @@ -19,6 +19,13 @@
   <!-- Top level module used to combine other types of modules. -->
   
        <import file="common.xml"/>
  +     <import file="dependency.xml"/>
  +     <import file="forrest.xml"/>
  +     
  +     <!-- Typically, project.name is all lower case and the title is mixed 
case, but
  +             the project name is still a good default. -->
  +             
  +     <property name="project.title" value="${project.name}"/>
        
        <macrodef name="reinvoke-ant">
                <attribute name="target" description="Target to achieve in each 
module."/>
  @@ -44,4 +51,25 @@
                <antcall target="common.clean"/>        
                
        </target>
  +     
  +     <target name="-setup-forrest-composite">
  +     
  +             <mkdir dir="${root.forrest.composite.dir}"/>
  +                     
  +             <!-- Create and empty this file. -->
  +             <mkdir dir="${root.forrest.composite.dir}/content/xdocs"/>
  +             <echo message="" file="${forrest.report-menu.file}"/>
  +                                             
  +     </target>
  +     
  +     <target name="site" description="Create project documentation." 
depends="-setup-forrest-composite">
  +     
  +             <antcall target="forrest.site"/>        
  +     </target>
  +     
  +     <target name="marshall-documentation" description="Marshall 
documentation in the project and in each module.">
  +             <antcall target="forrest.marshall-documentation"/>
  +             <reinvoke-ant target="marshall-documentation"/>
  +     </target>
  +     
   </project>
  
  
  
  1.2       +1 -21     jakarta-hivemind/common/javacc.xml
  
  Index: javacc.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/common/javacc.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- javacc.xml        20 May 2004 23:57:44 -0000      1.1
  +++ javacc.xml        25 May 2004 22:31:41 -0000      1.2
  @@ -19,27 +19,7 @@
                <fail unless="ant.file.common" message="Must import common.xml 
first."/>
                <fail unless="ant.file.dependency" message="Must import 
dependency.xml first."/>
                
  -             <property name="javacc.home.dir" 
value="${external.package.dir}/javacchome"/>
                <property name="javacc.dist.zip" 
value="${external.package.dir}/JavaCC.zip"/>
  -             
  -             <target name="-expand-javacc-home" unless="exists-javacc-home">
  -                     <grabber
  -                                     
src="${maven.ibiblio.url}/javacc/jars/JavaCC.zip"
  -                                     dest="${javacc.dist.zip}"/>
  -                                     
  -                     <!-- mkdir dir="${javacc.home.dir}"/>
  -                     
  -                     <unzip src="${javacc.dist.zip}" 
dest="${javacc.home.dir}"/ -->                  
  -             </target>
  -             
  -             <macrodef name="setup-javacc">
  -                     <sequential>
  -                             <available file="${javacc.home.dir}" type="dir" 
property="exists-javacc-home"/>
  -                             <antcall target="-expand-javacc-home"/>
  -                             <download-from-ibiblio jar="javacc-3.2.jar" 
group-id="javacc"/>                 
  -                             <mkdir dir="${generated-java.src.dir}"/>
  -                     </sequential>           
  -             </macrodef>
                
                <macrodef name="run-javacc">
                        <attribute name="input" description="The path to the 
input (.jj) file to compile."/>
  
  
  
  1.2       +38 -9     jakarta-hivemind/common/dependency.xml
  
  Index: dependency.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/common/dependency.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- dependency.xml    20 May 2004 23:57:44 -0000      1.1
  +++ dependency.xml    25 May 2004 22:31:41 -0000      1.2
  @@ -31,20 +31,23 @@
                        
        <target name="-display-download-warning" 
unless="download-warning-marker-displayed">
                <echo>
  -
  -***                  
  -*** Dependent libraries will be downloaded.  These are NOT necessarily 
downloaded from apache.com, and may
  -*** use other licences besides the Apache Software License. Dependencies 
will use an open-source
  -*** license compatible with the ASL, such as Berkeley Software Distribution 
(BSD) or
  -*** Mozilla Public License (MPL).
  -***
  -             
  
+**************************************************************************************************
  +*                                                                            
                    *
  +*                             D O W N L O A D   W A R N I N G                
                    *
  +*                                                                            
                    *
  +* Dependent libraries will be downloaded.  These are NOT necessarily 
downloaded from apache.org, *  
  +* and may use other licences besides the Apache Software License. 
Dependencies will use an       *
  +* open-source license compatible with the ASL, such as Berkeley Software 
Distribution (BSD) or   *
  +* Mozilla Public License (MPL).                                              
                    *
  +*                                                                            
                    *
  
+**************************************************************************************************
   </echo>
        
                <input 
                        validargs="continue" 
                        message="Enter 'continue' to continue with the build:"/>
        
  +             <mkdir dir="${external.package.dir}"/>
                <echo file="${download-warning-marker.file}">Download warning 
accepted.</echo>
                
        </target>
  @@ -83,6 +86,32 @@
                        
                </sequential>
        </macrodef>
  +     
  +     <available file="${unpack-zip-dir}" type="dir" 
property="unpacked-zip-dir-exists"/>
  +     
  +     <target name="-unpack-zip-dependency" unless="unpacked-zip-dir-exists" 
depends="-display-download-warning">
  +             <property name="local-copy-path" 
value="${external.package.dir}/${unpack-zip-name}"/>
  +             <grabber
  +                             src="${unpack-zip-url}"
  +                             dest="${local-copy-path}"/>
  +             <unzip src="${local-copy-path}" dest="${external.package.dir}"/>
  +     </target>
  +     
  +     <macrodef name="unpacked-zip-dependency">
  +             <attribute name="url" description="The URL of the folder 
containing the zip file."/>
  +             <attribute name="zip" description="The name of the zip file 
itself."/>
  +             <attribute name="dir" description="The name of the directory 
that will be created."/>
  +             
  +             <sequential>
  +                     <antcall target="-unpack-zip-dependency" 
inheritAll="false">
  +                             <param name="unpack-zip-dir" value="@{dir}"/>
  +                             <param name="unpack-zip-url" 
value="@{url}/@{zip}"/>
  +                             <param name="unpack-zip-name" value="@{zip}"/>
  +                     </antcall>
  +             </sequential>
  +             
  +     </macrodef>
  +
        
        <!-- An internal dependency to another library previously created
                   by a sibiling module.  Assumes that the module is infixed
  
  
  
  1.2       +15 -1     jakarta-hivemind/common/common.properties
  
  Index: common.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/common/common.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- common.properties 20 May 2004 23:57:44 -0000      1.1
  +++ common.properties 25 May 2004 22:31:41 -0000      1.2
  @@ -93,3 +93,17 @@
   
   # Directory to which javadoc is generated
   javadoc.target.dir=${doc.target.dir}/api
  +
  +# Directory to which project and module documentation files are ultimately 
copied (or generated)
  +root.forrest.composite.dir=${root.target.dir}/forrest-composite
  +
  +root.forrest.content.dir=${root.forrest.composite.dir}/content/xdocs
  +
  +# File into which reports can record menu items.
  
+forrest.report-menu.file=${root.forrest.composite.dir}/content/xdocs/report-menu.ent
  +
  +# Directory containing documentation to be copied into the composite.
  +forrest.documentation.dir=${src.dir}/documentation
  +
  +
  +
  
  
  
  1.3       +4 -1      jakarta-hivemind/common/common.xml
  
  Index: common.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/common/common.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- common.xml        21 May 2004 18:46:54 -0000      1.2
  +++ common.xml        25 May 2004 22:31:41 -0000      1.3
  @@ -38,5 +38,8 @@
                <delete dir="${external.package.dir}" quiet="true"/>    
        </target>
   
  +     <presetdef name="invoke-ant">
  +             <ant inheritAll="false"/>
  +     </presetdef>
   
   </project>
  
  
  
  1.1                  jakarta-hivemind/common/forrest.xml
  
  Index: forrest.xml
  ===================================================================
  <?xml version="1.0"?>
  <project name="forrest">
        
                <fail unless="ant.file.common" message="Must import common.xml 
first."/>
                <fail unless="ant.file.dependency" message="Must import 
dependency.xml first."/>
  
                <property name="forrest-package-dir" 
value="${external.package.dir}/apache-forrest-0.5.1-bin"/>
  
                <target name="site" description="Build site documentation using 
Forrest.">
                
                        <unpacked-zip-dependency
                                        
url="http://www.apache.org/dist/xml/forrest/binaries";
                                        zip="apache-forrest-0.5.1-bin.zip"
                                        dir="${forrest-package-dir}"/>
                        
                        <antcall target="marshall-documentation"/>
                        
                        <echo>
                                
  *** Invoking Forrest ...
                                
  </echo>
                        <ant 
antfile="${forrest-package-dir}/forrest.antproxy.xml" target="site">
                                <property name="project.home" 
location="${basedir}"/>
                                <property name="forrest.home" 
location="${forrest-package-dir}"/>
                        </ant>
                        
                        
                </target>
                
                <target name="marshall-documentation"
                        description="Copy static content into the forrest 
composite, and generate dynamic reports.">
        
                        <mkdir dir="${root.forrest.composite.dir}"/>    
                                                
                        <antcall target="copy-documentation-to-composite"/>
                        <antcall target="run-reports"/>
                        
                </target>
                        
                <target name="run-reports" description="Overridden in project 
or module to run dynamic reports."/>
                
                <available file="${forrest.documentation.dir}" type="dir" 
property="exists-forrest-documentation-dir"/>
                
                <target name="copy-documentation-to-composite" 
if="exists-forrest-documentation-dir">
                        <copy todir="${root.forrest.composite.dir}" 
includeEmptyDirs="no">
                                <fileset dir="${forrest.documentation.dir}"/>   
                        </copy>
                </target>
                
  </project>
  
  
  1.6       +56 -7     
jakarta-hivemind/framework/src/test/hivemind/test/rules/TestEnumerationTranslator.java
  
  Index: TestEnumerationTranslator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/rules/TestEnumerationTranslator.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- TestEnumerationTranslator.java    29 Feb 2004 20:57:09 -0000      1.5
  +++ TestEnumerationTranslator.java    25 May 2004 22:31:41 -0000      1.6
  @@ -19,9 +19,12 @@
   import org.apache.hivemind.ApplicationRuntimeException;
   import org.apache.hivemind.Element;
   import org.apache.hivemind.Location;
  +import org.apache.hivemind.impl.DefaultClassResolver;
   import org.apache.hivemind.impl.ElementImpl;
   import org.apache.hivemind.impl.LocationImpl;
  +import org.apache.hivemind.internal.Module;
   import org.apache.hivemind.schema.rules.EnumerationTranslator;
  +import org.easymock.MockControl;
   
   /**
    * Tests for [EMAIL PROTECTED] 
org.apache.hivemind.schema.rules.EnumerationTranslator}.
  @@ -43,29 +46,54 @@
   
       public void testNull()
       {
  +        MockControl c = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) c.getMock();
  +
  +        c.replay();
  +
           EnumerationTranslator t =
               new 
EnumerationTranslator("java.lang.Boolean,true=TRUE,false=FALSE");
   
  -        assertEquals(null, t.translate(new MockModule(), null, null));
  +        assertEquals(null, t.translate(m, null, null));
  +
  +        c.verify();
       }
   
       public void testMatch()
       {
  +        MockControl c = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) c.getMock();
  +
  +        m.getClassResolver();
  +        c.setReturnValue(new DefaultClassResolver());
  +
  +        c.replay();
  +
           EnumerationTranslator t =
               new 
EnumerationTranslator("java.lang.Boolean,true=TRUE,false=FALSE");
   
  -        assertEquals(Boolean.TRUE, t.translate(new MockModule(), null, 
"true"));
  -        assertEquals(Boolean.FALSE, t.translate(new MockModule(), null, 
"false"));
  +        assertEquals(Boolean.TRUE, t.translate(m, null, "true"));
  +        assertEquals(Boolean.FALSE, t.translate(m, null, "false"));
  +
  +        c.verify();
       }
   
       public void testBadClass()
       {
  +        MockControl c = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) c.getMock();
  +
  +             m.getClassResolver();
  +             c.setReturnValue(new DefaultClassResolver());
  +
  +        c.replay();
  +
           EnumerationTranslator t =
               new 
EnumerationTranslator("lava.jang.Boolean,true=TRUE,false=FALSE");
   
           try
           {
  -            t.translate(new MockModule(), null, "true");
  +            t.translate(m, null, "true");
   
               unreachable();
           }
  @@ -74,17 +102,26 @@
               assertExceptionSubstring(ex, "Could not load class 
lava.jang.Boolean");
           }
   
  +        c.verify();
       }
   
       public void testUnrecognizedValue() throws Exception
       {
  +        MockControl c = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) c.getMock();
  +
  +             m.getClassResolver();
  +             c.setReturnValue(new DefaultClassResolver());
  +
  +        c.replay();
  +
           EnumerationTranslator t =
               new 
EnumerationTranslator("java.lang.Boolean,true=TRUE,false=FALSE");
   
           try
           {
   
  -            t.translate(new MockModule(), null, "fred");
  +            t.translate(m, null, "fred");
               unreachable();
           }
           catch (ApplicationRuntimeException ex)
  @@ -92,16 +129,26 @@
               assertExceptionSubstring(ex, "'fred' is not a recognized 
enumerated value.");
           }
   
  +        c.verify();
  +
       }
   
       public void testBadField() throws Exception
       {
  +        MockControl c = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) c.getMock();
  +
  +             m.getClassResolver();
  +             c.setReturnValue(new DefaultClassResolver());
  +
  +        c.replay();
  +
           EnumerationTranslator t =
               new 
EnumerationTranslator("java.lang.Boolean,true=HONEST_TO_GOD_TRUE,false=FALSE");
   
           try
           {
  -            t.translate(new MockModule(), null, "true");
  +            t.translate(m, null, "true");
               unreachable();
           }
           catch (ApplicationRuntimeException ex)
  @@ -110,6 +157,8 @@
                   ex,
                   "Unable to obtain value for static field 
java.lang.Boolean.HONEST_TO_GOD_TRUE");
           }
  +
  +        c.verify();
       }
   
   }
  
  
  
  1.8       +14 -5     
jakarta-hivemind/framework/src/test/hivemind/test/rules/TestConfigurationTranslator.java
  
  Index: TestConfigurationTranslator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/rules/TestConfigurationTranslator.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- TestConfigurationTranslator.java  18 May 2004 15:34:01 -0000      1.7
  +++ TestConfigurationTranslator.java  25 May 2004 22:31:41 -0000      1.8
  @@ -14,13 +14,15 @@
   
   package hivemind.test.rules;
   
  -import java.util.List;
  -
   import hivemind.test.FrameworkTestCase;
   
  +import java.util.List;
  +
   import org.apache.hivemind.Registry;
  +import org.apache.hivemind.internal.Module;
   import org.apache.hivemind.internal.RegistryInfrastructure;
   import org.apache.hivemind.schema.rules.ConfigurationTranslator;
  +import org.easymock.MockControl;
   
   /**
    * Tests for [EMAIL PROTECTED] 
org.apache.hivemind.schema.rules.ConfigurationTranslator}.
  @@ -33,9 +35,16 @@
   
       public void testNull()
       {
  +        MockControl c = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) c.getMock();
  +
  +        c.replay();
  +
           ConfigurationTranslator t = new ConfigurationTranslator();
   
  -        assertNull(t.translate(new MockModule(), null, null));
  +        assertNull(t.translate(m, null, null));
  +
  +        c.verify();
       }
   
       public void testConfigurationTranslator() throws Exception
  @@ -54,7 +63,7 @@
   
       public void testFailure() throws Exception
       {
  -        Registry r = 
(Registry)buildFrameworkRegistry("ConfigurationTranslator.xml");
  +        Registry r = (Registry) 
buildFrameworkRegistry("ConfigurationTranslator.xml");
   
           interceptLogging();
   
  
  
  
  1.10      +33 -5     
jakarta-hivemind/framework/src/test/hivemind/test/rules/TestObjectTranslator.java
  
  Index: TestObjectTranslator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/rules/TestObjectTranslator.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- TestObjectTranslator.java 18 May 2004 15:34:01 -0000      1.9
  +++ TestObjectTranslator.java 25 May 2004 22:31:41 -0000      1.10
  @@ -20,12 +20,14 @@
   
   import org.apache.hivemind.ApplicationRuntimeException;
   import org.apache.hivemind.Location;
  -import org.apache.hivemind.Registry;
  +import org.apache.hivemind.impl.DefaultClassResolver;
   import org.apache.hivemind.impl.ElementImpl;
   import org.apache.hivemind.impl.LocationImpl;
  +import org.apache.hivemind.internal.Module;
   import org.apache.hivemind.internal.RegistryInfrastructure;
   import org.apache.hivemind.schema.rules.ClassTranslator;
   import org.apache.hivemind.schema.rules.ObjectTranslator;
  +import org.easymock.MockControl;
   
   /**
    * Fill in some gaps in
  @@ -52,15 +54,24 @@
           Location l = new 
LocationImpl(getResource("TestObjectTranslator.class"), 50);
           e.setLocation(l);
   
  +        MockControl c = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) c.getMock();
  +
  +        m.getClassResolver();
  +        c.setReturnValue(new DefaultClassResolver());
  +
  +        c.replay();
  +
           try
           {
  -            t.translate(new MockModule(), null, "bad.class.Name");
  +            t.translate(m, null, "bad.class.Name");
           }
           catch (ApplicationRuntimeException ex)
           {
               assertExceptionSubstring(ex, "Could not load class 
bad.class.Name");
           }
   
  +        c.verify();
       }
   
       public void testPrivateObject() throws Exception
  @@ -70,9 +81,17 @@
           Location l = new 
LocationImpl(getResource("TestObjectTranslator.class"), 50);
           e.setLocation(l);
   
  +        MockControl c = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) c.getMock();
  +
  +        m.getClassResolver();
  +        c.setReturnValue(new DefaultClassResolver());
  +
  +        c.replay();
  +
           try
           {
  -            t.translate(new MockModule(), null, 
PrivateObject.class.getName());
  +            t.translate(m, null, PrivateObject.class.getName());
               unreachable();
           }
           catch (ApplicationRuntimeException ex)
  @@ -102,11 +121,20 @@
   
       public void testClassTranslator() throws Exception
       {
  +        MockControl control = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) control.getMock();
  +
  +        m.getClassResolver();
  +        control.setReturnValue(new DefaultClassResolver());
  +
  +        control.replay();
  +
           ClassTranslator t = new ClassTranslator();
   
  -        Class c = (Class) t.translate(new MockModule(), null, 
getClass().getName());
  +        Class c = (Class) t.translate(m, null, getClass().getName());
   
           assertEquals(getClass(), c);
   
  +        control.verify();
       }
   }
  
  
  
  1.3       +2 -2      jakarta-hivemind/framework/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/build.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- build.xml 21 May 2004 18:46:55 -0000      1.2
  +++ build.xml 25 May 2004 22:31:41 -0000      1.3
  @@ -17,7 +17,7 @@
   -->
   <project name="HiveMind Framework" default="jar" basedir=".">
   
  -     <property name="jar.name" value="hivemind"/>
  +     <property name="module.name" value="hivemind"/>
        <property name="javadoc.package" value="org.apache.hivemind.*"/>
   
        <property name="root.dir" value=".."/>
  
  
  
  1.16      +26 -6     
jakarta-hivemind/framework/src/test/hivemind/test/TestMisc.java
  
  Index: TestMisc.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/TestMisc.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- TestMisc.java     19 May 2004 02:30:54 -0000      1.15
  +++ TestMisc.java     25 May 2004 22:31:41 -0000      1.16
  @@ -14,8 +14,6 @@
   
   package hivemind.test;
   
  -import hivemind.test.rules.MockModule;
  -
   import java.util.ArrayList;
   import java.util.Collections;
   import java.util.HashMap;
  @@ -26,12 +24,14 @@
   import org.apache.hivemind.SymbolSource;
   import org.apache.hivemind.impl.ContributionImpl;
   import org.apache.hivemind.impl.CreateClassServiceConstructor;
  +import org.apache.hivemind.impl.DefaultClassResolver;
   import org.apache.hivemind.impl.InvokeFactoryServiceConstructor;
   import org.apache.hivemind.impl.ModuleImpl;
   import org.apache.hivemind.impl.ServicePointImpl;
   import org.apache.hivemind.impl.SystemPropertiesSymbolSource;
   import org.apache.hivemind.internal.Module;
   import org.apache.hivemind.internal.ServicePoint;
  +import org.easymock.MockControl;
   
   /**
    * Additional tests to fill in minor code coverage gaps.
  @@ -112,7 +112,10 @@
   
       public void testCreateClassServiceConstructorAccessors()
       {
  -        Module m = new MockModule();
  +        MockControl control = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) control.getMock();
  +
  +        control.replay();
   
           CreateClassServiceConstructor c = new 
CreateClassServiceConstructor();
   
  @@ -123,11 +126,19 @@
           c.setInstanceClassName("java.util.HashMap");
   
           assertEquals("java.util.HashMap", c.getInstanceClassName());
  +
  +        control.verify();
       }
   
       public void testCreateClassServiceConstructorTwice()
       {
  -        Module m = new MockModule();
  +        MockControl control = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) control.getMock();
  +
  +             m.getClassResolver();
  +             control.setReturnValue(new DefaultClassResolver());
  +
  +        control.replay();
   
           CreateClassServiceConstructor c = new 
CreateClassServiceConstructor();
   
  @@ -142,11 +153,19 @@
   
           assertTrue(o1 instanceof HashMap);
           assertTrue(o2 instanceof HashMap);
  +
  +        control.verify();
       }
   
       public void testCreateClassServiceConstructorFailure()
       {
  -        Module m = new MockModule();
  +        MockControl control = MockControl.createStrictControl(Module.class);
  +        Module m = (Module) control.getMock();
  +
  +             m.getClassResolver();
  +             control.setReturnValue(new DefaultClassResolver());
  +
  +        control.replay();
   
           CreateClassServiceConstructor c = new 
CreateClassServiceConstructor();
   
  @@ -166,6 +185,7 @@
                   "Unable to find a constructor for class 
hivemind.test.PrivateBean.");
           }
   
  +        control.verify();
       }
   
       public void testSystemPropertiesSymbolSource()
  
  
  
  1.1                  jakarta-hivemind/src/documentation/conf/cli.xconf
  
  Index: cli.xconf
  ===================================================================
  <?xml version="1.0"?>
  
  <!--+
      |  This is the Apache Cocoon command line configuration file. 
      |  Here you give the command line interface details of where
      |  to find various aspects of your Cocoon installation.
      |
      |  If you wish, you can also use this file to specify the URIs
      |  that you wish to generate.
      |
      |  The current configuration information in this file is for
      |  building the Cocoon documentation. Therefore, all links here 
      |  are relative to the build context dir, which, in the build.xml 
      |  file, is set to ${build.context} 
      |
      |  Options:
      |    verbose:            increase amount of information presented
      |                        to standard output (default: false)
      |    follow-links:       whether linked pages should also be 
      |                        generated (default: true)
      |    precompile-only:    precompile sitemaps and XSP pages, but 
      |                        do not generate any pages (default: false)
      |    confirm-extensions: check the mime type for the generated page
      |                        and adjust filename and links extensions
      |                        to match the mime type 
      |                        (e.g. text/html->.html)
      |
      |  Note: Whilst using an xconf file to configure the Cocoon 
      |        Command Line gives access to more features, the use of 
      |        command line parameters is more stable, as there are 
      |        currently plans to improve the xconf format to allow 
      |        greater flexibility. If you require a stable and
      |        consistent method for accessing the CLI, it is recommended 
      |        that you use the command line parameters to configure 
      |        the CLI.</note>
      |
      | CVS: $Id: cli.xconf,v 1.1 2004/05/25 22:31:41 hlship Exp $
      +-->
      
  <cocoon verbose="true"  
          follow-links="true" 
          precompile-only="false" 
          confirm-extensions="false">
  
     <!--+
         |  The context directory is usually the webapp directory
         |  containing the sitemap.xmap file.
         |
         |  The config file is the cocoon.xconf file.
         |
         |  The work directory is used by Cocoon to store temporary
         |  files and cache files.
         |  
         |  The destination directory is where generated pages will
         |  be written (assuming the 'simple' mapper is used, see 
         |  below)
         +-->
     <context-dir>.</context-dir>
     <config-file>WEB-INF/cocoon.xconf</config-file>
     <work-dir>../tmp/cocoon-work</work-dir>
     <!-- Overridden in forrest.build.xml 
     <dest-dir>../docs</dest-dir>
     -->
  
     <!--+
         | Broken link reporting options:
         |   Report into a text file, one link per line:
         |     <broken-links type="text" report="filename"/>
         |   Report into an XML file:
         |     <broken-links type="xml" report="filename"/>
         |   Ignore broken links (default):
         |     <broken-links type="none"/>
         |
         |   Two attributes to this node specify whether a page should
         |   be generated when an error has occured. 'generate' specifies 
         |   whether a page should be generated (default: true) and
         |   extension specifies an extension that should be appended
         |   to the generated page's filename (default: none)
         |
         +-->
     <broken-links type="xml" 
                   file="../brokenlinks.xml"
                   generate="false"
                   extension=".error"/>
     
     <!--+
         |  Load classes at startup. This is necessary for generating
         |  from sites that use SQL databases and JDBC.
         |  The <load-class> element can be repeated if multiple classes
         |  are needed.
         +-->
     <!--
     <load-class>org.firebirdsql.jdbc.Driver</load-class>
     -->
  
     <!--+
         |
         +-->
     <!-- <logging log-kit="WEB-INF/logkit.xconf" logger="cli" level="ERROR" /> 
-->
  
     <!--+
         | Specifies the filename to be appended to URIs that
         | refer to a directory (i.e. end with a forward slash).
         +-->
     <default-filename>index.html</default-filename>
  
     <!--+
         |  Specifies a user agent string to the sitemap when
         |  generating the site.
         +-->
     <!--
     <user-agent>xxx</user-agent>
     -->
  
     <!--+
         |  Specifies an accept string to the sitemap when generating
         |  the site.
         +-->
     <accept>*/*</accept>
     
     <!--+
         |  Specifies the URIs that should be generated (using <uri>
         |  elements, and (if necessary) what should be done with the
         |  generated pages.
         |
         |  The old behaviour - appends uri to the specified destination
         |  directory (as specified in <dest-dir>):
         |
         |   <uri>documents/index.html</uri>
         |
         |  The "type" attribute specifies one of (append|replace|insert):
         |
         |  append:
         |  Append the generated page's URI to the end of the source URI:
         |
         |   <uri type="append" src-prefix="documents/" src="index.html"
         |   dest="build/dest/"/>
         |
         |  This means that 
         |   (1) the "documents/index.html" page is generated
         |   (2) the file will be written to "build/dest/documents/index.html"
         |
         |  replace:
         |  Completely ignore the generated page's URI - just 
         |  use the destination URI:
         |
         |   <uri type="replace" src-prefix="documents/" src="index.html" 
         |   dest="build/dest/docs.html"/>
         |  
         |  This means that 
         |   (1) the "documents/index.html" page is generated
         |   (2) the result is written to "build/dest/docs.html"
         |   (3) this works only for "single" pages - and not when links
         |       are followed
         |
         |  insert:
         |  Insert generated page's URI into the destination 
         |  URI at the point marked with a * (example uses fictional 
         |  zip protocol)
         |
         |   <uri type="insert" src-prefix="documents/" src="index.html" 
         |   dest="zip://*.zip/page.html"/>
         |
         |  This means that 
         |   (1)
         |
         |  In any of these scenarios, if the dest attribute is omitted,
         |  the value provided globally using the <dest-dir> node will 
         |  be used instead.
         +-->
  
     <!-- Includes and excludes can be used to limit which URLs are rendered -->
     <exclude pattern="**/"/>
     
     <!-- This is generated after the rest. -->
     
     <exclude pattern="hivedocs/**"/>
     <exclude pattern="hivemind/apidocs/**"/>
  
     <!-- Exclude tokens used in URLs to ASF mirrors (interpreted by a CGI) -->
     <exclude pattern="[preferred]/**"/>
     <exclude pattern="[location]"/>
     
     <uri src="favicon.ico"/>
  
     <!--+
         |  File containing URIs (plain text, one per line).
         +-->
     <!--
     <uri-file></uri-file>
     -->
     
  </cocoon>
  
  
  
  
  1.3       +24 -18    
jakarta-hivemind/framework/src/test/hivemind/test/impl/TestRegistryAssemblyImpl.java
  
  Index: TestRegistryAssemblyImpl.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/impl/TestRegistryAssemblyImpl.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestRegistryAssemblyImpl.java     28 Feb 2004 00:34:38 -0000      1.2
  +++ TestRegistryAssemblyImpl.java     25 May 2004 22:31:41 -0000      1.3
  @@ -14,17 +14,15 @@
   
   package hivemind.test.impl;
   
  -import java.util.List;
  -
   import org.apache.hivemind.Location;
   import org.apache.hivemind.Resource;
  -import org.apache.hivemind.impl.BaseLocatable;
   import org.apache.hivemind.impl.DefaultClassResolver;
   import org.apache.hivemind.impl.LocationImpl;
   import org.apache.hivemind.impl.RegistryAssemblyImpl;
   import org.apache.hivemind.schema.Schema;
   import org.apache.hivemind.test.HiveMindTestCase;
   import org.apache.hivemind.util.ClasspathResource;
  +import org.easymock.MockControl;
   
   /**
    * Suite of tests for [EMAIL PROTECTED] TestRegistryAssemblyImpl}.
  @@ -34,15 +32,6 @@
    */
   public class TestRegistryAssemblyImpl extends HiveMindTestCase
   {
  -    private static class MockSchema extends BaseLocatable implements Schema
  -    {
  -
  -        public List getElementModel()
  -        {
  -            return null;
  -        }
  -
  -    }
   
       private static class TestRunnable implements Runnable
       {
  @@ -57,18 +46,26 @@
       public void testAddSchema()
       {
           RegistryAssemblyImpl ra = new RegistryAssemblyImpl();
  -        Schema s = new MockSchema();
  +        MockControl control = MockControl.createStrictControl(Schema.class);
  +        Schema s = (Schema) control.getMock();
  +
  +        control.replay();
   
           ra.addSchema("foo.manchu", s);
   
           assertSame(s, ra.getSchema("foo.manchu"));
  +
  +        control.verify();
       }
   
       public void testAddDupeSchema() throws Exception
       {
           RegistryAssemblyImpl ra = new RegistryAssemblyImpl();
  -        MockSchema s1 = new MockSchema();
  -        MockSchema s2 = new MockSchema();
  +        MockControl c1 = MockControl.createStrictControl(Schema.class);
  +        MockControl c2 = MockControl.createStrictControl(Schema.class);
  +
  +        Schema s1 = (Schema) c1.getMock();
  +        Schema s2 = (Schema) c2.getMock();
   
           Resource r = new ClasspathResource(new DefaultClassResolver(), 
"/foo/bar");
           Location l1 = new LocationImpl(r, 20);
  @@ -76,8 +73,14 @@
   
           interceptLogging(ra.getClass().getName());
   
  -        s1.setLocation(l1);
  -        s2.setLocation(l2);
  +        s1.getLocation();
  +        c1.setReturnValue(l1);
  +
  +        s2.getLocation();
  +        c2.setReturnValue(l2);
  +
  +             c1.replay();
  +             c2.replay();
   
           ra.addSchema("foo.bar", s1);
           ra.addSchema("foo.bar", s2);
  @@ -85,6 +88,9 @@
           assertLoggedMessagePattern("Schema foo.bar \\(at classpath:/foo/bar, 
line 97\\) conflicts with existing schema at classpath:/foo/bar, line 20\\.");
   
           assertSame(s1, ra.getSchema("foo.bar"));
  +
  +        c1.verify();
  +        c2.verify();
       }
   
       public void testAddPostProcessor()
  
  
  
  1.1                  
jakarta-hivemind/src/documentation/resources/images/InterceptorStack.png
  
        <<Binary file>>
  
  
  1.1                  
jakarta-hivemind/src/documentation/resources/images/AdderExample-ProjectLayout.png
  
        <<Binary file>>
  
  
  1.1                  
jakarta-hivemind/src/documentation/resources/images/jakarta-logo.gif
  
        <<Binary file>>
  
  
  1.1                  
jakarta-hivemind/src/documentation/resources/images/HiveMind-Logo.png
  
        <<Binary file>>
  
  
  1.2       +2 -2      jakarta-hivemind/library/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/library/build.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- build.xml 20 May 2004 23:57:44 -0000      1.1
  +++ build.xml 25 May 2004 22:31:41 -0000      1.2
  @@ -17,7 +17,7 @@
   -->
   <project name="HiveMind Standard Library" default="jar">
   
  -     <property name="jar.name" value="hivemind-lib"/>
  +     <property name="module.name" value="hivemind-lib"/>
        <property name="javadoc.package" value="org.apache.hivemind.lib.*"/>
        
        <property name="root.dir" value=".."/>
  
  
  
  1.1                  jakarta-hivemind/src/documentation/skinconf.xml
  
  Index: skinconf.xml
  ===================================================================
  <?xml version="1.0"?>
  <!--
     Copyright 2004 The Apache Software Foundation
    
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
    
         http://www.apache.org/licenses/LICENSE-2.0
    
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  <!-- $Id: skinconf.xml,v 1.1 2004/05/25 22:31:41 hlship Exp $ -->
  <!--
  Skin configuration file. This file contains details of your project, which 
will
  be used to configure the chosen Forrest skin.
  -->
  
  <!DOCTYPE skinconfig [
  
    <!ENTITY % links.att 'name CDATA #REQUIRED'>
    <!ENTITY % link.att 'name CDATA #REQUIRED href CDATA #REQUIRED'>
    <!ELEMENT skinconfig (disable-search?, disable-print-link?, 
disable-pdf-link?,
    disable-xml-link?, disable-compliance-links?, searchsite-domain?, 
searchsite-name?,
    project-name, project-url, project-logo, group-name?, group-url?, 
group-logo?,
    host-url?, host-logo?, year?, vendor?, trail?, toc?, credits?)*>
    <!ELEMENT credits (credit*)>
    <!ELEMENT credit (name, url, image?, width?, height?)>
    <!-- id uniquely identifies the tool, and role indicates its function -->
    <!ATTLIST credit id   CDATA #IMPLIED
                     role CDATA #IMPLIED>
    <!ELEMENT disable-search (#PCDATA)>
    <!ELEMENT disable-print-link (#PCDATA)>
    <!ELEMENT disable-pdf-link (#PCDATA)>
    <!ELEMENT disable-xml-link (#PCDATA)>    
    <!ELEMENT disable-compliance-links (#PCDATA)>   
    <!ELEMENT searchsite-domain (#PCDATA)>
    <!ELEMENT searchsite-name (#PCDATA)>  
    <!ELEMENT project-name (#PCDATA)>
    <!ELEMENT project-url (#PCDATA)>
    <!ELEMENT project-logo (#PCDATA)>
    <!ELEMENT group-name (#PCDATA)>
    <!ELEMENT group-url (#PCDATA)>
    <!ELEMENT group-logo (#PCDATA)>
    <!ELEMENT host-url (#PCDATA)>
    <!ELEMENT host-logo (#PCDATA)>
    <!ELEMENT year (#PCDATA)>
    <!ELEMENT vendor (#PCDATA)>
    <!ELEMENT trail (link1, link2, link3)>
    <!ELEMENT link1 EMPTY>
    <!-- Seems we can't use param entity refs until this is DTDified -->
    <!ATTLIST link1 name CDATA #REQUIRED href CDATA #IMPLIED>
    <!ELEMENT link2 EMPTY>
    <!ATTLIST link2 name CDATA #REQUIRED href CDATA #IMPLIED>
    <!ELEMENT link3 EMPTY>
    <!ATTLIST link3 name CDATA #REQUIRED href CDATA #IMPLIED>
    <!ELEMENT name (#PCDATA)>
    <!ELEMENT url (#PCDATA)>
    <!ELEMENT image (#PCDATA)>
    <!ELEMENT width (#PCDATA)>
    <!ELEMENT height (#PCDATA)>
    <!ELEMENT toc EMPTY>
    <!ATTLIST toc level CDATA #IMPLIED>
    ]>
  
  <skinconfig>
    <!-- Do we want to disable the Google search box? -->
    <disable-search>true</disable-search>
    <!-- Do we want to disable the print link? -->
    <disable-print-link>true</disable-print-link>  
    <!-- Do we want to disable the PDF link? -->
    <disable-pdf-link>true</disable-pdf-link>
    <!-- Do we want to disable the xml source link? -->
    <disable-xml-link>true</disable-xml-link>
    <!-- Do we want to disable w3c compliance links? -->
    <disable-compliance-links>true</disable-compliance-links>
  
    <searchsite-domain>jakarta.apache.org</searchsite-domain>  
    <searchsite-name>Jakarta</searchsite-name>  
  
    <!-- mandatory project logo
         skin: forrest-site renders it at the top -->
    <project-name>Jakarta HiveMind Project</project-name>
    <project-url>http://jakarta.apache.org/hivemind/</project-url>
    <project-logo>images/HiveMind-Logo.png</project-logo>
    <!-- Alternative static image:
    <project-logo>images/project-logo.gif</project-logo> -->
  
    <!-- optional group logo
         skin: forrest-site renders it at the top-left corner -->
    <group-name>The Apache Jakarta Project</group-name>
    <group-url>http://jakarta.apache.org/</group-url>
    <group-logo>images/jakarta-logo.gif</group-logo>
    <!-- Alternative static image:
    <group-logo>images/group-logo.gif</group-logo> -->
  
    <!-- optional host logo (e.g. sourceforge logo)
         skin: forrest-site renders it at the bottom-left corner -->
    <host-url></host-url>
    <host-logo></host-logo>
  
    <!-- The following are used to construct a copyright statement -->
    <year>2004</year>
    <vendor>The Apache Software Foundation</vendor>
  
    <!-- Some skins use this to form a 'breadcrumb trail' of links. If you don't
    want these, set the attributes to blank. The DTD purposefully requires them.
    -->
    <trail>
      <link1 name="Apache" href="http://www.apache.org/"/>
      <link2 name="Jakarta" href="http://jakarta.apache.org/"/>
      <link3 name="HiveMind" href="http://jakarta.apache.org/hivemind/"/>
    </trail>
  
    <!-- Configure how many "section" levels need to be included in the
    generated Table of Contents (TOC). By default, if no toc element is provided
    below, then 2 levels are included. Level 0 does not generate any TOC at all.
    -->
    <toc level="3"/>
  
    <!-- Credits are typically rendered as a set of small clickable images in 
the
    page footer -->
    <credits>
      <credit>
        <name>Built with Apache Forrest</name>
        <url>http://xml.apache.org/forrest/</url>
        <image>images/built-with-forrest-button.png</image>
        <width>88</width>
        <height>31</height>
      </credit>
      <!-- A credit with @role='pdf' will have its name and url displayed in the
      PDF page's footer. -->
    </credits>
  
  </skinconfig>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to