gu.simplemq.ChannelDispatcher Maven / Gradle / Ivy
package gu.simplemq;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.*;
import com.alibaba.fastjson.JSONException;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import gu.simplemq.exceptions.SmqTypeException;
import gu.simplemq.exceptions.SmqUnsubscribeException;
import gu.simplemq.json.BaseJsonEncoder;
import gu.simplemq.utils.CommonUtils;
import gu.simplemq.utils.Synchronizer;
import gu.simplemq.utils.Synchronizer.ReadWriteSynchronizer;
/**
* (消息)频道订阅对象({@link Channel})管理类,负责频道的注册/注销,订阅/取消,消息数据解析及分发
* NOTE:如果不设置线程池对象,消息分发{@link #dispatch(String, String)}将以单线程工作,
* 参见{@link #setExecutor(ExecutorService)}
* @author guyadong
*
*/
public class ChannelDispatcher implements ISubscriber,Constant {
private BaseJsonEncoder encoder = BaseJsonEncoder.getEncoder();
private static class SingletonExecutor{
/** 默认单线程池对象 */
private static final ExecutorService DEFAULT_EXECUTOR = MoreExecutors.getExitingExecutorService(
new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
new ThreadFactoryBuilder().setNameFormat("channel-dispatcher-%d").build()));
}
private static class SingletonTimerExecutor{
/** 默认定时线程对象 */
private static final ScheduledExecutorService DEFAULT_TIMEREXECUTOR = MoreExecutors.getExitingScheduledExecutorService(
new ScheduledThreadPoolExecutor(
1,
new ThreadFactoryBuilder()
.setNameFormat("channel-dispatcher-timer-%d")
.build()));
}
/** 注册的频道对象 */
protected final LinkedHashMap> channelSubs = new LinkedHashMap>();
/** 订阅的频道名 */
private final Set subChannelSet= new LinkedHashSet();
private final Synchronizer sync = new ReadWriteSynchronizer();
/** 线程池对象,默认使用单线程池对象,确保不会丢失数据 */
private volatile ExecutorService executor;
/** 定时任务线程池 */
private volatile ScheduledExecutorService timerExecutor;
public ChannelDispatcher() {
}
public ChannelDispatcher(Channel>...channels) {
register(channels);
}
public ChannelDispatcher(Collection> channels) {
this(null ==channels?null:channels.toArray(new Channel[0]));
}
/**
* @see #registedOnlyAsSet(String...)
*/
public String[] registedOnly(String... channels) {
return registedOnlyAsSet(channels).toArray(new String[0]);
}
/**
* 返回{@code channels}指定的频道名中已经注册的频道名
* @param channels
*/
public HashSet registedOnlyAsSet(String... channels) {
sync.beginRead();
try{
HashSet chSet = new HashSet(CommonUtils.cleanEmptyAsList(channels));
if (!chSet.isEmpty()){
chSet.retainAll(channelSubs.keySet());
}
return chSet;
}finally{
sync.endRead();
}
}
/**
* 子类重写此方法,检查通道名是否合法
* @param name
* @return name 否则抛出异常
* @throws SmqTypeException
*/
protected String check(String name) throws SmqTypeException{return name;}
@Override
public Set> register(Channel>... channels) {
sync.beginWrite();
try {
HashSet> chSet = new HashSet>(CommonUtils.cleanNullAsList(channels));
for (Channel> ch : chSet) {
channelSubs.put(check(ch.name), ch);
}
subscribe(Channel.getChannelNames(chSet).toArray(new String[0]));
return chSet;
}finally{
sync.endWrite();
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void register(final Channel>channel,
long duration,
TimeUnit unit) {
register(checkNotNull(channel,"channel is null"));
if(duration > 0){
checkArgument(null != unit,"unit is null");
// 定时执行频道注销
final ScheduledFuture> timeUnregisterTask = this.getTimerExecutor().schedule(new Runnable(){
@Override
public void run() {
logger.debug("unregister channel '{}' caused by timeout", channel.name);
unregister(channel.name);
}},
duration,
unit);
channel.addUnregistedListener(new IUnregistedListener(){
@Override
public void apply(Channel channel) {
// 当执行注销时取消定时任务
if(!timeUnregisterTask.isDone() && timeUnregisterTask.getDelay(TimeUnit.MILLISECONDS) >0){
timeUnregisterTask.cancel(false);
logger.debug("time task cancelled");
}
}});
}
}
@Override
public Set unregister(String... channels) {
sync.beginWrite();
try {
HashSet chSet = new HashSet(CommonUtils.cleanEmptyAsList(channels));
// 这里要判断是否为空,因为unsubscribe方法对于空列表参数会清除所有订阅
if(!chSet.isEmpty()){
unsubscribe(chSet.toArray(new String[0]));
for (String ch : chSet) {
Channel> channel = this.channelSubs.get(ch);
if(null != channel){
this.channelSubs.remove(ch);
channel.onUnregisted();
}
}
}
return chSet;
}finally{
sync.endWrite();
}
}
@SuppressWarnings("rawtypes")
@Override
public Set unregister(Channel... channels) {
return unregister(Channel.getChannelNames(channels));
}
@Override
public Set unregister(final IMessageAdapter> messageAdapter) {
sync.beginWrite();
try {
String[] chSet = Maps.filterValues(channelSubs, new Predicate>() {
@Override
public boolean apply(Channel> input) {
return input.getAdapter() == messageAdapter;
}
}).keySet().toArray(new String[0]);
return unregister(chSet);
} finally {
sync.endWrite();
}
}
@SuppressWarnings("rawtypes")
@Override
public Channel getChannel(String channel) {
sync.beginRead();
try{
return channelSubs.get(channel);
}finally{
sync.endRead();
}
}
@SuppressWarnings("unchecked")
@Override
public void dispatch(final String channel, final String message) {
final Channel