package org.zbus.server;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.zbus.common.Helper;
import org.zbus.common.json.JSON;
import org.zbus.common.logging.Logger;
import org.zbus.common.logging.LoggerFactory;
import org.zbus.common.protocol.BrokerInfo;
import org.zbus.common.protocol.Proto;
import org.zbus.common.protocol.TrackTable;
import org.zbus.common.remoting.Message;
import org.zbus.common.remoting.MessageHandler;
import org.zbus.common.remoting.RemotingClient;
import org.zbus.common.remoting.RemotingServer;
import org.zbus.common.remoting.nio.Session;
public class TrackServer extends RemotingServer {
private static final Logger log = LoggerFactory.getLogger(TrackServer.class);
private long publishInterval = 10000;
private long probeInterval = 3000;
private final TrackTable trackTable = new TrackTable();
private Map<String, Session> subscribers = new ConcurrentHashMap<String, Session>();
private Map<String, RemotingClient> brokerProbes = new ConcurrentHashMap<String, RemotingClient>();
private final ScheduledExecutorService trackPubService = Executors.newSingleThreadScheduledExecutor();
private ExecutorService trackExecutor = new ThreadPoolExecutor(4,16, 120, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
public TrackServer(int serverPort){
this("0.0.0.0", serverPort);
}
public TrackServer(String serverHost, int serverPort) {
super(serverHost, serverPort);
this.serverName = "TrackServer";
this.trackPubService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
publishTrackTable();
}
}, 0, publishInterval, TimeUnit.MILLISECONDS);
this.trackPubService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
probeBrokers();
}
}, 0, probeInterval, TimeUnit.MILLISECONDS);
}
private void probeBrokers(){
Iterator<Entry<String, RemotingClient>> iter = brokerProbes.entrySet().iterator();
while(iter.hasNext()){
Entry<String, RemotingClient> entry = iter.next();
String brokerAddress = entry.getKey();
RemotingClient client = entry.getValue();
if(!client.hasConnected()){
trackTable.removeBroker(brokerAddress);
iter.remove();
}
}
log.info("Track: "+ trackTable);
}
private void publishTrackTable(){
if(subscribers.size()<1) return;
String json = JSON.toJSONString(this.trackTable);
Message msg = new Message();
msg.setCommand(Proto.TrackPub);
msg.setBody(json);
Iterator<Entry<String, Session>> iter = subscribers.entrySet().iterator();
while(iter.hasNext()){
Entry<String, Session> entry = iter.next();
Session sess = entry.getValue();
if(!sess.isActive()){
iter.remove();
continue;
}
try {
sess.write(msg);
} catch (IOException e) {
iter.remove();
//ignore
}
}
}
@Override
public void init() {
this.registerHandler(Proto.TrackReport, new MessageHandler() {
@Override
public void handleMessage(Message msg, Session sess) throws IOException {
final BrokerInfo brokerInfo = JSON.parseObject(msg.getBodyString(), BrokerInfo.class);
final String brokerAddress = brokerInfo.getBroker();
if(!brokerProbes.containsKey(brokerAddress)){
final RemotingClient client = new RemotingClient(brokerAddress);
trackExecutor.submit(new Runnable() {
@Override
public void run() {
try {
client.connectIfNeed();
brokerProbes.put(brokerAddress, client);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
});
}
trackTable.addBroker(brokerAddress, brokerInfo);
publishTrackTable();
}
});
this.registerHandler(Proto.TrackSub, new MessageHandler() {
@Override
public void handleMessage(Message msg, Session sess) throws IOException {
subscribers.put(sess.id(), sess);
String json = JSON.toJSONString(trackTable);
msg.setStatus("200");
msg.setBody(json);
sess.write(msg);
}
});
}
public static void main(String[] args) throws Exception{
int serverPort = Helper.option(args, "-p", 16666);
TrackServer track = new TrackServer(serverPort);
track.start();
}
}