package com.lambdaworks.redis.models.command; import java.util.*; import com.lambdaworks.redis.internal.LettuceAssert; /** * Parser for redis <a href="http://redis.io/commands/command">COMMAND</a>/<a * href="http://redis.io/commands/command-info">COMMAND INFO</a>command output. * * @author Mark Paluch * @since 3.0 */ @SuppressWarnings("serial") public class CommandDetailParser { /** * Number of array elements for a specific command. */ public static final int COMMAND_INFO_SIZE = 6; @SuppressWarnings("serial") protected static final Map<String, CommandDetail.Flag> FLAG_MAPPING; static { Map<String, CommandDetail.Flag> flagMap = new HashMap<>(); flagMap.put("admin", CommandDetail.Flag.ADMIN); flagMap.put("asking", CommandDetail.Flag.ASKING); flagMap.put("denyoom", CommandDetail.Flag.DENYOOM); flagMap.put("fast", CommandDetail.Flag.FAST); flagMap.put("loading", CommandDetail.Flag.LOADING); flagMap.put("noscript", CommandDetail.Flag.NOSCRIPT); flagMap.put("movablekeys", CommandDetail.Flag.MOVABLEKEYS); flagMap.put("pubsub", CommandDetail.Flag.PUBSUB); flagMap.put("random", CommandDetail.Flag.RANDOM); flagMap.put("readonly", CommandDetail.Flag.READONLY); flagMap.put("skip_monitor", CommandDetail.Flag.SKIP_MONITOR); flagMap.put("sort_for_script", CommandDetail.Flag.SORT_FOR_SCRIPT); flagMap.put("stale", CommandDetail.Flag.STALE); flagMap.put("write", CommandDetail.Flag.WRITE); FLAG_MAPPING = Collections.unmodifiableMap(flagMap); } private CommandDetailParser() { } /** * Parse the output of the redis COMMAND/COMMAND INFO command and convert to a list of {@link CommandDetail}. * * @param commandOutput the command output, must not be {@literal null} * @return RedisInstance */ public static List<CommandDetail> parse(List<?> commandOutput) { LettuceAssert.notNull(commandOutput, "CommandOutput must not be null"); List<CommandDetail> result = new ArrayList<>(); for (Object o : commandOutput) { if (!(o instanceof Collection<?>)) { continue; } Collection<?> collection = (Collection<?>) o; if (collection.size() != COMMAND_INFO_SIZE) { continue; } CommandDetail commandDetail = parseCommandDetail(collection); result.add(commandDetail); } return Collections.unmodifiableList(result); } private static CommandDetail parseCommandDetail(Collection<?> collection) { Iterator<?> iterator = collection.iterator(); String name = (String) iterator.next(); int arity = Math.toIntExact(getLongFromIterator(iterator, 0)); Object flags = iterator.next(); int firstKey = Math.toIntExact(getLongFromIterator(iterator, 0)); int lastKey = Math.toIntExact(getLongFromIterator(iterator, 0)); int keyStepCount = Math.toIntExact(getLongFromIterator(iterator, 0)); Set<CommandDetail.Flag> parsedFlags = parseFlags(flags); return new CommandDetail(name, arity, parsedFlags, firstKey, lastKey, keyStepCount); } private static Set<CommandDetail.Flag> parseFlags(Object flags) { Set<CommandDetail.Flag> result = new HashSet<>(); if (flags instanceof Collection<?>) { Collection<?> collection = (Collection<?>) flags; for (Object o : collection) { CommandDetail.Flag flag = FLAG_MAPPING.get(o); if (flag != null) { result.add(flag); } } } return Collections.unmodifiableSet(result); } private static long getLongFromIterator(Iterator<?> iterator, long defaultValue) { if (iterator.hasNext()) { Object object = iterator.next(); if (object instanceof String) { return Long.parseLong((String) object); } if (object instanceof Number) { return ((Number) object).longValue(); } } return defaultValue; } }