public enum Bit {

	zero {
		@Override
		public int value() {
			return 0;
		}
	},one {
		@Override
		public int value() {
			return 1;
		}
	};
	
	public abstract int value();
	
	public String toString(){
		return String.valueOf(value());
	}
	
	public static Bit create(int i) {
		if (i == 0) {
			return Bit.zero;
		} else if (i == 1) {
			return Bit.one;
		} else {
			return null;
		}
	}
	
} public enum BitopOperations {

	and {
		@Override
		public int operate(int i, int j) {
			return i & j;
		}
	},or {
		@Override
		public int operate(int i, int j) {
			return i | j;
		}
	},not {
		@Override
		public int operate(int i, int j) {
			return 1 - i;
		}
	},xor {
		@Override
		public int operate(int i, int j) {
			return i ^ j;
		}
	};
	
	public abstract int operate(int i, int j);
} public class BooleanResultCommand extends AbstractCommand<Boolean> {

	protected Boolean receive(MultibulkInputStream inputStream, Commands command, Object... arguments) throws Exception {
		String response = inputStream.readLine();
		if (ProtocolUtil.isOk(response)) {
			return true;
		} else {
			throw new RuntimeException(ProtocolUtil.extractResult(response));
		}
	}

	@Override
	public Boolean merge(Boolean current, Boolean next) {
		return current && next;
	}

} public interface Command<T> {

	public T execute(Connection connection,Commands command, Object... arguments);
	
	public T merge(T current, T next);

} public enum CommandCache {
	
	INSTANCE;
	
	private Map<Class<? extends Command<?>>, Command<?>> cache = new HashMap<Class<? extends Command<?>>, Command<?>>();
	
	@SuppressWarnings("unchecked")
	public <T> Command<T> get(Class<? extends Command<T>> clazz) {
		Command<?> commandInstance = cache.get(clazz);
		if (commandInstance != null) {
			return (Command<T>) commandInstance;
		}
		synchronized (cache) {
			commandInstance = cache.get(clazz);
			if (commandInstance == null) {
				try {
					commandInstance = clazz.getConstructor(new Class<?>[]{}).newInstance();
					cache.put(clazz, commandInstance);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		}
		return (Command<T>) commandInstance;
	}
	
} public enum Commands {
	
	/** Key */
	del,dump,exists,expire,expireat,keys,migrate,move,object,persist
	,pexpire,pexpireat,pttl,randomkey,rename,renamenx,restore,sort,ttl,type,scan,
	
	/** String */
	append,bitcount,bitop,decr,decrby,get,getbit,getrange,getset,incr,incrby
	,incrbyfloat,mget,mset,msetnx,psetex,set,setbit,setex,setnx,setrange,strlen,
	
	/** Hash */
	hdel,hexists,hget,hgetall,hincrby,hincrbyfloat,hkeys,hlen,hmget,hmset,hset
	,hsetnx,hvals,hscan,
	
	/** List */
	blpop,brpop,brpoplpush,lindex,linsert,llen,lpop,lpush,lpushx,lrange,lrem,lset
	,ltrim,rpop,rpoplpush,rpush,rpushx,
	
	/** Set */
	sadd,scard,sdiff,sdiffstore,sinter,sinterstore,sismember,smembers,smove,spop
	,srandmember,srem,sunion,sunionstore,sscan,
	
	/** SortedSet */
	zadd,zcard,zcount,zincrby,zrange,zrangebyscore,zrank,zrem,zremrangebyrank
	,zremrangebyscore,zrevrange,zrevrangebyscore,zrevrank,zscore,zunionstore,zinterstore
	,zscan,zrangebylex,zlexcount,zremrangebylex,
	
	/** HyperLog */
	pfadd,pfcount,pfmerge,
	
	/** Pub/Sub */
	psubscribe,publish,pubsub,punsubscribe,subscribe,unsubscribe,
	
	/** Transaction */
	discard,exec,multi,unwatch,watch,
	
	/** Script */
	eval,evalsha,script_exists,script_flush,script_kill,script_load,
	
	/** Connection */
	auth,echo,ping,quit,select,
	
	/** Server */
	bgrewriteaof,bgsave,client_getname,client_kill,client_list,client_setname
	,config_get,config,resetstat,config_rewrite,config_set,dbsize,debug_object
	,debug_segfault,flushall,flushdb,info,lastsave,monitor,psync,save,shutdown
	,slaveof,showlog,sync,time
	
} public interface Cursor {

	List<Integer> getCursorList();
	
	List<String> getResultList();
	
	
} public class CursorResultCommand extends AbstractCommand<Cursor> {

	@Override
	protected Cursor receive(MultibulkInputStream inputStream, Commands command, Object... arguments) throws Exception {
		String response = inputStream.readLine();
		List<String> list = new ArrayList<String>();
		Integer cursor = null;
		if (ProtocolUtil.isArrayLengthResultOk(response)) {
			response = inputStream.readLine();
			if (ProtocolUtil.isStringLengthResultOk(response)) {
				cursor = Integer.valueOf(inputStream.readLine());
			}
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("scan command ,cursor: " + cursor);
			}
			response = inputStream.readLine();
			if (ProtocolUtil.isArrayLengthResultOk(response)) {
				int length = Integer.valueOf(ProtocolUtil.extractResult(response));
				for (int i = 0; i < length; i++) {
					String line = inputStream.readLine();
					if (ProtocolUtil.isStringLengthResultOk(line)) {
						list.add(inputStream.readLine());
					}
				}
			}
		} else {
			throw new RuntimeException(ProtocolUtil.extractResult(response));
		}
		return new DefaultCursor(Arrays.asList(cursor == 0 ? -1 : cursor), list);
	}

	@Override
	public Cursor merge(Cursor current, Cursor next) {
		List<Integer> cursorList = new ArrayList<Integer>();
		List<String> resultList = new ArrayList<String>();
		cursorList.addAll(current.getCursorList());
		resultList.addAll(current.getResultList());
		cursorList.addAll(next.getCursorList());
		resultList.addAll(next.getResultList());
		return new DefaultCursor(cursorList, resultList);
	}

} public class DefaultCursor implements Cursor {
	
	public static final Cursor EMPTY_CURSOR;
	
	private List<Integer> cursorList;
	
	private List<String> resultList;
	
	static {
		EMPTY_CURSOR = new DefaultCursor(new ArrayList<Integer>(),new ArrayList<String>());
	}
	
	public DefaultCursor() {
		super();
	}
	
	/**
	 * @param cursorList the cursorList
	 * @param resultList the resultList
	 */
	public DefaultCursor(List<Integer> cursorList, List<String> resultList) {
		super();
		this.cursorList = cursorList;
		this.resultList = resultList;
	}

	/**
	 * @return the cursorList
	 */
	public List<Integer> getCursorList() {
		return cursorList;
	}

	/**
	 * @param cursorList the cursorList to set
	 */
	public void setCursorList(List<Integer> cursorList) {
		this.cursorList = cursorList;
	}

	/**
	 * @return the resultlist
	 */
	public List<String> getResultList() {
		return resultList;
	}

	/**
	 * @param resultList the resultlist to set
	 */
	public void setResultList(List<String> resultList) {
		this.resultList = resultList;
	}

} public class IntResultCommand extends AbstractCommand<Integer> {

	@Override
	protected Integer receive(MultibulkInputStream inputStream, Commands command, Object... arguments) throws Exception {
		String response = inputStream.readLine();
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("command is " + command + ", response is " + response + ", arguments.length = " + arguments.length);
			if (arguments != null ) {
				for (int i = 0;i < arguments.length; i++) {
					LOGGER.debug("arguments[" + i + "] = " + arguments[i]);
				}
			}
		}
		if (ProtocolUtil.isIntResultOk(response)) {
			return Integer.valueOf(ProtocolUtil.extractResult(response));
		} else {
			throw new RuntimeException(ProtocolUtil.extractResult(response));
		}
	}

	@Override
	public Integer merge(Integer current, Integer next) {
		return current + next;
	}

} public enum LInsertOptions {

	before, after
	
} public class ListResultCommand extends AbstractCommand<List<String>> {

	@Override
	protected List<String> receive(MultibulkInputStream inputStream, Commands command, Object... arguments) throws Exception {
		String response = inputStream.readLine();
		List<String> list = new ArrayList<String>();
		if (ProtocolUtil.isArrayLengthResultOk(response)) {
			int length = Integer.valueOf(ProtocolUtil.extractResult(response));
			for (int i = 0; i < length; i++) {
				String line = inputStream.readLine();
				if (ProtocolUtil.isStringLengthResultOk(line)) {
					list.add(inputStream.readLine());
				}
			}
		} else {
			throw new RuntimeException(ProtocolUtil.extractResult(response));
		}
		return list;
	}

	@Override
	public List<String> merge(List<String> current, List<String> next) {
		current.addAll(next);
		return current;
	}

} public class StringResultCommand extends AbstractCommand<String> {

	@Override
	protected String receive(MultibulkInputStream inputStream, Commands command, Object... arguments) throws Exception {
		String response = inputStream.readLine();
		String result = null;
		if (ProtocolUtil.isStringLengthResultOk(response)) {
			if (Integer.valueOf(ProtocolUtil.extractResult(response)) > 0) {
				result = TypeUtil.bytesToString(inputStream.readLineBytes());
			}
		} else {
			throw new RuntimeException(ProtocolUtil.extractResult(response));
		}
		return result;
	}

	@Override
	public String merge(String current, String next) {
		throw new UnsupportedOperationException();
	}

} public interface ConnectionPool {

	public Connection obtainConnection();

	public void releaseConnection(Connection connection);
	
} public interface LoadBalanceStrategy<T> {

	public T select(String key);
	
	public List<T> getAll();
	
} public class SimpleNodeStrategy<T> implements LoadBalanceStrategy<T> {
	
	private T node;
	
	private List<T> nodes;

	public SimpleNodeStrategy(List<T> nodes) {
		if (nodes == null || nodes.size() == 0) {
			throw new IllegalArgumentException("nodes can't be empty!");
		}
		this.node = nodes.get(0);
		this.nodes = Collections.unmodifiableList(nodes);
	}
	
	/* (non-Javadoc)
	 * @see cn.zxl.deerlet.redis.client.config.LoadBalanceStrategy#select(java.lang.String)
	 */
	@Override
	public T select(String key) {
		return node;
	}


	/* (non-Javadoc)
	 * @see cn.zxl.deerlet.redis.client.config.LoadBalanceStrategy#getAll()
	 */
	@Override
	public List<T> getAll() {
		return nodes;
	}

}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.zuoxiaolong.deerlet.redis.client.command.Bit;
import com.zuoxiaolong.deerlet.redis.client.command.BitopOperations;
import com.zuoxiaolong.deerlet.redis.client.command.BooleanResultCommand;
import com.zuoxiaolong.deerlet.redis.client.command.Command;
import com.zuoxiaolong.deerlet.redis.client.command.CommandCache;
import com.zuoxiaolong.deerlet.redis.client.command.Commands;
import com.zuoxiaolong.deerlet.redis.client.command.Cursor;
import com.zuoxiaolong.deerlet.redis.client.command.CursorResultCommand;
import com.zuoxiaolong.deerlet.redis.client.command.DefaultCursor;
import com.zuoxiaolong.deerlet.redis.client.command.IntResultCommand;
import com.zuoxiaolong.deerlet.redis.client.command.LInsertOptions;
import com.zuoxiaolong.deerlet.redis.client.command.ListResultCommand;
import com.zuoxiaolong.deerlet.redis.client.command.StringResultCommand;
import com.zuoxiaolong.deerlet.redis.client.connection.ConnectionPool;
import com.zuoxiaolong.deerlet.redis.client.strategy.LoadBalanceStrategy;
import com.zuoxiaolong.deerlet.redis.client.strategy.SimpleNodeStrategy;
package com.zuoxiaolong.deerlet.redis.client;



