org.springframework.data.redis.connection.jedis.JedisClientUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.data.redis.connection.jedis.JedisClientUtils.java

Source

/*
 * Copyright 2017-2019 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
 *
 *      https://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.jedis;

import redis.clients.jedis.Builder;
import redis.clients.jedis.Client;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Protocol.Command;
import redis.clients.jedis.Queable;
import redis.clients.jedis.Response;
import redis.clients.jedis.util.SafeEncoder;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.springframework.util.ReflectionUtils;

/**
 * Utility class to dispatch arbitrary Redis commands using Jedis commands.
 *
 * @author Christoph Strobl
 * @author Mark Paluch
 * @author Serhii Siryi
 * @since 2.1
 */
@SuppressWarnings({ "unchecked", "ConstantConditions" })
class JedisClientUtils {

    private static final Method GET_RESPONSE;
    private static final Set<String> KNOWN_COMMANDS;
    private static final Builder<Object> OBJECT_BUILDER;

    static {

        GET_RESPONSE = ReflectionUtils.findMethod(Queable.class, "getResponse", Builder.class);
        ReflectionUtils.makeAccessible(GET_RESPONSE);

        KNOWN_COMMANDS = Arrays.stream(Command.values()).map(Enum::name).collect(Collectors.toSet());

        OBJECT_BUILDER = new Builder<Object>() {
            public Object build(Object data) {
                return data;
            }

            public String toString() {
                return "Object";
            }
        };
    }

    /**
     * Execute an arbitrary on the supplied {@link Jedis} instance.
     *
     * @param command the command.
     * @param keys must not be {@literal null}, may be empty.
     * @param args must not be {@literal null}, may be empty.
     * @param jedis must not be {@literal null}.
     * @return the response, can be be {@literal null}.
     */
    static <T> T execute(String command, byte[][] keys, byte[][] args, Supplier<Jedis> jedis) {
        return execute(command, keys, args, jedis, it -> (T) it.getOne());
    }

    /**
     * Execute an arbitrary on the supplied {@link Jedis} instance.
     *
     * @param command the command.
     * @param keys must not be {@literal null}, may be empty.
     * @param args must not be {@literal null}, may be empty.
     * @param jedis must not be {@literal null}.
     * @param responseMapper must not be {@literal null}.
     * @return the response, can be be {@literal null}.
     * @since 2.1
     */
    static <T> T execute(String command, byte[][] keys, byte[][] args, Supplier<Jedis> jedis,
            Function<Client, T> responseMapper) {

        byte[][] commandArgs = getCommandArguments(keys, args);

        Client client = sendCommand(command, commandArgs, jedis.get());

        return responseMapper.apply(client);
    }

    /**
     * Send a Redis command and retrieve the {@link Client} for response retrieval.
     *
     * @param command the command.
     * @param args must not be {@literal null}, may be empty.
     * @param jedis must not be {@literal null}.
     * @return the {@link Client} instance used to send the command.
     */
    static Client sendCommand(String command, byte[][] args, Jedis jedis) {

        Client client = jedis.getClient();

        sendCommand(client, command, args);

        return client;
    }

    private static void sendCommand(Client client, String command, byte[][] args) {

        if (isKnownCommand(command)) {
            client.sendCommand(Command.valueOf(command.trim().toUpperCase()), args);
        } else {
            client.sendCommand(() -> SafeEncoder.encode(command.trim().toUpperCase()), args);
        }
    }

    private static boolean isKnownCommand(String command) {
        return KNOWN_COMMANDS.contains(command);
    }

    private static byte[][] getCommandArguments(byte[][] keys, byte[][] args) {

        if (keys.length == 0) {
            return args;
        }

        if (args.length == 0) {
            return keys;
        }

        byte[][] commandArgs = new byte[keys.length + args.length][];

        System.arraycopy(keys, 0, commandArgs, 0, keys.length);
        System.arraycopy(args, 0, commandArgs, keys.length, args.length);

        return commandArgs;
    }

    /**
     * @param jedis the client instance.
     * @return {@literal true} if the connection has entered {@literal MULTI} state.
     */
    static boolean isInMulti(Jedis jedis) {
        return jedis.getClient().isInMulti();
    }

    /**
     * Retrieve the {@link Response} object from a {@link redis.clients.jedis.Transaction} or a
     * {@link redis.clients.jedis.Pipeline} for response synchronization.
     *
     * @param target a {@link redis.clients.jedis.Transaction} or {@link redis.clients.jedis.Pipeline}, must not be
     *          {@literal null}.
     * @return the {@link Response} wrapper object.
     */
    static Response<Object> getResponse(Object target) {
        return (Response<Object>) ReflectionUtils.invokeMethod(GET_RESPONSE, target, OBJECT_BUILDER);
    }

}