Package com.trendmicro.mist.cmd

Source Code of com.trendmicro.mist.cmd.TmeConsole

package com.trendmicro.mist.cmd;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.Principal;
import java.sql.DriverManager;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.jms.BytesMessage;
import javax.jms.ConnectionFactory;
import javax.jms.TextMessage;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.nocrala.tools.texttablefmt.CellStyle;
import org.nocrala.tools.texttablefmt.CellStyle.HorizontalAlign;
import org.nocrala.tools.texttablefmt.Table;

import com.google.protobuf.ByteString;
import com.google.protobuf.TextFormat;
import com.sun.security.auth.UserPrincipal;
import com.trendmicro.codi.CODIException;
import com.trendmicro.codi.Id;
import com.trendmicro.codi.Perms;
import com.trendmicro.codi.ZKSessionManager;
import com.trendmicro.codi.ZNode;
import com.trendmicro.codi.lock.Lock.LockType;
import com.trendmicro.codi.lock.ZLock;
import com.trendmicro.mist.BrokerSpy;
import com.trendmicro.mist.Daemon;
import com.trendmicro.mist.client.MistClient;
import com.trendmicro.mist.client.MistClient.Role;
import com.trendmicro.mist.console.CommandExecutable;
import com.trendmicro.mist.console.Console;
import com.trendmicro.mist.mfr.ExchangeFarm;
import com.trendmicro.mist.proto.MistMessage;
import com.trendmicro.mist.proto.MistMessage.KeyValuePair;
import com.trendmicro.mist.proto.ZooKeeperInfo;
import com.trendmicro.mist.proto.ZooKeeperInfo.DropConfig;
import com.trendmicro.mist.util.Exchange;
import com.trendmicro.spn.common.util.Utils;
import com.trendmicro.tme.mfr.BrokerFarm;

public class TmeConsole {
    private static BrokerFarm brokerFarm = null;
    private static TmeConsole myApp;
    private static Console myConsole = new Console("tme-console");
    private static ZLock consoleLock = null;
    private CellStyle numberStyle = new CellStyle(HorizontalAlign.right);
    private static String loggedUser = null;

    private class MigrateThread extends Thread {
        class Forwarder extends Thread {
            private Exchange fwdExchange;
            private boolean ready = false;
            private boolean done = false;
            private boolean go = false;

            public Forwarder(Exchange exchange) {
                fwdExchange = exchange;
            }

            public boolean getReady() {
                return ready;
            }

            public void done() {
                done = true;
            }

            public void go() {
                go = true;
            }

            public void run() {
                MistClient sinkClient = null;
                try {
                    sinkClient = new MistClient(Role.PRODUCER, 1);
                    sinkClient.mount(true, fwdExchange.toString());
                    sinkClient.attach();
                }
                catch(Exception e) {
                    e.printStackTrace();
                    return;
                }

                if(fwdExchange.getBroker() == null) {
                    ready = true;
                    try {
                        sinkClient.close();
                    }
                    catch(Exception e) {
                        e.printStackTrace();
                    }
                    return;
                }

                javax.jms.Connection fromConn = null;
                javax.jms.Session fromSess = null;
                javax.jms.MessageConsumer fromConsumer = null;
                try {
                    ConnectionFactory fromFact = new com.sun.messaging.ConnectionFactory();
                    ((com.sun.messaging.ConnectionFactory) fromFact).setProperty(com.sun.messaging.ConnectionConfiguration.imqBrokerHostName, fwdExchange.getBroker());
                    ((com.sun.messaging.ConnectionFactory) fromFact).setProperty(com.sun.messaging.ConnectionConfiguration.imqBrokerHostPort, "7676");
                    ((com.sun.messaging.ConnectionFactory) fromFact).setProperty(com.sun.messaging.ConnectionConfiguration.imqDefaultUsername, "admin");
                    ((com.sun.messaging.ConnectionFactory) fromFact).setProperty(com.sun.messaging.ConnectionConfiguration.imqDefaultPassword, "admin");
                    fromConn = fromFact.createConnection();
                    fromConn.start();

                    fromSess = fromConn.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
                    javax.jms.Destination fromDest;
                    if(fwdExchange.isQueue())
                        fromDest = fromSess.createQueue(fwdExchange.getName());
                    else
                        fromDest = fromSess.createTopic(fwdExchange.getName());
                    fromConsumer = fromSess.createConsumer(fromDest);
                }
                catch(Exception e) {
                    e.printStackTrace();
                }
                ready = true;

                for(;;) {
                    if(!go) {
                        Utils.justSleep(100);
                    }
                    else
                        break;
                }

                while(!done) {
                    try {
                        javax.jms.Message msg = fromConsumer.receive(50);
                        if(msg != null) {
                            ByteArrayOutputStream bos = new ByteArrayOutputStream();
                            try {
                                if(msg instanceof BytesMessage) {
                                    byte[] buffer = new byte[256];
                                    int ret = -1;
                                    while((ret = ((BytesMessage) msg).readBytes(buffer)) > 0)
                                        bos.write(buffer, 0, ret);
                                }
                                else if(msg instanceof TextMessage) {
                                    byte[] buffer = ((TextMessage) msg).getText().getBytes("UTF-8");
                                    bos.write(buffer, 0, buffer.length);
                                }
                            }
                            catch(Exception e) {
                                e.printStackTrace();
                                continue;
                            }

                            byte[] buffer = bos.toByteArray();
                            MistMessage.MessageBlock.Builder msgBuilder = MistMessage.MessageBlock.newBuilder().setId(fwdExchange.toString()).setMessage(ByteString.copyFrom(buffer));
                            Enumeration<?> propNames = msg.getPropertyNames();
                            while(propNames.hasMoreElements()) {
                                String key = (String) propNames.nextElement();
                                String value = msg.getStringProperty(key);
                                if(key.equals("MIST_TTL"))
                                    msgBuilder.setTtl(Long.valueOf(value));
                                else
                                    msgBuilder.addProperties(KeyValuePair.newBuilder().setKey(key).setValue(value).build());
                            }
                            sinkClient.writeMessage(msgBuilder.build());
                            totalForwardedCount++;
                        }
                    }
                    catch(Exception e) {
                        e.printStackTrace();
                    }
                }

                try {
                    fromConsumer.close();
                    fromSess.close();
                    fromConn.close();

                    sinkClient.close();
                }
                catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }

        private Exchange miExchange;
        private int pendingCnt = -1;
        private boolean isReady = false;
        private long totalForwardedCount = 0;

