All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fiftyonred.mock_jedis.MockPipeline Maven / Gradle / Ivy

package com.fiftyonred.mock_jedis;

import com.fiftyonred.utils.WildcardMatcher;
import redis.clients.jedis.BuilderFactory;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.util.SafeEncoder;

import java.util.*;

public class MockPipeline extends Pipeline {
	private final WildcardMatcher wildcardMatcher = new WildcardMatcher();
	private final List> allKeys;
	private final List> allStorage;
	private final List>> allHashStorage;
    private final List>> allListStorage;
    private final List>> allSetStorage;

	private int currentDB;
	private static final int NUM_DBS = 16;
	private Map keys;
	private Map storage;
	private Map> hashStorage;
    private Map> listStorage;
    private Map> setStorage;

	public MockPipeline() {
		allKeys = new ArrayList>(NUM_DBS);
		allStorage = new ArrayList>(NUM_DBS);
		allHashStorage = new ArrayList>>(NUM_DBS);
		allListStorage = new ArrayList>>(NUM_DBS);
        allSetStorage = new ArrayList>>(NUM_DBS);
		for (int i = 0; i < NUM_DBS; ++i) {
			allKeys.add(new HashMap());
			allStorage.add(new HashMap());
			allHashStorage.add(new HashMap>());
            allListStorage.add(new HashMap>());
            allSetStorage.add(new HashMap>());
		}
		select(0);
	}

	public int getCurrentDB() {
		return currentDB;
	}

	protected static  T getRandomElementFromSet(final Set set) {
		return (T) set.toArray()[(int) (Math.random() * set.size())];
	}

	@Override
	public Response ping() {
		Response response = new Response(BuilderFactory.STRING);
		response.set("PONG".getBytes());
		return response;
	}

	@Override
	public Response echo(final String string) {
		Response response = new Response(BuilderFactory.STRING);
		response.set(echo(string.getBytes()).get());
		return response;
	}

	@Override
	public Response echo(final byte[] string) {
		Response response = new Response(BuilderFactory.BYTE_ARRAY);
		response.set(string);
		return response;
	}

	@Override
	public synchronized Response dbSize() {
		Response response = new Response(BuilderFactory.LONG);
		response.set((long) keys.size());
		return response;
	}

	@Override
	public synchronized Response flushAll() {
		Response response = new Response(BuilderFactory.STRING);
		for (int dbNum = 0; dbNum < NUM_DBS; ++dbNum) {
			allKeys.get(dbNum).clear();
			allStorage.get(dbNum).clear();
			allHashStorage.get(dbNum).clear();
			allListStorage.get(dbNum).clear();
		}
		response.set("OK".getBytes());
		return response;
	}

	@Override
	public synchronized Response flushDB() {
		Response response = new Response(BuilderFactory.STRING);
		keys.clear();
		storage.clear();
		hashStorage.clear();
		listStorage.clear();
		response.set("OK".getBytes());
		return response;
	}

	@Override
	public synchronized Response rename(final String oldkey, final String newkey) {
		if (oldkey.equals(newkey)) {
			throw new JedisDataException("ERR source and destination objects are the same");
		}
		Response response = new Response(BuilderFactory.STRING);
		final KeyInformation info = keys.get(oldkey);
		switch (info.getType()) {
			case HASH:
				hashStorage.put(newkey, hashStorage.get(oldkey));
				hashStorage.remove(oldkey);
				break;
			case LIST:
				listStorage.put(newkey, listStorage.get(oldkey));
				listStorage.remove(oldkey);
				break;
			case STRING:
			default:
				storage.put(newkey, storage.get(oldkey));
				storage.remove(oldkey);
		}
		keys.put(newkey, info);
		keys.remove(oldkey);
		response.set("OK".getBytes());
		return response;
	}

	@Override
	public Response rename(final byte[] oldkey, final byte[] newkey) {
		return rename(new String(oldkey), new String(newkey));
	}

	@Override
	public synchronized Response renamenx(final String oldkey, final String newkey) {
		if (oldkey.equals(newkey)) {
			throw new JedisDataException("ERR source and destination objects are the same");
		}
		Response response = new Response(BuilderFactory.LONG);
		final KeyInformation newInfo = keys.get(newkey);
		if (newInfo == null) {
			rename(oldkey, newkey);
			response.set(1L);
		} else {
			response.set(0L);
		}
		return response;
	}

	@Override
	public Response renamenx(final byte[] oldkey, final byte[] newkey) {
		return renamenx(new String(oldkey), new String(newkey));
	}

	@Override
	public synchronized Response set(final String key, final String value) {
		Response response = new Response(BuilderFactory.STRING);
		createOrUpdateKey(key, KeyType.STRING, true);
		storage.put(key, value);
		response.set("OK".getBytes());
		return response;
	}

