Package com.lambdaworks.redis

Source Code of com.lambdaworks.redis.AbstractRedisClient

package com.lambdaworks.redis;

import java.io.Closeable;
import java.net.SocketAddress;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.lambdaworks.redis.internal.ChannelGroupListener;
import com.lambdaworks.redis.protocol.CommandHandler;
import com.lambdaworks.redis.protocol.ConnectionWatchdog;
import com.lambdaworks.redis.pubsub.PubSubCommandHandler;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.ChannelGroupFuture;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.internal.ConcurrentSet;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a>
* @since 26.05.14 17:28
*/
public abstract class AbstractRedisClient {
    protected static final InternalLogger logger = InternalLoggerFactory.getInstance(RedisClient.class);
    protected EventLoopGroup group;
    protected HashedWheelTimer timer;
    protected ChannelGroup channels;
    protected long timeout;
    protected TimeUnit unit;
    protected ConnectionEvents connectionEvents = new ConnectionEvents();
    protected Set<Closeable> closeableResources = new ConcurrentSet<Closeable>();

    public AbstractRedisClient() {
        timer = new HashedWheelTimer();
        group = new NioEventLoopGroup();
        channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        timer.start();
    }

    /**
     * Set the default timeout for {@link com.lambdaworks.redis.RedisConnection connections} created by this client. The timeout
     * applies to connection attempts and non-blocking commands.
     *
     * @param timeout Default connection timeout.
     * @param unit Unit of time for the timeout.
     */
    public void setDefaultTimeout(long timeout, TimeUnit unit) {
        this.timeout = timeout;
        this.unit = unit;
    }

    protected <K, V, T extends RedisAsyncConnectionImpl<K, V>> T connectAsyncImpl(final CommandHandler<K, V> handler,
            final T connection, final Supplier<SocketAddress> socketAddressSupplier, final boolean withReconnect) {
        try {

            SocketAddress redisAddress = socketAddressSupplier.get();

            logger.debug("Connecting to Redis, address: " + redisAddress);

            final Bootstrap redisBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(group);
            redisBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) unit.toMillis(timeout));

            final ConnectionWatchdog watchdog = new ConnectionWatchdog(redisBootstrap, timer, socketAddressSupplier);

            redisBootstrap.handler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel ch) throws Exception {

                    if (withReconnect) {
                        watchdog.setReconnect(true);
                        ch.pipeline().addLast(watchdog);
                    }

                    ch.pipeline().addLast(new ChannelGroupListener(channels),
                            new ConnectionEventTrigger(connectionEvents, connection), handler, connection);
                }
            });

            redisBootstrap.connect(redisAddress).sync();

            connection.addListener(new CloseEvents.CloseListener() {
                @Override
                public void resourceClosed(Object resource) {
                    closeableResources.remove(resource);
                }
            });
            closeableResources.add(connection);

            return connection;
        } catch (Throwable e) {
            throw new RedisException("Unable to connect", e);
        }
    }

    /**
     * Shutdown this client and close all open connections. The client should be discarded after calling shutdown.
     */
    public void shutdown() {

        ImmutableList<Closeable> autoCloseables = ImmutableList.copyOf(closeableResources);
        for (Closeable closeableResource : autoCloseables) {
            try {
                closeableResource.close();
            } catch (Exception e) {
                logger.debug("Exception on Close: " + e.getMessage(), e);

            }
        }

        for (Channel c : channels) {
            ChannelPipeline pipeline = c.pipeline();

            CommandHandler<?, ?> commandHandler = pipeline.get(CommandHandler.class);
            if (commandHandler != null && !commandHandler.isClosed()) {
                commandHandler.close();
            }

            PubSubCommandHandler<?, ?> psCommandHandler = pipeline.get(PubSubCommandHandler.class);
            if (psCommandHandler != null && !psCommandHandler.isClosed()) {
                psCommandHandler.close();
            }
        }
        ChannelGroupFuture future = channels.close();
        future.awaitUninterruptibly();
        group.shutdownGracefully().syncUninterruptibly();
        timer.stop();
    }

    protected int getResourceCount() {
        return closeableResources.size();
    }

    protected int getChannelCount() {
        return channels.size();
    }

    /**
     * Add a listener for the RedisConnectionState. The listener is notified every time a connect/disconnect/IO exception
     * happens. The listeners are not bound to a specific connection, so every time a connection event happens on any
     * connection, the listener will be notified. The corresponding netty channel handler (async connection) is passed on the
     * event.
     *
     * @param listener
     */
    public void addListener(RedisConnectionStateListener listener) {
        connectionEvents.addListener(listener);
    }

    /**
     * Removes a listener.
     *
     * @param listener
     */
    public void removeListener(RedisConnectionStateListener listener) {
        connectionEvents.removeListener(listener);
    }
}
TOP

Related Classes of com.lambdaworks.redis.AbstractRedisClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.