Provides a distributed implementation of the classic Command Pattern (Wikipedia) built using Oracle Coherence.
The Command Pattern implementation is distributed in the jar file
called: coherence-commandpattern-11.3.3-SNAPSHOT.jar.
However as the Command Pattern has several other dependencies, we **strongly recommend** that developers adopt and use tools like Apache Maven/Ivy/Gradle to transitively resolve the said dependencies, instead of attempting to do so manually.
To configure your Apache Maven-based application to use the Command Pattern,
simply add the following declaration to your application pom.xml file
<dependencies> element.
<dependency>
<groupId>com.oracle.coherence.incubator</groupId>
<artifactId>coherence-commandpattern</artifactId>
<version>11.3.3-SNAPSHOT</version>
</dependency>
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.
The Command must provide a mechanism to perform the action, typically
represented by an execute method defined on the said Command.
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.)
The following diagram outlines the core classes and interfaces defined in this implementation of the Command Pattern.

The Command interface specifies the minimum requirements for Commands. 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 CommandExecutors, 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 Commands 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 Commands
for execution with a CommandSubmitter.
As
ContextandCommandinstances are stored in Coherence cluster members, they both must beSerializableor better still, implementExternalizableLiteorPortableObject.

The Client Application may be external to the Coherence Cluster when using Coherence Extend

Context
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)

Context is registered, an internal event establishes an appropriate
CommandExecutor and necessary infrastructure.
Command
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
Commandinstance may be submitted any number of times for execution to one or moreContexts. There is no need to create new instances of the sameCommandif it needs to be submitted for execution multiple times.

Commands may be submitted for execution at once.Commands are queued for execution (FIFO) in order of arrival at the Context
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).

Command has been executed, it is removed from the "commands" cache
(as is the backup of the Command).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:
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);
}
}
Second, let's write a quick test that submits a number (iCount) of
SetValueCommand s on "mycontext" as seen here:
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();
}
}
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:
java -Dtangosol.coherence.cacheconfig=$PATH_TO/coherence-commandpattern-cacheconfig.xml \
com.tangosol.net.DefaultCacheServer
Once the cache server is running you can start the CommandPatternExample as a
cache client as seen here:
java -Dtangosol.coherence.distributed.localstorage=false -Dtangosol.coherence.cacheconfig=$PATH_TO/coherence-commandpattern-cacheconfig.xml CommandPatternExample
The SetValueCommand.java, CommandPatternExample.java and coherence-commandpattern-cache-config.xml
files are included in the source code distribution.
The following table outlines the main differences.
| Description | 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^1 | Order of Submission |
| Supports Return Values? | Yes | No | Yes | Yes |
| Guaranteed to Execute?^2 | Yes | Yes | Yes^3 | Yes^4 and No^5 |
| Guaranteed to Execute?^6 | Yes | Yes | Yes^7 | No^8 |
| Recoverable?^9 | Yes^10 | Yes^10 | No | No |
| Request may be cancelled? | Yes | Yes | No | Yes ^5 |
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.
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.
Wikipedia - Command Pattern