1.3. The AdvancedCache Interface

Red Hat JBoss Data Grid offers an AdvancedCache interface, geared towards extending JBoss Data Grid, in addition to its simple Cache Interface. The AdvancedCache Interface can:
  • Inject custom interceptors
  • Access certain internal components
  • Apply flags to alter the behavior of certain cache methods
The following code snippet presents an example of how to obtain an AdvancedCache:
AdvancedCache advancedCache = cache.getAdvancedCache();

1.3.1. Flag Usage with the AdvancedCache Interface

Flags, when applied to certain cache methods in Red Hat JBoss Data Grid, alter the behavior of the target method. Use AdvancedCache.withFlags() to apply any number of flags to a cache invocation.

Example 1.3. Applying Flags to a Cache Invocation

advancedCache.withFlags(Flag.CACHE_MODE_LOCAL, Flag.SKIP_LOCKING)
   .withFlags(Flag.FORCE_SYNCHRONOUS)
   .put("hello", "world");

1.3.2. Custom Interceptors and the AdvancedCache Interface

The AdvancedCache Interface provides a mechanism that allows advanced developers to attach custom interceptors. Custom interceptors can alter the behavior of the Cache API methods and the AdvacedCache Interface can be used to attach such interceptors programmatically at run time.

1.3.3. Limitations of Map Methods

Specific Map methods, such as size(), values(), keySet() and entrySet(), can be used with certain limitations with Red Hat JBoss Data Grid as they are unreliable. These methods do not acquire locks (global or local) and concurrent modification, additions and removals are excluded from consideration in these calls. Furthermore, the listed methods are only operational on the local cache and do not provide a global view of state.
If the listed methods acted globally, it would result in a significant impact on performance and would produce a scalability bottleneck. As a result, it is recommended that these methods are used for informational and debugging purposes only.
Performance Concerns

From Red Hat JBoss Data Grid 6.3 onwards, the map methods size(), values(), keySet(), and entrySet() include entries in the cache loader by default whereas previously these methods only included the local data container. The underlying cache loader directly affects the performance of these commands. As an example, when using a database, these methods run a complete scan of the table where data is stored which can result in slower processing. Use Cache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD).values() to maintain the old behavior and not loading from the cache loader which would avoid the slower performance.

Changes to the size() Method (Embedded Caches)

In JBoss Data Grid 6.3 the Cache#size() method returned only the number of entries on the local node, ignoring other nodes for clustered caches and including any expired entries. While the default behavior has not been changed in JBoss Data Grid 6.4, accurate results can be enabled for bulk operations, including size(), by setting the infinispan.accurate.bulk.ops system property to true. In this mode of operation, the result returned by the size() method is affected by the flags org.infinispan.context.Flag#CACHE_MODE_LOCAL, to force it to return the number of entries present on the local node, and org.infinispan.context.Flag#SKIP_CACHE_LOAD, to ignore any passivated entries.

Changes to the size() Method (Remote Caches)

In JBoss Data Grid 6.3, the Hot Rod size() method obtained the size of a cache by invoking the STATS operation and using the returned numberOfEntries statistic. This statistic is not an accurate measurement of the number of entries in a cache because it does not take into account expired and passivated entries and it is only local to the node that responded to the operation. As an additional result, when security was enabled, the client would need the ADMIN permission instead of the more appropriate BULK_READ.

In JBoss Data Grid 6.4 the Hot Rod protocol has been enhanced with a dedicated SIZE operation, and the clients have been updated to use this operation for the size() method. The JBoss Data Grid server will need to be started with the infinispan.accurate.bulk.ops system property set to true so that size can be computed accurately.

1.3.4. Custom Interceptors

Custom interceptors can be added to Red Hat JBoss Data Grid declaratively or programmatically. Custom interceptors extend JBoss Data Grid by allowing it to influence or respond to cache modifications. Examples of such cache modifications are the addition, removal or updating of elements or transactions.

1.3.4.1. Custom Interceptor Design

To design a custom interceptor in Red Hat JBoss Data Grid, adhere to the following guidelines:
  • A custom interceptor must extend the CommandInterceptor.
  • A custom interceptor must declare a public, empty constructor to allow for instantiation.
  • A custom interceptor must have JavaBean style setters defined for any property that is defined through the property element.

1.3.4.2. Adding Custom Interceptors Declaratively

Each named cache in Red Hat JBoss Data Grid has its own interceptor stack. As a result, custom interceptors can be added on a per named cache basis.
A custom interceptor can be added using XML. Use the following procedure to add custom interceptors.

Procedure 1.2. Adding Custom Interceptors

<namedCache name="cacheWithCustomInterceptors">
   <customInterceptors>
      <interceptor position="FIRST" class="com.mycompany.CustomInterceptor1">
         <properties>
            <property name="attributeOne" value="value1" />
            <property name="attributeTwo" value="value2" />
         </properties>
      </interceptor>
      <interceptor position="LAST" class="com.mycompany.CustomInterceptor2"/>
      <interceptor index="3" class="com.mycompany.CustomInterceptor1"/>
      <interceptor before="org.infinispan.interceptors.CallInterceptor" class="com.mycompany.CustomInterceptor2"/>
      <interceptor after="org.infinispan.interceptors.CallInterceptor" class="com.mycompany.CustomInterceptor1"/>
   </customInterceptors>
</namedCache>
  1. Define Custom Interceptors

    All custom interceptors must extend org.infinispan.interceptors.base.BaseCustomInterceptor.
  2. Define the Position of the New Custom Interceptor

    Interceptors must have a defined position. These options are mutually exclusive, meaning an interceptor cannot have both a position attribute and index attribute. Valid options are:
    • via Position Attribute

      • FIRST - Specifies that the new interceptor is placed first in the chain.
      • LAST - Specifies that the new interceptor is placed last in the chain.
      • OTHER_THAN_FIRST_OR_LAST - Specifies that the new interceptor can be placed anywhere except first or last in the chain.
    • via Index Attribute

      • The index identifies the position of this interceptor in the chain, with 0 being the first position.
      • The after method places the new interceptor directly after the instance of the named interceptor specified via its fully qualified class name.
      • The before method places the new interceptor directly before the instance of the named interceptor specified via its fully qualified class name.
    • Define Interceptor Properties

      Define specific interceptor properties.
  3. Apply Other Custom Interceptors

    In this example, the next custom interceptor is called CustomInterceptor2.

Note

Custom interceptors with the position OTHER_THAN_FIRST_OR_LAST may cause the CacheManager to fail.

Note

This configuration is only valid for JBoss Data Grid's Library Mode.

1.3.4.3. Adding Custom Interceptors Programmatically

To add a custom interceptor programmatically in Red Hat JBoss Data Grid, first obtain a reference to the AdvancedCache.

Example 1.4. Obtain a Reference to the AdvancedCache

CacheManager cm = getCacheManager();
Cache aCache = cm.getCache("aName");
AdvancedCache advCache = aCache.getAdvancedCache();
Then use an addInterceptor() method to add the interceptor.

Example 1.5. Add the Interceptor

advCache.addInterceptor(new MyInterceptor(), 0);