	@Override
	public synchronized Response set(final byte[] key, final byte[] value) {
		return set(new String(key), new String(value));
	}

	@Override
	public synchronized Response setnx(final String key, final String value) {
		Response response = new Response(BuilderFactory.LONG);
		final String result = getStringFromStorage(key, false);
		if (result == null) {
			set(key, value);
			response.set(1L);
		} else {
			response.set(0L);
		}

		return response;
	}

	@Override
	public synchronized Response setnx(final byte[] key, final byte[] value) {
		return setnx(new String(key), new String(value));
	}

	@Override
	public synchronized Response get(String key) {
		final Response response = new Response(BuilderFactory.STRING);
		final String val = getStringFromStorage(key, false);
		response.set(val == null ? null : val.getBytes());
		return response;
	}

	@Override
	public Response get(final byte[] key) {
		final Response response = new Response(BuilderFactory.BYTE_ARRAY);
		final String result = get(new String(key)).get();
		response.set(result == null ? null : result.getBytes());
		return response;
	}

	@Override
	public synchronized Response getSet(final String key, final String value) {
		final Response response = get(key);
		set(key, value);
		return response;
	}

	@Override
	public synchronized Response getSet(final byte[] key, final byte[] value) {
		final Response response = get(key);
		set(key, value);
		return response;
	}

	@Override
	public Response dump(byte[] key) {
		return get(key);
	}

	@Override
	public Response dump(String key) {
		return get(key.getBytes());
	}

	@Override
	public Response restore(String key, int ttl, byte[] serializedValue) {
		return setex(key.getBytes(), ttl, serializedValue);
	}

	@Override
	public Response restore(byte[] key, int ttl, byte[] serializedValue) {
		return setex(key, ttl, serializedValue);
	}

	@Override
	public synchronized Response exists(final String key) {
		Response response = new Response(BuilderFactory.BOOLEAN);
		response.set(keys.containsKey(key) ? 1L : 0L);
		return response;
	}

	@Override
	public synchronized Response exists(final byte[] key) {
		return exists(new String(key));
	}

	@Override
	public synchronized Response type(final String key) {
		final Response response = new Response(BuilderFactory.STRING);
		final KeyInformation info = keys.get(key);
		if (info != null && info.getType() == KeyType.STRING) {
			response.set("string".getBytes());
		} else if (info != null && info.getType() == KeyType.LIST) {
			response.set("list".getBytes());
		} else if (info != null && info.getType() == KeyType.SET) {
			response.set("set".getBytes());
		} else {
			response.set("none".getBytes());
		}
		return response;
	}

	@Override
	public synchronized Response type(final byte[] key) {
		return type(new String(key));
	}

	@Override
	public Response move(final String key, final int dbIndex) {
		if (dbIndex < 0 || dbIndex > 15) {
			throw new JedisDataException("ERR index out of range");
		}
		final Response response = new Response(BuilderFactory.LONG);
		final KeyInformation info = keys.get(key);
		if (info == null) {
			response.set(0L);
		} else {
			final KeyInformation infoNew = allKeys.get(dbIndex).get(key);
			if (infoNew == null) {
				allKeys.get(dbIndex).put(key, info);
				switch (info.getType()) {
					case HASH:
						allHashStorage.get(dbIndex).put(key, hashStorage.get(key));
						hashStorage.remove(key);
						break;
					case LIST:
						allListStorage.get(dbIndex).put(key, listStorage.get(key));
						listStorage.remove(key);
						break;
					default:
					case STRING:
						allStorage.get(dbIndex).put(key, storage.get(key));
						storage.remove(key);
				}
				keys.remove(key);
				response.set(1L);
			} else {
				response.set(0L);
			}
		}
		return response;

	}

	@Override
	public synchronized Response move(final byte[] key, final int dbIndex) {
		return move(new String(key), dbIndex);
	}

	@Override
	public synchronized Response randomKey() {
		Response response = new Response(BuilderFactory.STRING);
		if (keys.size() == 0) {
			response.set(null);
		} else {
			final String result = getRandomElementFromSet(keys.keySet());
			response.set(result.getBytes());
		}
		return response;
	}

	@Override
	public Response randomKeyBinary() {
		Response response = new Response(BuilderFactory.BYTE_ARRAY);
		final String result = randomKey().get();
		response.set(result == null ? null : result.getBytes());
		return response;
	}

	@Override
	public Response select(final int dbIndex) {
		if (dbIndex < 0 || dbIndex > 15) {
			throw new JedisDataException("ERR invalid DB index");
		}
		Response response = new Response(BuilderFactory.STRING);
		currentDB = dbIndex;
		keys = allKeys.get(dbIndex);
		storage = allStorage.get(dbIndex);
		hashStorage = allHashStorage.get(dbIndex);
		listStorage = allListStorage.get(dbIndex);
        setStorage = allSetStorage.get(dbIndex);
		response.set("OK".getBytes());
		return response;
	}

