package com.lambdaworks.redis.commands.rx;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Set;
import com.lambdaworks.redis.api.StatefulConnection;
import com.lambdaworks.redis.api.StatefulRedisConnection;
import com.lambdaworks.redis.api.sync.RedisCommands;
import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection;
import com.lambdaworks.redis.internal.AbstractInvocationHandler;
import com.lambdaworks.redis.internal.LettuceSets;
import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection;
import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands;
import rx.Observable;
/**
* Invocation handler for testing purposes that exposes a synchronous API by calling commands using the reactive API.
*
* @author Mark Paluch
*/
public class RxSyncInvocationHandler<K, V> extends AbstractInvocationHandler {
private final StatefulConnection<?, ?> connection;
private final Object rxApi;
public RxSyncInvocationHandler(StatefulConnection<?, ?> connection, Object rxApi) {
this.connection = connection;
this.rxApi = rxApi;
}
@Override
@SuppressWarnings("unchecked")
protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
try {
Method targetMethod = rxApi.getClass().getMethod(method.getName(), method.getParameterTypes());
Object result = targetMethod.invoke(rxApi, args);
if (result == null || !(result instanceof Observable<?>)) {
return result;
}
Observable<?> observable = (Observable<?>) result;
if (!method.getName().equals("exec") && !method.getName().equals("multi")) {
if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) {
observable.subscribe();
return null;
}
}
List<?> value = observable.toList().toBlocking().first();
if (method.getReturnType().equals(List.class)) {
return value;
}
if (method.getReturnType().equals(Set.class)) {
return LettuceSets.newHashSet(value);
}
if (!value.isEmpty()) {
return value.get(0);
}
return null;
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
public static <K, V> RedisCommands<K, V> sync(StatefulRedisConnection<K, V> connection) {
RxSyncInvocationHandler<K, V> handler = new RxSyncInvocationHandler<>(connection, connection.reactive());
return (RedisCommands<K, V>) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
new Class<?>[] { RedisCommands.class }, handler);
}
public static <K, V> RedisCommands<K, V> sync(StatefulRedisClusterConnection<K, V> connection) {
RxSyncInvocationHandler<K, V> handler = new RxSyncInvocationHandler<>(connection, connection.reactive());
return (RedisCommands<K, V>) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
new Class<?>[] { RedisCommands.class }, handler);
}
public static <K, V> RedisSentinelCommands<K, V> sync(StatefulRedisSentinelConnection<K, V> connection) {
RxSyncInvocationHandler<K, V> handler = new RxSyncInvocationHandler<>(connection, connection.reactive());
return (RedisSentinelCommands<K, V>) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
new Class<?>[] { RedisSentinelCommands.class }, handler);
}
}