You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by hu...@apache.org on 2004/06/21 18:48:09 UTC

cvs commit: jakarta-commons-sandbox/chain/xdocs chapter-chain.xml

husted      2004/06/21 09:48:08

  Added:       chain/xdocs chapter-chain.xml
  Log:
  Initial checkin of the Commons Chain Cookbook. This is in DocBook and needs to be integrated with the Maven build, but I wanted to get it under CVS. We may need to downsize it to Simplified DocBook.
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/chain/xdocs/chapter-chain.xml
  
  Index: chapter-chain.xml
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
  <article>
    <title>Jakarta Commons Chain of Responsibility</title>
  
    <authorblurb>
      <para>The Commons Chain Cookbook is an extract from the Jakarta Cookbook
      [ISBN: TBA] which has been graciously donated to the Apache Software
      Foundation by O'Reilly &amp;&nbsp;Associates. The publication date for the
      Jakarta Cookbook has not been set.</para>
    </authorblurb>
  
    <section>
      <title>Introduction</title>
  
      <para>The essence of computing might be that for any expected input (A),
      we return the expected output (B). The challenge is getting from (A) to
      (B). For a simple program, (A) to (B) might be a single transformation.
      Say, shifting a character code 32 digits so that "a" becomes "A". In a
      complex application, A to B can be a long and winding road.</para>
  
      <para>We might need to confirm that the user is authorized to create (B)
      from (A). We might need to find that (A) is valid input for (B). We might
      need to convert (A) from another character set. We may need to insert a
      preamble before writing (B). We may need to merge another resource with
      (A) before creating (B). Meanwhile, iIf anything goes wrong during
      processing, the error must be handled, and even logged. Some tasks might
      be able to continue after a non-fatal error, or, if the error is fatal,
      all process might need to halt.</para>
  
      <para>There are many different ways programmers organize processing logic
      within an application. Often, the difference between an elegant
      architecture and a muddled ball-of mud is how control flows from one
      process to another. To realize and retain elegeance, we must organize
      complex, multi-step processes so that they are easy to discover and
      change.</para>
  
      <para><remark>[TODO:]</remark></para>
    </section>
  
    <section>
      <title>Separate "business" logic from "presentation" logic</title>
  
      <para><emphasis>Problem:</emphasis> You want to cleanly separate the
      execution and presentation layers without complicating the design of your
      application.</para>
  
      <para><citetitle><emphasis>Solution:</emphasis></citetitle> Use the
      <glossterm>Chain of Responsibility</glossterm> and
      <glossterm>Command</glossterm> patterns so that the presentation layer can
      execute a command, or chain of commands, without needing to know how the
      command is implemented.</para>
  
      <para><emphasis>Discussion</emphasis>: To be useful, most applications
      need to run a process and then tell the client what happened. In practice,
      we find mixing "running" and "telling" together creates code that can be
      hard to test and maintain. If we can have one component run (or execute)
      the process, and another component report (or present) the result, then we
      can test, create, and maintain each component separately. But, how can we
      cleanly separate the execution and presentation layers without
      complicating the design of an application?</para>
  
      <para>Most application frameworks, especially web application frameworks,
      rely on the Command pattern. An incoming HTTP request is mapped to some
      type of "command" object. The command object takes whatever action is
      required, using information passed in the HTTP request.</para>
  
      <para><remark><remark>[Glossary: "Chain of Responsibility pattern",
      "Command pattern" entry]</remark></remark></para>
  
      <figure>
        <title>Using information passed in the request, the Command object takes
        whatever action is required.</title>
  
        <olink><remark>[TODO: line art.]</remark></olink>
      </figure>
  
      <para>In practice, there are usually commands within commands. A Command
      object in a web application often looks like a sandwich. First, it does
      some things for the benefit of the presentation layer, then it executes
      the business logic, and then it does some more presentation layer things.
      The problem many developers face is how to cleanly separate the
      <glossterm>business logic</glossterm> in the middle of a web command from
      other necessary tasks that are part of the <glossterm>request/response
      transaction</glossterm>.</para>
  
      <para><remark><remark>[Glossary: "business logic" , "request/response
      transaction" entry]</remark></remark></para>
  
      <figure>
        <title>A Command object often looks like a business logic
        sandwich.</title>
  
        <olink><remark>[TODO: line art.]</remark></olink>
      </figure>
  
      <para>The <productname>Chain of Responsibility</productname> package in
      the Jakarta Commons [<link
      linkend="???">http://jakarta.apache.org/commons/</link>] combines the
      Command pattern with the classic <glossterm>Chain of Responsibility
      pattern</glossterm> to make it easy to call a business command as part of
      a larger application command. (For more about the patterns, see
      <productname>Design Patterns: Elements of Reusable Object Orientated
      Software</productname> [<productnumber>ISBN
      0-201-63361-2</productnumber>]).</para>
  
      <para><remark><remark>[Glossary: "Chain of Responsibility pattern"
      entry]</remark></remark></para>
  
      <para><figure>
          <title>The Chain package makes it easy to call a business operation
          from within a larger transaction.</title>
  
          <olink>[TODO: line art]</olink>
        </figure></para>
  
      <para>To implement the patterns, the <classname>Chain</classname> package
      defines five key interfaces:</para>
  
      <simplelist>
        <member>Context</member>
  
        <member>Command</member>
  
        <member>Chain</member>
  
        <member>Filter</member>
  
        <member>Catalog</member>
      </simplelist>
  
      <para><emphasis>Context.</emphasis> A <classname>Context</classname>
      represents the state of an application. In the Chain package,
      <classname>Context</classname> is a marker interface for a
      <classname>java.util.Map</classname>. The Context is an envelope
      containing the attributes needed to complete a transaction. In other
      words, a Context is a stateful object with member values.</para>
  
      <para><emphasis>Command.</emphasis> A <classname>Command</classname>
      represents a <glossterm>unit of work</glossterm>. A Command has a single
      entry method: <methodname>public boolean execute(Context
      context)</methodname>. A Command acts upon the state passed to it through
      a context object, but retains no state of its own. Commands may be
      assembled into a Chain, so that a complex transaction can be created from
      discrete units of work. If a Command returns <symbol>true</symbol>, then
      other Commands in a Chain should <emphasis>not</emphasis> be executed. If
      a Command returns <symbol>false</symbol>, then other Commands in the Chain
      (if any) may execute.</para>
  
      <para><remark><remark>[Glossary: "unit of work"
      entry]</remark></remark></para>
  
      <para><emphasis>Chain.</emphasis> <classname>Chain</classname> implements
      the <classname>Command</classname> interface, so a
      <classname>Chain</classname> can be used interchangeably with a
      <classname>Command</classname>. An application doesn't need to know if
      it's calling a Chain or a Command, so you can refactor from one to the
      other. A Chain can nest other Chains as desired. This property is known as
      the <emphasis><glossterm>Liskov substitution principle</glossterm>.
      </emphasis></para>
  
      <para><emphasis><remark>[Glossary: "<glossterm>Liskov substitution
      principle</glossterm>" entry]</remark></emphasis></para>
  
      <para><emphasis>Filter.</emphasis> Ideally, every command would be an
      island. In real life, we sometimes need to allocate resources and be
      assured the resources will be released no matter what happens. A
      <classname>Filter</classname> is a specialized
      <classname>Command</classname> that adds a
      <methodname>postProcess</methodname> method. A
      <classname>Chain</classname> is expected to call the
      <methodname>postProcess</methodname> method of any filters in the chain
      before returning. A Command that implements Filter can safely release any
      resources it allocated through the <methodname>postProcess</methodname>
      method, even if those resources are shared with other Commands.</para>
  
      <para><emphasis>Catalog.</emphasis> Many applications use "facades" and
      "factories" and other techniques to avoid binding layers too closely
      together. Layers need to interact, but often we don't want them to
      interact at the classname level. A <classname>Catalog</classname> is
      collection of logically named Commands (or Chains) that a client can
      execute, without knowing the Command's classname.</para>
  
      <para><figure>
          <title>The five core interfaces: Context, Command, Chain, Filter, and
          Catalog.</title>
  
          <olink><remark>[TODO: UML for Context, Command, Chain, Filter, and
          Catalog.]</remark></olink>
        </figure></para>
  
      <para>The rest of the chapter features recipes that will help you put the
      Chain of Responsibility package to work in your own applications.</para>
    </section>
  
    <section>
      <title>Test a Command</title>
  
      <para><emphasis>Problem:</emphasis> You want to start using
      <classname>Command</classname> objects in your application.</para>
  
      <para><emphasis>Solution:</emphasis> Use <glossterm>Test Driven
      Development</glossterm> to create a test for a Command, and let the test
      tell you how to write the Command. When the test passes, you will have a
      working Command to integrate into your application.</para>
  
      <para><emphasis><remark>[Glossary: "<glossterm>Test Driven
      Development</glossterm>" entry]</remark></emphasis></para>
  
      <para><emphasis>Discussion: </emphasis>Let's say we're working on an
      application that maintains a "<classname>Profile</classname>" object for
      each client. We need to change the state of the Profile during the
      client's "session" with the application, which may span several requests.
      Different application environments may preserve a Profile in different
      ways. A web application may store a Profile as an attribute of the
      HttpSession or as a client-side "cookie". An EJB application may maintain
      a Profile as an attribute of the client's environment. Regardless, you
      would like a single Command that can check to see if a client has a
      Profile object, and, if not, create one. The Command does not know how the
      application stores a Profile, or even if it is stored.</para>
  
      <para>One reason we use Commands is because they are easy to test. In this
      recipe, let's write a test for our Command. In another recipe, we will
      create the corresponding Command. This approach is known as Test Driven
      Development.</para>
  
      <para>To test our Command, we can simply</para>
  
      <orderedlist>
        <listitem>
          <para>Create a Context with a known state</para>
        </listitem>
  
        <listitem>
          <para>Create a Command instance to test</para>
        </listitem>
  
        <listitem>
          <para>Execute the Command, passing our Context</para>
        </listitem>
  
        <listitem>
          <para>Confirm that our Context now contains the expected state</para>
        </listitem>
      </orderedlist>
  
      <para>For the <classname>Context</classname>, we can use the
      <classname>ContextBase</classname> class provided as part of the Chain
      package. The <classname>ProfileCheck</classname> Command and Profile
      object are shown in the next recipe. The remaining code for our
      <classname>TestProfileCheck</classname> TestCase is shown as Example
      1.</para>
  
      <example>
        <title>Testing whether a Profile object is created</title>
  
        <programlisting>package org.apache.commons.mailreader;
  
  import junit.framework.TestCase;
  import org.apache.commons.chain.Command;
  import org.apache.commons.chain.Context;
  import org.apache.commons.chain.mailreader.commands.ProfileCheck;
  import org.apache.commons.chain.mailreader.commands.Profile;
  import org.apache.commons.chain.impl.ContextBase;
  
  public class ProfileCheckTest extends TestCase {
  
     public void testProfileCheckNeed() {[TODO:]
  
          Context context = new ContextBase();
          Command command = new ProfileCheck();
          try {
              command.execute(context);
          } catch (Exception e) {
              fail(e.getMessage());
          }
  
          Profile profile = (Profile) context.get(Profile.PROFILE_KEY);
          assertNotNull("Missing Profile", profile);
  
      }</programlisting>
      </example>
  
      <para>Since we're using a test-first approach, we can't run or even
      compile this class (yet). But we can use the test class to tell us which
      other classes we need to write. The next recipe shows how to create a
      Command.</para>
    </section>
  
    <section>
      <title>Create a Command</title>
  
      <para><emphasis>Problem:</emphasis> You need to create a
      <classname>Command</classname> for your application, so that a test of the
      Command will succeed.</para>
  
      <para><emphasis>Solution:</emphasis> Use the test to tell you what code
      will realize the Command's <glossterm><emphasis>API
      contract</emphasis></glossterm>.</para>
  
      <para><remark>[Glossary: <emphasis>"API contract</emphasis>"
      entry.]</remark></para>
  
      <para><emphasis>Discussion:</emphasis> A key reason for using Commands,
      and chains of Commands, is testability. Since Commands are designed to act
      on whatever <classname>Context</classname> they receive, we can create a
      Context with a known state to test our Command. In the preceding recipe,
      we created a test for a <classname>ProfileCheck</classname> command. Let's
      implement that Command so that it passes our test.</para>
  
      <para>To pass the ProfileCheck test, we need to</para>
  
      <orderedlist>
        <listitem>
          <para>Retrieve the Profile from the Context, using Profile.PROFILE_KEY
          as the attribute name.</para>
        </listitem>
  
        <listitem>
          <para>If Profile is NULL, create a Profile and store it in the
          Context.</para>
        </listitem>
  
        <listitem>
          <para>Return <symbol>false</symbol> or <symbol>true</symbol> to the
          caller.</para>
        </listitem>
      </orderedlist>
  
      <para>Whether to return <symbol>false</symbol> or <symbol>true</symbol> at
      step 3 is optional. You could choose to return <symbol>true</symbol>,
      since this Command did check the profile. Or, you could decide to return
      <symbol>false</symbol>, so that the Command can be used as part of a
      Chain. The return value controls whether a chain terminates or continues.
      True forces a chain to end. False allows a chain to continue. For now,
      we'll just return <symbol>false</symbol>, so that our Command could be
      used as part of a larger chain of Commands.</para>
  
      <para>The code implementing our ProfileCheck Command is shown as Example
      2.</para>
  
      <example>
        <title>A Command to create a Profile, if one doesn't exist.</title>
  
        <programlisting>package org.apache.commons.chain.mailreader.commands;
  
  import org.apache.commons.chain.Command;
  import org.apache.commons.chain.Context;
  
  public class ProfileCheck implements Command {
  
      public boolean newProfile(Context context) { return new Profile(); }
  
      public boolean execute(Context context) throws Exception {
          Object profile = context.get(Profile.PROFILE_KEY);
          if (null == profile) {
              profile = newProfile(context);
              context.put(Profile.PROFILE_KEY, profile);
          }
          return false;
      }
  }</programlisting>
      </example>
  
      <para>To compile our Command and run our test, we also need a
      <classname>Profile</classname> class. Example 3 shows the simplest
      implementation of Profile that will pass our test.</para>
  
      <example>
        <title>The simplest Profile class that can possibly work.</title>
  
        <programlisting>package org.apache.commons.chain.mailreader.commands; 
  public class Profile { 
      public static String PROFILE_KEY = "profile"; 
  }</programlisting>
      </example>
  
      <para>Note that we used a separate method to create the Profile object. If
      we buried a call to "new Profile()" in the Execute method, we could not be
      reuse our CheckProfile Command to create specialized Profiles. Using
      helper methods to create objects is known as the
      <glossterm>Factory</glossterm> pattern.</para>
  
      <para><remark><remark>[Glossary: "Factory pattern"
      entry]</remark></remark></para>
  
      <para>We should now be able to compile all three classes and run our
      test.</para>
  
      <para><figure>
          <title>Green bar for org.apache.commons.mailreader.ProfileCheckTest
          [TODO: Screen capture]</title>
  
          <mediaobject>
            <imageobject>
              <imagedata fileref="???" />
            </imageobject>
          </mediaobject>
        </figure></para>
    </section>
  
    <section>
      <title>Create a Context</title>
  
      <para><emphasis>Problem:</emphasis> You want a
      <classname>Context</classname> that is
      <glossterm><emphasis>type-safe</emphasis></glossterm>,
      <glossterm><emphasis>encapsulated</emphasis></glossterm>, or interoperable
      with components that expect <glossterm>JavaBean</glossterm>
      properties.</para>
  
      <para><remark>[Glossary entry: <emphasis>type-safety</emphasis>,
      <emphasis>encapsulate, JavaBean]</emphasis></remark></para>
  
      <para><emphasis>Solution:</emphasis> Extend your Context class from
      <classname>ContextBase</classname>, and add whatever JavaBean properties
      you need.</para>
  
      <para><emphasis>Discussion</emphasis>: Many components already use a
      "context". Each of the various Java Servlet "scopes" have a context
      object. The <productnumber>Apache Velocity</productnumber> product relies
      on a context object. Most operating systems have a list of simple
      "environment" settings that is a "context". These examples all use a "map"
      or "dictionary" style context. These contexts are a simple list of
      entries, where each entry is a key and a value.</para>
  
      <para>Other components also use what amounts to a context but predefine
      the entries as object properties. The Apache Struts framework is one
      example. Developers can define a JavaBean (or
      "<classname>ActionForm</classname>") to act as the context for a request.
      Some components mix both approaches. The Servlet request and session
      objects expose a Map-style context along with several predefined
      properties. Struts supports a variant of the ActionForm that utilizes a
      Map.</para>
  
      <para>Architects will often choose a Map-style context because they are
      easy to implement and <emphasis>very</emphasis> easy to extend. Usually,
      developers can add their own entries to a Map-style context at will. Of
      course, as illustrated by figure 6, every engineering decision is a
      trade-off. Maps trade type-safety and encapsulation for flexibility and
      extensibility. Other times, architects will decide to trade flexibility
      for type-safety. Or, we may decide to trade extensibility for
      encapsulation. Often, these decisions are driven by the need to
      interoperate with other components that may expect either a Map or a
      JavaBean.</para>
  
      <figure>
        <title>Every engineering decision is a trade-off.</title>
  
        <olink>[:TODO: line art -- (Do it right; Do it soon; Do it cheap: Choose
        any two.)]</olink>
      </figure>
  
      <para>The Jakarta Commons Chain of Command architects have chosen a
      Map-style context as the default. The Chain Context is nothing but a
      "marker interface" for the standard Java <classname>Map</classname>
      interface.</para>
  
      <para><example>
          <title>The Context interface is a "marker" interface extending
          Map.</title>
  
          <para><programlisting>public interface Context extends Map {
  }</programlisting></para>
        </example>However, to provide developers with type-safety,
      encapsulation, and interoperability, Chain provides a sophisticated
      <classname>ContextBase</classname> class that also supports JavaBean
      properties.</para>
  
      <para>If a developer declares a JavaBean property on a subclass of
      ContextBase, this property is automatically used by the Map methods. The
      Map <methodname>get</methodname> and <methodname>put</methodname> methods
      of ContextBase introspect the subclass. If they find a JavaBean property
      named after the key argument, the getter or setter method is called
      instead.</para>
  
      <para>This bit of wizardry enforces type-safety for any declared
      properties, but developers can still use the context as if it were an
      ordinary Map. If all needed attributes are defined as properties, then a
      ContextBase can interoperate with components that expect a Map and also
      with components that expect a JavaBean -- all at the same time. Everything
      is transparent, and there are no special requirements for the
      caller.</para>
  
      <para>Let's create a test for a ContextBase subclass to prove the JavaBean
      properties and Map methods are interoperable and type-safe.</para>
  
      <para>To test the context for interoperability, we'll need to do four
      things:</para>
  
      <orderedlist>
        <listitem>
          <para>Assign a value to a typed property using a JavaBean
          setter</para>
        </listitem>
  
        <listitem>
          <para>Retrieve the same value using the Map get method</para>
        </listitem>
  
        <listitem>
          <para>Assign another value using the Map set method</para>
        </listitem>
  
        <listitem>
          <para>Retrieve the update value using a JavaBean setter</para>
        </listitem>
      </orderedlist>
  
      <para>To test the context for type-safety, we will also need to
      <orderedlist>
          <listitem>
            <para>Assign a <classname>String</classname> to a typed property
            using the Map get method</para>
          </listitem>
  
          <listitem>
            <para>Confirm that the assignation throws a "type mismatch"
            exception</para>
          </listitem>
        </orderedlist></para>
  
      <para>To write these tests, let's create a context with a
      <emphasis>Locale</emphasis> property for an application named
      "MailReader". The code for our <classname>LocaleValueTest</classname> is
      shown in Example 5.<example>
          <title>LocaleValueTest proves that our context is interoperable and
          type-safe.</title>
  
          <para><programlisting>package org.apache.commons.mailreader;
  import junit.framework.TestCase;
  import junit.framework.Assert;
  import org.apache.commons.chain.mailreader.MailReader;
  import java.util.Locale;
  
  public class LocaleValueTest extends TestCase {
  
      MailReader context;
  
      public void setUp() {
          context = new MailReader();
      }
  
      public void testLocaleSetPropertyGetMap() {
          Locale expected = Locale.CANADA_FRENCH;
          context.setLocale(expected);
          Locale locale = (Locale) context.get(MailReader.LOCALE_KEY);
          Assert.assertNotNull(locale);
          Assert.assertEquals(expected, locale);
      }
  
      public void testLocalePutMapGetProperty() {
          Locale expected = Locale.ITALIAN;
          context.put(MailReader.LOCALE_KEY, expected);
          Locale locale = context.getLocale();
          Assert.assertNotNull(locale);
          Assert.assertEquals(expected, locale);
      }
  
      public void testLocaleSetTypedWithStringException() {
          String localeString = Locale.US.toString();
          try {
              context.put(MailReader.LOCALE_KEY, localeString);
              fail("Expected 'argument type mismatch' error");
          } catch (UnsupportedOperationException expected) {
              ;
          }
      }
  }</programlisting></para>
        </example>A <classname>MailReader</classname> Context object that passes
      the LocaleValueTest is shown as Example 6.<example>
          <title>The simplest MailReader object that will pass
          LocalValueTest.</title>
  
          <para><programlisting>package org.apache.commons.chain.mailreader;
  import org.apache.commons.chain.impl.ContextBase;
  import java.util.Locale;
  
  public class MailReader extends ContextBase {Prop
      public static String LOCALE_KEY = "locale";
      private Locale locale;
      public Locale getLocale() {
          return locale;
      }
      public void setLocale(Locale locale) {
          this.locale = locale;
      }
  }</programlisting></para>
        </example>The MailReader object in Example 6 shows how much utility is
      built into ContextBase class. All we had to do was define the property.
      The base class took care of the rest. Of course, there is no free lunch.
      ContextBase has to go through the bother of introspection to tell if an
      attribute has a property or not. The ContextBase code is written to be
      efficient, but if your application can just use a Map-style context, you
      could use the leaner version of a MailReader context shown in Example
      7.<example>
          <title>An even simpler MailReader Context (but that would fail
          LocalValueTest).</title>
  
          <para><programlisting>package org.apache.commons.chain.mailreader;
  import org.apache.commons.chain.Context;
  import java.util.Hashmap;
  
  public class MailReader extends Hashmap implements Context {
      public static String LOCALE_KEY = "locale";
  }</programlisting></para>
        </example>By extending the stock ContextBase subclass, or rolling your
      own class with a HashMap, you can use whatever type of context is best for
      your own artichtecture.</para>
    </section>
  
    <section>
      <title>Create a Catalog</title>
  
      <para><emphasis>Problem:</emphasis> You want to layer your application
      without creating dependencies on <classname>Command</classname> objects
      that exist in different layers.</para>
  
      <para><emphasis>Solution:</emphasis> Assign each command a logical name so
      that it can be called from a "catalog". A catalog moves dependency on to
      the logical name and away from the Java classname or classnames. The
      caller has a dependency on the catalog but not on the actual Command
      classes.</para>
  
      <para><emphasis>Discussion:</emphasis> Context and Command objects are
      usually used to join layers of an application together. How can one layer
      call Commands in another layer without creating new dependencies between
      the two layers?</para>
  
      <para>Interlayer dependencies are a common dilemma in enterprise
      applications. We want to layer our application so that it becomes robust
      and cohesive, but we also need a way for the different layers to interact
      with each other. The Commons Chain package offers a
      <classname>Catalog</classname> object to help solve problems with
      dependencies between layers, as well as between components on the same
      layer.</para>
  
      <para>A Catalog can be configured through <glossterm>metadata</glossterm>
      (an XML document) and instantiated at application startup. Clients can
      retrieve whatever <classname>Commands</classname> they need from the
      Catalog at runtime. If Commands need to be refactored, new classnames can
      be referenced in the metadata, with zero-changes to the application
      code.</para>
  
      <para><remark>[Glossary: Add "metadata"<emphasis>
      entry.]</emphasis></remark></para>
  
      <para>Let's take a look at some code that uses a Catalog. Example 8 shows
      a method that executes a Command from a Catalog stored in a web
      application's servlet context. <example>
          <title>A Catalog stores Commands that an application can lookup and
          execute.</title>
  
          <para><programlisting>   boolean executeCatalogCommand(Context context, String name, HttpServletRequest request) 
          throws Exception {
      
          ServletContext servletContext = request.getSession().getServletContext();  
          Catalog catalog = (Catalog) servletContext.getAttribute("catalog");
          Command command = catalog.getCommand(name);
          boolean stop = command.execute(context);
          return stop;
          
      } </programlisting></para>
        </example></para>
  
      <para><remark>[Glossary: Add <emphasis>"type-safety"</emphasis>,
      "<emphasis>encapsulate", "JavaBean" entry.]</emphasis></remark></para>
  
      <para>Notice that we only pass the name of a Command into the method. Also
      note that we retrieve the Command and pass it the Context without knowing
      the precise type of either object. All references are to the standard
      interfaces.</para>
  
      <para>Example 9 shows an XML document that can be used to create a
      Catalog, like the one called in Example 8.<example>
          <title>A Catalog can be configured using metadata (an XML
          document).</title>
  
          <para><programlisting>&lt;?xml version="1.0" ?&gt;
  &lt;chains&gt;
    &lt;command 
      name="LocaleChange" 
      className="org.apache.commons.chain.mailreader.commands.LocaleChange"/&gt;
    &lt;command 
      name="LogonUser" 
      className="org.apache.commons.chain.mailreader.commands.LogonUser"/&gt;
  &lt;/chains&gt;</programlisting></para>
        </example>The application needs to know the name given to a Command we
      want to execute, but it does not need to know the classname of the
      Command. The Command could also be a <classname>Chain</classname> of
      Commands. We can refactor Commands within the Catalog and make
      zero-changes to the application. For example, we might decide to check for
      a user profile before changing a user's locale setting. If we wanted to
      make running a <classname>CheckProfile</classname> Command part of
      "LocaleChange", we could change the Catalog to make "LocaleChange" a
      Chain. Example 10 shows Catalog metadata where "LocaleChange" is a Chain.
      <example>
          <title>A Catalog can be refactored with zero-changes to the
          application code.</title>
  
          <para><programlisting>&lt;chains&gt;
   &lt;chain name="LocaleChange"&gt; 
      &lt;command 
        className="org.apache.commons.chain.mailreader.commands.ProfileCheck"/&gt;
      &lt;command 
        className="org.apache.commons.chain.mailreader.commands.LocaleChange"/&gt;
    &lt;/chain&gt;
    &lt;command 
      name="LogonUser" 
      className="org.apache.commons.chain.mailreader.commands.LogonUser"/&gt;
  &lt;/chains&gt;</programlisting></para>
        </example></para>
  
      <para>In the "Create a Command" recipe, we use a factory method to create
      a "Profile" object. If we subclass that Command to create a specialized
      Profile, we can cite the new classname in the Catalog, with zero changes
      to the rest of the application.</para>
  
      <para>Being able to make quick and easy changes to an application can have
      a big effect on the bottom line. The recurring, annual maintenance cost of
      applications can range between 25% to 50% of the initial development cost
      (Gartner Group, May 2002).</para>
    </section>
  
    <section>
      <title>Load a Catalog From a Web Application</title>
  
      <para><emphasis>Problem:</emphasis> You'd like to load a catalog
      automatically when a web application starts.</para>
  
      <para><emphasis>Solution:</emphasis> Utilize the
      <classname>ChainListener</classname> bundled with the Commons Chain of
      Responsibility Package.</para>
  
      <para><emphasis>Discussion:</emphasis> A Catalog can be created
      progmatically, using conventional Java statements, or by specifying the
      catalog members as metadata (an XML document). For testing, it can be
      easiest to create a catalog progmatically. For deployment, catalogs are
      much easier to maintain as metadata. The downside of using metadata is
      that it needs to be parsed so that the specified objects can be created.
      Happily, the Common Chain of Responsibility package comes bundled with a
      Listener that can read a Catalog metadata file and create the
      corresponding object graph.</para>
  
      <para>To use ChainListener in a web application, just add a reference to
      your application's web.xml (yet another metadata document). One such
      reference is shown as Example 11. <example>
          <title>Loading a ChainListener via a web.xml</title>
  
          <programlisting>    &lt;!-- Commons Chain listener to load catalogs  --&gt;
      &lt;context-param&gt;
          &lt;param-name&gt;org.apache.commons.chain.CONFIG_CLASS_RESOURCE&lt;/param-name&gt;
          &lt;param-value&gt;resources/catalog.xml&lt;/param-value&gt;
      &lt;/context-param&gt;
      &lt;listener&gt;
          &lt;listener-class&gt;org.apache.commons.chain.web.ChainListener&lt;/listener-class&gt;
      &lt;/listener&gt;</programlisting>
        </example>The elements in Example 11 expect that there is a
      "catalog.xml" file stored on the application's classpath under a directory
      named "resources". Usually, this would mean that there is a "resources"
      directory under "WEB-INF/classes". If you are using Maven to build your
      application, Maven can copy metadata files from your source tree to the
      web infrastructure tree automatically. Many teams do the same with custom
      Ant build files. Example 12 shows a fragment of a Maven properties file
      that copies <filename>catalog.xml</filename> from a directory under
      "<filename>src/resources/chain</filename>" to
      "<filename>/WEB-INF/classpath/resources</filename>" under the web
      deployment directory. <example>
          <title>Managing resources in a Maven properties file</title>
  
          <para><programlisting>&lt;!-- ... --&gt;
  
      &lt;build&gt;
         &lt;sourceDirectory&gt;src/java&lt;/sourceDirectory&gt;
         &lt;resources&gt;
             &lt;resource&gt;
               &lt;directory&gt;${basedir}/src/resources/chain&lt;/directory&gt;
               &lt;targetPath&gt;resources&lt;/targetPath&gt;
               &lt;includes&gt;
                 &lt;include&gt;catalog.xml&lt;/include&gt;
               &lt;/includes&gt;
             &lt;/resource&gt;
         &lt;/resources&gt;
      &lt;/build&gt;
  
  &lt;!-- ... --&gt;</programlisting></para>
        </example></para>
  
      <para>By default, ChainListener will create an application-scope attribute
      by the name of "catalog".</para>
  
      <para>The default attribute name can be changed, if needed, You can also
      configure ChainListener to read files from a system path or from a JAR.
      See the JavaDoc for all the configuration details. There is also a
      <classname>ChainServlet</classname> if you are using the Servlet 2.2
      platform.</para>
  
      <para>Using the default attribute, and given an
      <classname>HttpServletRequest</classname> instance, you can access the
      catalog by coding:</para>
  
      <para><programlisting>        Catalog catalog = (Catalog) request.getSession().getServletContext().getAttribute("catalog");</programlisting></para>
  
      <para>Given the catalog, you can execute a command and pass it a context,
      like so:</para>
  
      <para><programlisting>        Command command = catalog.getCommand(commandName);  
          boolean stop = command.execute(context);</programlisting></para>
  
      <para>Of course, the hard part is populating the context and determining
      which command we need to run for a given request. That work is often left
      to a Front Controller, like the one implemented by Apache Struts.
      Accordingly, we include a "Call a Command from Struts" recipe In this
      chapter. If you like Controllers, but don't like Struts, there are also
      "Create a Controller" and "Call a Command from a Servlet" recipes.</para>
    </section>
  
    <section>
      <title>Call a Command From Struts</title>
  
      <para><emphasis>Problem:</emphasis> You'd like to call Commands from
      within a Struts application.</para>
  
      <para><emphasis>Solution:</emphasis> Use a CommandAction to call a Command
      named for your ActionForm.</para>
  
      <para><emphasis>Discussion:</emphasis> As a Front Controller, the Apache
      Struts web application framework has three primary responsibilities.
      <orderedlist>
          <listitem>
            <para>Validate a user request</para>
          </listitem>
  
          <listitem>
            <para>Process a user request</para>
          </listitem>
  
          <listitem>
            <para>Create a response to the request</para>
          </listitem>
        </orderedlist>The third item is usually delegated to a server page.
      Struts provides framework-aware components, like JSP tag libraries, to
      encourage developers to use another resource to create the response. In
      this way, Struts needs only to select the resource. The actual response
      creation is handled elsewhere.</para>
  
      <para>Struts also bundles a component to help validate the user request.
      The Struts Validator utilizes metadata to vet request values and create
      user prompts should validation fail.</para>
  
      <para>To discharge its responsibility to "Process a user request", Struts
      provides an extension point called the "<classname>Action</classname>"
      class. The Struts Action is a blank slate where developers can do whatever
      is necessary to process the request. Some developers even make JDBC calls
      from Actions, but such practices are discouraged. The Struts best practice
      is for Actions to delegate business and system logic calls to another
      component, such as a <glossterm>business facade</glossterm>. The Struts
      Action passes appropriate values to one or methods on the facade. The
      outcome is used to determine an appropriate response. Often, the outcome
      of an Action is described as either "success " or "failure".</para>
  
      <para><remark>[Glossary: "Business facade" entry]</remark></para>
  
      <para>Aside from the blank Action, Struts distributes several "standard"
      Actions, such as the <classname>DispatchAction</classname>. The standard
      Actions are designed to be used several times in different ways within an
      application. To allow reuse of Actions, Struts provides a
      <glossterm>Decorator</glossterm> class called an
      <classname>ActionMapping</classname>. Runtime details can be specified
      through the <classname>ActionMappings</classname>, so that each usage of a
      standard Action can be slightly different.</para>
  
      <para>To solve the problem of calling a Command from Struts, we can use a
      standard Action to retrieve the Catalog and call the Command. We can
      specify runtime details in the ActionMapping. Our details include which
      set of validations to pass and which CommanIn this chapter, d to
      run.</para>
  
      <para>In practice, the set of validations we need to pass and the command
      we need to run are closely coupled. In fact, it can be a good practice to
      create a distinct set of validations for each Command. If a Command
      changes, then its validations can change with it, without affecting other
      Commands.</para>
  
      <para>In Struts, the set of validations is coupled to the ActionForm name.
      The ActionForm name is a logical identifier, separate from the ActionForm
      classname. When you use the Struts Validator, the "form" name for the
      Validations is the same string as the ActionForm "name" specified by the
      ActionMapping. A database guru would call this a 1:1 relation; the
      Validator form name and the ActionForm name are shared keys. If we want
      each Command to have its own set of validations, and it's own
      ActionMapping, it follows that we should use the same "key" throughout.
      The Command name can be the ActionForm name as well as the Validator form
      name.</para>
  
      <para>Example 13 shows how the names line up in the three metadata files,
      the catalog.xml, the validation.xml, and the struts-config.xml. The token,
      or "key", that links the three files together is "LocaleChange"<example>
          <title>A tale of three metadata files: catalog.xml, validation.xml,
          and struts-config.xml</title>
  
          <para><programlisting>&lt;!-- catalog.xml --&gt;
  &lt;?xml version="1.0" ?&gt;
  &lt;chains&gt;
      &lt;command
          name="<emphasis>LocaleChange</emphasis>"
          className="org.apache.commons.chain.mailreader.commands.LocaleChange" /&gt;
  &lt;/chains&gt;
  
  &lt;!-- validation.xml --&gt;
  &lt;?xml version="1.0" ?&gt;
  &lt;!DOCTYPE form-validation PUBLIC
            "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1//ENIn this chapter, "
            "http://jakarta.apache.org/commons/dtds/validator_1_1.dtd"&gt;
  &lt;form-validation&gt;
      &lt;formset&gt;
          &lt;form name="<emphasis>LocaleChange</emphasis>"&gt;
              &lt;field property="language" depends="required"&gt;
                  &lt;arg0 key="prompt.language"/&gt;
              &lt;/field&gt;
          &lt;/form&gt;
      &lt;/formset&gt;
  &lt;/form-validation&gt;
  
  &lt;!-- struts-config.xml --&gt;
  &lt;?xml version="1.0" ?&gt;
  &lt;!DOCTYPE struts-config PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
            "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd"&gt;
  &lt;struts-config&gt;
      &lt;form-beans&gt;
          &lt;form-bean
              name="<emphasis>LocaleChange</emphasis>"
              type="org.apache.struts.validator.DynaValidatorForm"&gt;
             &lt;form-property name="language" type="java.lang.String"/&gt;
             &lt;form-property name="country" type="java.lang.String"/&gt;
           &lt;/form-bean&gt;
       &lt;/form-beans&gt;
      &lt;action-mappings&gt;
          &lt;action path="/LocaleChange"
              name="<emphasis>LocaleChange</emphasis>"
              type="org.apache.commons.chain.mailreader.struts.CommandAction"&gt;
          &lt;forward name="success" path="/Welcome.do" /&gt;
          &lt;/action&gt;
      &lt;/action-mappings&gt;
  &lt;struts-config&gt;</programlisting></para>
        </example>In Example 13, we used "LocaleChange" for the Command name,
      the validation Form name, and the Action form-bean name. To trigger the
      thread, all we need to do is define a generic Action that will use the
      form-bean name as the Command name. Example 14 shows our
      <classname>CommandAction</classname>. <example>
          <title>The CommandAction links the form-bean name with the Command
          name</title>
  
          <para><programlisting>package org.apache.commons.chain.mailreader.struts;
  import org.apache.commons.chain.Catalog;
  import org.apache.commons.chain.Command;
  import org.apache.commons.chain.Context;
  import org.apache.commons.chain.web.servlet.ServletWebContext;
  import org.apache.struts.action.Action;
  import org.apache.struts.action.ActionForm;
  import org.apache.struts.action.ActionForward;as the ActionForm name.
  import org.apache.struts.action.ActionMapping;
  import javax.servlet.ServletContext;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  public class CommandAction extends Action {
  
      protected Command getCommand(ActionMapping mapping,
                                   ActionForm form,
                                   HttpServletRequest request,
                                   HttpServletResponse response) throws Exception {
          Catalog catalog = (Catalog) request.getSession().getServletContext().getAttribute("catalog");
          String name = mapping.getName();
          Command command = catalog.getCommand(name);
          return command;
      }
  
      protected Context getContext(ActionMapping mapping,
                                   ActionForm form,
                                   HttpServletRequest request,
                                   HttpServletResponse response) throws Exception {
          ServletContext application = request.getSession().getServletContext();
          Context context = new ServletWebContext(application, request, response);
          return context;
      }
  
      protected static String SUCCESS = "success";
  
      protected ActionForward findLocation(ActionMapping mapping, boolean stop) {
          if (stop) return mapping.getInputForward(); // Something failed
          return mapping.findForward(SUCCESS);
      }
  
      public ActionForward execute(
              ActionMapping mapping,
              ActionForm form,
              HttpServletRequest request,
              HttpServletResponse response)
              throws Exception {
          Command command = getCommand(mapping, form, request, response);
          Context context = getContext(mapping, form, request, response);
          boolean stop = command.execute(context);
          ActionForward location = findLocation(mapping, stop);
          return location;
      }</programlisting></para>
        </example>The entry point to an Action class is the
      <methodname>execute</methodname> method. Our execute method calls
      <methodname>getCommand</methodname> and
      <methodname>getContext</methodname> methods that we have defined to obtain
      the Command from the catalog and to build a Context based on the web
      request. Keeping life simple, we use the
      <classname>ServletWebContext</classname> bundled with Commons Chain.
      Depending on your needs, you might want to define your own specialized
      Context.(See "Create a Context" Recipe.) Our execute method then calls the
      command's <methodname>execute</methodname> method. We pass the return
      value of command.execute to our <methodname>findLocation</methodname>
      method, which determines "success" or "failure".</para>
  
      <para>Another way to write CommandAction would be to use the ActionMapping
      "<property>parameter</property>" property to indicate the Command name .
      To do that, we'd patch <methodname>getCommand</methodname> to call
      <methodname>mapping.getParameter()</methodname> instead of
      <methodname>getName()</methodname>, like this:<programlisting>  -     String name = mapping.getName();
    +     String name = mapping.getParameter();</programlisting></para>
  
      <para>(The minus sign means remove, or subtract, the line. The plus sign
      means insert, or add, the line. The Unix patch program follows this
      format.)</para>
  
      <para><remark>[Glossary: "patch" entry]</remark></para>
  
      <para>The "parameter" approach in the preceding example lets us name the
      form-beans independently of the Command name. But, a consequence is that
      we have to specify the Command name for each ActionMapping.
      (<emphasis>Bor-ring!</emphasis>) You could also merge the two approaches
      and return the parameter property only when it is used, like
      this:<programlisting>        String name = mapping.getParameter();
    +     if ((null==name) || (name=="")) name = mapping.getName();</programlisting></para>
  
      <para>Or you could mix and match the two approches, using CommandAction
      when the formbean name and the command name match, and a
      CommandParamterAction, when they do not. Struts allows you to use as many
      Actions, and standard Actions, as you like.</para>
  
      <para>Note that our Command is expected to do the "custom" work usually
      delegated to the Action. Consequently, we do not need to create an Action
      subclass for each task. We can use one or two standard Actions and have
      them call the appropriate Command class. A set of related tasks (or
      "story") might share an ActionForm class and a Command class, but, most
      often, the Actions can be standard, reusable Actions.</para>
  
      <para>Something else to note about Example 14 is that we use the
      "LocaleChange" token as the <property>path</property> attribute. This
      means that the story would be trigged by opening (for example) the
      "<filename>/LocaleChange.do</filename>" page. Even so, the path is
      <emphasis>not</emphasis> part of our <glossterm>semantic
      chain</glossterm>. The path is not a fully logical name that we control.
      The path token is shared with the container, and the container may have
      its own constraints on the path. (JAAS pattern matching, for example.) The
      path can't be part of our chain of keys, since it is shared with the
      container's "business logic".</para>
  
      <para><remark>[Glossary: <emphasis>Add "Semantic chain pattern"</emphasis>
      entry.]</remark></para>
  
      <para>Having used "LocaleChange" for everything else, using it for the
      path token seems natural. Most of us would do the same. But, the path can
      vary as needed, without upsetting the rest of the semantic chain. If the
      "path" needs to change to suit a change in the JAAS configuration, nothing
      else needs to change.</para>
  
      <para>Of course, there would be several other ways to call a Command from
      a Struts Action. Since the request is passed to the Action, it's easy to
      obtain a Catalog stored in application scope. Once you have access to the
      Catalog, the rest is easy.</para>
  
      <para>Other frameworks, like WebWorks and Maverick, have components
      similar to Struts Actions. Any of these components can be used to create a
      Context, access the Catalog, and execute a Command.</para>
    </section>
  
    <section>
      <title>Create a Controller</title>
  
      <para><emphasis>Problem:</emphasis> You want to base your application's
      <glossterm>Controller</glossterm> components on the Commons Chain of
      Command package.</para>
  
      <para><remark>[Glossary: <emphasis>Add "Controller pattern"</emphasis>
      entry, along with Application Controller and Front
      Controller.]</remark></para>
  
      <para><emphasis>Solution:</emphasis> Create a set of interfaces for a
      Controller package that can be implemented using base classes from the
      Chain of Command package.</para>
  
      <para><emphasis>Warning: Since we are creating a base package, this recipe
      is longer than most. Each individual component is simple enough, but there
      are several components to cover. Since the components are interrelated,
      covering them separately would be confusing. So, sit back, loosen your
      belt, and enjoy, while we whip up a "seven-course meal".</emphasis></para>
  
      <para><emphasis>Discussion:</emphasis> Many applications use
      implementations of the Controller pattern to field user requests.
      <productname>Core J2EE Patterns: Best Practices and Design
      Strategies</productname> <productnumber>[ISBN:
      0-13-142246-4]</productnumber> describes a controller as a component that
      "interacts with a client, controlling and managing the handling of each
      request." There are several flavors of controllers, including Application
      Controllers and Front Controllers. Many web application frameworks, like
      Apache Struts, utilize a Front Controller.</para>
  
      <para>Often, an implementation of the Controller pattern will in turn use
      the Command pattern or Chain of Command pattern. How can we use the
      Commons Chain of Command package to implement a Controller?</para>
  
      <para>Following the general description from Core J2EE Patterns, let's
      start by defining a test that passes a request to a controller and
      confirms that an appropriate response is returned.</para>
  
      <para>To write our test, we need to:<orderedlist>
          <listitem>
            <para>Create a Controller.</para>
          </listitem>
  
          <listitem>
            <para>Add a Handler for our Request to the Controller.</para>
          </listitem>
  
          <listitem>
            <para>Create a Request and pass it to the Controller.</para>
          </listitem>
  
          <listitem>
            <para>Confirm that the Request returns the expected Response.</para>
          </listitem>
        </orderedlist></para>
  
      <para>To simplify writing the test, lets make a few executive
      decisions:</para>
  
      <orderedlist>
        <listitem>
          <para>The Request and Response object have "name" properties.</para>
        </listitem>
  
        <listitem>
          <para>The name of a Response matches the name of its Request (a shared
          key).</para>
        </listitem>
  
        <listitem>
          <para>The test will be based on interfaces; implemented classes will
          extend Common Chain members.</para>
        </listitem>
  
        <listitem>
          <para>The Controller extends Catalog.</para>
        </listitem>
  
        <listitem>
          <para>The Request and Response extend Context.</para>
        </listitem>
  
        <listitem>
          <para>The Request Handler extends Command.</para>
        </listitem>
  
        <listitem>
          <para>For no particular reason, we'll call our controller package
          "Agility".</para>
        </listitem>
      </orderedlist>
  
      <para>Example 15 shows a <classname>ProcessingTest</classname> class with
      our <methodname>testRequestResponseNames</methodname> method.<example>
          <title>Test to assert that our Controller can process a Request and
          return an appropriate Response</title>
  
          <para><programlisting>package org.apache.commons.agility;
  
  import junit.framework.TestCase; 
  import org.apache.commons.agility.impl.ControllerCatalog;
  import org.apache.commons.agility.impl.HandlerCommand;
  import org.apache.commons.agility.impl.RequestContext;
  
  public class ProcessingTest extends TestCase {
  
      public void testRequestResponseName() {
          
          String NAME = "TestProcessing"; 
  
          Controller controller = new ControllerCatalog();
  
          RequestHandler handler = new HandlerCommand(NAME);
          controller.addHandler(handler);
          Request request = new RequestContext(NAME);
          controller.process(request);
          Response response = request.getResponse();
  
          assertNotNull(response);
          assertEquals(NAME, response.getName());
      }
  }</programlisting></para>
        </example>To compile the ProcessingTest class, we will need interface
      members for <classname>Controller</classname>,
      <classname>RequestHandler</classname>, <classname>Request</classname>, and
      <classname>Response</classname>, and class members for
      <classname>ControllerCatalog</classname>,
      <classname>HandlerCommand</classname>, and
      <classname>RequestContext</classname>. Figure 7 shows the UML for the four
      interfaces.<figure>
          <title>The four interfaces needed to realize ProcessingTest</title>
  
          <olink><remark>[TODO: UML for Controller, RequestHandler, Request, and
          Response ]</remark></olink>
        </figure></para>
  
      <para>Referring to the UML in Figure 7, we can write the code for our
      interface members, as shown in Example 16. <example>
          <title>To compile ProcessTest, we need to define four
          interfaces.</title>
  
          <para><programlisting>// Controller.java
  package org.apache.commons.agility;
  public interface Controller {
      void addHandler(RequestHandler handler);
      RequestHandler getHandler(String name) throws ProcessException;
      void process(Request request) throws ProcessException;
  }
  
  // Request.java
  package org.apache.commons.agility;
  public interface Request {
      String getName();
      Response getResponse();
      void setResponse(Response response);
  }
  
  // Response.java
  package org.apache.commons.agility;
  public interface Response {
      String getName();
  }
  
  // RequestHandler.java
  package org.apache.commons.agility;
  public interface RequestHandler {
      String getName();
      void handle(Request request) throws ProcessException;
  }
  
  // ProcessException.java
  package org.apache.commons.agility;
  public class ProcessException extends Exception {
      public ProcessException(Throwable cause) {
          super(cause);
      }
  }</programlisting></para>
        </example></para>
  
      <para>With the interfaces out of the way, we can turn to the classes we
      need to implement. The UML for the class members we need is shown as
      Figure 8. <figure>
          <title>The thee classes needed to realize ProcessingTest.</title>
  
          <olink><remark>[TODO: UML for ControllerCatalog, RequestContext, and
          HandlerCommand.]</remark></olink>
        </figure></para>
  
      <para>If we create the classes indicated by Figure 8, and stub-out the
      methods, we can get the code to compile. The test will run, but skeleton
      classes won't pass muster. Let's implement each class, starting with
      HandlerCommand, which is shown as Example 17.</para>
  
      <para><example>
          <title>HandlerCommand provides default behavior that subclasses can
          override</title>
  
          <para><programlisting>package org.apache.commons.agility.impl;
  
  import org.apache.commons.agility.ProcessException;
  import org.apache.commons.agility.Request;
  import org.apache.commons.agility.RequestHandler;
  import org.apache.commons.agility.Response;
  import org.apache.commons.chain.Command;
  import org.apache.commons.chain.Context;
  
  public class HandlerCommand implements Command, RequestHandler {
      String name =  null;
  
      public HandlerCommand(String name) {
          this.name = name;
      }
  
      public String getName() {
          return name;
      }
  
      public boolean execute(Context context) throws Exception {
          handle((Request) context);
          return true;
      }
  
      public void handle(Request request) throws ProcessException {
          try {
              String name = request.getName();
              Response response = new ResponseContext(name);
              request.setResponse(response);
          } catch (Exception e) {
              throw new ProcessException(e);
          }
      }
  }</programlisting></para>
        </example>The <methodname>handle(Request)</methodname> method of
      HandlerCommand realizes the prime responsibility for this class: create a
      Response for the Request. The execute(Context) method is an
      <glossterm>adapter</glossterm> that delegates to the handle method. Now we
      can call execute or handle and achieve the same result. The constructor
      assigns each instance of HandlerCommand a name so that it can be matched
      with a Request.</para>
  
      <para><remark><remark>[Glossary: "apapter pattern"
      entry]</remark></remark></para>
  
      <para>The handle(Request) method shown here is not very useful. However,
      it will pass our test and prove the infrastructure is working. Subclasses
      can override handle(Request) to create the appropriate Response for a
      given Request. Since HandlerCommands are still Commands, we can itemize
      our HandlerCommand subclasses as metadata (an XML document). This will
      make it easy to handle new Requests as our application grows.</para>
  
      <para>The HandlerCommand class creates a ResponseContext instance and sets
      it as the Response. The ResponseContext class is shown as Example
      18.</para>
  
      <para><example>
          <title>Many other implementations of ResponseContext are possible.
          They just need to implement Response and extend ContextBase.</title>
  
          <para><programlisting>package org.apache.commons.agility.impl;
  
  import org.apache.commons.agility.Response;
  import org.apache.commons.chain.impl.ContextBase;
  
  public class ResponseContext extends ContextBase implements Response {
  
      private String name;
  
      public ResponseContext(String name) {
          super();
          this.name = name;
      }
  
      public String getName() {
          return name;
      }
  }</programlisting></para>
        </example>Since we're just testing the infrastructure, our
      ResponseContext is rudimentary. A Front Controller for a web application
      framework might define several attributes for a Response, such as the
      location of a server page. The RequestHandler can create any kind of
      Response object that might be needed.</para>
  
      <para>Whatever RequestHandlers we need are added to the Catalog, either as
      metadata or programatically. Our tests add the handler programatically, so
      we need to implement the AddHandler method. Example 19 shows our
      implementation of CatalogController. <example>
          <title>RequestHandlers can be added to the CatalogController
          programatically or through metadata</title>
  
          <para><programlisting>package org.apache.commons.agility.impl;
  
  import org.apache.commons.agility.Controller;
  import org.apache.commons.agility.ProcessException;
  import org.apache.commons.agility.Request;
  import org.apache.commons.agility.RequestHandler;
  import org.apache.commons.chain.impl.CatalogBase;
  import org.apache.commons.chain.Command;
  
  public class ControllerCatalog extends CatalogBase implements Controller {
      public RequestHandler getHandler(String name) {
          return (RequestHandler) getCommand(request.getName());
      }
  
      public void addHandler(RequestHandler handler) {
          this.addCommand(handler.getName(), (Command) handler);
      }
  
      public void process(Request request) throws ProcessException {
          Handler handler = getHandler(request.getName());
          if (handler != null) handler.handle(request);
      }
  }</programlisting></para>
        </example>The main entry point to our Controller is the
      <methodname>process(Request)</methodname> method. This method could host a
      great deal of functionality. We could even implement the process method as
      a series of Commands or Chains of Commands. An application could then
      fine-tune the request processing by specifying different Commands in a
      metadata catalog. The Struts web application framework uses this approach
      for its request processor.</para>
  
      <para>But for now, we just want to pass our test. All the process method
      needs to do is find the RequestHandler and call its handle(Request)
      method. We can do that just by looking up the name of the Request in our
      catalog and retrieving the matching RequestHandler (or Command).</para>
  
      <para>The <methodname>addHandler(RequestHandler)</methodname> method is
      another adapter that delegates to an inherited method. In this case,
      addHandler calls <methodname>addCommand(String,Command)</methodname>.
      Since our RequestHandlers are Commands, they can be passed to the
      superclass method. The <methodname>getHandler(String)</methodname> method
      is yet another adapter/delegate.</para>
  
      <para>Last but not least is the RequestContext class, shown as Example
      20.</para>
  
      <para><example>
          <title>RequestContext ties it all together</title>
  
          <para><programlisting>package org.apache.commons.agility.impl;
  
  import org.apache.commons.agility.Request;
  import org.apache.commons.agility.Response;
  import org.apache.commons.chain.impl.ContextBase;
  
  public class RequestContext extends ContextBase implements Request {
  
      private String name;
      private Response response;
  
      public RequestContext(String name) {
          super();
          this.name = name;
      }
  
      public String getName() {
          return name;
      }
  
      public Response getResponse() {
          return response;
      }
  
      public void setResponse(Response response) {
          this.response = response;
      }
  }</programlisting></para>
        </example>Like the ResponseContext, an application could add several
      properties to its Request class. A web application might wrap or transfer
      attributes from the HttpServletRequest. But so long as the class
      implements Request and Context, it will plug into our Controller
      implementation.</para>
  
      <para>Using the interfaces and base classes shown here, you can create
      whatever Controllers you need.</para>
    </section>
  
    <section>
      <title>Call a Command From a Servlet</title>
  
      <para><emphasis>Problem:</emphasis> You would like to call commands during
      your application using a servlet.</para>
  
      <para><emphasis>Solution:</emphasis> Use the Listener from the "Load a
      Catalog from a Web Application" recipe to setup a list of Commands, and
      the Controller from the "Create a Controller" recipe to process the
      request.</para>
  
      <para><emphasis>Discussion: [<remark>TODO:]</remark></emphasis></para>
  
      <para>###</para>
    </section>
  </article>
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org