	@Override
	public Response setex(String key, int seconds, String value) {
		return psetex(key, seconds * 1000, value);
	}

	@Override
	public Response setex(byte[] key, int seconds, byte[] value) {
		return setex(new String(key), seconds, new String(value));
	}

	@Override
	public synchronized Response psetex(final String key, final int milliseconds, final String value) {
		final Response response = set(key, value);
		pexpire(key, milliseconds);
		return response;
	}

	@Override
	public Response psetex(final byte[] key, final int milliseconds, final byte[] value) {
		return psetex(new String(key), milliseconds, new String(value));
	}

	@Override
	public Response expire(final String key, final int seconds) {
		return expireAt(key, System.currentTimeMillis() / 1000 + seconds);
	}

	@Override
	public Response expire(final byte[] key, final int seconds) {
		return expire(new String(key), seconds);
	}

	@Override
	public Response expireAt(final String key, final long seconds) {
		return pexpireAt(key, seconds * 1000);
	}

	@Override
	public Response expireAt(final byte[] key, final long seconds) {
		return expireAt(new String(key), seconds);
	}

	@Override
	public Response pexpire(final String key, final int milliseconds) {
		return pexpireAt(key, System.currentTimeMillis() + milliseconds);
	}

	@Override
	public Response pexpire(final byte[] key, final int milliseconds) {
		return pexpire(new String(key), milliseconds);
	}

	@Override
	public synchronized Response pexpireAt(final String key, final long millisecondsTimestamp) {
		final Response response = new Response(BuilderFactory.LONG);
		final KeyInformation info = keys.get(key);
		if (info == null || info.isTTLSetAndKeyExpired()) {
			response.set(0L);
		} else {
			info.setExpiration(millisecondsTimestamp);
			response.set(1L);
		}

		return response;
	}

	@Override
	public synchronized Response pexpireAt(final byte[] key, final long millisecondsTimestamp) {
		return pexpireAt(new String(key), millisecondsTimestamp);
	}

	@Override
	public Response ttl(String key) {
		Long pttlInResponse = pttl(key).get();

		Response response = new Response(BuilderFactory.LONG);
		if (pttlInResponse != -1L) {
			if (pttlInResponse > 0L && pttlInResponse < 1000L) {
				pttlInResponse = 1000L;
			}
			response.set(pttlInResponse / 1000L);
		} else {
			response.set(pttlInResponse);
		}
		return response;
	}

	@Override
	public synchronized Response append(final String key, final String value) {
		final Response response = new Response(BuilderFactory.LONG);
		final String newVal = getStringFromStorage(key, true) + value;
		set(key, newVal);
		response.set((long) newVal.length());
		return response;
	}

	@Override
	public Response append(final byte[] key, final byte[] value) {
		return append(new String(key), new String(value));
	}

	@Override
	public Response ttl(byte[] key) {
		return ttl(new String(key));
	}

	@Override
	public synchronized Response pttl(final String key) {
		Response response = new Response(BuilderFactory.LONG);
		final KeyInformation info = keys.get(key);
		response.set(info == null ? -1L : info.getTTL());
		return response;
	}

	@Override
	public synchronized Response persist(String key) {
		Response response = new Response(BuilderFactory.LONG);
		final KeyInformation info = keys.get(key);
		if (response == null || info.getTTL() == -1) {
			response.set(0L);
		} else {
			info.setExpiration(-1L);
			response.set(1L);
		}
		return response;
	}

	@Override
	public Response persist(byte[] key) {
		return persist(new String(key));
	}

	@Override
	public synchronized Response> mget(final String... keys) {
		if (keys.length <= 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'mget' command");
		}

		final Response> response = new Response>(BuilderFactory.STRING_LIST);

		final List result = new ArrayList();
		for (final String key : keys) {
			final String val = getStringFromStorage(key, false);
			result.add(val == null ? null : val.getBytes());
		}
		response.set(result);
		return response;
	}

	@Override
	public synchronized Response> mget(final byte[]... keys) {
		if (keys.length <= 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'mget' command");
		}

		final Response> response = new Response>(BuilderFactory.BYTE_ARRAY_LIST);

		final List result = new ArrayList();
		for (final byte[] key : keys) {
			final String val = getStringFromStorage(new String(key), false);
			result.add(val == null ? null : val.getBytes());
		}
		response.set(result);
		return response;
	}

	@Override
	public synchronized Response mset(final String... keys) {
		if (keys.length <= 0 || keys.length % 2 != 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'mset' command");
		}

		for (int i = 0; i < keys.length; i += 2) {
			set(keys[i], keys[i + 1]);
		}

		final Response response = new Response(BuilderFactory.STRING);
		response.set("OK".getBytes());
		return response;
	}