        public Exchange getExchange() {
            return miExchange;
        }

        public int getPendingCnt() {
            return pendingCnt;
        }

        public boolean isReady() {
            return isReady;
        }

        public MigrateThread(Exchange exchange) {
            miExchange = exchange;
        }
       
        public long getMigrateCount(){
            return totalForwardedCount;
        }

        public void migrate() {
            String nodePath = miExchange.toString();

            try {
                ZNode node = new ZNode("/exchange/" + nodePath);
                ZooKeeperInfo.Exchange.Builder exBuilder = ZooKeeperInfo.Exchange.newBuilder();
                try {
                    TextFormat.merge(new String(node.getContent()), exBuilder);
                }
                catch(CODIException.NoNode e) {
                    myConsole.logResponseNL("exchange " + miExchange.toString() + " does not exist!");
                    isReady = true;
                    return;
                }
                String oldhost = exBuilder.build().getHost();

                ZooKeeperInfo.Broker brk = brokerFarm.getBrokerByHost(oldhost);
                boolean hasOld = !(brk == null);
                if(hasOld) {
                    hasOld = false;
                    Socket sock = null;
                    try {
                        sock = new Socket();
                        sock.setReuseAddress(true);
                        sock.setTcpNoDelay(true);
                        sock.connect(new InetSocketAddress(brk.getHost(), Integer.parseInt(brk.getPort())));
                        BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
                        int wait_cnt;
                        for(wait_cnt = 0; wait_cnt < 20 && !in.ready(); wait_cnt++) {
                            Utils.justSleep(500);
                        }
                        if(in.ready()) {
                            if(brk.getBrokerType().equals("openmq")) {
                                String line = in.readLine();
                                if(line.startsWith("101 imqbroker"))
                                    hasOld = true;
                            }
                        }
                    }
                    catch(IOException e) {
                    }
                    finally {
                        try {
                            sock.getInputStream().close();
                            sock.close();
                        }
                        catch(IOException e) {
                        }
                    }
                }

                node.setContent(ZooKeeperInfo.Exchange.newBuilder().setHost("").build().toString().getBytes());

                miExchange.setBroker(hasOld ? oldhost: null);
                Forwarder fwder = new Forwarder(miExchange);
                fwder.start();
                while(!fwder.getReady()) {
                    Utils.justSleep(100);
                }
                isReady = true;

                String newhost = "";
                for(;;) {
                    exBuilder = ZooKeeperInfo.Exchange.newBuilder();
                    TextFormat.merge(new String(node.getContent()), exBuilder);
                    newhost = exBuilder.build().getHost();

                    if(newhost.compareTo(oldhost) == 0) {
                        myConsole.logResponse("[%s] warning: exchange is still on the same broker %s, migration completed%n", miExchange.toString(), newhost);
                        fwder.done();
                        fwder.go();
                        fwder.join();
                        return;
                    }
                    else if(newhost.compareTo("") != 0)
                        break;

                    myConsole.logResponse("[%s] waiting for clients to migrate...%n", miExchange.toString());
                    Utils.justSleep(1000);
                }
                myConsole.logResponse("[%s] exchange has been created on %s%n", miExchange.toString(), newhost);

                fwder.go();

                List<String> refList = node.getChildren();
                ArrayList<String> hostList = new ArrayList<String>();
                for(String refPath : refList) {
                    String data = new String(new ZNode("/exchange/" + nodePath + "/" + refPath).getContent());
                    ZooKeeperInfo.Reference.Builder refBuilder = ZooKeeperInfo.Reference.newBuilder();
                    TextFormat.merge(data, refBuilder);
                    ZooKeeperInfo.Reference ref = refBuilder.build();
                    String host = ref.getHost();
                    if(!hostList.contains(host))
                        hostList.add(host);
                }

                myConsole.logResponse("[%s] %d mist clients to migrate: %n", miExchange.toString(), hostList.size());
                for(String host : hostList) {
                    myConsole.logResponse("[%s] informing %n", miExchange.toString(), host);
                    ZooKeeperInfo.Command cmd = ZooKeeperInfo.Command.newBuilder().setType(ZooKeeperInfo.Command.Type.MIGRATE_EXCHANGE).addArgument(nodePath).build();
                    ZNode.createSequentialNode("/local/mist_client/" + host + "/cmd", false, cmd.toString().getBytes());
                }

                if(hasOld) {
                    BrokerSpy brokerSpy = new BrokerSpy(oldhost);

                    for(;;) {
                        String producer = brokerSpy.getExchangeAttribs(miExchange.isQueue(), miExchange.getName(), "NumProducers");
                        String consumer = brokerSpy.getExchangeAttribs(miExchange.isQueue(), miExchange.getName(), "NumConsumers");
                        if(producer.compareTo("0") == 0 && consumer.compareTo("1") == 0)
                            break;
                        else {
                            myConsole.logResponse("[%s] waiting for %s producer(s) and %d consumer(s) to migrate%n", miExchange.toString(), producer, (Integer.valueOf(consumer) - 1));
                            Utils.justSleep(1000);
                        }
                    }

                    for(;;) {
                        String pending = brokerSpy.getExchangeAttribs(miExchange.isQueue(), miExchange.getName(), "NumMsgs");
                        if(pending.compareTo("0") == 0)
                            break;
                        try {
                            pendingCnt = Integer.valueOf(pending);
                        }
                        catch(Exception e) {
                        }
                        Utils.justSleep(1000);
                    }
                }

                fwder.done();
                fwder.join();
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }

        public void run() {
            migrate();
        }
    }

    private class BrokerCommand implements CommandExecutable {
        private Options opts = new Options();

