You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hivemind.apache.org by hl...@apache.org on 2005/01/16 01:40:22 UTC

cvs commit: jakarta-hivemind/library/src/descriptor/META-INF hivemodule.xml

hlship      2005/01/15 16:40:22

  Modified:    src/documentation/content/xdocs links.ent site.xml
               .        status.xml
               library/src/descriptor/META-INF hivemodule.xml
  Added:       library/src/test/org/apache/hivemind/lib/chain
                        TestChainBuilder.java ChainInterface.java
               library/src/java/org/apache/hivemind/lib/chain
                        ChainBuilder.java ChainBuilderImpl.java
               library/src/documentation/content/xdocs/hivemind-lib
                        ChainBuilder.xml
  Log:
  Add hivemind.lib.ChainBuilder service, an implementation of Gang Of Four Chain of Command.
  
  Revision  Changes    Path
  1.21      +2 -1      jakarta-hivemind/src/documentation/content/xdocs/links.ent
  
  Index: links.ent
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/src/documentation/content/xdocs/links.ent,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- links.ent	11 Nov 2004 14:13:45 -0000	1.20
  +++ links.ent	16 Jan 2005 00:40:22 -0000	1.21
  @@ -155,4 +155,5 @@
   
   <!ENTITY hivemind.lib.EJBProxyFactory '<link href="site:hivemind.lib.EJBProxyFactory">hivemind.lib.EJBProxyFactory</link>'>
   <!ENTITY hivemind.lib.NameLookup '<link href="site:hivemind.lib.NameLookup">hivemind.lib.NameLookup</link>'>
  -<!ENTITY hivemind.lib.RemoteExceptionCoordinator '<link href="site:hivemind.lib.RemoteExceptionCoordinator">hivemind.lib.RemoteExceptionCoordinator</link>'>
  \ No newline at end of file
  +<!ENTITY hivemind.lib.RemoteExceptionCoordinator '<link href="site:hivemind.lib.RemoteExceptionCoordinator">hivemind.lib.RemoteExceptionCoordinator</link>'>
  +<!ENTITY hivemind.lib.ChainBuilder '<link href="site:hivemind.lib.ChainBuilder">hivemind.lib.ChainBuilder</link>'>
  \ No newline at end of file
  
  
  
  1.38      +1 -0      jakarta-hivemind/src/documentation/content/xdocs/site.xml
  
  Index: site.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/src/documentation/content/xdocs/site.xml,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- site.xml	5 Jan 2005 21:53:31 -0000	1.37
  +++ site.xml	16 Jan 2005 00:40:22 -0000	1.38
  @@ -116,6 +116,7 @@
   		<services label="Services">
         <hivemind.lib.AdapterRegistryFactory label="AdapterRegistryFactory" href="AdapterRegistryFactory.html"/>
         <hivemind.lib.BeanFactoryBuilder label="BeanFactoryBuilder" href="BeanFactoryBuilder.html"/>
  +      <hivemind.lib.ChainBuilder label="ChainBuilder" href="ChainBuilder.html"/>
         <hivemind.lib.DefaultImplementationBuilder label="DefaultImplementationBuilder" href="DefaultImplementationBuilder.html"/>
   			<hivemind.lib.EJBProxyFactory label="EJBProxyFactory" href="EJBProxyFactory.html"/>
   			<hivemind.lib.NameLookup label="NameLookup" href="NameLookup.html"/>
  
  
  
  1.1                  jakarta-hivemind/library/src/test/org/apache/hivemind/lib/chain/TestChainBuilder.java
  
  Index: TestChainBuilder.java
  ===================================================================
  // Copyright 2005 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package org.apache.hivemind.lib.chain;
  
  import java.lang.reflect.Modifier;
  import java.util.ArrayList;
  import java.util.List;
  
  import org.apache.hivemind.Registry;
  import org.apache.hivemind.impl.RegistryBuilder;
  import org.apache.hivemind.service.BodyBuilder;
  import org.apache.hivemind.service.ClassFab;
  import org.apache.hivemind.service.MethodFab;
  import org.apache.hivemind.service.MethodSignature;
  import org.apache.hivemind.test.HiveMindTestCase;
  import org.easymock.MockControl;
  
  /**
   * Tests for {@link org.apache.hivemind.lib.chain.ChainBuilderImpl}.
   * 
   * @author Howard M. Lewis Ship
   * @since 1.1
   */
  public class TestChainBuilder extends HiveMindTestCase
  {
      public void testDefaultforReturnType()
      {
          ChainBuilderImpl cb = new ChainBuilderImpl();
  
          assertEquals("null", cb.defaultForReturnType(Object.class));
          assertEquals("false", cb.defaultForReturnType(boolean.class));
          assertEquals("null", cb.defaultForReturnType(Boolean.class));
          assertEquals("null", cb.defaultForReturnType(boolean[].class));
          assertEquals("0", cb.defaultForReturnType(int.class));
          assertEquals("null", cb.defaultForReturnType(Integer.class));
      }
  
      private MethodFab newMethodFab()
      {
          return (MethodFab) newMock(MethodFab.class);
      }
  
      /**
       * Tests adding a void method, also tests creation of a toString() method.
       */
      public void testAddVoidMethod()
      {
          MockControl cfc = newControl(ClassFab.class);
          ClassFab cf = (ClassFab) cfc.getMock();
  
          MethodSignature sig = new MethodSignature(void.class, "run", null, null);
  
          BodyBuilder builder = new BodyBuilder();
          builder.begin();
          builder.addln("java.util.Iterator i = _commands.iterator();");
          builder.addln("while (i.hasNext())");
          builder.begin();
          builder.addln("java.lang.Runnable command = (java.lang.Runnable) i.next();");
          builder.addln("command.run($$);");
          builder.end();
          builder.end();
  
          cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
          cfc.setReturnValue(newMethodFab());
  
          replayControls();
  
          ChainBuilderImpl cb = new ChainBuilderImpl();
  
          cb.addMethod(cf, Runnable.class, sig);
  
          verifyControls();
      }
  
      public void testAddNonVoidMethod()
      {
          MockControl cfc = newControl(ClassFab.class);
          ClassFab cf = (ClassFab) cfc.getMock();
  
          MethodSignature sig = new MethodSignature(boolean.class, "execute", new Class[]
          { String.class }, null);
  
          BodyBuilder builder = new BodyBuilder();
          builder.begin();
          builder.addln("boolean result = false;");
          builder.addln("java.util.Iterator i = _commands.iterator();");
          builder.addln("while (i.hasNext())");
          builder.begin();
          builder
                  .addln("org.apache.hivemind.lib.chain.ChainInterface command = (org.apache.hivemind.lib.chain.ChainInterface) i.next();");
          builder.addln("result = command.execute($$);");
          builder.addln("if (result != false) break;");
          builder.end();
          builder.addln("return result;");
          builder.end();
  
          cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
          cfc.setReturnValue(newMethodFab());
  
          replayControls();
  
          ChainBuilderImpl cb = new ChainBuilderImpl();
  
          cb.addMethod(cf, ChainInterface.class, sig);
  
          verifyControls();
      }
  
      /**
       * Test it all together inside the descriptor.
       */
  
      private ChainInterface newCommand(String parameter, boolean returnValue)
      {
          MockControl control = newControl(ChainInterface.class);
          ChainInterface chain = (ChainInterface) control.getMock();
  
          chain.execute(parameter);
          control.setReturnValue(returnValue);
  
          return chain;
      }
  
      public void testIntegration()
      {
          Registry r = RegistryBuilder.constructDefaultRegistry();
  
          ChainBuilder cb = (ChainBuilder) r.getService(ChainBuilder.class);
  
          List commands = new ArrayList();
  
          commands.add(newCommand("fred", false));
          commands.add(newCommand("fred", false));
  
          ChainInterface chain = (ChainInterface) cb.buildImplementation(
                  ChainInterface.class,
                  commands,
                  "<Chain>");
  
          replayControls();
  
          assertEquals(false, chain.execute("fred"));
          assertEquals("<Chain>", chain.toString());
  
          verifyControls();
      }
  
      /**
       * Confirm that proceses of commands stops with the first one that returns a non-default value
       * (i.e., true).
       */
  
      public void testIntegrationWithCancel()
      {
          Registry r = RegistryBuilder.constructDefaultRegistry();
  
          ChainBuilder cb = (ChainBuilder) r.getService(ChainBuilder.class);
  
          List commands = new ArrayList();
  
          commands.add(newCommand("barney", true));
          commands.add(newMock(ChainInterface.class));
  
          ChainInterface chain = (ChainInterface) cb.buildImplementation(
                  ChainInterface.class,
                  commands,
                  "<Chain>");
  
          replayControls();
  
          assertEquals(true, chain.execute("barney"));
  
          verifyControls();
      }
  
  }
  
  
  1.1                  jakarta-hivemind/library/src/test/org/apache/hivemind/lib/chain/ChainInterface.java
  
  Index: ChainInterface.java
  ===================================================================
  // Copyright 2005 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package org.apache.hivemind.lib.chain;
  
  /**
   * Used to test {@link org.apache.hivemind.lib.chain.ChainBuilderImpl}.
   * 
   * @author Howard M. Lewis Ship
   * @since 3.1
   */
  public interface ChainInterface
  {
      public boolean execute(String parameter);
  }
  
  
  1.1                  jakarta-hivemind/library/src/java/org/apache/hivemind/lib/chain/ChainBuilder.java
  
  Index: ChainBuilder.java
  ===================================================================
  // Copyright 2005 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package org.apache.hivemind.lib.chain;
  
  import java.util.List;
  
  /**
   * Service interface for <code>hivemind.lib.ChainBuilder</code>, a service which can assemble an
   * implementation based on a command interface, and an ordered list of objects implementing that
   * interface (the "commands"). This is an implementation of the Gang of Four Chain Of Command
   * pattern.
   * <p>
   * For each method in the interface, the chain implementation will call the corresponding method on
   * each command object in turn. If any of the command objects return true, then the chain of command
   * stops and the initial method invocation returns true. Otherwise, the chain of command continues
   * to the next command (and will return false if none of the commands returns true).
   * <p>
   * For methods whose return type is not boolean, the chain stops with the first non-null (for object
   * types), or non-zero (for numeric types). The chain returns the value that was returned by the
   * command. The chain If the method return type is void, all command will be invoked.
   * <p>
   * Method invocations will also be terminated if an exception is thrown.
   * 
   * @author Howard M. Lewis Ship
   * @since 1.1
   */
  public interface ChainBuilder
  {
      /**
       * Builds an implementation.
       * 
       * @param commandInterface
       *            the interface the implementation implements.
       * @param commands
       *            a non-null list of command objects implementing the interface.
       * @param toString
       *            The value to be returned from the implementation's <code>toString()</code>
       *            method (unless <code>toString()</code> is expressly part of the service
       *            interface, in which case it is treated as any other method.
       */
      public Object buildImplementation(Class commandInterface, List commands, String toString);
  }
  
  
  1.1                  jakarta-hivemind/library/src/java/org/apache/hivemind/lib/chain/ChainBuilderImpl.java
  
  Index: ChainBuilderImpl.java
  ===================================================================
  // Copyright 2005 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package org.apache.hivemind.lib.chain;
  
  import java.lang.reflect.Modifier;
  import java.util.List;
  
  import org.apache.hivemind.service.BodyBuilder;
  import org.apache.hivemind.service.ClassFab;
  import org.apache.hivemind.service.ClassFabUtils;
  import org.apache.hivemind.service.ClassFactory;
  import org.apache.hivemind.service.MethodIterator;
  import org.apache.hivemind.service.MethodSignature;
  import org.apache.hivemind.util.ConstructorUtils;
  import org.apache.hivemind.util.Defense;
  
  /**
   * TODO: All implementations for a given interface are identical, so we could (should?) cache those
   * implementations.
   * 
   * @author Howard M. Lewis Ship
   * @since 3.1
   */
  public class ChainBuilderImpl implements ChainBuilder
  {
      private ClassFactory _classFactory;
  
      public Object buildImplementation(Class commandInterface, List commands, String toString)
      {
          Defense.notNull(commandInterface, "commandInterface");
          Defense.notNull(commands, "commands");
          Defense.notNull(toString, "toString");
  
          String name = ClassFabUtils.generateClassName(commandInterface);
  
          ClassFab cf = _classFactory.newClass(name, Object.class);
  
          addInfrastructure(cf, commandInterface);
  
          addMethods(cf, commandInterface, toString);
  
          return createInstance(cf, commands, toString);
      }
  
      void addInfrastructure(ClassFab cf, Class commandInterface)
      {
          cf.addInterface(commandInterface);
          cf.addField("_commands", List.class);
          cf.addField("_toString", String.class);
  
          cf.addConstructor(new Class[]
          { List.class, String.class }, null, "{ _commands = $1; _toString = $2; }");
      }
  
      private Object createInstance(ClassFab cf, List commands, String toString)
      {
          Class instanceClass = cf.createClass();
  
          return ConstructorUtils.invokeConstructor(instanceClass, new Object[]
          { commands, toString });
      }
  
      void addMethods(ClassFab cf, Class commandInterface, String toString)
      {
          MethodIterator mi = new MethodIterator(commandInterface);
  
          while (mi.hasNext())
          {
              MethodSignature sig = mi.next();
  
              addMethod(cf, commandInterface, sig);
          }
  
          if (!mi.getToString())
              addToString(cf, toString);
      }
  
      void addMethod(ClassFab cf, Class commandInterface, MethodSignature sig)
      {
          Class returnType = sig.getReturnType();
  
          if (returnType.equals(void.class))
          {
              addVoidMethod(cf, commandInterface, sig);
              return;
          }
  
          String defaultValue = defaultForReturnType(returnType);
  
          BodyBuilder builder = new BodyBuilder();
          builder.begin();
  
          builder
                  .addln(
                          "{0} result = {1};",
                          ClassFabUtils.getJavaClassName(returnType),
                          defaultValue);
          builder.addln("java.util.Iterator i = _commands.iterator();");
          builder.addln("while (i.hasNext())");
  
          builder.begin();
          builder.addln("{0} command = ({0}) i.next();", commandInterface.getName());
          builder.addln("result = command.{0}($$);", sig.getName());
  
          builder.addln("if (result != {0}) break;", defaultValue);
  
          builder.end();
  
          builder.addln("return result;");
          builder.end();
  
          cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
      }
  
      String defaultForReturnType(Class returnType)
      {
          // For all object and array types.
  
          if (!returnType.isPrimitive())
              return "null";
  
          if (returnType.equals(boolean.class))
              return "false";
  
          // Assume, then, that it is a numeric type (this method
          // isn't called for void).
  
          return "0";
      }
  
      private void addVoidMethod(ClassFab cf, Class commandInterface, MethodSignature sig)
      {
          BodyBuilder builder = new BodyBuilder();
  
          builder.begin();
  
          builder.addln("java.util.Iterator i = _commands.iterator();");
          builder.addln("while (i.hasNext())");
  
          builder.begin();
  
          builder.addln("{0} command = ({0}) i.next();", commandInterface.getName());
          builder.addln("command.{0}($$);", sig.getName());
  
          builder.end();
  
          builder.end();
  
          cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
      }
  
      void addToString(ClassFab cf, String toString)
      {
          MethodSignature sig = new MethodSignature(String.class, "toString", null, null);
  
          cf.addMethod(Modifier.PUBLIC, sig, "return _toString;");
      }
  
      public void setClassFactory(ClassFactory classFactory)
      {
          _classFactory = classFactory;
      }
  }
  
  
  1.92      +5 -2      jakarta-hivemind/status.xml
  
  Index: status.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/status.xml,v
  retrieving revision 1.91
  retrieving revision 1.92
  diff -u -r1.91 -r1.92
  --- status.xml	10 Jan 2005 13:14:59 -0000	1.91
  +++ status.xml	16 Jan 2005 00:40:22 -0000	1.92
  @@ -134,7 +134,7 @@
         <action type="add" dev="HLS">
           Allow services to be serialized (that is, service proxies can be serialized and
           deserialized).
  -      </action>     
  +      </action>   
           <action type="fix" dev="KW" fixes-bug="HIVEMIND-15" due-to="James Carman">
             Smart translator properly returns attribute values as Strings when used with
             a &lt;push-attribute&gt; rule.
  @@ -142,7 +142,10 @@
           <action type="fix" dev="KW" fixes-bug="HIVEMIND-57">
             Attribute values are symbol-expanded by a &lt;push-attribute&gt; rule before being
             translated and pushed on the stack.
  -        </action>
  +        </action> 
  +      <action type="add" dev="HLS">
  +        Add hivemind.lib.ChainBuilder service, an implementation of Gang Of Four Chain of Command.
  +      </action> 
       </release>
   
      <release version="1.0" date="Sep 22 2004">
  
  
  
  1.1                  jakarta-hivemind/library/src/documentation/content/xdocs/hivemind-lib/ChainBuilder.xml
  
  Index: ChainBuilder.xml
  ===================================================================
  <?xml version="1.0"?>
  <!-- 
     Copyright 2005 The Apache Software Foundation
  
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
         http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.3//EN" 
    "http://xml.apache.org/forrest/dtd/document-v13.dtd" [
    <!ENTITY projectroot '../'>
    <!ENTITY % common-links SYSTEM "../links.ent">
    %common-links;
    ]>
  <document>
    <header>
      <title>hivemind.lib.ChainBuilder Service</title>
    </header>
    <body>
      <p>The <link href="&hivedoc;/service/hivemind.lib.ChainBuilder.html">ChainBuilder</link> service implements the 
        Gang of Four <em>Chain of Command</em> pattern. </p>
      <p> The ChainBuilder is provided with: </p>
      <ul>
        <li>A command interface</li>
        <li>A list of <em>commands</em> that implements the command interface</li>
        <li>A <em>toString</em> value (to be returned by the chain in response to <code>toString()</code>)</li>
      </ul>
      <p> From this, the ChainBuilder creates a new chain implementation object. The chain object implements the command 
        interface. </p>
      <p> Invoking a method on the chain object will, in turn, re-invoke the same method, with the same parameters, on 
        each command object. </p>
      <p> If a command object returns a value that is not null, false or 0, then the chain terminates and returns that 
        value. Command methods may take any number of parameters and may return any value type (including void).</p>
      <p> Commands are free to throw a checked or unchecked exception; these are not caught by the chain. </p>
    </body>
  </document>
  
  
  1.20      +15 -0     jakarta-hivemind/library/src/descriptor/META-INF/hivemodule.xml
  
  Index: hivemodule.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/library/src/descriptor/META-INF/hivemodule.xml,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- hivemodule.xml	6 Jan 2005 01:45:16 -0000	1.19
  +++ hivemodule.xml	16 Jan 2005 00:40:22 -0000	1.20
  @@ -374,4 +374,19 @@
       
     </service-point>
     
  +  <service-point id="ChainBuilder" interface="org.apache.hivemind.lib.chain.ChainBuilder">
  +    
  +    Constructs an Gang of Four Chain of Command implementation
  +    for an interface, and a list of objects
  +    implementing that interface.  Primarily used
  +    by the ChainFactory service implementation factory.
  +    
  +    <invoke-factory>
  +      <construct class="org.apache.hivemind.lib.chain.ChainBuilderImpl">
  +        <set-service property="classFactory" service-id="hivemind.ClassFactory"/>
  +      </construct>
  +    </invoke-factory>
  +    
  +  </service-point>
  +  
   </module>
  
  
  

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