/**
* Copyright 2016 Netflix, Inc.
*
* 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 com.netflix.dyno.redisson;
import io.netty.channel.EventLoopGroup;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisClient;
import com.netflix.dyno.connectionpool.AsyncOperation;
import com.netflix.dyno.connectionpool.Connection;
import com.netflix.dyno.connectionpool.ConnectionContext;
import com.netflix.dyno.connectionpool.ConnectionFactory;
import com.netflix.dyno.connectionpool.ConnectionObservor;
import com.netflix.dyno.connectionpool.Host;
import com.netflix.dyno.connectionpool.HostConnectionPool;
import com.netflix.dyno.connectionpool.ListenableFuture;
import com.netflix.dyno.connectionpool.Operation;
import com.netflix.dyno.connectionpool.OperationMonitor;
import com.netflix.dyno.connectionpool.OperationResult;
import com.netflix.dyno.connectionpool.exception.DynoConnectException;
import com.netflix.dyno.connectionpool.exception.DynoException;
import com.netflix.dyno.connectionpool.exception.ThrottledException;
import com.netflix.dyno.connectionpool.impl.ConnectionContextImpl;
import com.netflix.dyno.connectionpool.impl.FutureOperationalResultImpl;
import com.netflix.dyno.connectionpool.impl.OperationResultImpl;
public class RedissonConnectionFactory implements ConnectionFactory<RedisAsyncConnection<String, String>> {
private final EventLoopGroup eventGroupLoop;
private final OperationMonitor opMonitor;
public RedissonConnectionFactory(EventLoopGroup group, OperationMonitor operationMonitor) {
eventGroupLoop = group;
opMonitor = operationMonitor;
}
@Override
public Connection<RedisAsyncConnection<String, String>> createConnection(HostConnectionPool<RedisAsyncConnection<String, String>> pool, ConnectionObservor connectionObservor) throws DynoConnectException, ThrottledException {
return new RedissonConnection(pool, eventGroupLoop, opMonitor);
}
public static class RedissonConnection implements Connection<RedisAsyncConnection<String, String>> {
private final HostConnectionPool<RedisAsyncConnection<String, String>> hostPool;
private final RedisClient client;
private final OperationMonitor opMonitor;
private RedisAsyncConnection<String, String> rConn = null;
private final AtomicReference<DynoConnectException> lastEx = new AtomicReference<DynoConnectException>(null);
private final ConnectionContextImpl context = new ConnectionContextImpl();
public RedissonConnection(HostConnectionPool<RedisAsyncConnection<String, String>> hPool, EventLoopGroup eventGroupLoop, OperationMonitor opMonitor) {
this.hostPool = hPool;
Host host = hostPool.getHost();
this.opMonitor = opMonitor;
this.client = new RedisClient(eventGroupLoop, host.getHostAddress(), host.getPort());
}
@Override
public <R> OperationResult<R> execute(Operation<RedisAsyncConnection<String, String>, R> op) throws DynoException {
try {
R result = op.execute(rConn, null); // Note that connection context is not implemented yet
return new OperationResultImpl<R>(op.getName(), result, opMonitor)
.attempts(1)
.setNode(getHost());
} catch (DynoConnectException e) {
lastEx.set(e);
throw e;
}
}
@Override
public <R> ListenableFuture<OperationResult<R>> executeAsync(AsyncOperation<RedisAsyncConnection<String, String>, R> op) throws DynoException {
final long start = System.currentTimeMillis();
try {
Future<R> future = op.executeAsync(rConn);
return new FutureOperationalResultImpl<R>(op.getName(), future, start, opMonitor).node(getHost());
} catch (DynoConnectException e) {
lastEx.set(e);
throw e;
}
}
@Override
public void close() {
rConn.close();
client.shutdown();
}
@Override
public Host getHost() {
return hostPool.getHost();
}
@Override
public void open() throws DynoException {
rConn = client.connectAsync();
}
@Override
public DynoConnectException getLastException() {
return lastEx.get();
}
@Override
public HostConnectionPool<RedisAsyncConnection<String, String>> getParentConnectionPool() {
return hostPool;
}
@Override
public void execPing() {
try {
rConn.ping().get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
throw new DynoConnectException(e);
}
}
@Override
public ConnectionContext getContext() {
return context;
}
}
}