
com.lambdaworks.redis.pubsub.RedisPubSubConnection Maven / Gradle / Ivy
// Copyright (C) 2011 - Will Glozer. All rights reserved.
package com.lambdaworks.redis.pubsub;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.protocol.Command;
import com.lambdaworks.redis.protocol.CommandArgs;
import org.jboss.netty.channel.*;
import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.*;
import static com.lambdaworks.redis.protocol.CommandType.*;
/**
* An asynchronous thread-safe pub/sub connection to a redis server. After one or
* more channels are subscribed to only pub/sub related commands or {@link #quit}
* may be called.
*
* Incoming messages and results of the {@link #subscribe}/{@link #unsubscribe}
* calls will be passed to all registered {@link RedisPubSubListener}s.
*
* A {@link com.lambdaworks.redis.protocol.ConnectionWatchdog} monitors each
* connection and reconnects automatically until {@link #close} is called. Channel
* and pattern subscriptions are renewed after reconnecting.
*
* @author Will Glozer
*/
public class RedisPubSubConnection extends RedisAsyncConnection {
private List> listeners;
private Set channels;
private Set patterns;
/**
* Initialize a new connection.
*
* @param queue Command queue.
* @param codec Codec used to encode/decode keys and values.
* @param timeout Maximum time to wait for a responses.
* @param unit Unit of time for the timeout.
*/
public RedisPubSubConnection(BlockingQueue> queue, RedisCodec codec, long timeout, TimeUnit unit) {
super(queue, codec, timeout, unit);
listeners = new CopyOnWriteArrayList>();
channels = new HashSet();
patterns = new HashSet();
}
/**
* Add a new listener.
*
* @param listener Listener.
*/
public void addListener(RedisPubSubListener listener) {
listeners.add(listener);
}
/**
* Remove an existing listener.
*
* @param listener Listener.
*/
public void removeListener(RedisPubSubListener listener) {
listeners.remove(listener);
}
public void psubscribe(K... patterns) {
dispatch(PSUBSCRIBE, new PubSubOutput(codec), args(patterns));
}
public void punsubscribe(K... patterns) {
dispatch(PUNSUBSCRIBE, new PubSubOutput(codec), args(patterns));
}
public void subscribe(K... channels) {
dispatch(SUBSCRIBE, new PubSubOutput(codec), args(channels));
}
public void unsubscribe(K... channels) {
dispatch(UNSUBSCRIBE, new PubSubOutput(codec), args(channels));
}
@Override
public synchronized void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelConnected(ctx, e);
if (channels.size() > 0) {
subscribe(toArray(channels));
channels.clear();
}
if (patterns.size() > 0) {
psubscribe(toArray(patterns));
patterns.clear();
}
}
@Override
@SuppressWarnings("unchecked")
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
PubSubOutput output = (PubSubOutput) e.getMessage();
for (RedisPubSubListener listener : listeners) {
switch (output.type()) {
case message:
listener.message(output.channel(), output.get());
break;
case pmessage:
listener.message(output.pattern(), output.channel(), output.get());
break;
case psubscribe:
patterns.add(output.pattern());
listener.psubscribed(output.pattern(), output.count());
break;
case punsubscribe:
patterns.remove(output.pattern());
listener.punsubscribed(output.pattern(), output.count());
break;
case subscribe:
channels.add(output.channel());
listener.subscribed(output.channel(), output.count());
break;
case unsubscribe:
channels.remove(output.channel());
listener.unsubscribed(output.channel(), output.count());
break;
}
}
}
private CommandArgs args(K... keys) {
CommandArgs args = new CommandArgs(codec);
args.addKeys(keys);
return args;
}
@SuppressWarnings("unchecked")
private T[] toArray(Collection c) {
Class cls = (Class) c.iterator().next().getClass();
T[] array = (T[]) Array.newInstance(cls, c.size());
return c.toArray(array);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy