package redis.clients.jedis;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;

import redis.clients.jedis.exceptions.JedisDataException;

/**
 * Transaction is nearly identical to Pipeline, only differences are the multi/discard behaviors
 */
public class Transaction extends MultiKeyPipelineBase implements Closeable {

  protected boolean inTransaction = true;

  protected Transaction() {
    // client will be set later in transaction block
  }

  public Transaction(final Client client) {
    this.client = client;
  }

  @Override
  protected Client getClient(String key) {
    return client;
  }

  @Override
  protected Client getClient(byte[] key) {
    return client;
  }

  public void clear() {
    if (inTransaction) {
      discard();
    }
  }

  public List<Object> exec() {
    // Discard QUEUED or ERROR
    client.getMany(getPipelinedResponseLength());
    client.exec();
    inTransaction = false;

    List<Object> unformatted = client.getObjectMultiBulkReply();
    if (unformatted == null) {
      return null;
    }
    List<Object> formatted = new ArrayList<>();
    for (Object o : unformatted) {
      try {
        formatted.add(generateResponse(o).get());
      } catch (JedisDataException e) {
        formatted.add(e);
      }
    }
    return formatted;
  }

  public List<Response<?>> execGetResponse() {
    // Discard QUEUED or ERROR
    client.getMany(getPipelinedResponseLength());
    client.exec();
    inTransaction = false;

    List<Object> unformatted = client.getObjectMultiBulkReply();
    if (unformatted == null) {
      return null;
    }
    List<Response<?>> response = new ArrayList<>();
    for (Object o : unformatted) {
      response.add(generateResponse(o));
    }
    return response;
  }

  public String discard() {
    client.getMany(getPipelinedResponseLength());
    client.discard();
    inTransaction = false;
    clean();
    return client.getStatusCodeReply();
  }

  public void setClient(Client client) {
    this.client = client;
  }

  @Override
  public void close() {
    clear();
  }
}
@@ -2079,9 +2079,767 @@
 ();%0A  %7D%0A
-%7D
+%0A  private static final String WATCH_INSIDE_MULTI_MESSAGE = %22WATCH inside MULTI is not allowed%22;%0A%0A  /**%0A   * @param keys%0A   * @return%0A   * @throws UnsupportedOperationException%0A   * @deprecated %7B@value #WATCH_INSIDE_MULTI_MESSAGE%7D%0A   */%0A  @Override%0A  @Deprecated%0A  public Response%3CString%3E watch(String... keys) throws UnsupportedOperationException %7B%0A    throw new UnsupportedOperationException(WATCH_INSIDE_MULTI_MESSAGE);%0A  %7D%0A%0A  /**%0A   * @param keys%0A   * @return%0A   * @throws UnsupportedOperationException%0A   * @deprecated %7B@value #WATCH_INSIDE_MULTI_MESSAGE%7D%0A   */%0A  @Override%0A  @Deprecated%0A  public Response%3CString%3E watch(byte%5B%5D... keys) throws UnsupportedOperationException %7B%0A    throw new UnsupportedOperationException(WATCH_INSIDE_MULTI_MESSAGE);%0A  %7D%0A%7D%0A

Disable WATCH within Transaction (#2362)