PRODUCTS AND SERVICES INDUSTRIES SUPPORT PARTNERS COMMUNITIES ABOUT
  The Coherence Incubator
  Command Pattern 2.3.0
compared with
Current by Rob Misek
on Aug 12, 2009 10:18.


 
Key
These lines were removed. This word was removed.
These lines were added. This word was added.

View page history


There are 1 changes. View first change.

  {note}This documentation applies to the Command Pattern 2.3.0. The latest Coherence Common documentation is available is [here|Command Pattern].{note}
  {note}This documentation applies to the Command Pattern 2.3.0. The latest Command Pattern documentation is available is [here|Command Pattern].{note}
  
 {section}
 {column:width=50%}
 h3. The Command Pattern
 This is an {color:green}*example implementation*{color} of the [Command Pattern (Wikipedia)|http://en.wikipedia.org/wiki/Command_pattern] design pattern build on top of Coherence.
  
 *The Command Pattern advocates that;*
 # An action to be performed zero or more times at some point in the future should be represented as an object called a _Command_.
 # All necessary parameters required to perform the said action, should be encapsulated as attributes with in the said _Command_ object.
 # The _Command_ object must provide a mechanism to perform the action (typically represented an _execute_ method defined on the said _Command_ object)
  
 *This implementation of the Command Pattern additionally advocates that;*
 # A _Command_ may only be executed with in the scope of a target object, called a _Context_.
 # To execute a _Command_ it must be _submitted_ to a _Context_.
 # Once _submitted_ , _Commands_ are executed asynchronously. That is, the submitter of the _Command_ does not block or wait for the _Command_ to be executed after it has been _submitted_.
 # _Commands_ are executed one-at-a-time, in the order in which they arrive at their _Context_.
 # A _Command_ may not return a value to the application that _submitted_ the said _Command_. If you require a _Command_ that returns a value after execution, you need a _Functor_ (see the [Functor Pattern])
  
 h3. Dependencies
 This project (like other Coherence Incubator projects) uses [Apache Ivy|http://ant.apache.org/ivy/] for dependency specification and management. While a standard {{ivy.xml}} definition file ships with the source and documentation distribution, the following diagram visually indicates the current dependencies.
  
 {center}
 !Incubator-Dependencies-Command.png!
 {center}
 {column}
  
 {column:width=50%}
 h3. Outline
 || *Release Name:* | *{color:red}Version 2.3.0: March 30th, 2009{color}* |
 || *Target Platforms:* | Java Standard Edition 5+ |
 || *Requires Coherence Version:* | 3.3.1+ or 3.4+ |
 || *Dependencies:* | [Coherence Common 1.3.0] |
 || *Download:* | [^coherence-commandpattern-2.3.0.jar] \\MD5:20f01dd0cf3161e10034e456327e27a7 |
 || *Source Code and Documentation:* | [^coherence-commandpattern-2.3.0-src.zip] \\MD5:64756ade6f4d24ecdb317f02af4b7974 |
 || *Previous Releases:* | [Command Pattern 2.2.0] \\ [Command Pattern 2.1.1] |
  
 h3. Rationale
 The Command Pattern provides a useful alternative to Oracle Coherence _EntryProcessors_ with the advantage that _Commands_ are executed asynchronously, instead of synchronously as is the case with _EntryProcessors_.
  
 Additionally this implementation of the Command Pattern provides essential infrastructure for several other Incubator projects (namely the [Store and Forward Messaging Pattern]) to permit guaranteed, in-order, asynchronous processing of Commands.
 {column}
 {section}
  
 h3. What's New?
 The following changes have been made since the [Command Pattern 2.2.0] release.
  
 * Migrated to use [Apache Ivy|http://ant.apache.org/ivy/] for dependency management, building and publishing artifacts
  
 * Upgraded to use [Coherence Common 1.3.0]
  
 * Added generic exception handler to the CommandExecutor.execute() method so that the underlying Java
 ExecutorServices don't just ignore internal exceptions (and not log them).
 This can help debug serialization problems caused by defective Commands.
  
 * Added the ability to cancel the execution of a Command after it has been submitted, but before it has been executed with the new method;
  
 {code}CommandSubmitter.cancelCommand(Identifier commandIdentifier);{code}
  
 * A CommandSubmitter will now return the Identifier that was allocated to the submitted Command
  when calling one of the submitCommand(...) methods.
  
 * Added support for PriorityCommands through the addition of the PriorityCommand marker interface.
  
 * Added the ability to convert regular commands into priority commands with the PriorityCommandAdapter.
  
 * Fixed the ContextWrapper POF writeExternal method to correctly write out longs as longs instead of Objects
  
 * Added the ability to extract values from a Context using ContextsManager.extractValueFromContext method
  
 * Resolved potential race-condition when concurrently submitting Commands and a Context is in the process of recovering due to partition recovery or balancing.
  
 h3. Structure
  
 The following diagram outlines the core classes and interfaces defined in this implementation of the Command Pattern.
  
 !command-pattern-uml.png!
  
 The {{Command}} interface specifies the minimum requirements for _Command_ objects. It defines a single method called {{execute}} that is invoked by the internal {{CommandExecutor}} when a _Command_ is to be executed. The {{execute}} method requires a single parameter, called the {{ExecutionEnvironment}}. The {{ExecutionEnvironment}} provides valuable information to the {{execute}} method, including the {{Context}} in which the _Command_ is being executed. To submit _Commands_ for execution by {{CommandExecutor}} s, you must use an implementation of the {{CommandSubmitter}} interface (the DefaultCommandSubmitter class provides the standard implementation).
  
 To define and register a {{Context}} about which you may submit {{Command}} s for execution, use an implementation of the {{ContextsManager}} interface (the DefaultContextsManager class provides the standard implementation). Once a {{Context}} is registered, you may use the returned {{Identifier}} to submit {{Command}} s for execution with a {{CommandSubmitter}}.
  
 {note:title=Be Careful}
 As {{Context}} and {{Command}} instances are stored in Coherence cluster members within the Data Grid, they must be {{Serializable}} or better still, implement {{ExternalizableLite}} or {{PortableObject}}
 {note}
  
 h3. Command Pattern Usage Walkthrough
  
 {section}
 {column:width=50%}
 h6. Step 1: The Initial Environment
 !walkthrough-step-1.png!
 * One Client Application
 * Two Coherence Cache Servers
 * All part of the same Coherence Cluster ^*^
  
 ^*^ The Client Application may be external to the Coherence Cluster when using Coherence *Extend
 {column}
 {column:width=50%}
 h6. Step 2: {{Context}} Creation
 !walkthrough-step-2.png!
 * The client application creates an instance of a {{Context}}
 {column}
 {section}
  
 {section}
 {column:width=50%}
 h6. Step 3: {{Context}} Registration
 !walkthrough-step-3.png!
 * The client application registers the created {{Context}} using a {{ContextsManager}} ^*^
 * The {{ContextsManager}} places the {{Context}} into a "primary partition" of the "contexts" Distributed Cache.
 * Coherence ensures a backup of the {{Context}} is made to a "backup partition" (on separate JVMs and different machines where possible)
  
 ^*^ Typically an instance of the {{DefaultContextsManager}}
 {column}
 {column:width=50%}
 h6. Step 4: Establishing the {{CommandExecutor}} (automatic)
 !walkthrough-step-4.png!
 * When a {{Context}} is registered, an internal event establishes an appropriate {{CommandExecutor}} and necessary infrastructure.
 {column}
 {section}
  
 {section}
 {column:width=50%}
 h6. Step 5: Creating a {{Command}}
 !walkthrough-step-5.png!
 * The client application creates an instance of a {{Command}}
 {column}
 {column:width=50%}
 h6. Step 6: Submitting a {{Command}} for execution
 !walkthrough-step-6.png!
 * The client application uses a {{CommandSubmitter}} to submit a {{Command}} for execution with an identified {{Context}} ^*^
 * The submitted {{Command}} is placed into the "commands" Distributed Cache (and automatically backed up)
 * The submitted {{Command}} is then automatically queued (FIFO) and scheduled for asynchronous execution by the {{CommandExecutor}} for the {{Context}}
  
 ^*^ An individual {{Command}} instance may be submitted any number of times for execution to one or more {{Contexts}}. There is no need to create new instances of the same {{Command}} if it needs to be submitted for execution multiple times.
 {column}
 {section}
  
 {section}
 {column:width=50%}
 h6. Step 7: Numerous {{Commands}} Submitted
 !walkthrough-step-7.png!
 * Multiple {{Commands}} may be submitted for execution at once.
 * {{Commands}} are queued for execution (FIFO) in order of arrival at the {{Context}}
 {column}
 {column:width=50%}
 h6. Step 8: {{Commands}} are executed by the {{CommandExecutor}} (Asynchronously)
 !walkthrough-step-8.png!
 * When {{Commands}} are queued for execution, an internal event notifies the {{CommandExecutor}} to start executing the {{Commands}}
 * For efficiency, the {{CommandExecutor}} may execute {{Commands}} in batches (but remaining in order).
 {column}
 {section}
  
 {section}
 {column:width=50%}
 h6. Step 9: {{Commands}} Automatically Cleaned-up when Executed.
 !walkthrough-step-9.png!
 * Once a {{Command}} has been executed, it is removed from the "commands" cache (as is the backup of the {{Command}}).
 {column}
 {section}
  
  
 h3. Example
  
 Let's start with a simple example where we use the Command Pattern to {{setValue(T)}} on the {{GenericContext}}.
  
 First, we'll start by writing a simple {{SetValueCommand}} that extends {{AbstractCommand}} as seen here:
 {code:java|title=SetValueCommand.java|borderStyle=solid}
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
  
 import com.oracle.coherence.patterns.command.Command;
 import com.oracle.coherence.patterns.command.ExecutionEnvironment;
 import com.tangosol.io.ExternalizableLite;
 import com.tangosol.util.ExternalizableHelper;
  
 @SuppressWarnings("serial")
 public class SetValueCommand<T> implements Command<GenericContext<T>>, ExternalizableLite {
  
  private T value;
  
  public SetValueCommand() {
  }
  
  public SetValueCommand(T value) {
  this.value = value;
  }
  
  public void execute(ExecutionEnvironment<GenericContext<T>> executionEnvironment) {
  GenericContext<T> context = executionEnvironment.getContext();
  context.setValue(value);
  executionEnvironment.setContext(context);
  }
  
  @SuppressWarnings("unchecked")
  public void readExternal(DataInput in) throws IOException {
  this.value = (T)ExternalizableHelper.readObject(in);
  }
  
  public void writeExternal(DataOutput out) throws IOException {
  ExternalizableHelper.writeObject(out, value);
  }
  
  public String toString() {
  return String.format("SetValueCommand{value=%s}", value);
  }
 }
 {code}
  
 Second, let's write a quick test that submits a number ({{iCount}}) of {{SetValueCommand}} s on "mycontext" as seen here:
 {code:java|title=CommandPatternExample.java|borderStyle=solid}
 import com.oracle.coherence.common.identifiers.Identifier;
 import com.oracle.coherence.patterns.command.CommandSubmitter;
 import com.oracle.coherence.patterns.command.ContextsManager;
 import com.oracle.coherence.patterns.command.DefaultCommandSubmitter;
 import com.oracle.coherence.patterns.command.DefaultContextConfiguration;
 import com.oracle.coherence.patterns.command.DefaultContextsManager;
 import com.oracle.coherence.patterns.command.ContextConfiguration.ManagementStrategy;
 import com.tangosol.net.CacheFactory;
  
 public class CommandPatternExample {
  /**
  * @param args
  * @throws InterruptedException
  */
  public static void main(String[] args) throws InterruptedException {
  
  DefaultContextConfiguration contextConfiguration = new DefaultContextConfiguration(ManagementStrategy.DISTRIBUTED);
  ContextsManager contextsManager = DefaultContextsManager.getInstance();
  
  Identifier contextIdentifier = contextsManager.registerContext("mycontext", new GenericContext<Long>(0L), contextConfiguration);
  
  CommandSubmitter commandSubmitter = DefaultCommandSubmitter.getInstance();
  
  commandSubmitter.submitCommand(contextIdentifier, new LoggingCommand("Commenced", 0));
  
  for (long i = 1; i <= 10000; i++) {
  commandSubmitter.submitCommand(contextIdentifier, new SetValueCommand<Long>(i));
  }
  
  commandSubmitter.submitCommand(contextIdentifier, new LoggingCommand("Completed", 0));
  CacheFactory.shutdown();
  }
 }
 {code}
  
 To run this test you will need to start a Coherence cache server, in this example we use the {{DefaultCacheServer}} that ships with Coherence as seen here:
  
 {code}java -Dtangosol.coherence.cacheconfig=$PATH_TO/coherence-commandpattern-cacheconfig.xml com.tangosol.net.DefaultCacheServer{code}
  
 Once the cache server is running you can start the {{CommandPatternExample}} as a cache client as seen here:
  
 {code}-Dtangosol.coherence.distributed.localstorage=false -Dtangosol.coherence.cacheconfig=$PATH_TO/coherence-commandpattern-cacheconfig.xml CommandPatternExample{code}
  
 {info}The {{SetValueCommand.java}}, {{CommandPatternExample.java}} and {{commandpattern-cacheconfig.xml}} files are included in the source code distribution.{info}
  
 h3. Frequently Asked Questions
  
 (*b) *What is the relationship between the Functor Pattern, Command Pattern, Entry Processors and the Invocation Service for performing work in a cluster?*
  
 The following table outlines the main differences.
  
 || || Functor Pattern || Command Pattern || EntryProcessors || InvocationService ||
 | Processing Target | A Context | A Context | A Cache Entry | A Cluster Member |
 | Submission Behavior | Non-Blocking | Non-Blocking | Blocking | Blocking and Non-Blocking |
 | Execution Order | Order of Submission | Order of Submission | Order of Submission (unless using PriorityTasks) | Order of Submission |
 | Supports Return Values?\\(and re-throwing Exceptions) | Yes | No | Yes | Yes |
 | Guaranteed to Execute?\\(if Submitter terminates after submission) | Yes | Yes | Yes (submitter blocks) | Yes (for blocking), No (for non-blocking) |
 | Guaranteed to Execute?\\(if Target JVM terminates during execution) | Yes | Yes | Yes (submitter automatically retries) | No (retry up to developer) |
 | Submitted requests recoverable from disk? | Yes (when using Cache Store) | Yes (when using Cache Store) | No | No |
 | Request may be cancelled? | Yes | Yes | No | Yes (for non-blocking) |
  
 (*b) *What is a {{ManagementStrategy}} ?*
  
 A {{ManagementStrategy}} defines how {{Commands}} are managed in a Coherence Cluster. By default {{Commands}} are always co-located in the JVM that is hosting the {{Context}} associated with the said {{Commands}}. This provides instant access to the {{Commands}} for a {{CommandExecutor}} but has the disadvantage of limiting the number of {{Commands}} that may be queued for execution (before a JVM may run out of memory). The alternative is to use the *DISTRIBUTED* strategy, where the {{Commands}} are distributed across the cluster and only retrieved for execution when required. This provides the advantage of enabling massive capacity (scaling to the size of the cluster and beyond when disk storage is configured), but has the disadvantage that retrieving {{Commands}} for execution may take longer.
  
 (*b) *How do I monitor the execution of {{Commands}} ?*
  
 The Command Pattern {{CommandExecutors}} are JMX enabled by default. In order to monitor {{Command}} execution for a {{Context}}, simply enable JMX for Coherence and look for the "CommandExecutors" in your JMX monitoring application (ie: Something like JConsole). All kinds of JMX information is available, including Min, Max and Average Execution time, together with the number of current {{Commands}} pending to be executed and those that have been executed.
  
 h3. References and Additional Information
  
 * [Functor Pattern]
  
 * Wikipedia - [Command Pattern|http://en.wikipedia.org/wiki/Command_pattern]