	@Override
	public Response mset(final byte[]... keys) {
		return mset(convertToStrings(keys));
	}

	@Override
	public synchronized Response msetnx(final String... keys) {
		if (keys.length <= 0 || keys.length % 2 != 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'msetnx' command");
		}

		long result = 1L;
		for (int i = 0; i < keys.length; i += 2) {
			if (setnx(keys[i], keys[i + 1]).get() == 0L) {
                result = 0L;
			}
		}

		final Response response = new Response(BuilderFactory.LONG);
		response.set(result);
		return response;
	}

	@Override
	public Response msetnx(final byte[]... keys) {
		return msetnx(convertToStrings(keys));
	}

	@Override
	public Response decr(String key) {
		return decrBy(key, 1);
	}

	@Override
	public Response decr(final byte[] key) {
		return decr(new String(key));
	}

	@Override
	public Response decrBy(String key, long integer) {
		return incrBy(key, -integer);
	}

	@Override
	public Response decrBy(final byte[] key, final long integer) {
		return decrBy(new String(key), integer);
	}

	@Override
	public Response incr(String key) {
		return incrBy(key, 1);
	}

	@Override
	public Response incr(final byte[] key) {
		return incr(new String(key));
	}

	@Override
	public synchronized Response incrBy(String key, long integer) {
		final Response response = new Response(BuilderFactory.LONG);
		final String val = getStringFromStorage(key, true);

		final long oldValue;
		try {
			oldValue = val == null || "".equals(val) ? 0L : Long.parseLong(val);
		} catch (final NumberFormatException ignored) {
			throw new JedisDataException("ERR value is not an integer or out of range");
		}

		// check for overflow
		if (oldValue > 0 ? integer > Long.MAX_VALUE - oldValue : integer < Long.MIN_VALUE - oldValue) {
			throw new JedisDataException("ERR value is not an integer or out of range");
		}

		final long result = oldValue + integer;
		storage.put(key, Long.toString(result));
		response.set(result);
		return response;
	}

	@Override
	public Response incrBy(final byte[] key, long integer) {
		return incrBy(new String(key), integer);
	}

	@Override
	public synchronized Response incrByFloat(final String key, final double integer) {
		final Response response = new Response(BuilderFactory.DOUBLE);
		final String val = getStringFromStorage(key, true);
		final Double result;
		try {
			result = val == null || "".equals(val) ? integer : Double.parseDouble(val) + integer;
		} catch (final NumberFormatException ignored) {
			throw new JedisDataException("ERR value is not a valid float");
		}
		storage.put(key, result.toString());
		response.set(result.toString().getBytes());
		return response;
	}

	@Override
	public Response incrByFloat(final byte[] key, final double integer) {
		return incrByFloat(new String(key), integer);
	}

	@Override
	public Response strlen(final String key) {
		final Response response = new Response(BuilderFactory.LONG);
		final String val = getStringFromStorage(key, false);
		response.set(val == null ? 0L : (long) val.length());
		return response;
	}

	@Override
	public Response strlen(final byte[] key) {
		return strlen(new String(key));
	}

	@Override
	public Response del(final String... keys) {
		Response response = new Response(BuilderFactory.LONG);
		long result = 0L;
		for (String key : keys) {
			result += del(key).get();
		}

		response.set(result);
		return response;
	}

	@Override
	public Response del(final byte[]... keys) {
		Response response = new Response(BuilderFactory.LONG);
		long result = 0L;
		for (byte[] key : keys) {
			result += del(key).get();
		}

		response.set(result);
		return response;
	}

	@Override
	public synchronized Response del(final String key) {
		Response response = new Response(BuilderFactory.LONG);
		long result = 0L;
		final KeyInformation info = this.keys.remove(key);
		if (info != null) {
			switch (info.getType()) {
				case HASH:
					hashStorage.remove(key);
					break;
				case LIST:
					listStorage.remove(key);
					break;
				case STRING:
				default:
					storage.remove(key);
			}
			++result;
		}
		response.set(result);
		return response;
	}

	@Override
	public Response del(final byte[] key) {
		return del(new String(key));
	}

	@Override
	public synchronized Response hget(final String key, final String field) {
		final Response response = new Response(BuilderFactory.STRING);
		final Map result = getHashFromStorage(key, false);
		if (result != null) {
			response.set(result.containsKey(field) ? result.get(field).getBytes() : null);
		}
		return response;
	}

	@Override
	public synchronized Response> hgetAll(final String key) {
		final Response> response = new Response>(BuilderFactory.STRING_MAP);
		final Map result = getHashFromStorage(key, false);

		if (result != null) {
			final List encodedResult = new ArrayList();
			for (Map.Entry e : result.entrySet()) {
				encodedResult.add(SafeEncoder.encode(e.getKey()));
				encodedResult.add(SafeEncoder.encode(e.getValue()));
			}
			response.set(encodedResult);
		} else {
			response.set(new ArrayList());
		}
		return response;
	}