/**
 * 客户端的默认实现，采用连接池管理连接。
 *
 * @author zuoxiaolong
 * @since 2015 2015年3月6日 下午11:38:36
 */
public class ClusterDeerletRedisClient extends AbstractDeerletRedisClient implements DeerletRedisClient {

    public ClusterDeerletRedisClient(LoadBalanceStrategy<ConnectionPool> strategy) {
    	super(strategy);
    }

    protected int getServerSize() {
        return strategy.getAll().size();
    }

	/* **************key************* */
    
    @Override
    public int del(String... keys) {
        int result = 0;
        for (int i = 0; i < keys.length; i++) {
            result += executeCommand(keys[i], IntResultCommand.class, Commands.del, keys[i]);
        }
        return result;
    }

    @Override
    public List<String> keys(String pattern) {
        return executeCommand(ListResultCommand.class, Commands.keys, pattern);
    }

    @Override
    public boolean rename(String key, String newKey) {
        return set(newKey, get(key)) && (del(key) == 1);
    }

    @Override
    public boolean renamenx(String key, String newKey) {
        if (exists(newKey)) {
            return false;
        }
        return rename(key, newKey);
    }

    @Override
    public Cursor scan(Cursor cursor, String pattern, Integer count) {
        if (cursor == null) {
            cursor = DefaultCursor.EMPTY_CURSOR;
        }
        List<Integer> cursorList = cursor.getCursorList();
        List<ConnectionPool> connectionPools = strategy.getAll();
        if (cursorList.size() != connectionPools.size() && cursor != DefaultCursor.EMPTY_CURSOR) {
            throw new IllegalArgumentException("cursorList.size() != connectionPools.size()!");
        }
        Command<Cursor> cursorResultCommand = CommandCache.INSTANCE.get(CursorResultCommand.class);