2 Building Your First Extend Application

Build and run a simple Coherence*Extend client that accesses and uses a Coherence cache. The example client that is used in this chapter is a Java-based extend client; however, the concepts that are demonstrated are common to both C++ and .NET extend clients. For complete C++ and .NET examples, see the Coherence Examples that are distributed as part of the Coherence for Java distribution.

This chapter includes the following sections:

Overview of the Extend Example

The Coherence*Extend example is organized into a set of steps that are used to create, configure, and run a basic Coherence*Extend client. The steps demonstrate many fundamental Coherence*Extend concepts, such as: configuring an extend proxy, configuring a remote cache, configuring the remote invocation service, and using the Coherence API.

Coherence for Java must be installed to complete the steps. For simplicity and ease of deployment, the client and cache server in this example are run on the same computer. Typically, extend clients and cache servers are located on separate systems.

Step 1: Configure the Cluster Side

The example extend client requires a proxy and cache to be configured in the cluster's cache configuration deployment descriptor. The extend proxy configured in this example is automatically assigned a proxy port to listen for client TCP/IP communication. A distributed cache named dist-extend is defined and is used to store client data in the cluster.

To configure the cluster side:

  1. Create an XML file named example-config.xml.
  2. Copy the following XML to the file.
    <?xml version="1.0"?>
    
    <cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
       xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config
       coherence-cache-config.xsd">
       <caching-scheme-mapping>
          <cache-mapping>
             <cache-name>dist-extend</cache-name>
             <scheme-name>extend</scheme-name>
          </cache-mapping>
       </caching-scheme-mapping>
    
       <caching-schemes>
          <distributed-scheme>
             <scheme-name>extend</scheme-name>
             <lease-granularity>member</lease-granularity>
             <backing-map-scheme>
                <local-scheme/>
             </backing-map-scheme>
             <autostart>true</autostart>
          </distributed-scheme>
    
          <proxy-scheme>
             <service-name>ExtendTcpCacheService</service-name>
             <autostart>true</autostart>
          </proxy-scheme>
       </caching-schemes>
    </cache-config>
    
  3. Save and close the file.

Step 2: Configure the Client Side

The example client queries a remote cache and also invokes a task which is run on a remote cluster node. To complete these operations, the example extend client requires a remote cache scheme and a remote invocation scheme. Invoking tasks is considered a more advanced use case.

The remote cache scheme includes a service name that matches the service name of a proxy service on the cluster to which the client connects. In addition, the cache name that is used in the cluster must also be used as the name of the remote cache scheme. For this example (based on Step 1), the remote cache scheme service name is ExtendTcpCacheService and the cache name is dist-extend. Lastly, the remote cache scheme includes the address and port of the cluster's name service, which is used to find a proxy. The name service runs on the cluster port which is 7574 by default.

The example extend client invokes a task on the remote cache and therefore requires a remote invocation scheme. The remote invocation scheme defines the ExtendTcpInvocationService service, which allows the client to create an Invocable instance and send it to the cluster for processing. The remote invocation scheme uses the name service to find a proxy and includes the name of the proxy service to which it connects.

To configure the client side:

  1. Create an XML file named example-client-config.xml.
  2. Copy the following XML to the file.
    <?xml version="1.0"?>
    
    <cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
       xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config
       coherence-cache-config.xsd">
       <caching-scheme-mapping>
          <cache-mapping>
             <cache-name>dist-extend</cache-name>
             <scheme-name>remote</scheme-name>
          </cache-mapping>
       </caching-scheme-mapping>
      
       <caching-schemes>
          <remote-cache-scheme>
             <scheme-name>remote</scheme-name>
             <service-name>ExtendTcpCacheService</service-name>
             <initiator-config>
                <tcp-initiator>
                   <name-service-addresses>
                      <socket-address>
                         <address>127.0.0.1</address>
                         <port>7574</port>
                      </socket-address>
                   </name-service-addresses>
                </tcp-initiator>
                <outgoing-message-handler>
                   <request-timeout>5s</request-timeout>
                </outgoing-message-handler>
             </initiator-config>
          </remote-cache-scheme>
     
          <remote-invocation-scheme>
             <scheme-name>extend-invocation</scheme-name>
             <service-name>ExtendTcpInvocationService</service-name>
             <proxy-service-name>ExtendTcpCacheService</proxy-service-name>
             <initiator-config>
                <tcp-initiator>
                   <name-service-addresses>
                      <socket-address>
                         <address>127.0.0.1</address>
                         <port>7574</port>
                      </socket-address>
                   </name-service-addresses>
                </tcp-initiator>
                <outgoing-message-handler>
                   <request-timeout>5s</request-timeout>
                </outgoing-message-handler>
             </initiator-config>
          </remote-invocation-scheme>
       </caching-schemes>
    </cache-config>
    
  3. Save and close the file.

