content: package redis.clients.jedis;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import redis.clients.jedis.exceptions.*;
  import redis.clients.util.JedisClusterCRC16;
  
  /**
   * Created by yijunzhang on 14-7-19.
   */
  public class SubPubClusterCommand {
      private final Logger logger = LoggerFactory.getLogger(this.getClass());
  
      protected final PipelineCluster pipelineCluster;
  
      private final JedisClusterConnectionHandler connectionHandler;
  
      private final int redirections;
  
      private ThreadLocal<Jedis> askConnection = new ThreadLocal<Jedis>();
  
      public SubPubClusterCommand(PipelineCluster pipelineCluster, JedisClusterConnectionHandler connectionHandler,
              int redirections) {
          this.pipelineCluster = pipelineCluster;
          this.connectionHandler = connectionHandler;
          this.redirections = redirections;
      }
  
      private Jedis returnRetriesJedis(String key, int redirections,
                                       boolean tryRandomNode, boolean asking) {
          if (redirections <= 0) {
              throw new JedisClusterMaxRedirectionsException(
                      "Too many Cluster redirections? key=" + key);
          }
  
          Jedis jedis = null;
          try {
              if (asking) {
                  // TODO: Pipeline asking with the original command to make it
                  // faster....
                  jedis = askConnection.get();
                  jedis.asking();
  
                  // if asking success, reset asking flag
                  asking = false;
              } else if (tryRandomNode) {
                  jedis = connectionHandler.getConnection();
              } else {
                  jedis = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));
              }
  
              return jedis;
          } catch (JedisConnectionException jce) {
              if (tryRandomNode) {
                  // maybe all connection is down
                  throw jce;
              }
  
              releaseConnection(jedis);
              // retry with random connection
              return returnRetriesJedis(key, redirections--, true, asking);
          }  catch (JedisRedirectionException jre) {
              // if MOVED redirection occurred,
              if (jre instanceof JedisMovedDataException) {
                  // it rebuilds cluster's slot cache
                  // recommended by Redis cluster specification
                  this.connectionHandler.renewSlotCache(jedis);
              }
  
              // release current connection before recursion or renewing
              releaseConnection(jedis);
              jedis = null;
  
              if (jre instanceof JedisAskDataException) {
                  asking = true;
                  askConnection.set(this.connectionHandler.getConnectionFromNode(jre.getTargetNode()));
              } else if (jre instanceof JedisMovedDataException) {
              } else {
                  throw new JedisClusterException(jre);
              }
  
              return returnRetriesJedis(key, redirections - 1, false, asking);
          }
      }
  
      public Jedis getJedis(String channel) {
          return returnRetriesJedis(channel, this.redirections, false, false);
      }
  
      public Jedis getNewJedis(String channel, int timeout) {
          Jedis jedis = getJedis(channel);
          try {
              String host = jedis.getClient().getHost();
              int port = jedis.getClient().getPort();
              Jedis newJedis = new Jedis(host, port, timeout);
              String pong = newJedis.ping();
              if (pong == null || !pong.equals("PONG")) {
                  throw new JedisException("SubPubCluster:jedis is not ping !");
              }
              return newJedis;
          } finally {
              releaseConnection(jedis);
          }
      }
  
      public void releaseConnection(Jedis connection) {
          if (connection != null) {
              connection.close();
          }
      }
  
  }
  