/** @author <a href="mailto:[email protected]">Ales Justin</a> */
public class VersioningInterceptor extends CommandInterceptor {
  private static final FieldInvocation<Long> VERSION =
      ReflectionUtils.cacheField(
          "org.infinispan.container.versioning.SimpleClusteredVersion", "version");

  private DataContainer dataContainer;

  @Inject
  public void init(DataContainer dataContainer) {
    this.dataContainer = dataContainer;
  }

  @Override
  public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command)
      throws Throwable {
    if (ctx.isOriginLocal()) {
      Entity entity = extractEntity(command.getValue());
      EntryVersion entryVersion = getEntryVersion(ctx, command.getKey());
      applyVersion(entity, entryVersion);
    }
    return invokeNextInterceptor(ctx, command);
  }

  @Override
  public Object visitPutMapCommand(InvocationContext ctx, PutMapCommand command) throws Throwable {
    if (ctx.isOriginLocal()) {
      Map<Object, Object> map = command.getMap();
      for (Map.Entry<Object, Object> entry : map.entrySet()) {
        Entity entity = extractEntity(entry.getValue());
        EntryVersion entryVersion = getEntryVersion(ctx, entry.getKey());
        applyVersion(entity, entryVersion);
      }
    }
    return invokeNextInterceptor(ctx, command);
  }

  protected Entity extractEntity(Object wrappedValue) {
    if (wrappedValue instanceof MarshalledValue)
      return extractEntity(((MarshalledValue) wrappedValue).get());
    else return (Entity) wrappedValue;
  }

  @SuppressWarnings("UnusedParameters")
  protected EntryVersion getEntryVersion(InvocationContext ctx, Object key) {
    CacheEntry cacheEntry = dataContainer.get(key);
    return (cacheEntry != null) ? cacheEntry.getVersion() : null;
  }

  protected void applyVersion(Entity entity, EntryVersion entryVersion) {
    long version = (entryVersion != null) ? VERSION.invoke(entryVersion) : 0L;
    entity.setProperty(Entity.VERSION_RESERVED_PROPERTY, version + 1L);
  }
}
 private void setCachedBlobKey(AppEngineFile file, BlobKey blobKey) {
   ReflectionUtils.invokeInstanceMethod(file, "setCachedBlobKey", BlobKey.class, blobKey);
 }
 private BlobKey getCachedBlobKey(AppEngineFile file) {
   return (BlobKey) ReflectionUtils.invokeInstanceMethod(file, "getCachedBlobKey");
 }