| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" |
| "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> |
| <article> |
| <title>Apache 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 & 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 Apache Commons [<link |
| linkend="???">http://commons.apache.org/</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 Apache 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><?xml version="1.0" ?> |
| <chains> |
| <command |
| name="LocaleChange" |
| className="org.apache.commons.chain.mailreader.commands.LocaleChange"/> |
| <command |
| name="LogonUser" |
| className="org.apache.commons.chain.mailreader.commands.LogonUser"/> |
| </chains></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><chains> |
| <chain name="LocaleChange"> |
| <command |
| className="org.apache.commons.chain.mailreader.commands.ProfileCheck"/> |
| <command |
| className="org.apache.commons.chain.mailreader.commands.LocaleChange"/> |
| </chain> |
| <command |
| name="LogonUser" |
| className="org.apache.commons.chain.mailreader.commands.LogonUser"/> |
| </chains></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> <!-- Commons Chain listener to load catalogs --> |
| <context-param> |
| <param-name>org.apache.commons.chain.CONFIG_CLASS_RESOURCE</param-name> |
| <param-value>resources/catalog.xml</param-value> |
| </context-param> |
| <listener> |
| <listener-class>org.apache.commons.chain.web.ChainListener</listener-class> |
| </listener></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><!-- ... --> |
| |
| <build> |
| <sourceDirectory>src/java</sourceDirectory> |
| <resources> |
| <resource> |
| <directory>${basedir}/src/resources/chain</directory> |
| <targetPath>resources</targetPath> |
| <includes> |
| <include>catalog.xml</include> |
| </includes> |
| </resource> |
| </resources> |
| </build> |
| |
| <!-- ... --></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><!-- catalog.xml --> |
| <?xml version="1.0" ?> |
| <chains> |
| <command |
| name="<emphasis>LocaleChange</emphasis>" |
| className="org.apache.commons.chain.mailreader.commands.LocaleChange" /> |
| </chains> |
| |
| <!-- validation.xml --> |
| <?xml version="1.0" ?> |
| <!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"> |
| <form-validation> |
| <formset> |
| <form name="<emphasis>LocaleChange</emphasis>"> |
| <field property="language" depends="required"> |
| <arg0 key="prompt.language"/> |
| </field> |
| </form> |
| </formset> |
| </form-validation> |
| |
| <!-- struts-config.xml --> |
| <?xml version="1.0" ?> |
| <!DOCTYPE struts-config PUBLIC |
| "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" |
| "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd"> |
| <struts-config> |
| <form-beans> |
| <form-bean |
| name="<emphasis>LocaleChange</emphasis>" |
| type="org.apache.struts.validator.DynaValidatorForm"> |
| <form-property name="language" type="java.lang.String"/> |
| <form-property name="country" type="java.lang.String"/> |
| </form-bean> |
| </form-beans> |
| <action-mappings> |
| <action path="/LocaleChange" |
| name="<emphasis>LocaleChange</emphasis>" |
| type="org.apache.commons.chain.mailreader.struts.CommandAction"> |
| <forward name="success" path="/Welcome.do" /> |
| </action> |
| </action-mappings> |
| <struts-config></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> |