        private void list() {
            Map<String, ZooKeeperInfo.Loading> loading = brokerFarm.getAllLoading();
            Vector<String> reserved = new Vector<String>();
            Table tab = new Table(5);
            tab.addCell("Broker");
            tab.addCell("Status");
            tab.addCell("Loading");
            tab.addCell("Reserved");
            tab.addCell("Last Update");
            for(ZooKeeperInfo.Broker b: brokerFarm.getAllBrokers().values()){
                tab.addCell(b.getHost() + ":" + b.getPort());
                tab.addCell(b.getStatus().toString());
                tab.addCell(String.valueOf(loading.get(b.getHost()).getLoading()), numberStyle);
                tab.addCell(String.valueOf(b.getReserved()), new CellStyle(HorizontalAlign.center));
                tab.addCell(new SimpleDateFormat("HH:mm:ss").format(loading.get(b.getHost()).getLastUpdate()), new CellStyle(HorizontalAlign.center));
                if(b.getReserved())
                    reserved.add(b.getHost());
            }
            myConsole.logResponseNL(tab.render());

            HashMap<String, List<String>> allFixed = new HashMap<String, List<String>>();
            try {
                ZNode fixNode = new ZNode(ExchangeCommand.ZNODE_FIXED);
                List<String> nodes = fixNode.getChildren();
                for(String name: nodes) {
                    ZooKeeperInfo.Exchange.Builder builder = ZooKeeperInfo.Exchange.newBuilder();
                    TextFormat.merge(new String(new ZNode(ExchangeCommand.ZNODE_FIXED + "/" + name).getContent()), builder);
                    String host = builder.build().getHost();
                    if(allFixed.containsKey(host))
                        allFixed.get(host).add(name);
                    else {
                        List<String> v = new ArrayList<String>();
                        v.add(name);
                        allFixed.put(host, v);
                    }
                }
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }

            for(String host: reserved) {
                if(allFixed.containsKey(host)) {
                    myConsole.logResponse("Broker %s reserved for: %n", host);
                    for(String ex_name: allFixed.get(host))
                        myConsole.logResponse("    %s%n", ex_name);
                }
            }
        }

        private void start(String broker_ip) {
            if(!isValidBrokerIP(broker_ip)) {
                myConsole.logResponse("broker_ip `%s' not available%n", broker_ip);
                return;
            }
            if(brokerFarm.getBrokerByHost(broker_ip).getStatus() == ZooKeeperInfo.Broker.Status.ONLINE) {
                myConsole.logResponse("broker `%s' is already started%n", broker_ip);
                return;
            }

            myConsole.logResponse("starting `%s' ... ", broker_ip);
            String lockPath = "/locks/brk_" + broker_ip;
            ZLock brokerLock = new ZLock(lockPath);
            ZNode brokerNode = new ZNode("/broker/" + broker_ip);
            try{

                brokerLock.acquire(LockType.WRITE_LOCK);
                ZooKeeperInfo.Broker.Builder brkBuilder = ZooKeeperInfo.Broker.newBuilder();
                TextFormat.merge(new String(brokerNode.getContent()), brkBuilder);
                brkBuilder.clearStatus().setStatus(ZooKeeperInfo.Broker.Status.ONLINE);
                brokerNode.setContent(brkBuilder.build().toString().getBytes());
                myConsole.logResponseNL("success");
            }
            catch(Exception e){
                myConsole.logResponseNL("failed");
                myConsole.logResponseNL(e.toString());
            }
            finally {
                try {
                    brokerLock.release();
                    if(brokerLock.getChildren().isEmpty())
                        brokerLock.delete();
                }
                catch(CODIException e) {
                }
            }
        }

        @SuppressWarnings("unchecked")
        private void stop(String broker_ip) {
            if(!isValidBrokerIP(broker_ip)) {
                myConsole.logResponse("broker_ip `%s' not available%n", broker_ip);
                return;
            }
            if(brokerFarm.getBrokerByHost(broker_ip).getStatus() == ZooKeeperInfo.Broker.Status.OFFLINE) {
                myConsole.logResponse("broker `%s' is already stopped%n", broker_ip);
                return;
            }

            int availBrkCnt = 0;
            for(ZooKeeperInfo.Broker b : brokerFarm.getAllBrokers().values()){
                if(b.getStatus() == ZooKeeperInfo.Broker.Status.ONLINE)
                    availBrkCnt++;
            }
            if(availBrkCnt <= 1) {
                System.out.print("You're stopping the last broker in cluster!!! Are you sure? (Y/N): ");
                try {
                    int c = System.in.read();
                    if(c != 'Y' && c != 'y') {
                        myConsole.logResponseNL("Aborted");
                        return;
                    }
                }
                catch(Exception e) {
                }
            }

            myConsole.logResponse("stopping `%s' ...%n", broker_ip);
            String lockPath = "/locks/brk_" + broker_ip;
            ZLock brokerLock = new ZLock(lockPath);
            ZNode brokerNode = new ZNode("/broker/" + broker_ip);
            try {
                brokerLock.acquire(LockType.WRITE_LOCK);
                ZooKeeperInfo.Broker.Builder brkBuilder = ZooKeeperInfo.Broker.newBuilder();
                TextFormat.merge(new String(brokerNode.getContent()), brkBuilder);
                brkBuilder.clearStatus().setStatus(ZooKeeperInfo.Broker.Status.OFFLINE);
                brokerNode.setContent(brkBuilder.build().toString().getBytes());

                if(availBrkCnt > 1) {
                    BrokerSpy brokerSpy = new BrokerSpy(broker_ip);
                    ArrayList<Exchange> exchangeList = brokerSpy.getAllExchangeMetadata();

                    ArrayList<MigrateThread> migrateList = new ArrayList<MigrateThread>();
                    for(Exchange exg : exchangeList) {
                        migrateList.add(new MigrateThread(exg));
                    }

                    while(migrateList.size() > 0) {
                        Iterator<MigrateThread> iter = migrateList.iterator();
                        ArrayList<MigrateThread> runningList = new ArrayList<MigrateThread>();
                        for(int i = 0; i < 8; i++) {
                            if(iter.hasNext()) {
                                MigrateThread th = iter.next();
                                th.start();
                                runningList.add(th);
                            }
                        }

                        ArrayList<MigrateThread> pendingList = (ArrayList<MigrateThread>)migrateList.clone();
                        for(MigrateThread th : runningList)
                            pendingList.remove(th);

                        for(;;) {
                            Utils.justSleep(2000);
                            boolean allReady = true;
                            for(MigrateThread th : runningList)
                                allReady &= th.isReady();
                            if(!allReady)
                                continue;

                            boolean hasAlive = false;
                            if(pendingList.size() > 0) {
                                System.out.print("pending to be migrated: ");
                                for(MigrateThread th : pendingList)
                                    System.out.print(th.getExchange() + ", ");
                                myConsole.logResponseNL("");
                            }
                            for(MigrateThread th : runningList) {
                                hasAlive |= th.isAlive();
                                if(th.isAlive()){
                                    if(th.getPendingCnt()>0)
                                        myConsole.logResponseNL("[%s] %d messages left", th.getExchange(), th.getPendingCnt());
                                }
                            }
                            if(!hasAlive)
                                break;
                        }

                        for(MigrateThread th : runningList) {
                            myConsole.logResponseNL("[" + th.getExchange() + "] Migration completed! " + th.getMigrateCount() + " messages forwarded");
                            th.join();
                            migrateList.remove(th);
                        }
                    }
                }
                myConsole.logResponse("stopping `%s' ... success%n", broker_ip);
            }
            catch(Exception e) {
                myConsole.logResponse("stopping `%s' ... failed%n", broker_ip);
                myConsole.logResponseNL(e.toString());
            }
            finally{
                try {
                    brokerLock.release();
                    if(brokerLock.getChildren().isEmpty())
                        brokerLock.delete();
                }
                catch(CODIException e) {
                }
            }
        }