	@Override
	public synchronized Response> hkeys(final String key) {
		final Response> response = new Response>(BuilderFactory.STRING_SET);
		final Map result = getHashFromStorage(key, false);

		if (result != null) {
			final List encodedResult = new ArrayList();
			for (String k : result.keySet()) {
				encodedResult.add(SafeEncoder.encode(k));
			}
			response.set(encodedResult);
		} else {
			response.set(new ArrayList());
		}
		return response;
	}

	@Override
	public synchronized Response> hvals(final String key) {
		final Response> response = new Response>(BuilderFactory.STRING_LIST);
		final Map result = getHashFromStorage(key, false);

		if (result != null) {
			final List encodedResult = new ArrayList();
			for (String v : result.values()) {
				encodedResult.add(SafeEncoder.encode(v));
			}
			response.set(encodedResult);
		} else {
			response.set(new ArrayList());
		}
		return response;
	}

	@Override
	public synchronized Response hset(final String key, final String field, final String value) {
		final Response response = new Response(BuilderFactory.LONG);
		final Map m = getHashFromStorage(key, true);
		response.set(m.containsKey(field) ? 0L : 1L);
		m.put(field, value);

		return response;
	}

	@Override
	public synchronized Response hsetnx(final String key, final String field, final String value) {
		final Response response = new Response(BuilderFactory.LONG);
		final Map m = getHashFromStorage(key, true);
		long result = 0L;
		if (!m.containsKey(field)) {
			m.put(field, value);
			result = 1L;
		}
		response.set(result);

		return response;
	}

	@Override
	public synchronized Response> hmget(final String key, final String... fields) {
		final Response> response = new Response>(BuilderFactory.STRING_LIST);
		final List result = new ArrayList();
		final Map hash = getHashFromStorage(key, false);
		if (hash == null) {
			for (String field : fields) {
				result.add(null);
			}
			response.set(result);
			return response;
		}

		for (String field : fields) {
			final String v = getHashFromStorage(key, false).get(field);
			result.add(v != null ? v.getBytes() : null);
		}
		response.set(result);
		return response;
	}

	@Override
	public synchronized Response hmset(final String key, Map hash) {
		final Response response = new Response(BuilderFactory.STRING);
		final Map m = getHashFromStorage(key, true);
		for (Map.Entry e : hash.entrySet()) {
			m.put(e.getKey(), e.getValue());
		}
		response.set("OK".getBytes());
		return response;
	}

	@Override
	public synchronized Response hincrBy(final String key, final String field, final long value) {
		final Response response = new Response(BuilderFactory.LONG);
		final Map m = getHashFromStorage(key, true);

		String val = m.get(field);
		if (val == null) {
			val = Long.valueOf(0L).toString();
		}
		final Long result;
		try {
			result = Long.valueOf(val) + value;
		} catch (final NumberFormatException ignored) {
			throw new JedisDataException("ERR value is not an integer or out of range");
		}
		m.put(field, result.toString());
		response.set(result);
		return response;
	}

	@Override
	public synchronized Response hincrByFloat(final String key, final String field, final double value) {
		final Response response = new Response(BuilderFactory.DOUBLE);
		final Map m = getHashFromStorage(key, true);

		String val = m.get(field);
		if (val == null) {
			val = Double.valueOf(0D).toString();
		}
		final Double result;
		try {
			result = Double.parseDouble(val) + value;
		} catch (final NumberFormatException ignored) {
			throw new JedisDataException("ERR value is not a valid float");
		}
		m.put(field, result.toString());
		response.set(result.toString().getBytes());
		return response;
	}

	@Override
	public synchronized Response hdel(final String key, final String... fields) {
		final Response response = new Response(BuilderFactory.LONG);
		final Map m = getHashFromStorage(key, true);
		long result = 0;
		for (String field : fields) {
			if (m.remove(field) != null) {
				++result;
			}
		}
		response.set(result);

		return response;
	}

	@Override
	public synchronized Response hexists(final String key, final String field) {
		final Response response = new Response(BuilderFactory.BOOLEAN);
		final Map hash = getHashFromStorage(key, false);
		if (hash != null) {
			response.set(hash.containsKey(field) ? 1L : 0L);
		}

		return response;
	}

	@Override
	public synchronized Response hlen(final String key) {
		final Response response = new Response(BuilderFactory.LONG);
		final Map hash = getHashFromStorage(key, false);
		if (hash != null) {
			response.set((long) hash.size());
		} else {
			response.set(0L);
		}

		return response;
	}

