package org.zbus.server; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentMap; 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.json.JSONObject; import org.zbus.common.logging.Logger; import org.zbus.common.logging.LoggerFactory; import org.zbus.common.protocol.BrokerInfo; import org.zbus.common.protocol.MessageMode; import org.zbus.common.protocol.MqInfo; import org.zbus.common.protocol.Proto; import org.zbus.common.remoting.Message; import org.zbus.common.remoting.MessageHandler; import org.zbus.common.remoting.RemotingClient; import org.zbus.common.remoting.callback.ErrorCallback; import org.zbus.common.remoting.nio.Session; import org.zbus.server.mq.MessageQueue; import org.zbus.server.mq.PubsubQueue; import org.zbus.server.mq.ReplyHelper; import org.zbus.server.mq.RequestQueue; import org.zbus.server.mq.store.MessageStore; public class AdminHandler extends SubCommandHandler { private static final Logger log = LoggerFactory.getLogger(AdminHandler.class); protected long trackDelay = 1000; protected long trackInterval = 3000; protected final ScheduledExecutorService trackReportService = Executors.newSingleThreadScheduledExecutor(); protected final List<RemotingClient> trackClients = new ArrayList<RemotingClient>(); protected ExecutorService reportExecutor = new ThreadPoolExecutor(4,16, 120, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); protected final ConcurrentMap<String, MessageQueue> mqTable; protected final ExecutorService mqExecutor; protected final String serverAddr; protected MessageStore messageStore = null; public AdminHandler(ConcurrentMap<String, MessageQueue> mqTable, ExecutorService mqExecutor, String serverAddr){ this.mqTable = mqTable; this.mqExecutor = mqExecutor; this.serverAddr = serverAddr; this.initCommands(); } public void initCommands(){ this.registerHandler(Proto.AdminCreateMQ, new MessageHandler() { @Override public void handleMessage(Message msg, Session sess) throws IOException { JSONObject params = null; try{ params = JSON.parseObject(msg.getBodyString()); } catch(Exception e) { log.error(e.getMessage(), e); msg.setBody("register param json body invalid"); ReplyHelper.reply400(msg, sess); return; } String msgId= msg.getMsgId(); String mqName = params.getString("mqName"); String accessToken = params.getString("accessToken"); String type = params.getString("mqMode"); int mode = 0; try{ mode = Integer.valueOf(type); } catch (Exception e){ msg.setBody("mqMode invalid"); ReplyHelper.reply400(msg, sess); return; } if(mqName == null){ msg.setBody("Missing mq_name filed"); ReplyHelper.reply400(msg, sess); return; } MessageQueue mq = null; synchronized (mqTable) { mq = mqTable.get(mqName); if(mq == null){ if(MessageMode.isEnabled(mode, MessageMode.PubSub)){ mq = new PubsubQueue(serverAddr, mqName, mqExecutor, mode); mq.setAccessToken(accessToken); mq.setCreator(sess.getRemoteAddress()); } else {//默认到消息队列 mq = new RequestQueue(serverAddr, mqName, mqExecutor, mode); mq.setMessageStore(messageStore); mq.setAccessToken(accessToken); mq.setCreator(sess.getRemoteAddress()); if(messageStore != null){ messageStore.onMessageQueueCreated(mq); } } mqTable.putIfAbsent(mqName, mq); log.info("MQ Created: %s", mq); ReplyHelper.reply200(msgId, sess); reportToTrackServer(); return; } } if(MessageMode.isEnabled(mode, MessageMode.MQ) && !(mq instanceof RequestQueue)){ msg.setBody("MsgQueue, type not matched"); ReplyHelper.reply400(msg, sess); return; } if(MessageMode.isEnabled(mode, MessageMode.PubSub) && !(mq instanceof PubsubQueue)){ msg.setBody("Pubsub, type not matched"); ReplyHelper.reply400(msg, sess); return; } ReplyHelper.reply200(msgId, sess); } }); this.registerHandler("", new MessageHandler() { @Override public void handleMessage(Message msg, Session sess) throws IOException { msg = new Message(); msg.setStatus("200"); msg.setHead("content-type","text/html"); String body = Helper.loadFileContent("zbus.htm"); msg.setBody(body); sess.write(msg); } }); this.registerHandler("jquery", new MessageHandler() { @Override public void handleMessage(Message msg, Session sess) throws IOException { msg = new Message(); msg.setStatus("200"); msg.setHead("content-type","application/javascript"); String body = Helper.loadFileContent("jquery.js"); msg.setBody(body); sess.write(msg); } }); this.registerHandler("data", new MessageHandler() { @Override public void handleMessage(Message msg, Session sess) throws IOException { msg = packServerInfo(); msg.setStatus("200"); msg.setHead("content-type", "application/json"); sess.write(msg); } }); } private Message packServerInfo(){ Map<String, MqInfo> table = new HashMap<String, MqInfo>(); for(Map.Entry<String, MessageQueue> e : this.mqTable.entrySet()){ table.put(e.getKey(), e.getValue().getMqInfo()); } Message msg = new Message(); BrokerInfo info = new BrokerInfo(); info.setBroker(serverAddr); info.setMqTable(table); msg.setBody(JSON.toJSONString(info)); return msg; } public void setupTrackServer(String trackServerAddr){ if(trackServerAddr == null) return; trackClients.clear(); String[] serverAddrs = trackServerAddr.split("[;]"); for(String addr : serverAddrs){ addr = addr.trim(); if( addr.isEmpty() ) continue; RemotingClient client = new RemotingClient(addr); client.onError(new ErrorCallback() { @Override public void onError(IOException e, Session sess) throws IOException { //ignore } }); trackClients.add(client); } this.trackReportService.scheduleAtFixedRate(new Runnable() { @Override public void run() { reportToTrackServer(); } }, trackDelay, trackInterval, TimeUnit.MILLISECONDS); } private void reportToTrackServer(){ reportExecutor.submit(new Runnable() { @Override public void run() { Message msg = packServerInfo(); msg.setCommand(Proto.TrackReport); for(RemotingClient client : trackClients){ try { client.invokeAsync(msg, null); } catch (IOException e) { //ignore } } } }); } public void close(){ this.trackReportService.shutdown(); for(RemotingClient client : this.trackClients){ client.close(); } } public long getTrackDelay() { return trackDelay; } public void setTrackDelay(long trackDelay) { this.trackDelay = trackDelay; } public long getTrackInterval() { return trackInterval; } public void setTrackInterval(long trackInterval) { this.trackInterval = trackInterval; } public MessageStore getMessageStore() { return messageStore; } public void setMessageStore(MessageStore messageStore) { this.messageStore = messageStore; } }