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

cvs commit: jakarta-commons/chain/src/java/org/apache/commons/chain/generic DispatchCommand.java

germuska    2005/01/07 13:10:30

  Added:       chain/src/test/org/apache/commons/chain/generic
                        DispatchCommandTestCase.java
               chain/src/java/org/apache/commons/chain/generic
                        DispatchCommand.java
  Log:
  add DispatchCommand and test case
  
  Revision  Changes    Path
  1.1                  jakarta-commons/chain/src/test/org/apache/commons/chain/generic/DispatchCommandTestCase.java
  
  Index: DispatchCommandTestCase.java
  ===================================================================
  package org.apache.commons.chain.generic;
  
  import junit.framework.TestCase;
  import org.apache.commons.chain.Context;
  import org.apache.commons.chain.impl.ContextBase;
  
  /* JUnitTest case for class: org.apache.commons.chain.generic.DispatchCommand */
  public class DispatchCommandTestCase extends TestCase {
  
      public DispatchCommandTestCase(String _name) {
          super(_name);
      }
  
      /* setUp method for test case */
      protected void setUp() {
      }
  
      /* tearDown method for test case */
      protected void tearDown() {
      }
  
      /* Executes the test case */
      public static void main(String[] argv) {
          String[] testCaseList = {DispatchCommandTestCase.class.getName()};
          junit.textui.TestRunner.main(testCaseList);
      }
  
      public void testMethodDispatch() throws Exception {
          TestCommand test = new TestCommand();
  
          test.setMethod("testMethod");
          Context context = new ContextBase();
          assertNull(context.get("foo"));
          boolean result = test.execute(context);
          assertTrue(result);
          assertNotNull(context.get("foo"));
          assertEquals("foo", context.get("foo"));
  
  
      }
  
  
      public void testMethodKeyDispatch() throws Exception {
          TestCommand test = new TestCommand();
  
          test.setMethodKey("foo");
          Context context = new ContextBase();
          context.put("foo", "testMethodKey");
          assertNull(context.get("bar"));
          boolean result = test.execute(context);
          assertFalse(result);
          assertNotNull(context.get("bar"));
          assertEquals("bar", context.get("bar"));
  
  
      }
  
      public void testAlternateContext() throws Exception {
          TestAlternateContextCommand test = new TestAlternateContextCommand();
  
          test.setMethod("foo");
          Context context = new ContextBase();
          assertNull(context.get("elephant"));
          boolean result = test.execute(context);
          assertTrue(result);
          assertNotNull(context.get("elephant"));
          assertEquals("elephant", context.get("elephant"));
  
  
      }
  
      
      class TestCommand extends DispatchCommand {
          
  
          public boolean testMethod(Context context) {
              context.put("foo", "foo");
              return true;
          }
  
          public boolean testMethodKey(Context context) {
              
              context.put("bar", "bar");
              return false;
          }
  
      }
  
      /**
       * Command which uses alternate method signature.
       * <p>Title: Commons Chain</p>
       * <p>Description: An implmentation of the GoF Chain of Responsibility pattern</p>
       * <p>Copyright: Copyright (c) 2003-2004 The Apache Software Foundation - All Rights Reserved.</p>
       * <p>Company: The Apache Software Foundation</p>
       * @author germuska
       * @version 0.2-dev
       */
      class TestAlternateContextCommand extends DispatchCommand {
  
  
          protected Class[] getSignature() {
              return new Class[] { TestAlternateContext.class };
          }
  
          protected Object[] getArguments(Context context) {
              return new Object[] { new TestAlternateContext(context) };
          }
  
          public boolean foo(TestAlternateContext context) {
              context.put("elephant", "elephant");
              return true;
          }
          
      }
  
  
      class TestAlternateContext extends java.util.HashMap implements Context {
          Context wrappedContext = null;
           TestAlternateContext(Context context) {
              this.wrappedContext = context;
          }
  
          public Object get(Object o) {
              return this.wrappedContext.get(o);
          }
  
          public Object put(Object key, Object value) {
              return this.wrappedContext.put(key, value);
          }
  
      }
  }
  
  
  1.1                  jakarta-commons/chain/src/java/org/apache/commons/chain/generic/DispatchCommand.java
  
  Index: DispatchCommand.java
  ===================================================================
  package org.apache.commons.chain.generic;
  
  import org.apache.commons.chain.Command;
  import org.apache.commons.chain.Context;
  import java.lang.reflect.Method;
  import java.util.WeakHashMap;
  import java.lang.reflect.InvocationTargetException;
  
  /**
   * An abstract base command which uses introspection to look up a method to execute.  
   * For use by developers who prefer to group related functionality into a single class
   * rather than an inheritance family.
   */
  public abstract class DispatchCommand implements Command {
  
      protected WeakHashMap methods = new WeakHashMap();
  
      protected String method = null;
  
      protected String methodKey = null;
  
      /**
       * The base implementation expects dispatch methods to take a <code>Context</code>
       * as their only argument.
       */
      protected static final Class[] DEFAULT_SIGNATURE = new Class[] { Context.class };
  
  
      /**
       * Look up the method specified by either "method" or "methodKey" and invoke it,
       * returning a boolean value as interpreted by <code>evaluateResult</code>.
       * @param context
       * @return
       * @throws Exception
       */
      public boolean execute(Context context) throws Exception {
  
          if (this.getMethod() == null && this.getMethodKey() == null) {
              throw new IllegalStateException("Neither 'method' nor 'methodKey' properties are defined ");
          }
  
          Method methodObject = extractMethod(context);
  
          return evaluateResult(methodObject.invoke(this, getArguments(context)));
      }
  
      /**
       * Extract the dispatch method.  The base implementation uses the command's 
       * <code>method</code> property at the name of a method to look up, or, if that is not defined,
       * 
       * and <code>methodKey</code>
       * @param context
       * @return
       * @throws NoSuchMethodException if no method can be found under the specified name.
       * @throws NullPointerException if no methodName can be determined
       */
      protected Method extractMethod(Context context) throws NoSuchMethodException {
  
          String methodName = this.getMethod();
  
          if (methodName == null) {
              Object methodContextObj = context.get(this.getMethodKey());
              if (methodContextObj == null) {
                  throw new NullPointerException("No value found in context under " + this.getMethodKey());
              }
              methodName = methodContextObj.toString();
          }
  
  
          Method theMethod = null;
  
          synchronized (methods) {
              theMethod = (Method) methods.get(methodName);
  
              if (theMethod == null) {
                  theMethod = getClass().getMethod(methodName, getSignature());
                  methods.put(methodName, theMethod);
              }
          }
  
          return theMethod;
      }
  
      /**
       * Evaluate the result of the method invocation as a boolean value.  Base implementation
       * expects that the invoked method returns boolean true/false, but subclasses might
       * implement other interpretations.
       * @param o
       * @return
       */
      protected boolean evaluateResult(Object o) {
          
          Boolean result = (Boolean) o;
          return (result != null && result.booleanValue());
          
      }
  
      /**
       * Return a <code>Class[]</code> describing the expected signature of the method 
       * @return
       */
      protected Class[] getSignature() {
          return DEFAULT_SIGNATURE;
      }
      
      /**
       * Get the arguments to be passed into the dispatch method.  
       * Default implementation simply returns the context which was passed in, but subclasses
       * could use this to wrap the context in some other type, or extract key values from the 
       * context to pass in.  The length and types of values returned by this must coordinate
       * with the return value of <code>getSignature()</code>
       * @param context
       * @return
       */
      protected Object[] getArguments(Context context) {
          return new Object[] { context };
      }
  
      public String getMethod() {
          return method;
      }
      public String getMethodKey() {
          return methodKey;
      }
      public void setMethod(String method) {
          this.method = method;
      }
      public void setMethodKey(String methodKey) {
          this.methodKey = methodKey;
      }
  
      
  
  }
  
  

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