Interceptors

You can add intercept operations and execute your own business logic synchronously blocking the operation. You can change the returned value from a get operation, change the value to be put or cancel operations by throwing exception.

Interceptors are different from listeners as with listeners you just take an action after the operation has been completed. Interceptor actions are synchronous and you can alter the behavior of operation, change the values or totally cancel it.

IMap API has two methods for adding and removing interceptor to the map:

/**
 * Adds an interceptor for this map. Added interceptor will intercept operations
 * and execute user defined methods and will cancel operations if user defined method throw exception.
 * 
 *
 * @param interceptor map interceptor
 * @return id of registered interceptor
 */
String addInterceptor( MapInterceptor interceptor );

/**
 * Removes the given interceptor for this map. So it will not intercept operations anymore.
 * 
 *
 * @param id registration id of map interceptor
 */
void removeInterceptor( String id );

Here is the MapInterceptor interface:

public interface MapInterceptor extends Serializable {

  /**
   * Intercept get operation before returning value.
   * Return another object to change the return value of get(..)
   * Returning null will cause the get(..) operation return original value,
   * namely return null if you do not want to change anything.
   * 
   *
   * @param value the original value to be returned as the result of get(..) operation
   * @return the new value that will be returned by get(..) operation
   */
  Object interceptGet( Object value );

  /**
   * Called after get(..) operation is completed.
   * 
   *
   * @param value the value returned as the result of get(..) operation
   */
  void afterGet( Object value );

  /**
   * Intercept put operation before modifying map data.
   * Return the object to be put into the map.
   * Returning null will cause the put(..) operation to operate as expected,
   * namely no interception. Throwing an exception will cancel the put operation.
   * 
   *
   * @param oldValue the value currently in map
   * @param newValue the new value to be put
   * @return new value after intercept operation
   */
  Object interceptPut( Object oldValue, Object newValue );

  /**
   * Called after put(..) operation is completed.
   * 
   *
   * @param value the value returned as the result of put(..) operation
   */
  void afterPut( Object value );

  /**
   * Intercept remove operation before removing the data.
   * Return the object to be returned as the result of remove operation.
   * Throwing an exception will cancel the remove operation.
   * 
   *
   * @param removedValue the existing value to be removed
   * @return the value to be returned as the result of remove operation
   */
  Object interceptRemove( Object removedValue );

  /**
   * Called after remove(..) operation is completed.
   * 
   *
   * @param value the value returned as the result of remove(..) operation
   */
  void afterRemove( Object value );
}

Example Usage:

public class InterceptorTest {

  @Test
  public void testMapInterceptor() throws InterruptedException {
    HazelcastInstance hazelcastInstance1 = Hazelcast.newHazelcastInstance();
    HazelcastInstance hazelcastInstance2 = Hazelcast.newHazelcastInstance();
    IMap<Object, Object> map = hazelcastInstance1.getMap( "testMapInterceptor" );
    SimpleInterceptor interceptor = new SimpleInterceptor();
    map.addInterceptor( interceptor );
    map.put( 1, "New York" );
    map.put( 2, "Istanbul" );
    map.put( 3, "Tokyo" );
    map.put( 4, "London" );
    map.put( 5, "Paris" );
    map.put( 6, "Cairo" );
    map.put( 7, "Hong Kong" );

    try {
      map.remove( 1 );
    } catch ( Exception ignore ) {
    }
    try {
      map.remove( 2 );
    } catch ( Exception ignore ) {
    }

    assertEquals( map.size(), 6) ;

    assertEquals( map.get( 1 ), null );
    assertEquals( map.get( 2 ), "ISTANBUL:" );
    assertEquals( map.get( 3 ), "TOKYO:" );
    assertEquals( map.get( 4 ), "LONDON:" );
    assertEquals( map.get( 5 ), "PARIS:" );
    assertEquals( map.get( 6 ), "CAIRO:" );
    assertEquals( map.get( 7 ), "HONG KONG:" );

    map.removeInterceptor( interceptor );
    map.put( 8, "Moscow" );

    assertEquals( map.get( 8 ), "Moscow" );
    assertEquals( map.get( 1 ), null );
    assertEquals( map.get( 2 ), "ISTANBUL" );
    assertEquals( map.get( 3 ), "TOKYO" );
    assertEquals( map.get( 4 ), "LONDON" );
    assertEquals( map.get( 5 ), "PARIS" );
    assertEquals( map.get( 6 ), "CAIRO" );
    assertEquals( map.get( 7 ), "HONG KONG" );
  }

  static class SimpleInterceptor implements MapInterceptor, Serializable {

    @Override
    public Object interceptGet( Object value ) {
      if (value == null)
        return null;
      return value + ":";
    }

    @Override
    public void afterGet( Object value ) {
    }

    @Override
    public Object interceptPut( Object oldValue, Object newValue ) {
      return newValue.toString().toUpperCase();
    }

    @Override
    public void afterPut( Object value ) {
    }

    @Override
    public Object interceptRemove( Object removedValue ) {
      if(removedValue.equals( "ISTANBUL" ))
        throw new RuntimeException( "you can not remove this" );
      return removedValue;
    }

    @Override
    public void afterRemove( Object value ) {
      // do something
    }
  }
}