        private void reserve(String [] argv) {
            if(argv.length == 1) {
                myConsole.logResponseNL("missing `flag'");
                return;
            }
            String broker_ip = argv[0];
            String flag = argv[1];
            if(!isValidBrokerIP(broker_ip)) {
                myConsole.logResponse("broker_ip `%s' not available%n", broker_ip);
                return;
            }

            ZooKeeperInfo.Broker broker = brokerFarm.getBrokerByHost(broker_ip);
            ZooKeeperInfo.Broker.Builder builder = ZooKeeperInfo.Broker.newBuilder();
            builder.mergeFrom(broker);
            if(flag.equals("true") || flag.equals("1"))
                builder.setReserved(true);
            else if(flag.equals("false") || flag.equals("0"))
                builder.setReserved(false);
            else {
                myConsole.logResponse("invalid flag `%s'%n", flag);
                return;
            }
            broker = builder.build();

            try {
                new ZNode("/broker/" + broker_ip).setContent(broker.toString().getBytes());
                myConsole.logResponse("broker `%s' reserved = %b%n", broker_ip, broker.getReserved());
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        ////////////////////////////////////////////////////////////////////////////////

        public BrokerCommand() {
            Option optHelp = new Option("h", "help", false, "display help message");
            Option optList = new Option("l", "list", false, "list all brokers and their states");
            Option optStart = new Option("s", "start", true, "start the broker");
            optStart.setArgName("broker_ip");
            Option optStop = new Option("t", "stop", true, "stop the broker");
            optStop.setArgName("broker_ip");
            Option optReserve = new Option("r", "reserve", true, "mark reserved brokers\n`flag' = {true|false}");
            optReserve.setArgName("broker_ip flag");
            optReserve.setArgs(2);

            opts.addOption(optList);
            opts.addOption(optStart);
            opts.addOption(optStop);
            opts.addOption(optReserve);
            opts.addOption(optHelp);
        }

        public void execute(String [] argv) {
            try {
                CommandLine line = new GnuParser().parse(opts, argv);
                if(line.hasOption("list"))
                    list();
                else if(line.hasOption("start"))
                    start(line.getOptionValue("start"));
                else if(line.hasOption("stop"))
                    stop(line.getOptionValue("stop"));
                else if(line.hasOption("reserve"))
                    reserve(line.getOptionValues("reserve"));
                else
                    help();
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        public void help() {
            HelpFormatter formatter = new HelpFormatter();
            formatter.setWidth(256);
            formatter.printHelp("broker", opts);
        }

        public String explain() {
            return "manage brokers";
        }

        public Options getOptions() {
            return opts;
        }
    }

    private class StatusCommand implements CommandExecutable {
        private Options opts = new Options();

        private void all() {
            zookeeper();
            mistd();
            bridge();
        }

        private void bridge() {
            try {
                myConsole.logResponseNL("==> all tme-bridge(s)");
                List<String> all_bridge = new ZNode("/bridge").getChildren();
                boolean showed = false;
                for(String b: all_bridge) {
                    List<String> masters = new ZNode("/bridge/" + b + "/master").getChildren();
                    List<String> slaves = new ZNode("/bridge/" + b + "/slave").getChildren();
                    if(masters.size() + slaves.size() > 0) {
                        myConsole.logResponse("    %s:%n", b);
                        for(String m: masters)
                            myConsole.logResponse("        %s (master)%n", m);
                        for(String m: slaves)
                            myConsole.logResponse("        %s (slave)%n", m);
                        showed = true;
                    }
                }
                if(!showed)
                    myConsole.logResponseNL("    no bridge(s)");
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        private void mistd() {
            try {
                myConsole.logResponseNL("==> all mistd clients");
                List<String> all_mistd = new ZNode("/local/mist_client").getChildren();
                if(all_mistd.size() == 0)
                    myConsole.logResponseNL("    no clients");
                else {
                    for(String m: all_mistd)
                        myConsole.logResponse("    %s%n", m);
                }
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        private boolean verifyZooKeeper(String host) {
            if(!Utils.checkSocketConnectable(host))
                return false;
            String zkPath = "/ZK_TEST_NODE";
            String zkData = "02a7e44daac8046f43de84b2546a4d63";
            try {
                ZNode node = new ZNode(zkPath);
                node.create(false, zkData.getBytes());
                String res = new String(node.getContent());
                node.delete();
                if(res.compareTo(zkData) == 0)
                    return true;
                else
                    return false;
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
                return false;
            }
        }

        private void zookeeper() {
            String [] servers = Daemon.propMIST.getProperty("mistd.zookeeper").split(",");
            myConsole.logResponseNL("==> all zookeeper servers");
            for(String host: servers)
                myConsole.logResponse("    %-25s %-20s%n", host, verifyZooKeeper(host) ? "available": "missing");
        }

        ////////////////////////////////////////////////////////////////////////////////

        public StatusCommand() {
            Option optHelp = new Option("h", "help", false, "display help message");
            Option optAll = new Option("a", "all", false, "list all status");
            Option optBridge = new Option("b", "bridge", false, "list tme-bridge status");
            Option optClient = new Option("m", "mistd", false, "list mistd status");
            Option optZooKeeper = new Option("z", "zookeeper", false, "list zookeeper status");

            opts.addOption(optAll);
            opts.addOption(optBridge);
            opts.addOption(optClient);
            opts.addOption(optZooKeeper);
            opts.addOption(optHelp);
        }

        public void execute(String [] argv) {
            try {
                CommandLine line = new GnuParser().parse(opts, argv);
                if(line.hasOption("all"))
                    all();
                else if(line.hasOption("bridge"))
                    bridge();
                else if(line.hasOption("mistd"))
                    mistd();
                else if(line.hasOption("zookeeper"))
                    zookeeper();
                else
                    help();
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        public void help() {
            HelpFormatter formatter = new HelpFormatter();
            formatter.setWidth(256);
            formatter.printHelp("status", opts);
        }

        public String explain() {
            return "show cluster status";
        }

        public Options getOptions() {
            return opts;
        }
}

    private class ConfigCommand implements CommandExecutable {
        private Options opts = new Options();
        private static final String ZNODE_PORTAL_DB = "/global/portal_db";
        private static final String ZNODE_MAIL_SMTP = "/global/mail_smtp";
        private static final String ZNODE_MAIL_ALERT = "/global/mail_alert";
        private static final String ZNODE_MAIL_SENDER = "/global/mail_sender";

        private boolean checkDBConnection(ZooKeeperInfo.PortalDB db) {
            String connectionURL = String.format("jdbc:mysql://%s:%s/%s?user=%s&password=%s", db.getHost(), db.getPort(), db.getName(), db.getUser(), db.getPassword());
            try {
                Class.forName("com.mysql.jdbc.Driver");
                java.sql.Connection conn = DriverManager.getConnection(connectionURL);
                conn.close();
                return true;
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
                return false;
            }
        }

        private void portaldb(String connectString) {
            String [] v = connectString.split(":");
            if(v.length < 5) {
                myConsole.logResponseNL("connect string `%s' not valid", connectString);
                return;
            }

            String host = String.format("%s:%s", v[0], v[1]);
            if(!Utils.checkSocketConnectable(host)) {
                myConsole.logResponseNL("`%s' not connectable, please check out ip or port", host);
                return;
            }

            ZooKeeperInfo.PortalDB.Builder p_builder = ZooKeeperInfo.PortalDB.newBuilder();
            p_builder.setHost(v[0]).setPort(v[1]);
            p_builder.setUser(v[2]).setPassword(v[3]);
            p_builder.setName(v[4]);
            ZooKeeperInfo.PortalDB pdb = p_builder.build();

            if(!checkDBConnection(pdb)) {
                myConsole.logResponseNL("`%s' not connectable, please check out account for db", connectString);
                return;
            }

            createAndSetNode(ZNODE_PORTAL_DB, pdb.toString().getBytes());
            myConsole.logResponseNL("%s => %s", ZNODE_PORTAL_DB, "{ " + pdb.toString().replace("\n", "; ") + " }");
        }

        private void unportaldb() {
            if(deleteNode(ZNODE_PORTAL_DB))
                myConsole.logResponseNL("`%s' removed", ZNODE_PORTAL_DB);
            else
                myConsole.logResponseNL("no previous setting of `%s'", ZNODE_PORTAL_DB);
        }

        private void smtp(String server) {
            try {
                String host = server + ":25";
                if(!Utils.checkSocketConnectable(host)) {
                    myConsole.logResponse("`%s' not connectable%n", server);
                    return;
                }

                createAndSetNode(ZNODE_MAIL_SMTP, server.getBytes());
                myConsole.logResponseNL("%s => %s", ZNODE_MAIL_SMTP, server);
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        private void unsmtp() {
            if(deleteNode(ZNODE_MAIL_SMTP))
                myConsole.logResponseNL("`%s' removed", ZNODE_MAIL_SMTP);
            else
                myConsole.logResponseNL("no previous setting of `%s'", ZNODE_MAIL_SMTP);
        }

        private void alert(String mail_list) {
            createAndSetNode(ZNODE_MAIL_ALERT, mail_list.getBytes());
            myConsole.logResponseNL("%s => %s", ZNODE_MAIL_ALERT, mail_list);
        }

        private void unalert() {
            if(deleteNode(ZNODE_MAIL_ALERT))
                myConsole.logResponseNL("`%s' removed", ZNODE_MAIL_ALERT);
            else
                myConsole.logResponseNL("no previous setting of `%s'", ZNODE_MAIL_ALERT);
        }
       
        private void sender(String mail_sender) {
            createAndSetNode(ZNODE_MAIL_SENDER, mail_sender.getBytes());
            myConsole.logResponseNL("%s => %s", ZNODE_MAIL_SENDER, mail_sender);
        }

        private void unsender() {
            if(deleteNode(ZNODE_MAIL_SENDER))
                myConsole.logResponseNL("`%s' removed", ZNODE_MAIL_SENDER);
            else
                myConsole.logResponseNL("no previous setting of `%s'", ZNODE_MAIL_SENDER);
        }

        private void list() {
            ArrayList<String> configs = new ArrayList<String>();
            configs.add(ZNODE_PORTAL_DB);
            configs.add(ZNODE_MAIL_SMTP);
            configs.add(ZNODE_MAIL_ALERT);
            configs.add(ZNODE_MAIL_SENDER);

            boolean showed = false;
            for(String key: configs) {
                try {
                    String value = new String(new ZNode(key).getContent()).trim();
                    if(value.length() > 0) {
                        if(key.equals(ZNODE_PORTAL_DB))
                            myConsole.logResponseNL("%-24s => %s", key, "{ " + value.replace("\n", "; ") + " }");
                        else
                            myConsole.logResponseNL("%-24s => %s", key, value);
                        showed = true;
                    }
                }
                catch(Exception e) {
                }
            }
            if(!showed)
                myConsole.logResponseNL("no config(s)");
        }

        ////////////////////////////////////////////////////////////////////////////////

        public ConfigCommand() {
            Option optHelp = new Option("h", "help", false, "display help message");
            Option optPortalDB = new Option("p", "portal-db", true, "specify Portal DB\n`connect_string' = host:port:user:password:db_name");
            optPortalDB.setArgName("connect_string");
            Option optUnPortalDB = new Option("P", "un-portal-db", false, "remove Portal DB setting");
            Option optList = new Option("l", "list", false, "list all configurations");
            Option optSmtp = new Option("m", "mail-smtp", true, "set SMTP mail server");
            optSmtp.setArgName("server");
            Option optUnSmtp = new Option("M", "un-mail-smtp", false, "remove SMTP mail server");
            Option optAlert = new Option("a", "mail-alert", true, "set mail alert recipients\n`mail_list' = user1@host;user2@host");
            optAlert.setArgName("mail_list");
            Option optUnAlert = new Option("A", "un-mail-alert", false, "remove mail alert recipients");
            Option optSender = new Option("s", "mail-sender", true, "set mail alert sender\n`mail_sender' = user1@host");
            Option optUnSender = new Option("S", "un-mail-sender", false, "remove mail alert sender");
            optSender.setArgName("sender_mail");

            opts.addOption(optPortalDB);
            opts.addOption(optUnPortalDB);
            opts.addOption(optHelp);
            opts.addOption(optList);
            opts.addOption(optSmtp);
            opts.addOption(optUnSmtp);
            opts.addOption(optAlert);
            opts.addOption(optUnAlert);
            opts.addOption(optSender);
            opts.addOption(optUnSender);
        }

        public void execute(String [] argv) {
            try {
                CommandLine line = new GnuParser().parse(opts, argv);
                if(line.hasOption("portal-db"))
                    portaldb(line.getOptionValue("portal-db"));
                else if(line.hasOption("un-portal-db"))
                    unportaldb();
                else if(line.hasOption("mail-smtp"))
                    smtp(line.getOptionValue("mail-smtp"));
                else if(line.hasOption("un-mail-smtp"))
                    unsmtp();
                else if(line.hasOption("mail-alert"))
                    alert(line.getOptionValue("mail-alert"));
                else if(line.hasOption("un-mail-alert"))
                    unalert();
                else if(line.hasOption("mail-sender"))
                    sender(line.getOptionValue("mail-sender"));
                else if(line.hasOption("un-mail-sender"))
                    unsender();
                else if(line.hasOption("list"))
                    list();
                else
                    help();
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        public void help() {
            HelpFormatter formatter = new HelpFormatter();
            formatter.setWidth(256);
            formatter.printHelp("config", opts);
        }

        public String explain() {
            return "global configuration";
        }

        public Options getOptions() {
            return opts;
        }
    }

    private class ExchangeCommand implements CommandExecutable {
        private Options opts = new Options();

        private void list() {
            List<ExchangeFarm.ExchangeInfo> exchanges = ExchangeFarm.getAllExchanges();
            myConsole.logResponse("%d exchanges%n", exchanges.size());
            if(exchanges.size() > 0) {
                Table tab = new Table(3);
                tab.addCell("Exchange");
                tab.addCell("Host");
                tab.addCell("Clients");
                for(ExchangeFarm.ExchangeInfo info: exchanges) {
                    tab.addCell(info.name);
                    tab.addCell(info.host);
                    tab.addCell(String.valueOf(info.refCount), numberStyle);
                }
                myConsole.logResponseNL(tab.render());
            }

            try {
                Table tab = new Table(3);
                tab.addCell("Exchange");
                tab.addCell("Config. Type");
                tab.addCell("Remark");
               
                List<String> fixed_ex = new ZNode(ZNODE_FIXED).getChildren();
                for(String name: fixed_ex) {
                    ZooKeeperInfo.Exchange.Builder builder = ZooKeeperInfo.Exchange.newBuilder();
                    TextFormat.merge(new String(new ZNode(ZNODE_FIXED + "/" + name).getContent()), builder);
                    tab.addCell("{queue,topic}:" + name);
                    tab.addCell("Fixed", new CellStyle(HorizontalAlign.center));
                    tab.addCell(builder.build().getHost());
                }
               
                List<String> drop_ex = new ZNode(ZNODE_DROP).getChildren();
                for(String name : drop_ex) {
                    ZooKeeperInfo.DropConfig.Builder drop_builder = ZooKeeperInfo.DropConfig.newBuilder();
                    TextFormat.merge(new String(new ZNode(ZNODE_DROP + "/" + name).getContent()), drop_builder);
                    tab.addCell(name);
                    tab.addCell("Drop Polocy", new CellStyle(HorizontalAlign.center));
                    tab.addCell(drop_builder.build().getPolicy() == DropConfig.Policy.NEWEST ? "newest": "oldest");
                }
               
                List<String> limit_ex = new ZNode(ZNODE_LIMIT).getChildren();
                for(String name : limit_ex) {
                    ZooKeeperInfo.TotalLimit.Builder limit_builder = ZooKeeperInfo.TotalLimit.newBuilder();
                    TextFormat.merge(new String(new ZNode(ZNODE_LIMIT + "/" + name).getContent()), limit_builder);
                    tab.addCell(name);
                    tab.addCell("Maximum limit", new CellStyle(HorizontalAlign.center));
                    ZooKeeperInfo.TotalLimit limit = limit_builder.build();
                    tab.addCell(String.format("%d bytes / %d messages", limit.getSizeBytes(), limit.getCount()));
                }

                List<String> alert_limit_ex = new ZNode(ZNODE_ALERT_LIMIT).getChildren();
                for(String name : alert_limit_ex) {
                    ZooKeeperInfo.AlertConfig.Builder alert_limit_builder = ZooKeeperInfo.AlertConfig.newBuilder();
                    TextFormat.merge(new ZNode(ZNODE_ALERT_LIMIT + "/" + name).getContentString(), alert_limit_builder);
                    ZooKeeperInfo.AlertConfig alertConfig = alert_limit_builder.build();
                    tab.addCell(name);
                    tab.addCell("Alert limit", new CellStyle(HorizontalAlign.center));
                    tab.addCell(String.format("%d messages to %s", alertConfig.getCount(), alertConfig.getReceiver()));
                }

                myConsole.logResponse("%d configured exchanges%n", fixed_ex.size() + drop_ex.size() + limit_ex.size());
                if(fixed_ex.size() + drop_ex.size() + limit_ex.size() > 0)
                    myConsole.logResponseNL(tab.render());
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        private void fix(String [] argv) {
            if(argv.length == 1) {
                myConsole.logResponse("exchange: `%s', missing broker_ip%n", argv[0]);
                return;
            }
            Exchange ex = new Exchange(argv[0]);
            String broker_ip = argv[1];
            if(!isValidBrokerIP(broker_ip)) {
                myConsole.logResponse("broker_ip `%s' not available%n", broker_ip);
                return;
            }

            ZooKeeperInfo.Exchange.Builder builder = ZooKeeperInfo.Exchange.newBuilder();
            builder.setHost(broker_ip);
            ZooKeeperInfo.Exchange ex_data = builder.build();

            String path = String.format("/global/fixed_exchange/%s", ex.getName());
            createAndSetNode(path, ex_data.toString().getBytes());
            myConsole.logResponse("exchange `%s' fixed on broker `%s'%n", ex.getName(), broker_ip);
        }

        private void unfix(String exchange) {
            Exchange ex = new Exchange(exchange);
            String path = String.format("/global/fixed_exchange/%s", ex.getName());
            if(deleteNode(path))
                myConsole.logResponse("fixed exchange `%s' removed%n", ex.getName());
            else
                myConsole.logResponse("fixed exchange `%s' not found%n", ex.getName());
        }

        public void migrate(String exchange) {
            MigrateThread th = new MigrateThread(new Exchange(exchange));
            th.start();
            while(th.isAlive()) {
                if(th.getPendingCnt() > 0)
                    myConsole.logResponseNL("[" + exchange + "] " + th.getPendingCnt() + " messages left");
                Utils.justSleep(2000);
            }
            myConsole.logResponseNL("Migration completed! " + th.getMigrateCount() + " messages forwarded");
            try {
                th.join();
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }

        private void drop(String policy) {
            String strArray[] = policy.split(":");
            if(strArray.length != 2) {
                help();
                return;
            }
            if(strArray[1].compareTo("newest") != 0 && strArray[1].compareTo("oldest") != 0) {
                System.out.println("Drop policy should be either [newest] or [oldest]!");
                return;
            }
            Exchange ex = new Exchange(strArray[0]);
            String path = ZNODE_DROP + "/" + ex.getName();
            ZooKeeperInfo.DropConfig dropConfig = ZooKeeperInfo.DropConfig.newBuilder().setPolicy(strArray[1].compareTo("newest") == 0 ? DropConfig.Policy.NEWEST: DropConfig.Policy.OLDEST).build();
            createAndSetNode(path, dropConfig.toString().getBytes());
           
            try {
                if(dropConfig.getPolicy().equals(ZooKeeperInfo.DropConfig.Policy.NEWEST))
                    BrokerSpy.setExchangeFlowControl(ex, ExchangeFarm.FlowControlBehavior.DROP_NEWEST);
                else
                    BrokerSpy.setExchangeFlowControl(ex, ExchangeFarm.FlowControlBehavior.DROP_OLDEST);
            }
            catch(Exception e) {
            }
        }

        private void block(String exchange) {
            Exchange ex = new Exchange(exchange);
            String path = ZNODE_DROP + "/" + ex.getName();
            if(deleteNode(path))
                System.out.printf(String.format("drop policy on `%s' removed%n", ex.getName()));
            else
                System.out.printf(String.format("`%s' not found%n", ex.getName()));
            try {
                BrokerSpy.setExchangeFlowControl(ex, ExchangeFarm.FlowControlBehavior.BLOCK);
            }
            catch(Exception e) {
            }
        }
       
        private void limit(String limitStr) {
            if(!limitStr.matches(".*:\\d+:\\d+")) {
                help();
                return;
            }
            String strArray[] = limitStr.split(":");
            Exchange ex = new Exchange(strArray[0]);
            long size = Long.valueOf(strArray[1]);
            long count = Long.valueOf(strArray[2]);

            ZooKeeperInfo.TotalLimit limitConfig = ZooKeeperInfo.TotalLimit.newBuilder().setSizeBytes(size).setCount(count).build();
            String path = ZNODE_LIMIT + "/" + ex.getName();
            createAndSetNode(path, limitConfig.toString().getBytes());

            try {
                BrokerSpy.setExchangeTotalLimit(ex, size, count);
            }
            catch(Exception e) {
            }
        }

        private void defLimit(String exchange) {
            Exchange ex = new Exchange(exchange);
            String path = ZNODE_LIMIT + "/" + ex.getName();
            if(deleteNode(path))
                System.out.printf(String.format("limit on `%s' changed to default%n", ex.getName()));
            else
                System.out.printf(String.format("`%s' not found%n", ex.getName()));

            try {
                BrokerSpy.setExchangeTotalLimit(ex, 10485760L, 100000);
            }
            catch(Exception e) {
            }
        }

        private void alertLimit(String limitStr) {
            if(!limitStr.matches(".*:\\d+:.*")) {
                help();
                return;
            }
            String strArray[] = limitStr.split(":");
            Exchange ex = new Exchange(strArray[0]);
            long count = Long.valueOf(strArray[1]);
            String receiver = strArray.length == 3 ? strArray[2]: "";

            String path = ZNODE_ALERT_LIMIT + "/" + ex.getName();
            if(count <= 0) {
                deleteNode(path);
            }
            else {
                ZooKeeperInfo.AlertConfig.Builder alertConfigBuilder = ZooKeeperInfo.AlertConfig.newBuilder();
                alertConfigBuilder.setCount(count);
                if(!receiver.isEmpty()) {
                    alertConfigBuilder.setReceiver(receiver);
                }
                createAndSetNode(path, alertConfigBuilder.build().toString().getBytes());
            }
        }

        ////////////////////////////////////////////////////////////////////////////////

        public static final String ZNODE_FIXED = "/global/fixed_exchange";
        public static final String ZNODE_DROP = "/global/drop_exchange";
        public static final String ZNODE_LIMIT = "/global/limit_exchange";
        public static final String ZNODE_ALERT_LIMIT = "/global/alert_limit_exchange";

        public ExchangeCommand() {
            Option optHelp = new Option("h", "help", false, "display help message");
            Option optList = new Option("l", "list", false, "list all exchanges");
            Option optMigrate = new Option("m", "migrate", true, "migrate the exchange to another broker");
            optMigrate.setArgName("exchange");
            Option optFix = new Option("f", "fix", true, "specify an exchange with a fixed broker");
            optFix.setArgName("exchange broker_ip");
            optFix.setArgs(2);
            Option optUnFix = new Option("F", "un-fix", true, "remove fixed exchange");
            optUnFix.setArgName("exchange");
            Option optDrop = new Option("d", "drop", true, "make exchange to drop [policy] message when full");
            optDrop.setArgName("policy");
            Option optBlock = new Option("b", "block", true, "make exchange to block sending when full");
            optBlock.setArgName("exchange");
            Option optLimit = new Option("L", "limit", true, "exchange's maximum total message count and size limit");
            optLimit.setArgName("limit");
            Option optDefaultLimit = new Option("D", "default-limit", true, "change the size and count limit of a exchange back to default (10M/100000)");
            optDefaultLimit.setArgName("exchange");
            Option optAlertLimit = new Option("a", "alert-limit", true, "change the limit that triggers the alert when the exchange is not consumed, set to 0 will alert when there is any pending message, receiver is seperated by ; and overrides the default mail receiver");
            optAlertLimit.setArgName("alert-limit");

            opts.addOption(optList);
            opts.addOption(optMigrate);
            opts.addOption(optFix);
            opts.addOption(optUnFix);
            opts.addOption(optHelp);
            opts.addOption(optDrop);
            opts.addOption(optBlock);
            opts.addOption(optLimit);
            opts.addOption(optDefaultLimit);
            opts.addOption(optAlertLimit);
        }

        public void execute(String [] argv) {
            try {
                CommandLine line = new GnuParser().parse(opts, argv);
                if(line.hasOption("list"))
                    list();
                else if(line.hasOption("fix"))
                    fix(line.getOptionValues("fix"));
                else if(line.hasOption("un-fix"))
                    unfix(line.getOptionValue("un-fix"));
                else if(line.hasOption("migrate"))
                    migrate(line.getOptionValue("migrate"));
                else if(line.hasOption("drop"))
                    drop(line.getOptionValue("drop"));
                else if(line.hasOption("block"))
                    block(line.getOptionValue("block"));
                else if(line.hasOption("limit"))
                    limit(line.getOptionValue("limit"));
                else if(line.hasOption("default-limit"))
                    defLimit(line.getOptionValue("default-limit"));
                else if(line.hasOption("alert-limit"))
                    alertLimit(line.getOptionValue("alert-limit"));
                else
                    help();
            }
            catch(Exception e) {
                myConsole.logResponseNL(e.getMessage());
            }
        }

        public void help() {
            HelpFormatter formatter = new HelpFormatter();
            formatter.setWidth(256);
            formatter.printHelp("exchange", opts);
            myConsole.logResponseNL("notations: ");
            myConsole.logResponseNL(" `exchange' = {queue|topic}:EXCHANGENAME");
            myConsole.logResponseNL(" `policy' = EXCHANGENAME:[newest|oldest]");
            myConsole.logResponseNL(" `limit' = EXCHANGENAME:size:count");
            myConsole.logResponseNL(" `alert-limit' = EXCHANGENAME:count:receiver");
        }

        public String explain() {
            return "manage exchanges";
        }

        public Options getOptions() {
            return opts;
        }
    }

    private void addShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                myApp.shutdown();
            }
        });
        myConsole.logResponse("Welcome to the TME 2.0 console!%n%n");
        myConsole.logResponse("Connected to `%s'%n%n", Daemon.propMIST.getProperty("mistd.zookeeper"));
        myConsole.logResponse("Type `help' for help message, `exit' to exit.%n");
    }

    private void shutdown() {
        if(consoleLock != null){
            try {
                consoleLock.release();
                if(consoleLock.getChildren().isEmpty())
                    consoleLock.delete();
            }
            catch(CODIException e){
            }
        }
        myConsole.logResponse("Bye-bye!%n");
    }

    private boolean isValidBrokerIP(String broker_ip) {
        String path = String.format("/broker/%s", broker_ip);
        try {
            if(new ZNode(path).exists())
                return true;
        }
        catch(CODIException e) {
            e.printStackTrace();
        }
        return false;
    }

    private boolean createAndSetNode(String path, byte[] data) {
        ZNode node = new ZNode(path);
        try {
            if(!node.exists()) {
                node.create(false, data);
                return true;
            }
            else {
                node.setContent(data);
                return true;
            }

        }
        catch(Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private boolean deleteNode(String path) {
        ZNode node = new ZNode(path);
        try {
            if(!node.exists())
                return false;
            node.delete();
        }
        catch(CODIException e) {
            e.printStackTrace();
        }
        return true;
    }

    ////////////////////////////////////////////////////////////////////////////////

    public TmeConsole() {
        myConsole.addCommand("broker", new BrokerCommand());
        myConsole.addCommand("exchange", new ExchangeCommand());
        myConsole.addCommand("config", new ConfigCommand());
        myConsole.addCommand("status", new StatusCommand());
    }

    public void start() {
        if(loggedUser != null)
            myConsole.setLogUser(loggedUser);
        myConsole.launch();
    }

    public static void main(String [] argv) {
        boolean locked = false;
        try {
            locked = authenticateLock();
            brokerFarm = new BrokerFarm();
            myApp = new TmeConsole();
            myApp.addShutdownHook();
            myApp.start();
        }
        catch(CODIException coe) {
            myConsole.logResponseNL("User or password is wrong. Exit now!");
        }
        catch(Exception e) {
            myConsole.logResponseNL(e.getMessage());
        }
        finally {
            System.exit(authenticateUnlock(locked));
        }
    }
   
    private static final String ACL_NODE = "/global/acl/console_admins";

    private static boolean authenticateLock() throws Exception {
        ZKSessionManager.initialize(Daemon.propMIST.getProperty("mistd.zookeeper") + Daemon.propMIST.getProperty("mistd.zookeeper.tmeroot"), Integer.valueOf(Daemon.propMIST.getProperty("mistd.zookeeper.timeout")));
        ZKSessionManager zksm = ZKSessionManager.instance();
        zksm.waitConnected();

        ZNode authNode = new ZNode(ACL_NODE);
        if(authNode.exists()) {
            LoginContext lc = new LoginContext("ldaploginmodule", new CallbackHandler() {

                @Override
                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
                    for(Callback cb : callbacks) {
                        if(cb instanceof NameCallback) {
                            System.out.print("Enter username: ");
                            ((NameCallback) cb).setName(System.console().readLine());
                        }
                        else if(cb instanceof PasswordCallback) {
                            System.out.print("Enter password: ");
                            ((PasswordCallback) cb).setPassword(System.console().readPassword());
                        }
                    }
                }
            });
            lc.login();

            boolean authorized = false;
            for(String admin : authNode.getContentString().split(",")) {
                for(Principal p : lc.getSubject().getPrincipals()) {
                    if(p instanceof UserPrincipal) {
                        if(p.getName().equals(admin.trim())) {
                            authorized = true;
                        }
                    }
                }
            }
            if(!authorized)
                throw new Exception("You are not authorized to console, please contact with operation");
        }
        else
            myConsole.logResponseNL("Warning: Can't get authorization information, running under unprotected mode!\n");

        zksm.setDefaultPerms(Id.ANYONE, EnumSet.allOf(Perms.class));

        String lockPath = "/global/tme-console.lock";
        consoleLock = new ZLock(lockPath);

        if(consoleLock.tryAcquire(LockType.WRITE_LOCK, 3000) == false)
            throw new Exception("Cannot get administration lock! Another instance of tme-console might be running, exiting.");
       
        return true;
    }

    private static int authenticateUnlock(boolean locked) {
        if(!locked) {
            if(consoleLock != null) {
                try {
                    consoleLock.release();
                    if(consoleLock.getChildren().isEmpty())
                        consoleLock.delete();
                }
                catch(CODIException e) {
                }
            }
            return 1;
        }
        return 0;
    }
}
TOP

Related Classes of com.trendmicro.mist.cmd.TmeConsole

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.