Chapter 1. Bootstrapping GemFire through the Spring container

One of the first tasks when using GemFire and Spring is to configure the data grid using dependency injection via the Spring container. While this is possible out of the box, the configuration tends to be verbose and only address basic cases. To address this problem, the Spring GemFire project provides several classes that enable the configuration of distributed caches or regions to support a variety of scenarios with minimal effort.

[Note]Note

The M2 release of Spring GemFire will include Spring namespaces that will make it even easier to create and configure the cache and specific region types (e.g. replicated, partitioned, etc.).

1.1. Configuring the GemFire Cache

In order to use the GemFire Fabric, one needs to either create a new Cache or connect to an existing one. As of the current version of GemFire (6.0.x) there can be only one opened cache per application. In most cases the cache is created once and then all other consumers connect to it.

In its simplest form, a cache can be defined in one line:

<object name="default-cache" type="Spring.Data.GemFire.CacheFactoryObject, Spring.Data.GemFire"/>  

Here, the default-cache will try to connect to an existing cache and, in case one does not exist, create a local client cache. Since no additional properties were specified the created cache uses the default cache configuration.

The name of the cache will be the name of the Spring objectd definition unless you specify a different name using the NameValueCollection property described next. Note, you can specify the name of the underlying DistributedSystem that will be created with the property DistributedSystemName

Especially in environments with opened caches, this basic configuration can go a long way. For scenarios where the cache needs to be configured, the user can pass in a reference the GemFire configuration file:

<object name="cache-with-xml" type="Spring.Data.GemFire.CacheFactoryObject, Spring.Data.GemFire">
  <property name="CacheXml" value="cache.xml"/>
</object>

In this example, if the cache needs to be created, it will use the file named cache.xml located in the runtime directory.

In addition to referencing an external configuration file one can specify GemFire settings directly through .NET name value properties. This can be quite handy when just a few settings need to be changed:

<object name="cache-with-props" type="Spring.Data.GemFire.CacheFactoryObject, Spring.Data.GemFire"> 
  <property name="Properties">
    <name-values>
      <add key="log-level" value="warning"/>
    </name-values>
  </property>
</object>

The 'name' property is used to set the name of the Cache object. For a complete list of properties refer to the GemFire reference documentation.

Spring object definitions support property replacement through the use of variable replacement. The following configuration allows you to externalize the properties from the Spring configuration file which is a best practice. The Spring configuration file is usually an embedded assembly resource so as to prevent accidental changes in production. There are seven locations supported out of the box in Spring.NET where you can place your externalized configuration data and can be extended to support your own locations. In the following example the configuration flues would come from a name-value configuration section in App/Web.config

<object name="cache-with-props" type="Spring.Data.GemFire.CacheFactoryObject, Spring.Data.GemFire"> 
  <property name="Properties">
    <name-values>
      <add key="name" value="StockCache"/>
      <add key="log-level" value="${cache.log-level}"/>
    </name-values>
  </property>
</object>

<object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core">
   <property name="VariableSources">
      <list>
         <object type="Spring.Objects.Factory.Config.ConfigSectionVariableSource, Spring.Core">
            <property name="SectionNames" value="CacheConfiguration" />
         </object>
      </list>
   </property>
</object>

The CacheConfiguration section in App.config would then look like the following

<configuration>
  <configSections>
    <section name="CacheConfiguration" type="System.Configuration.NameValueSectionHandler"/>
  </configSections>

  <CacheConfiguration>
    <add key="cache.log-level" value="warning"/>
  </CacheConfiguration>

</configuration>

It is worth pointing out again, that the cache settings apply only if the cache needs to be created, there is no opened cache in existence otherwise the existing cache will be used and the configuration will simply be discarded.

1.2. Configuring a GemFire Region

Once the Cache is configured, one needs to configure one or more Regions to interact with the data fabric. In a similar manner to the CacheFactoryObject, the RegionFactoryObject allows existing Regions to retrieved or, in case they don't exist, created using various settings. One can specify the Region name, whether it will be destroyed on shutdown (thereby acting as a temporary cache), the associated CacheLoaders, CacheListeners and CacheWriters and if needed, the RegionAttributes for full customization.

