/* * Copyright 2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.MapScanCursor; import io.lettuce.core.ScanArgs; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisHashCommands; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; /** * @author Christoph Strobl * @since 2.0 */ class LettuceHashCommands implements RedisHashCommands { private final LettuceConnection connection; public LettuceHashCommands(LettuceConnection connection) { this.connection = connection; } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hSet(byte[], byte[], byte[]) */ @Override public Boolean hSet(byte[] key, byte[] field, byte[] value) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hset(key, field, value))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hset(key, field, value))); return null; } return getConnection().hset(key, field, value); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hSetNX(byte[], byte[], byte[]) */ @Override public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hsetnx(key, field, value))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hsetnx(key, field, value))); return null; } return getConnection().hsetnx(key, field, value); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hDel(byte[], byte[][]) */ @Override public Long hDel(byte[] key, byte[]... fields) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hdel(key, fields))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hdel(key, fields))); return null; } return getConnection().hdel(key, fields); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hExists(byte[], byte[]) */ @Override public Boolean hExists(byte[] key, byte[] field) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hexists(key, field))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hexists(key, field))); return null; } return getConnection().hexists(key, field); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hGet(byte[], byte[]) */ @Override public byte[] hGet(byte[] key, byte[] field) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hget(key, field))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hget(key, field))); return null; } return getConnection().hget(key, field); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hGetAll(byte[]) */ @Override public Map<byte[], byte[]> hGetAll(byte[] key) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hgetall(key))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hgetall(key))); return null; } return getConnection().hgetall(key); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], long) */ @Override public Long hIncrBy(byte[] key, byte[] field, long delta) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hincrby(key, field, delta))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hincrby(key, field, delta))); return null; } return getConnection().hincrby(key, field, delta); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], double) */ @Override public Double hIncrBy(byte[] key, byte[] field, double delta) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hincrbyfloat(key, field, delta))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hincrbyfloat(key, field, delta))); return null; } return getConnection().hincrbyfloat(key, field, delta); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hKeys(byte[]) */ @Override public Set<byte[]> hKeys(byte[] key) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); return null; } return LettuceConverters.toBytesSet(getConnection().hkeys(key)); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hLen(byte[]) */ @Override public Long hLen(byte[] key) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hlen(key))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hlen(key))); return null; } return getConnection().hlen(key); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hMGet(byte[], byte[][]) */ @Override public List<byte[]> hMGet(byte[] key, byte[]... fields) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hmget(key, fields), LettuceConverters.keyValueListUnwrapper())); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hmget(key, fields), LettuceConverters.keyValueListUnwrapper())); return null; } return LettuceConverters.<byte[], byte[]> keyValueListUnwrapper().convert(getConnection().hmget(key, fields)); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hMSet(byte[], java.util.Map) */ @Override public void hMSet(byte[] key, Map<byte[], byte[]> tuple) { try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().hmset(key, tuple))); return; } if (isQueueing()) { transaction(connection.newLettuceTxStatusResult(getConnection().hmset(key, tuple))); return; } getConnection().hmset(key, tuple); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hVals(byte[]) */ @Override public List<byte[]> hVals(byte[] key) { try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hvals(key))); return null; } if (isQueueing()) { transaction(connection.newLettuceTxResult(getConnection().hvals(key))); return null; } return getConnection().hvals(key); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } /* (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) */ @Override public Cursor<Entry<byte[], byte[]>> hScan(byte[] key, ScanOptions options) { return hScan(key, 0, options); } /** * @since 1.4 * @param key * @param cursorId * @param options * @return */ public Cursor<Entry<byte[], byte[]>> hScan(byte[] key, long cursorId, ScanOptions options) { return new KeyBoundCursor<Entry<byte[], byte[]>>(key, cursorId, options) { @Override protected ScanIteration<Entry<byte[], byte[]>> doScan(byte[] key, long cursorId, ScanOptions options) { if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException("'HSCAN' cannot be called in pipeline / transaction mode."); } io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); ScanArgs scanArgs = connection.getScanArgs(options); MapScanCursor<byte[], byte[]> mapScanCursor = getConnection().hscan(key, scanCursor, scanArgs); String nextCursorId = mapScanCursor.getCursor(); Map<byte[], byte[]> values = mapScanCursor.getMap(); return new ScanIteration<>(Long.valueOf(nextCursorId), values.entrySet()); } protected void doClose() { LettuceHashCommands.this.connection.close(); } }.open(); } private boolean isPipelined() { return connection.isPipelined(); } private boolean isQueueing() { return connection.isQueueing(); } private void pipeline(LettuceResult result) { connection.pipeline(result); } private void transaction(LettuceTxResult result) { connection.transaction(result); } private RedisClusterAsyncCommands<byte[], byte[]> getAsyncConnection() { return connection.getAsyncConnection(); } public RedisClusterCommands<byte[], byte[]> getConnection() { return connection.getConnection(); } private DataAccessException convertLettuceAccessException(Exception ex) { return connection.convertLettuceAccessException(ex); } }