package org.jboss.cache.interceptors.base;

import org.jboss.cache.InvocationContext;
import org.jboss.cache.commands.VisitableCommand;
import org.jboss.cache.commands.read.ExistsCommand;
import org.jboss.cache.commands.read.GetChildrenNamesCommand;
import org.jboss.cache.commands.read.GetDataMapCommand;
import org.jboss.cache.commands.read.GetKeyValueCommand;
import org.jboss.cache.commands.read.GetKeysCommand;
import org.jboss.cache.commands.read.GetNodeCommand;
import org.jboss.cache.commands.read.GravitateDataCommand;
import org.jboss.cache.commands.tx.CommitCommand;
import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
import org.jboss.cache.commands.tx.PrepareCommand;
import org.jboss.cache.commands.tx.RollbackCommand;
import org.jboss.cache.commands.write.*;

/**
 * This interceptor will call {@link #doAfterCall(org.jboss.cache.InvocationContext,org.jboss.cache.commands.VisitableCommand)} after invoking each visit method
 * (and the {@link #handleDefault(org.jboss.cache.InvocationContext, org.jboss.cache.commands.VisitableCommand)} method) in
 * a <tt>finally</tt> block.
 * <p/>
 * It is useful if common cleanup code is required at the end of each call.
 * <p/>
 * Instead of overriding visitXXX() methods, implementations should override their handleXXX() counterparts defined in this class
 * instead, as well as the {@link #doAfterCall(org.jboss.cache.InvocationContext,org.jboss.cache.commands.VisitableCommand)} method.
 *
 * @author Mircea.Markus@jboss.com
 * @since 2.2
 */
public abstract class PostProcessingCommandInterceptor extends CommandInterceptor
{
   @Override
   public final Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
   {
      try
      {
         return handlePutDataMapCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handlePutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
   {
      try
      {
         return handlePutKeyValueCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   @Override
   public final Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
   {
      try
      {
         return handlePutForExternalReadCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }


   protected Object handlePutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   protected Object handlePutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }


   @Override
   public final Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
   {
      try
      {
         return handleRemoveNodeCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitCreateNodeCommand(InvocationContext ctx, CreateNodeCommand command) throws Throwable
   {
      try
      {
         return handleCreateNodeCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleCreateNodeCommand(InvocationContext ctx, CreateNodeCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }


   @Override
   public final Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
   {
      try
      {
         return handleClearDataCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitEvictFqnCommand(InvocationContext ctx, EvictCommand command) throws Throwable
   {
      try
      {
         return handleEvictFqnCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleEvictFqnCommand(InvocationContext ctx, EvictCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitInvalidateCommand(InvocationContext ctx, InvalidateCommand command) throws Throwable
   {
      try
      {
         return handleInvalidateCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleInvalidateCommand(InvocationContext ctx, InvalidateCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
   {
      try
      {
         return handleRemoveKeyCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitGetDataMapCommand(InvocationContext ctx, GetDataMapCommand command) throws Throwable
   {
      try
      {
         return handleGetDataMapCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleGetDataMapCommand(InvocationContext ctx, GetDataMapCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitExistsNodeCommand(InvocationContext ctx, ExistsCommand command) throws Throwable
   {
      try
      {
         return handleExistsNodeCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleExistsNodeCommand(InvocationContext ctx, ExistsCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
   {
      try
      {
         return handleGetKeyValueCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
   {
      try
      {
         return handleGetNodeCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
   {
      try
      {
         return handleGetKeysCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
   {
      try
      {
         return handleGetChildrenNamesCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
   {
      try
      {
         return handleMoveCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitGravitateDataCommand(InvocationContext ctx, GravitateDataCommand command) throws Throwable
   {
      try
      {
         return handleGravitateDataCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleGravitateDataCommand(InvocationContext ctx, GravitateDataCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitPrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable
   {
      try
      {
         return handlePrepareCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handlePrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitRollbackCommand(InvocationContext ctx, RollbackCommand command) throws Throwable
   {
      try
      {
         return handleRollbackCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleRollbackCommand(InvocationContext ctx, RollbackCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitCommitCommand(InvocationContext ctx, CommitCommand command) throws Throwable
   {
      try
      {
         return handleCommitCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleCommitCommand(InvocationContext ctx, CommitCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   @Override
   public final Object visitOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable
   {
      try
      {
         return handleOptimisticPrepareCommand(ctx, command);
      }
      finally
      {
         doAfterCall(ctx, command);
      }
   }

   protected Object handleOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable
   {
      return handleDefault(ctx, command);
   }

   /**
    * Callback that is invoked after every handleXXX() method defined above.
    *
    * @param ctx     invocation context
    * @param command command which was invoked
    */
   protected abstract void doAfterCall(InvocationContext ctx, VisitableCommand command);
}
