You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by hl...@apache.org on 2003/09/09 01:07:22 UTC

cvs commit: jakarta-commons-sandbox/hivemind/xdocs case1.xml navigation.xml

hlship      2003/09/08 16:07:22

  Modified:    hivemind/xdocs navigation.xml
  Added:       hivemind/xdocs case1.xml
  Log:
  Add case study #1: Vista.
  
  Revision  Changes    Path
  1.16      +21 -13    jakarta-commons-sandbox/hivemind/xdocs/navigation.xml
  
  Index: navigation.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/xdocs/navigation.xml,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- navigation.xml	8 Sep 2003 20:14:18 -0000	1.15
  +++ navigation.xml	8 Sep 2003 23:07:22 -0000	1.16
  @@ -4,25 +4,33 @@
   	<title>HiveMind</title>
   	<body>
   		<menu name="Reference">
  -			<item name="Services" href="/services.html"/>	
  +			<item name="Services" href="/services.html"/>
   			<item name="Extension Points" href="/extension-points.html"/>
  -			<item name="Localization" href="/localization.html"/>
  -		  <item name="Inversion of Control" href="/ioc.html"/>
  -		  <item name="Multi-Threading" href="/multithreading.html"/>
  -		  <item name="Bootstrapping" href="/bootstrap.html"/>
  -			<item name="Module Descriptor" href="/descriptor.html" collapse="true">
  -				<item name="XML Processing Rules" href="/rules.html"/>	
  +			<item name="Module Descriptor" href="/descriptor.html"
  +				collapse="true">
  +				<item name="XML Processing Rules" href="/rules.html"/>
   			</item>
  -			<item name="HiveMind Registry" href="/registry.html"/>
   			<item name="Ant Tasks" href="/ant/index.html" collapse="true">
  -				<item name="ManifestClassPath" href="/ant/ManifestClassPath.html"/>
  -				<item name="ConstructRegistry" href="/ant/ConstructRegistry.html"/>	
  +				<item name="ManifestClassPath"
  +					href="/ant/ManifestClassPath.html"/>
  +				<item name="ConstructRegistry"
  +					href="/ant/ConstructRegistry.html"/>
   			</item>
   		</menu>
  +		<menu name="Tutorials and Information">
  +			<item name="Bootstrapping" href="/bootstrap.html"/>
  +			<item name="HiveMind Registry Documentation" href="/registry.html"/>
  +			<item name="Localization" href="/localization.html"/>
  +			<item name="Inversion of Control" href="/ioc.html"/>
  +			<item name="Multi-Threading" href="/multithreading.html"/>
  +			<item name="Case Study #1: Vista Startup/Shutdown"
  +				href="case1.html"/>
  +		</menu>
   		<menu name="Resources">
  -			<item name="Downloads" href="http://jakarta.apache.org/~hlship/hivemind/"/>
  +			<item name="Downloads"
  +				href="http://jakarta.apache.org/~hlship/hivemind/"/>
   			<item name="Tapestry and HiveMind Blog"
  -					href="http://javatapestry.blogspot.com/"/>
  +				href="http://javatapestry.blogspot.com/"/>
   		</menu>
   	</body>
   </project>
  
  
  
  1.1                  jakarta-commons-sandbox/hivemind/xdocs/case1.xml
  
  Index: case1.xml
  ===================================================================
  <?xml version="1.0"?>
  <!-- $Id: case1.xml,v 1.1 2003/09/08 23:07:22 hlship Exp $ -->
  <!DOCTYPE document [
  	<!ENTITY % common-links SYSTEM "../common/links.xml">
  	%common-links;
  	]>
  <document>
  	<properties>
  		<title>Case Study #1: Vista Startup</title>
  		<author email="hlship@apache.org">Howard M. Lewis Ship</author>
  	</properties>
  	<body>
  
  <section name="Introduction">
  
  <p>
  <a href="http://www.webct.com/products/viewpage?name=products_vista">Vista</a> is the
  enterprise academic software offering from WebCT. Vista is a fairly large product, consisting
  of well over six thousand classes, divided into a large number of tools and services.
  Vista has been a production project for several years, long before HiveMind was available. 
  HiveMind's introduction into Vista (on something of a trial basis) was to cleanup the startup
  and shutdown process for the application.
  </p>	
  
  <p>
  Vista 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 Vista Help service caches help data stored in the database; the Vista 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.
  The small WebLogic startup class would invoke the EJB, and the EJB would invoke static methods
  on many other classes.  This approach had grown quite unwieldy, especially in lite of efforts
  to improve and modularize the Vista build process.	HiveMind was brought in to rationalize
  this aspect of Vista, with the goal being to make the fewest possible number of changes
  to existing code.
  </p>
  
  </section>
  
  <section name="Overview">
  
  <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 Vista; each module  contributes tasks to a Startup or Shutdown extension 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 name="Module vista.framework.initshut">
  
  <p>
  The <code>vista.framework.initshut</code> ("initialization and shutdown") module
  contains the services and extension points for startup and shutdown.  It also contains
  Java classes corresponding to task contributions.
  </p>	
  	
  <source><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
  <module id="vista.framework.initshut" version="1.0.0">
  	<description>Module for startup and shutdown code within Vista.</description>
  	
  	<extension-point id="Bootstrap">
  		<description>Bootstrap elements are simple Runnable objects. The
  			contributed elements will each be executed in turn. The order of
  			execution is not defined.</description>
  		<schema id="run-schema">
  			<element name="run">
  				<description>Contributes a Runnable object or service.</description>
  				<attribute name="runnable">
  					<description>The name of a class implementing Runnable.</description>
  				</attribute>
  				<attribute name="service-id">
  					<description>The id of a service implementing Runnable.</description>
  				</attribute>
  				<rules>
  					<create-object
  						class="com.webct.platform.framework.initshut.service.RunnableWrapper"
  						/>
  					<read-attribute attribute="runnable" property="runnable"
  						translator="class"/>
  					<read-attribute attribute="service-id" property="runnable"
  						translator="service"/>
  					<invoke-parent method="addElement"/>
  				</rules>
  			</element>
  		</schema>
  	</extension-point>
  	
  	<extension point-id="Bootstrap">
  		<run service-id="Startup"/>
  	</extension>
  	
  	<service id="Bootstrap" interface="java.lang.Runnable">
  		<description>The Boostrap service reads the Bootstrap configuration and
  			executes each element.</description>
  		<invoke-factory service-id="hivemind.BuilderFactory">
  			<construct
  				class="com.webct.platform.framework.initshut.service.BootstrapImpl"
  				log-property="log"
  				messages-property="messages"
  				>
  				<set-extension-point property="runnables" point-id="Bootstrap"/>
  			</construct>
  		</invoke-factory>
  		<interceptor service-id="hivemind.LoggingInterceptor"/>
  	</service>
  	
  	<extension-point id="Teardown">
  		<description>Similar to the Bootstrap, except it occurs when the
  			application is being shutdown.</description>
  		<schema ref-id="run-schema"/>
  	</extension-point>
  	
  	<extension point-id="Teardown">
  		<run service-id="Shutdown"/>
  	</extension>
  	
  	<service id="Teardown" interface="java.lang.Runnable">
  		<description>The Teardown service reads the Teardown configuration and
  			executes each element.</description>
  		<invoke-factory service-id="hivemind.BuilderFactory">
  			<construct
  				class="com.webct.platform.framework.initshut.service.BootstrapImpl"
  				log-property="log"
  				messages-property="messages"
  				>
  				<set property="failureKey" value="teardown-failure"/>
  				<set-extension-point property="runnables" point-id="Teardown"/>
  			</construct>
  		</invoke-factory>
  		<interceptor service-id="hivemind.LoggingInterceptor"/>
  	</service>
  	
  	<extension-point id="Startup">
  		<description>Defines startup tasks.</description>
  		<schema id="task-schema">
  			<element name="task">
  				<description>A task which may be executed.</description>
  				<attribute name="order" required="true">
  					<description>Numeric value used to set the order of
  						execution for tasks.</description>
  				</attribute>
  				<attribute name="title" required="true">
  					<description>Title displayed as the task is executed.</description>
  				</attribute>
  				<attribute name="class">
  					<description>Name of class implementing the Executable
  						interface.</description>
  				</attribute>
  				<attribute name="service-id">
  					<description>
  					Id of a service that implements the Executable interface.	
  					</description>	
  				</attribute>
  				<rules>
  					<create-object
  						class="com.webct.platform.framework.initshut.service.Task"
  						/>
  					<read-attribute attribute="order" property="order"
  						translator="int"/>
  					<read-attribute attribute="title" property="title"/>
  					<read-attribute attribute="class" property="executable"
  						translator="class"/>
  					<read-attribute attribute="service-id" property="executable" 
  						translator="service"/>
  					<invoke-parent method="addElement"/>
  				</rules>
  				<element name="invoke-static">
  					<description>Used to invoke a public static method of a
  						class.</description>
  					<attribute name="class" required="true">
  						<description>The name of the class to invoke.</description>
  					</attribute>
  					<attribute name="method">
  						<description>Name of method to invoke; default is
  							"init".</description>
  					</attribute>
  					<rules>
  						<create-object
  							class="com.webct.platform.framework.initshut.service.StaticTask"
  							/>
  						<read-attribute attribute="class" property="className"/>
  						<read-attribute attribute="method" property="methodName"
  							/>
  						<invoke-parent method="setExecutable"/>
  					</rules>
  				</element>
  			</element>
  		</schema>
  	</extension-point>
  	
  	<extension-point id="Shutdown">
  		<description>Defines startup tasks.</description>
  		<schema ref-id="task-schema"/>
  	</extension-point>
  	
  	<extension point-id="Startup">
  		<task title="Python" order="50"
  			class="com.webct.platform.framework.initshut.ejb.PythonStartup"/>
  	</extension>
  	
  	<extension point-id="Shutdown">
  		
  		<task title="Update Status" order="100">
  			<invoke-static
  				class="com.webct.platform.framework.initshut.ejb.VistaStatus"
  				method="shutdown"/>
  		</task>
  
  	</extension>
  	
  	<service id="Startup" interface="java.lang.Runnable">
  		<invoke-factory service-id="hivemind.BuilderFactory">
  			<construct
  				class="com.webct.platform.framework.initshut.service.TaskExecutor"
  				log-property="log"
  				messages-property="messages"
  				>
  				<set-extension-point property="tasks" point-id="Startup"/>
  				<set property="kind" value="%startup"/>
  			</construct>
  		</invoke-factory>
  		<interceptor service-id="hivemind.LoggingInterceptor"/>
  	</service>
  	
  	<service id="Shutdown" interface="java.lang.Runnable">
  		<invoke-factory service-id="hivemind.BuilderFactory">
  			<construct
  				class="com.webct.platform.framework.initshut.service.TaskExecutor"
  				log-property="log"
  				messages-property="messages"	
  				>
  				<set-extension-point property="tasks" point-id="Shutdown"/>
  				<set property="kind" value="%shutdown"/>
  			</construct>
  		</invoke-factory>
  		<interceptor service-id="hivemind.LoggingInterceptor"/>
  	</service>
   	
  </module>]]></source>
  
  <p>
  HiveMind does not require that the module id match a package name; in this case,
  the module id ("vista.framework.initshut") is shorter and simpler than the
  principal package ("com.webct.platform.framework.initshut").	
  </p>
  
  <subsection name="Bootstrap extension point">
  
  <p>
  At runtime, the servlet will construct the registry and use the Bootstrap extension point
  to kick off the startup process.  The parameter schema for the Bootstrap extension point
  allows for contributions that identify runnable objects; objects that 
  implement the interface <code>java.lang.Runnable</code>.
  </p>
  
  <p>
  The schema allows for contributions of the form:
  <code>
  &lt;run runnable="..."/&gt;
  </code>	
  or
  <code>
  &lt;run service-id="..."/&gt;
  </code>.
  </p>
  
  <p>
  The first form allows an arbitrary Java object, implementing the interface, to be
  specified; the second allows a HiveMind service (also implementing the interface)
  to be specified.	
  </p>
  
  <p>
  The only contribution is the Startup service itself.
  </p>
  
  	
  </subsection>
  
  <subsection name="Bootstrap service">
  
  <p>
  The Bootstrap service uses the Boostrap extension point elements to, indirectly,
  activate the Startup service.  In theory, other kinds of startup tasks could also
  be activated via the Bootstrap service.
  
  <source><![CDATA[
  package com.webct.platform.framework.initshut.service;
  
  import java.util.List;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.hivemind.Messages;
  
  /**
   * Bootstraps the startup process by executing all the
   * Runnable objects contributed to the <code>vista.framework.initshut.Bootstrap</code>
   * configuration.  Can also be configured for the
   * <code>vista.framework.initshut.Teardown</code> configuration.
   */
  public class BootstrapImpl implements Runnable
  {
      private Log _log;
      private Messages _messages;
      private List _runnables;
      private String _failureKey = "bootstrap-failure";
  
      public void run()
      {
          int count = _runnables.size();
  
          for (int i = 0; i < count; i++)
          {
              Runnable r = (Runnable)_runnables.get(i);
  
              run(r);
          }
      }
  
      private void run(Runnable r)
      {
          try
          {
              r.run();
          }
          catch (Exception ex)
          {
              _log.error(_messages.format(_failureKey, r, ex.getMessage()), ex);
          }
      }
  
      public void setFailureKey(String string)
      {
          _failureKey = string;
      }
  
      public void setLog(Log log)
      {
          _log = log;
      }
  
      public void setMessages(Messages messages)
      {
          _messages = messages;
      }
  
      public void setRunnables(List list)
      {
          _runnables = list;
      }
  
  }	]]>
  </source>	
  </p>
  	
  </subsection>
  
  <subsection name="Startup extension point">
  
  <p>
  The Startup extension 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 extension 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:
  <ul>
  <li>As a Java class implementing the
  	 <code>com.webct.platform.framework.initshut.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>
  	
  <p>
  The <code>Executable</code> interface is similar to the <code>java.lang.Runnable</code> interface:
  <source>
  package com.webct.platform.framework.initshut.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>
  </subsection>
  
  <subsection name="Task class">
  
  <p>
  The Task class is used to hold the information collected by the Startup extension point.
  </p>	
  
  <source>
  package com.webct.platform.framework.initshut.service;
  
  import org.apache.commons.hivemind.Orderable;
  
  /**
   * Configuration element for the <code>vista.framework.initshut.Startup</code> or
   * <code>vista.framework.initshut.Shutdown</code>
   * extension points.  Each element has a title,
   * an {@link com.webct.platform.framework.initshut.service.Executable}
   * object, and an order
   * (used to sort the Startup items 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
  <a href="apidocs/org/apache/commons/hivemind/Orderable.html">Orderable</a>, which simply defines the <code>order</code>
  property (but simplifies sorting of the elements).
  </p>
  </subsection>
  
  
  
  <subsection name="Startup service">
  
  <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.webct.platform.framework.initshut.service;
  
  import java.util.List;
  
  import org.apache.commons.hivemind.HiveMind;
  import org.apache.commons.hivemind.Messages;
  import org.apache.commons.logging.Log;
  
  /**
   * Implementation for the <code>vista.runtime.Startup</code> service.
   * 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>
  </subsection>
  
  <subsection name="StaticTask class">
  	
  <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.webct.platform.framework.initshut.service;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  
  import org.apache.commons.hivemind.ApplicationRuntimeException;
  import org.apache.commons.hivemind.impl.BaseLocatable;
  import org.apache.commons.lang.StringUtils;
  
  /**
   * Implementation of
   * {@link com.webct.platform.framework.initshut.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>
  </subsection>
  
  </section>
  
  <section name="Other Modules">
  
  <p>
  Other modules, in their HiveMind module deployment descriptors, make contributions
  into the Startup and Shutdown extension points of the <code>vista.framework.initshut</code>
  module.  For example:
  
  <source><![CDATA[
  <?xml version="1.0"?>
  <module id="vista.coreservice.mail" version="1.0.0">
  		
  	<extension point-id="vista.framework.initshut.Startup">
  
  		<task title="Mail" order="2600" 
  			class="com.webct.platform.coreservice.mail.startup.MailStartup"/>	
  	  
  	</extension>
  	
  </module>	
  ]]></source>
  </p>
  
  <p>
  Here, the Mail service contributes an instance of class <code>MailStartup</code>.
  Other modules take advantage of the &lt;invoke-static&gt; element:
  
  <source><![CDATA[<?xml version="1.0"?>
  <module id="vista.coreservice.garbagecollection" version="1.0.0">
  	
  	<extension point-id="vista.framework.initshut.Startup">
  		
  		<task title="Scheduling Garbage Collection" order="3900">
  			<invoke-static
  				class="com.webct.platform.coreservice.garbagecollection.startup.GarbageCollectionStartup"
  				/>
  		</task>
  			
  	</extension>
  </module>]]></source>
  </p>
  
  	
  </section>
  
  <section name="Servlet Initialization">
  	
  <p>
  The servlet for the web application is responsible for constructing the registry
  and storing it (using <code>HiveMind.setDefault()</code>) so that
  other code may access it.
  </p>
  	
  <source><![CDATA[
      public void init() throws ServletException
      {
          LOG.info("*** Bootstrapping HiveMind Registry ***");
  
          if (HiveMind.isInitialized())
          {
              LOG.info(
                  "Registry is already initialized (the application appears to have been redeployed).");
              return;
          }
  
           try
           {
               RegistryBuilder builder = new RegistryBuilder(new RegistryBuilderErrorHandler());
  
               IResourceResolver resolver = new DefaultResourceResolver();
  
               builder.processModules(resolver);
  
               Registry registry = builder.constructRegistry(Locale.getDefault());
  
               HiveMind.setDefault(registry);
  
               Runnable bootstrap =
                   (Runnable)registry.getService("vista.framework.initshut.Bootstrap", Runnable.class);
  
               LOG.info("*** Executing vista.framework.initshut.Bootstrap service ***");
  
               bootstrap.run();
           }
           catch (Exception ex)
           {
               LOG.error(
                   "Unable to execute vista.framework.initshut.Bootstrap service: " + ex.getMessage());
           }
       }
  ]]></source>
  	
  <p>
  After building the registry, the servlet uses the Boostrap service to indirectly
  execute all the startup tasks; the idea of the extra layer is to insulate the
  servlet from any potential changes to the Startup service. The servlet calls the Boostrap service,
  and the Bootstrap service calls the Startup service.
  </p>
  
  </section>
  
  <section name="Handling Shutdown">
  
  <p>
  We take advantage of a WebLogic extension to know when the application server is being shut down.
  
  <source>
  package com.webct.platform.framework.initshut;
  import javax.naming.InitialContext;
  import javax.rmi.PortableRemoteObject;
  
  import com.webct.platform.framework.initshut.ejb.initshut;
  import com.webct.platform.framework.initshut.ejb.initshutHome;
  
  /**
   * Shutdown class called by the WebLogic container.
   */
  public class Shutdown
  {
      private final static String INIT_EJB_JNDI_NAME =
          "com.webct.platform.framework.initshut.ejb.initshutHome";
  
      /** Prevent instantiation */
      private Shutdown()
      {
      }
  
      /**
       *  Gets the initshut EJB and invokes <code>shutdown()</code>.
       */
  
      public static void main(String args[]) throws Exception
      {
          // Call the initshut EJB
          InitialContext context = new InitialContext();
          initshutHome home =
              (initshutHome)PortableRemoteObject.narrow(
                  context.lookup(INIT_EJB_JNDI_NAME),
                  initshutHome.class);
                  
          initshut bean = (initshut)home.create();
          
          bean.shutdown();
      }
  
  }	
  </source>
  </p>	
  
  <p>
  The implementation of the initshut EJB is similarily straight-forward:
  <source><![CDATA[
  package com.webct.platform.framework.initshut.ejb;
  
  import java.rmi.RemoteException;
  
  import javax.ejb.CreateException;
  
  import org.apache.commons.hivemind.HiveMind;
  import org.apache.commons.hivemind.Registry;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  import com.webct.platform.framework.ejb.BaseSessionBean;
  
  /**
   * Handles shutdown logic.
   *
   */
  
  public class initshutEJB extends BaseSessionBean implements Iinitshut
  {
      private static final Log LOG = LogFactory.getLog(initshutEJB.class);
  
      public void ejbCreate() throws RemoteException, CreateException
      {
      }
  
      /**
       * Called by J2EE Container shutdown calss for Vista shutdown processing.
       * 
       * <p>
       * Gets the <code>vista.framework.initshut.Teardown</code> service and executes it.
       * 
       */
      
      public void shutdown() throws RemoteException
      {
          Registry registry = HiveMind.getDefault();
  
          if (registry == null)
          {
              LOG.error(
                  "No HiveMind module registry is in place, unable to execute an orderly shutdown.");
              return;
          }
  
          Runnable r =
              (Runnable)registry.getService("vista.framework.initshut.Teardown", Runnable.class);
  
          r.run();
  
          LOG.info("**** Vista shutdown complete ****");
      }
  }]]>
  </source>	
  </p>
  
  </section>
  
  <section name="Summary">
  
  <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 an extension point. The startup and shutdown logic is kept close to the contributing
  modules', in those modules' HiveMind deployment descriptor.  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.  Courtesy of HiveMind.	
  </p>
  	
  </section>
  
  </body>
  </document>