PRODUCTS AND SERVICES INDUSTRIES SUPPORT PARTNERS COMMUNITIES ABOUT
  The Coherence Incubator
  Functor Pattern 1.0.0
Added by Brian Oliver, last edited by Rob Misek on Aug 12, 2009  (view change)

Labels

 
This documentation applies to the Functor Pattern 1.0.0. The latest Functor Pattern documentation is available is here.

The Functor Pattern

This is an example implementation of Function Objects (Wikipedia) or as it is also known, the Functor Pattern, built with Coherence.

The Functor Pattern is an extension to the Command Pattern. In fact the semantics are identical with the exception that the Functor Pattern additionally provides a mechanism to return values (or re-throw exceptions) to the Submitter (using Java 5+ Futures) where as the Command Pattern does not provide such capabilities. Consequently in order to use Functor Pattern it is highly recommended that you understand the Command Pattern.

Rationale

The Functor Pattern provides a useful alternative to Oracle Coherence EntryProcessors with the advantage that Functors are executed asynchronously, instead of synchronously as is the case with EntryProcessors.

Outline

Project Lead: Brian Oliver, Oracle
Release Name: Version 1.0.0: November 24th, 2008
Target Platforms: Java Standard Edition 5+
Requires Coherence: 3.3.1 or 3.4.0
Other Dependencies: Coherence Common 1.2.0
Command Pattern 2.2.0
Download: coherence-functorpattern-1.0.0.jar
MD5:68e59dec3b1ade90156e101ab6bd7a9f
Source Code and
Documentation:
coherence-functorpattern-1.0.0-src.zip
MD5:da1d23b81f6651c4e7ae759fcfe9e502
Previous Releases: (none)

Example

Let's start with a simple example where we use the Functor Pattern to asynchronously increment and return the value of a Counter

First, we'll start by writing a simple Counter:

Counter.java
import java.io.Serializable;
import com.oracle.coherence.patterns.command.Context;

public class Counter implements Context, Serializable {
  private long next;
  public Counter(long initialValue) {
    this.next = initialValue;
  }
	
  public long next() {
    return next++;
  }
	
  public String toString() {
    return String.format("Counter{next=%d}", next);
  }
}

Second, let's write a Functor that will increment the value of a Counter

NextValueFunctor.java
import java.io.Serializable;
import com.oracle.coherence.patterns.command.ExecutionEnvironment;
import com.oracle.coherence.patterns.functor.Functor;

public class NextValueFunctor implements Functor<Counter, Long>, Serializable {
  private static final long serialVersionUID = 4841498972676821911L;

  public Long execute(ExecutionEnvironment<Counter> executionEnvironment) {
    Counter counter = executionEnvironment.getContext();		
    long next = counter.next();
    executionEnvironment.setContext(counter);
    return next;
  }
}

Lastly, let's write a simple example to test our Functor.

FunctorPatternExample.java
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.oracle.coherence.common.identifiers.Identifier;
import com.oracle.coherence.patterns.command.ContextsManager;
import com.oracle.coherence.patterns.command.DefaultContextsManager;
import com.oracle.coherence.patterns.functor.DefaultFunctorSubmitter;
import com.oracle.coherence.patterns.functor.FunctorSubmitter;
import com.tangosol.net.CacheFactory;

public class FunctorPatternExample {
  public static void main(String[] args) throws InterruptedException, ExecutionException {
	
    ContextsManager contextsManager = DefaultContextsManager.getInstance();
    Identifier contextIdentifier = contextsManager.registerContext("myCounter", new Counter(0));
		
    FunctorSubmitter functorSubmitter = DefaultFunctorSubmitter.getInstance();
    functorSubmitter.submitCommand(contextIdentifier, new LoggingCommand("Commenced", 0));

    for (int i = 0; i < 50; i++) {
      Future<Long> future = functorSubmitter.submitFunctor(contextIdentifier, new NextValueFunctor());
      System.out.println(future.get());
    }
		
    functorSubmitter.submitCommand(contextIdentifier, new LoggingCommand("Completed", 0));
		
    Thread.sleep(2000);
		
    Counter counter = (Counter)contextsManager.getContext(contextIdentifier);
    System.out.println(counter);
  }
}

Frequently Asked Questions

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 but executed requests recoverable from disk? Yes (when using Cache Store) Yes (when using Cache Store) No No

Can Functors and Commands be submitted to the same Context?
Yes. Functors and Commands may be submitted for execution against the same Context. They will be executed in the order of submission from the Submitter. Further, FunctorSubmitters may be used instead of CommandSubmitters (as the FunctorSubmitter interface is a sub-interface of the CommandSubmitter interface)

How do I monitor the execution of Functors ?

As the Functor Pattern uses the Command Pattern for the internal implementation (and that is JMX enabled), all you need to do is simply enable JMX.

References and Additional Information