	@Override
	public synchronized Response lpush(final String key, final String... string) {
		final Response response = new Response(BuilderFactory.LONG);
		List list = getListFromStorage(key, true);
		if (list == null) {
			list = new ArrayList();
			listStorage.put(key, list);
		}
		Collections.addAll(list, string);
		response.set((long) list.size());
		return response;
	}

	@Override
	public Response lpush(final byte[] key, final byte[]... string) {
		return lpush(new String(key), convertToStrings(string));
	}

	@Override
	public synchronized Response lpop(String key) {
		final Response response = new Response(BuilderFactory.STRING);
		final List list = getListFromStorage(key, true);
		if (list == null || list.isEmpty()) {
			response.set(null);
		} else {
			response.set(list.remove(list.size() - 1).getBytes());
		}
		return response;
	}

	@Override
	public synchronized Response lpop(final byte[] key) {
		final Response response = new Response(BuilderFactory.BYTE_ARRAY);
		final List list = getListFromStorage(new String(key), true);
		if (list == null || list.isEmpty()) {
			response.set(null);
		} else {
			response.set(list.remove(list.size() - 1).getBytes());
		}
		return response;
	}

	@Override
	public synchronized Response llen(String key) {
		final Response response = new Response(BuilderFactory.LONG);
		final List list = getListFromStorage(key, false);
		if (list == null) {
			response.set(0L);
		} else {
			response.set((long) list.size());
		}
		return response;
	}

	@Override
	public Response llen(final byte[] key) {
		return llen(new String(key));
	}

	@Override
	public void sync() {
		// do nothing
	}

	@Override
	public synchronized Response> keys(final String pattern) {
		Response> response = new Response>(BuilderFactory.STRING_SET);

		List result = new ArrayList();
		filterKeys(pattern, keys.keySet(), result);

		response.set(result);
		return response;
	}

	@Override
	public Response> keys(final byte[] pattern) {
		final Response> response = new Response>(BuilderFactory.BYTE_ARRAY_ZSET);
		final List result = new ArrayList();
		for (final String key : keys(new String(pattern)).get()) {
			result.add(key.getBytes());
		}

		response.set(result);
		return response;
	}

	public void filterKeys(final String pattern, final Collection collection, final List result) {
		for (String key : collection) {
			if (wildcardMatcher.match(key, pattern)) {
				result.add(key.getBytes());
			}
		}
	}

	protected boolean createOrUpdateKey(final String key, final KeyType type, final boolean resetTTL) {
		KeyInformation info = keys.get(key);
		if (info == null) {
			info = new KeyInformation(type);
			keys.put(key, info);
			return true;
		} else {
			if (info.getType() != type) {
				throw new JedisDataException("ERR Operation against a key holding the wrong kind of value");
			}
			if (resetTTL) {
				info.setExpiration(-1L);
			}
			return false;
		}
	}

	protected String getStringFromStorage(final String key, final boolean createIfNotExist) {
		final KeyInformation info = keys.get(key);
		if (info == null) {
			if (createIfNotExist) {
				createOrUpdateKey(key, KeyType.STRING, true);
				storage.put(key, "");
				return "";
			}
			return null; // no such key exists
		}
		if (info.getType() != KeyType.STRING) {
			throw new JedisDataException("ERR Operation against a key holding the wrong kind of value");
		}
		if (info.isTTLSetAndKeyExpired()) {
			storage.remove(key);
			keys.remove(key);
			return null;
		}
		return storage.get(key);
	}

	protected Map getHashFromStorage(final String key, final boolean createIfNotExist) {
		final KeyInformation info = keys.get(key);
		if (info == null) {
			if (createIfNotExist) {
				createOrUpdateKey(key, KeyType.HASH, false);
				Map result = new HashMap();
				hashStorage.put(key, result);
				return result;
			}
			return null; // no such key exists
		}
		if (info.getType() != KeyType.HASH) {
			throw new JedisDataException("ERR Operation against a key holding the wrong kind of value");
		}
		if (info.isTTLSetAndKeyExpired()) {
			hashStorage.remove(key);
			keys.remove(key);
			return null;
		}
		return hashStorage.get(key);
	}

	protected List getListFromStorage(final String key, final boolean createIfNotExist) {
		final KeyInformation info = keys.get(key);
		if (info == null) {
			if (createIfNotExist) {
				createOrUpdateKey(key, KeyType.LIST, false);
				List result = new ArrayList();
				listStorage.put(key, result);
				return result;
			}
			return null; // no such key exists
		}
		if (info.getType() != KeyType.LIST) {
			throw new JedisDataException("ERR Operation against a key holding the wrong kind of value");
		}
		if (info.isTTLSetAndKeyExpired()) {
			listStorage.remove(key);
			keys.remove(key);
			return null;
		}
		return listStorage.get(key);
	}