Let us start with a simple region declaration, named basic using a nested cache declaration:

<object name="basic" type="Spring.Data.GemFire.RegionFactoryObject, Spring.Data.GemFire">
  <property Name="Cache">
    <object type="Spring.Data.GemFire.CacheFactoryObject, Spring.Data.GemFire"/> 
  </property> 
</object>

By default the region name is the name of the object definition unless explicitly specified using the Name property.

It is worth pointing out, that for the vast majority of cases configuring the cache loader, listener and writer through the Spring container is preferred since the same instances can be reused across multiple regions and additionally, the instances themselves can benefit from the container's rich feature set:

  <object name="baseRegion" abstract="true">
    <property name="Endpoints" value="localhost:40404"/>
    <property name="Cache" ref="Cache"/>   <!-- definition not shown here -->
  </object>

  <object name="listeners" type="Spring.Data.GemFire.RegionFactoryObject, Spring.Data.GemFire"
          parent="baseRegion">
    <property name="CacheListener">
      <object type="Spring.Data.GemFire.Tests.SimpleCacheListener, Spring.Data.GemFire.Tests">
        <!-- set properties or constructor arguments -->
      </object>
    </property>
    <property name="CacheLoader">
      <object type="Spring.Data.GemFire.Tests.SimpleCacheLoader, Spring.Data.GemFire.Tests"/>      
    </property>
    <property name="CacheWriter">
      <object type="Spring.Data.GemFire.Tests.SimpleCacheWriter, Spring.Data.GemFire.Tests"/>
    </property>
  </object>

1.2.1. Configuring update interest for client Region

Client interests can be registered in both key and regex form through AllKeysInterest, KeyInterest, and RegexInterest classes in the Spring.Data.GemFire namespace. Here is an example of how to configure the AllKeys interest in the region.

  <object name="baseRegion" abstract="true">
    <property name="Endpoints" value="localhost:40404"/>
    <property name="Cache" ref="Cache"/>   <!-- definition not shown here -->
  </object>

  <object name="basic-interest" type="Spring.Data.GemFire.RegionFactoryObject, Spring.Data.GemFire"
          parent="baseRegion">
    <property name="ClientNotification" value="true"/>
    <property name="interests">
      <list>
        <object type="Spring.Data.GemFire.AllKeysInterest"/>
      </list>
    </property>
  </object>

To register interest for a set of key, use the KeyInterest class, as shown below from the sample application

  <object name="Region" type="Spring.Data.GemFire.RegionFactoryObject, Spring.Data.GemFire">
    <property name="Endpoints" value="localhost:40404"/>
    <property name="Cache" ref="Cache"/>
    <property name="Name" value="exampleregion"/>
    <property name="ClientNotification" value="true"/>
    <property name="Interests">
      <list>
        <object type="Spring.Data.GemFire.KeyInterest">
          <property name="Keys">
            <list>
              <object type="GemStone.GemFire.Cache.CacheableString" factory-method="Create">
                <constructor-arg value="Key-123"/>
              </object>
            </list>
          </property>
        </object>
      </list>
    </property>
  </object>

To register interest based on a regular expression, use the following configuration

  <object name="Region" type="Spring.Data.GemFire.RegionFactoryObject, Spring.Data.GemFire">
    <property name="Endpoints" value="localhost:40404"/>
    <property name="Cache" ref="Cache"/>
    <property name="Name" value="exampleregion"/>
    <property name="ClientNotification" value="true"/>
    <property name="Interests">
      <list>
        <object type="Spring.Data.GemFire.RegexInterest">
          <property name="Regex" value="Key-.*"/>
        </object>
      </list>
    </property>
  </object>

This would only register interest in keys of the type 'Key-123' or 'Key-4abc'.

[Note]Note

For the M2 release the use of namespaces and type converters for 'ICacheableKey' subclasses will make this configuration significantly less verbose. Also, there will a means to specify the collection class that can be filled with the intial cache values.

Please refer to the API documentation for more information on the various IInterest subclasses.