Package com.lambdaworks.redis

Source Code of com.lambdaworks.redis.RedisClient

// Copyright (C) 2011 - Will Glozer.  All rights reserved.

package com.lambdaworks.redis;

import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.codec.Utf8StringCodec;
import com.lambdaworks.redis.protocol.*;
import com.lambdaworks.redis.pubsub.PubSubCommandHandler;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.group.*;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.*;

/**
* A scalable thread-safe <a href="http://redis.io/">Redis</a> client. Multiple threads
* may share one {@link RedisConnection} provided they avoid blocking and transactional
* operations such as BLPOP and MULTI/EXEC.
*
* @author Will Glozer
*/
public class RedisClient {
    private ClientBootstrap bootstrap;
    private Timer timer;
    private ChannelGroup channels;
    private int timeout;
    private TimeUnit unit;

    /**
     * Create a new client that connects to the supplied host on the default port.
     *
     * @param host    Server hostname.
     */
    public RedisClient(String host) {
        this(host, 6379);
    }

    /**
     * Create a new client that connects to the supplied host and port.
     *
     * @param host    Server hostname.
     * @param port    Server port.
     */
    public RedisClient(String host, int port) {
        ExecutorService connectors = Executors.newFixedThreadPool(1);
        ExecutorService workers    = Executors.newCachedThreadPool();
        ClientSocketChannelFactory factory = new NioClientSocketChannelFactory(connectors, workers);

        InetSocketAddress addr = new InetSocketAddress(host, port);

        bootstrap = new ClientBootstrap(factory);
        bootstrap.setOption("remoteAddress", addr);

        setDefaultTimeout(60, TimeUnit.SECONDS);

        channels = new DefaultChannelGroup();
        timer    = new HashedWheelTimer();
    }

    /**
     * Set the default timeout for connections created by this client.
     *
     * @param timeout   Default connection timeout.
     * @param unit      Unit of time for the timeout.
     */
    public void setDefaultTimeout(int timeout, TimeUnit unit) {
        this.timeout = timeout;
        this.unit    = unit;
        bootstrap.setOption("connectTimeoutMillis", unit.toMillis(timeout));
    }

    /**
     * Open a new connection to the redis server that treats all keys and
     * values as UTF-8 strings.
     *
     * @return A new connection.
     */
    public RedisConnection<String, String> connect() {
        return connect(new Utf8StringCodec());
    }

    /**
     * Open a new pub/sub connection to the redis server that treats all
     * keys and values as UTF-8 strings.
     *
     * @return A new connection.
     */
    public RedisPubSubConnection<String, String> connectPubSub() {
        return connectPubSub(new Utf8StringCodec());
    }

    /**
     * Open a new connection to the redis server. Use the supplied
     * {@link RedisCodec codec} to encode/decode keys and values.
     *
     * @param codec Use this codec to encode/decode keys and values.
     *
     * @return A new connection.
     */
    public <K, V> RedisConnection<K, V> connect(RedisCodec<K, V> codec) {
        try {
            BlockingQueue<Command<?>> queue = new LinkedBlockingQueue<Command<?>>();

            ConnectionWatchdog watchdog = new ConnectionWatchdog(bootstrap, channels, timer);
            CommandHandler handler = new CommandHandler(queue);
            RedisConnection<K, V> connection = new RedisConnection<K, V>(queue, codec, timeout, unit);

            ChannelPipeline pipeline = Channels.pipeline(watchdog, handler, connection);
            Channel channel = bootstrap.getFactory().newChannel(pipeline);

            ChannelFuture future = channel.connect((SocketAddress) bootstrap.getOption("remoteAddress"));
            future.await();

            if (!future.isSuccess()) {
                throw future.getCause();
            }

            watchdog.setReconnect(true);

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

    /**
     * Open a new pub/sub connection to the redis server. Use the supplied
     * {@link RedisCodec codec} to encode/decode keys and values.
     *
     * @param codec Use this codec to encode/decode keys and values.
     *
     * @return A new pub/sub connection.
     */
    public <K, V> RedisPubSubConnection<K, V> connectPubSub(RedisCodec<K, V> codec) {
        try {
            BlockingQueue<Command<?>> queue = new LinkedBlockingQueue<Command<?>>();

            ConnectionWatchdog watchdog = new ConnectionWatchdog(bootstrap, channels, timer);
            PubSubCommandHandler<K, V> handler = new PubSubCommandHandler<K, V>(queue, codec);
            RedisPubSubConnection<K, V> connection = new RedisPubSubConnection<K, V>(queue, codec, timeout, unit);

            ChannelPipeline pipeline = Channels.pipeline(watchdog, handler, connection);
            Channel channel = bootstrap.getFactory().newChannel(pipeline);

            ChannelFuture future = channel.connect((SocketAddress) bootstrap.getOption("remoteAddress"));
            future.await();

            if (!future.isSuccess()) {
                throw future.getCause();
            }

            watchdog.setReconnect(true);

            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() {
        for (Channel c : channels) {
            ChannelPipeline pipeline = c.getPipeline();
            RedisConnection connection = pipeline.get(RedisConnection.class);
            connection.close();
        }
        ChannelGroupFuture future = channels.close();
        future.awaitUninterruptibly();
        bootstrap.releaseExternalResources();
    }
}
TOP

Related Classes of com.lambdaworks.redis.RedisClient

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.