    protected Set getSetFromStorage(final String key, boolean createIfNotExist) {
        final KeyInformation info = keys.get(key);
        if (info == null) {
            if (createIfNotExist) {
                createOrUpdateKey(key, KeyType.SET, false);
                Set result = new HashSet();
                setStorage.put(key, result);
                return result;
            }
            return null; // no such key exists
        }
        if (info.getType() != KeyType.SET) {
            throw new JedisDataException("ERR Operation against a key holding the wrong kind of value");
        }
        if (info.isTTLSetAndKeyExpired()) {
            setStorage.remove(key);
            keys.remove(key);
            return null;
        }
        return setStorage.get(key);
    }

	protected static String[] convertToStrings(final byte[][] b) {
		final String[] result = new String[b.length];
		for (int i = 0; i < b.length; ++i) {
			result[i] = new String(b[i]);
		}
		return result;
	}

    @Override
    public synchronized Response sadd(String key, String... members) {
        final Response response = new Response(BuilderFactory.LONG);
        Set set = getSetFromStorage(key, true);

        Long added = 0L;
        for (String s: members) {
            if (set.add(s)) added++;
        }

        response.set(added);
        return response;
    }

	@Override
	public Response sadd(byte[] key, byte[]... members) {
		return sadd(new String(key), convertToStrings(members));
	}

    @Override
    public synchronized Response srem(String key, String... members) {
        final Response response = new Response(BuilderFactory.LONG);
        Set set = getSetFromStorage(key, true);
        Long removed = 0L;
        for (String s: members) {
            if (set.remove(s)) removed++;
        }
        response.set(removed);
        return response;
    }

	@Override
	public Response srem(byte[] key, byte[]... members) {
		return srem(new String(key), convertToStrings(members));
	}

	@Override
	public synchronized Response scard(String key) {
		final Response response = new Response(BuilderFactory.LONG);
		final Set set = getSetFromStorage(key, true);
		response.set((long) set.size());

		return response;
	}

	@Override
	public Response scard(byte[] key) {
		return scard(new String(key));
	}

	@Override
	public synchronized Response> sdiff(final String... keys) {
		if (keys.length <= 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'sdiff' command");
		}
		final Response> response = new Response>(BuilderFactory.STRING_SET);
		final Set firstSet = new HashSet(getSetFromStorage(keys[0], true));
		for (int i = 1; i < keys.length; ++i) {
			final Set set = getSetFromStorage(keys[i], true);
			firstSet.removeAll(set);
		}

		final List builderData = new ArrayList(firstSet.size());
		for (final String value : firstSet) {
			builderData.add(value.getBytes());
		}
		response.set(builderData);

		return response;
	}

	@Override
	public Response> sdiff(final byte[]... keys) {
		final Response> response = new Response>(BuilderFactory.BYTE_ARRAY_ZSET);
		final Set members = sdiff(convertToStrings(keys)).get();
		final List result = new ArrayList(members.size());
		for (final String member : members) {
			result.add(member.getBytes());
		}
		response.set(result);
		return response;
	}

	@Override
	public synchronized Response sdiffstore(final String dstKey, final String... keys) {
		if (keys.length <= 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'sdiff' command");
		}
		final Response response = new Response(BuilderFactory.LONG);
		final Set diff = sdiff(keys).get();
		final Set dst = getSetFromStorage(dstKey, true);
		if (dst.size() > 0) {
			dst.clear();
		}
		dst.addAll(diff);
		response.set((long) diff.size());

		return response;
	}

	@Override
	public Response sdiffstore(final byte[] dstKey, final byte[]... keys) {
		return sdiffstore(new String(dstKey), convertToStrings(keys));
	}

	@Override
	public synchronized Response> sinter(final String... keys) {
		if (keys.length <= 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'sinter' command");
		}
		final Response> response = new Response>(BuilderFactory.STRING_SET);
		final Set firstSet = new HashSet(getSetFromStorage(keys[0], true));
		for (int i = 1; i < keys.length; ++i) {
			final Set set = getSetFromStorage(keys[i], true);
			firstSet.retainAll(set);
		}

		final List builderData = new ArrayList(firstSet.size());
		for (final String value : firstSet) {
			builderData.add(value.getBytes());
		}
		response.set(builderData);

		return response;
	}

	@Override
	public synchronized Response> sinter(final byte[]... keys) {
		final Response> response = new Response>(BuilderFactory.BYTE_ARRAY_ZSET);
		final Set members = sinter(convertToStrings(keys)).get();
		final List result = new ArrayList(members.size());
		for (final String member : members) {
			result.add(member.getBytes());
		}
		response.set(result);
		return response;
	}

	@Override
	public synchronized Response sinterstore(final String dstKey, final String... keys) {
		if (keys.length <= 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'sinterstore' command");
		}
		final Response response = new Response(BuilderFactory.LONG);
		final Set inter = sinter(keys).get();
		final Set dst = getSetFromStorage(dstKey, true);
		if (dst.size() > 0) {
			dst.clear();
		}
		dst.addAll(inter);
		response.set((long) inter.size());

		return response;
	}