Step 3: Create the Sample Client

The client application for this example is a simple client that increments an Integer value in a remote cache using the CacheService and then retrieves the value from the cache using the InvocationService. The client writes the value to the system output before exiting.

Note:

  • The client class must be on the classpath for all cache servers in the cluster. The TestClient$1 class is an anonymous inner class that is generated during compilation. It is serialized and sent to the InvocationService running on a cluster member. In this example, the client and cluster member run on a single computer. Therefore, both Java invocations use the same classpath.

  • This example could also be run on a Coherence node (that is, within the cluster) as is. The fact that operations are being sent to a remote cluster node over TCP/IP is completely transparent to the client application.

To create the sample application:

  1. Create a text file.
  2. Copy the following Java code to the file:
    import com.tangosol.net.AbstractInvocable;
    import com.tangosol.net.CacheFactory;
    import com.tangosol.net.InvocationService;
    import com.tangosol.net.NamedCache;
    import java.util.Map;
    
    public class TestClient {
        public static void main(String[] asArgs)
                throws Throwable
            {
            NamedCache cache  = CacheFactory.getCache("dist-extend");
            Integer IValue = (Integer) cache.get("key");
            if (IValue == null)
                {
                IValue = new Integer(1);
                }
            else
                {
                IValue = new Integer(IValue.intValue() + 1);
                }
            cache.put("key", IValue);
     
            InvocationService service = (InvocationService)
                    CacheFactory.getConfigurableCacheFactory()
                        .ensureService("ExtendTcpInvocationService");
     
            Map map = service.query(new AbstractInvocable()
                {
                    public void run()
                        {
                        System.out.println("This has been run by 
                           ExtendTcpInvocationService on: " +
                           CacheFactory.getCluster().getLocalMember());
                        setResult(CacheFactory.getCache("dist-extend").get("key"));
                        }
                }, null);
     
            Integer IValue1 = (Integer) map.get(service.getCluster().
                getLocalMember());
            System.out.print("The value of the key is " + IValue1);
            }
    }
    
  3. Save the file as TestClient.java and close the file.
  4. Compile TestClient.java:
    javac -cp .;COHERENCE_HOME\lib\coherence.jar TestClient.java
    

Coherence*Extend InvocationService

Since, by definition, a Coherence*Extend client has no direct knowledge of the cluster and the members running within the cluster, the Coherence*Extend InvocationService only allows Invocable tasks to be executed on the JVM to which the client is connected. Therefore, you should always pass a null member set to the query() method. As a consequence, the single result of the execution is keyed by the local Member, which is null if the client is not part of the cluster. This Member can be retrieved by calling service.getCluster().getLocalMember(). Additionally, the Coherence*Extend InvocationService only supports synchronous task execution (that is, the execute() method is not supported).

Step 4: Start the Cache Server Process

Extend Proxies are started as part of a cache server process(DefaultCacheServer). The cache server must be configured to use the cache configuration that was created in Step 1. In addition, the cache server process must be able to find the TestClient application on the classpath at run time.

The following command line starts a cache server process and explicitly names the cache configuration file created in Step 1 by using the coherence.cacheconfig system property:

java -cp COHERENCE_HOME\lib\coherence.jar;PATH_TO_CLIENT -Dcoherence.cacheconfig=PATH\example-config.xml com.tangosol.net.DefaultCacheServer

Check the console output to verify that the proxy service is started. The output message is similar to the following:

(thread=Proxy:ExtendTcpProxyService:TcpAcceptor, member=1): TcpAcceptor now
 listening for connections on 192.168.1.5:7077

Step 5: Run the Application

The TestClient application is started using the java command and must be configured to use the cache configuration file.

The following command line runs the application and assumes that the TestClient class is located in the current directory. The cache configuration file is explicitly named using the coherence.cacheconfig system property:

java -cp .;COHERENCE_HOME\lib\coherence.jar -Dcoherence.cacheconfig=PATH\example-client-config.xml TestClient

The output displays (among other things) that the client successfully connected to the extend proxy TCP address and the current value of the key in the cache. Run the client again to increment the key's value.

Note:

Check the cache server process output for the message confirming that the invocation task was executed remotely using the ExtendTcpInvocationService service.

This has been run...