	@Override
	public Response sinterstore(final byte[] dstKey, final byte[]... keys) {
		return sinterstore(new String(dstKey), convertToStrings(keys));
	}

	@Override
	public synchronized Response sismember(final String key, final String member) {
		final Response response = new Response(BuilderFactory.BOOLEAN);
		final Set set = getSetFromStorage(key, false);
		response.set(set.contains(member) ? 1L : 0L);
		return response;
	}

	@Override
	public Response sismember(final byte[] key, final byte[] member) {
		return sismember(new String(key), new String(member));
	}

	@Override
	public synchronized Response smove(final String srckey, final String dstkey, final String member) {
		final Response response = new Response(BuilderFactory.LONG);
		final Set src = getSetFromStorage(srckey, false);
		final Set dst = getSetFromStorage(dstkey, true);
		if (src.remove(member)) {
			dst.add(member);
			response.set(1L);
		} else {
			response.set(0L);
		}

		return response;
	}

	@Override
	public Response smove(final byte[] srckey, final byte[] dstkey, final byte[] member) {
		return smove(new String(srckey), new String(dstkey), new String(member));
	}

	@Override
	public synchronized Response spop(final String key) {
		final Response response = srandmember(key);
		if (response.get() != null) {
			final Set src = getSetFromStorage(key, false);
			src.remove(response.get());
		}
		return response;
	}

	@Override
	public Response spop(final byte[] key) {
		final Response response = new Response(BuilderFactory.BYTE_ARRAY);
		final String result = spop(new String(key)).get();
		response.set(result == null ? null : result.getBytes());
		return response;
	}

	@Override
	public synchronized Response srandmember(final String key) {
		final Response response = new Response(BuilderFactory.STRING);
		final Set src = getSetFromStorage(key, false);
		if (src == null) {
			response.set(null);
		} else {
			final String result = getRandomElementFromSet(src);
			response.set(result.getBytes());
		}
		return response;
	}

	@Override
	public Response srandmember(final byte[] key) {
		final Response response = new Response(BuilderFactory.BYTE_ARRAY);
		final String result = srandmember(new String(key)).get();
		response.set(result == null ? null : result.getBytes());
		return response;
	}

	@Override
	public synchronized Response> smembers(String key) {
		final Response> response = new Response>(BuilderFactory.STRING_SET);
		Set set = getSetFromStorage(key, true);

		// BuilderFactory.STRING_SET uses a List internally so we can't just send the Set
		List builderData = new ArrayList(set.size());
		for (String s : set) {
			builderData.add(s.getBytes());
		}

		response.set(builderData);

		return response;
	}

	@Override
	public Response> smembers(byte[] key) {
		final Response> response = new Response>(BuilderFactory.BYTE_ARRAY_ZSET);
		final Set members = smembers(new String(key)).get();
		final List result = new ArrayList(members.size());
		for (final String member : members) {
			result.add(member.getBytes());
		}
		response.set(result);

		return response;
	}

	@Override
	public synchronized Response> sunion(final String... keys) {
		if (keys.length <= 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'sunion' command");
		}
		final Response> response = new Response>(BuilderFactory.STRING_SET);
		final Set firstSet = new HashSet(getSetFromStorage(keys[0], true));
		for (int i = 1; i < keys.length; ++i) {
			final Set set = getSetFromStorage(keys[i], true);
			firstSet.addAll(set);
		}

		final List builderData = new ArrayList(firstSet.size());
		for (final String value : firstSet) {
			builderData.add(value.getBytes());
		}
		response.set(builderData);

		return response;
	}

	@Override
	public Response> sunion(final byte[]... keys) {
		final Response> response = new Response>(BuilderFactory.BYTE_ARRAY_ZSET);
		final Set members = sunion(convertToStrings(keys)).get();
		final List result = new ArrayList(members.size());
		for (final String member : members) {
			result.add(member.getBytes());
		}
		response.set(result);
		return response;
	}

	@Override
	public synchronized Response sunionstore(final String dstKey, final String... keys) {
		if (keys.length <= 0) {
			throw new JedisDataException("ERR wrong number of arguments for 'sunionstore' command");
		}
		final Response response = new Response(BuilderFactory.LONG);
		final Set inter = sunion(keys).get();
		final Set dst = getSetFromStorage(dstKey, true);
		if (dst.size() > 0) {
			dst.clear();
		}
		dst.addAll(inter);
		response.set((long) inter.size());

		return response;
	}

	@Override
	public Response sunionstore(final byte[] dstKey, final byte[]... keys) {
		return sunionstore(new String(dstKey), convertToStrings(keys));
	}
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy