com.sds.acube.ndisc.mts.xserver.XNDiscServer.java Source code

Java tutorial

Introduction

Here is the source code for com.sds.acube.ndisc.mts.xserver.XNDiscServer.java

Source

/*
 * <pre>
 * Copyright (c) 2014 Samsung SDS.
 * All right reserved.
 *
 * This software is the confidential and proprietary information of Samsung
 * SDS. You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license agreement
 * you entered into with Samsung SDS.
 *
 * Author             : Takkies
 * Date                : 2014. 04. 01.
 * Description      : 
 * </pre>
 */
package com.sds.acube.ndisc.mts.xserver;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.lang.StringUtils;
import org.xsocket.connection.BlockingConnection;
import org.xsocket.connection.BlockingConnectionPool;
import org.xsocket.connection.IConnection.FlushMode;
import org.xsocket.connection.IServer;
import org.xsocket.connection.NonBlockingConnection;
import org.xsocket.connection.NonBlockingConnectionPool;
import org.xsocket.connection.Server;

import org.xsocket.connection.multiplexed.MultiplexedConnection;
import org.xsocket.connection.multiplexed.MultiplexedProtocolAdapter;

import com.sds.acube.ndisc.mts.filter.iface.FilterIF;
import com.sds.acube.ndisc.mts.logger.iface.LoggerIF;
import com.sds.acube.ndisc.mts.storage.iface.StorageIF;
import com.sds.acube.ndisc.mts.util.loader.DynamicClassLoader;
import com.sds.acube.ndisc.mts.xserver.factory.XNDiscSSLContextFactory;
import com.sds.acube.ndisc.mts.xserver.factory.XNDiscThreadFactory;
import com.sds.acube.ndisc.mts.xserver.handler.XNDiscHandler;
import com.sds.acube.ndisc.mts.xserver.util.XNDiscConfig;
import com.sds.acube.ndisc.mts.xserver.util.XNDiscUtils;

/**
 * XNDisc Server  ?<br>
 * XNApi Client?  ??? <br>
 * ? NApi ? ?? ?<br>
 * <br>
 * ? Single-Thread(Procedural Processor) ? ?? <br>
 * Multi-Thread ?   <br>
 * Multiplexing (jdk 1.5  nio ? ? )  <br>
 *  socket connection(channel)  thread ? <br>
 * channel? multiplexing  ??? thread  channel?   ?.<br>
 * <br>
 * -- Multiplexing ??  <br>
 * ---- ??? ?  ??? ? ? ? <br>
 * ---- ? ??? ? <br>
 * ---- ? ? ???   <br>
 * <br>
 *  Multiplexing ? ?.<br>
 * ? Multiplexing ?  ( ?, ? ???  )? <br>
 * Multiplexing ?  ??? Multi-Thread    ?.<br>
 * {@link IServer}   {@link MultiplexedProtocolAdapter}  Handler  ?.<br>
 * ? XNApi? Connection  {@link MultiplexedConnection} <br>
 * {@link NonBlockingConnection} ? {@link BlockingConnection}? ??? .<br>
 * Multi-Thread ?  Pool  .<br>
 * {@link NonBlockingConnectionPool} ? {@link BlockingConnectionPool} ? ? ?.<br>
 * 
 * @author Takkies
 * 
 */
public class XNDiscServer {

    /* XNDisc Server   */
    private static String XNDISC_SERVER_VERSION;

    /*  ? Clear Command */
    private static final String CLEAR_TERMINAL_ANSI_CMD = new String(new byte[] { 27, 91, 50, 74, 27, 91, 72 });

    /* XNDisc Server  ?(Windows : LISTENING, UNIX : LISTEN) */
    private static final String XNDISC_LISTEN_STATUS = "LISTEN";

    /* xsocket debugging   */
    Logger xsocket_log = Logger.getLogger("org.xsocket.connection");

    /*  ? */
    private IServer server;

    /* Log ? */
    private LoggerIF logger = null;

    /* Storage ? */
    private StorageIF storage = null;

    // XNDisc Server ?  : ?  ? 

    /*  Worker Pool (Server ?  ) */
    private String SIZE_WORKER_POOL = XNDiscConfig.getString(XNDiscConfig.SIZE_WORKER_POOL, "100");

    /*  Worker Pool (Server ? ) */
    private String MIN_SIZE_WORKER_POOL = XNDiscConfig.getString(XNDiscConfig.MIN_SIZE_WORKER_POOL, "4");

    /* Worker Thread Pool (Executors ) */
    private Integer WORKER_THREAD_POOL = XNDiscConfig.getInt(XNDiscConfig.WORKER_POOL_THREAD_COUNT, 15);

    /* Worker Pool (? Fixed) */
    private String WORKER_POOL_TYPE = XNDiscConfig.getString(XNDiscConfig.WORKER_POOL_TYPE, "F");

    /*  ?  */
    private String DISPATCHER_INIT_COUNT = XNDiscConfig.getString(XNDiscConfig.DISPATCHER_INIT_COUNT, "3");

    /* ??    */
    private String DISPATCHER_MAX_HANDLES = XNDiscConfig.getString(XNDiscConfig.DISPATCHER_MAX_HANDLES, "20");

    /* ? ? (client, server ?  true) */
    private String READ_BUFFER_USEDIRECT = XNDiscConfig.getString(XNDiscConfig.READ_BUFFER_USEDIRECT, "true");

    /* ?? ?  ? detach */
    private String DETACH_HANDLE_NO_OPERATION = XNDiscConfig.getString(XNDiscConfig.DETACH_HANDLE_NO_OPERATION,
            "false");

    /* XNDisc Server IP  */
    private String HOST = XNDiscConfig.getString(XNDiscConfig.HOST, XNDiscConfig.LOCAL_HOST);

    /* XNDisc Server Port  */
    private int PORT = XNDiscConfig.getInt(XNDiscConfig.PORT, XNDiscConfig.LOCAL_PORT);

    /* DB   ?  */
    private String MTS_STORAGE = XNDiscConfig.getString(XNDiscConfig.STORAGE);

    /* Log   ?  */
    private String MTS_LOGGER = XNDiscConfig.getString(XNDiscConfig.LOGGER);

    /* ??  ?  */
    private String FILTER_ENC = XNDiscConfig.getString(XNDiscConfig.ENCRYPT);

    /*   ?  */
    private String FILTER_COMP = XNDiscConfig.getString(XNDiscConfig.COMPRESS);

    /* XNDisc Server SSL   */
    private boolean USE_SSL = XNDiscConfig.getBoolean(XNDiscConfig.USE_SSL);

    private boolean XSOCKET_DEBUG = XNDiscConfig.getBoolean(XNDiscConfig.XSOCKET_DEBUG);

    /* OS  ?? */
    private String LINE_SEPERATOR = System.getProperty("line.separator");

    static {
        XNDISC_SERVER_VERSION = "XNDisc " + XNDiscUtils.getXNDiscVersion() + "("
                + XNDiscUtils.getXNDiscPublshingDate() + ")";
    }

    /**
     *    
     * 
     * @throws Exception
     *              ?
     */
    private void init() throws Exception {

        /* xsocket  - FINE ???     ?  ? ?  ? */
        if (XSOCKET_DEBUG) {
            xsocket_log.setLevel(Level.ALL);
        } else {
            xsocket_log.setLevel(Level.INFO);
        }
        ConsoleHandler console = new ConsoleHandler();
        if (XSOCKET_DEBUG) {
            console.setLevel(Level.ALL);
        } else {
            console.setLevel(Level.INFO);
        }
        xsocket_log.addHandler(console);
        /* xsocket  - FINE ???     ?  ? ?  ? */

        initLogger();

        initFilter();

        initStorage();

        InetAddress ia = InetAddress.getByName(HOST);
        if (ia == null) {
            ia = InetAddress.getLocalHost();
        }

        /*  ?   ( ) - Receive Buffer Size  ? */
        Map<String, Object> options = new HashMap<String, Object>();

        // - 2014.04.29 - ?   - START - Multiplexing?   .
        // options.put(IConnection.SO_REUSEADDR, true);
        // options.put(IConnection.SO_LINGER, "5"); // ?  ??     (? ? ?  )
        // options.put(IConnection.SO_KEEPALIVE, true);
        // options.put(IConnection.TCP_NODELAY, true);
        // options.put(IConnection.SO_RCVBUF, XNDiscConfig.INIT_BUFFER_SIZE);
        // options.put(IConnection.SO_SNDBUF, XNDiscConfig.INIT_BUFFER_SIZE);
        // - 2014.04.29 - ?   - END - Multiplexing?   .

        /* SERVER? ?  ?  */

        /*  workerpool (?? ?  ? )?    ?. */
        /* ? ? workerpool? ? ?    workerpool ? ?. ? 100. */
        System.setProperty(XNDiscUtils.XSOCKET_WORKER_POOL_MIN_SIZE, SIZE_WORKER_POOL);
        /*  workerpool?    ?. ? 4 */
        System.setProperty(XNDiscUtils.XSOCKET_WORKER_POOL_MIN_SIZE, MIN_SIZE_WORKER_POOL);
        /* ? ? (NIO Selectors)? . ? 2 ?  ?. */
        System.setProperty(XNDiscUtils.XSOKET_DISPATCHER_INIT_COUNT, DISPATCHER_INIT_COUNT);
        /*  ?? ? ??   */
        /*  , ??  ?? ?. ? ??  . */
        System.setProperty(XNDiscUtils.XSOCKET_DISPATCHER_MAX_HANDLE, DISPATCHER_MAX_HANDLES);
        /* ?  ? ?    ?? ?? ? . ? false. */
        System.setProperty(XNDiscUtils.XSOCKET_SERVER_READ_BUFFER_USEDIRECT, READ_BUFFER_USEDIRECT);

        // - 2014.04.25 - ByteBuffer Direct   - START
        System.setProperty(XNDiscUtils.XSOCKET_CLIENT_READ_BUFFER_USEDIRECT, READ_BUFFER_USEDIRECT);
        System.setProperty(XNDiscUtils.XSOCKET_WRITE_BUFFER_USEDIRECT, READ_BUFFER_USEDIRECT);
        // - 2014.04.25 - ByteBuffer Direct   - END

        // - 2014.04.29 -    - START
        System.setProperty(XNDiscUtils.XSOCKET_SUPPRESS_SYNC_FLUSH_WARNING, "true");
        System.setProperty(XNDiscUtils.XSOCKET_SUPPRESS_REUSE_BUFFER_WARNING, "true"); // or FlushMode.SYNC (GET ? )
        System.setProperty(XNDiscUtils.XSOCKET_SUPPRESS_SYNC_FLUSH_COMPLETION_HANDLER_WARNING, "true");
        System.setProperty(XNDiscUtils.XSOCKET_DISPATCHER_BYPASSING_WRITE_ALLOWED, "true");
        // - 2014.04.29 -    - END

        /* (NIO SelectionKey)?  ? true ? ?? detach?. ?? ???  .  false. */
        System.setProperty(XNDiscUtils.XSOCKET_DISPATCHER_DETACH_HANDLE_ON_NO_OPS, DETACH_HANDLE_NO_OPERATION);
        /* ? ??  ? ??   ? ?   (1024 * 16) */
        Integer mapped_bytebuffer_maxsize = 1024
                * XNDiscConfig.getInt(XNDiscConfig.TRANSFER_MAPPED_BYTE_BUFFER_MAXSIZE, 16);
        System.setProperty(XNDiscUtils.XSOCKET_TRANFER_MAPPED_BYTEBUFFER_MAX_SIZE,
                mapped_bytebuffer_maxsize.toString());

        /* ? Sever  - SSL ?   ?    Connection? ?  ?! */
        if (USE_SSL) {
            this.server = new Server(ia, PORT, options,
                    new MultiplexedProtocolAdapter(new XNDiscHandler(storage, logger)),
                    XNDiscSSLContextFactory.getSSLContext(), true);
            // this.server = new Server(ia, PORT, options, new XNDiscHandler(storage, logger), XNDiscSSLContextFactory.getSSLContext(), true);
        } else {
            this.server = new Server(ia, PORT, options,
                    new MultiplexedProtocolAdapter(new XNDiscHandler(storage, logger)), null, false);
            // this.server = new Server(ia, PORT, options, new XNDiscHandler(storage, logger), null, false);
        }

        /*  ThreadPool? ? , Cached ?   ? ??? ?  ? ?  ?. */
        /* SERVER? ?  ? (? Fixed) */
        /*   ?  :  ? ?  ?? Runtime.availableProcessors() ? ? ?? ???   */
        /* newFixedThreadPool ?  ?  ? corePoolSize, maximumPoolSize  .  ?  */
        /* newCachedThreadPool ?  corePoolSize = 0, maximumPoolSize  Integer.MAX_VALUE  .  ? 1 */

        if (WORKER_POOL_TYPE.equals("C")) {
            this.server.setWorkerpool(Executors.newCachedThreadPool(new XNDiscThreadFactory(true)));
        } else {
            if (XNDiscConfig.getBoolean(XNDiscConfig.MULTIPLICATION_THREAD_AVAILABLE_PROCESSORS)) {
                WORKER_THREAD_POOL = Runtime.getRuntime().availableProcessors() * WORKER_THREAD_POOL;
            }
            this.server
                    .setWorkerpool(Executors.newFixedThreadPool(WORKER_THREAD_POOL, new XNDiscThreadFactory(true)));
        }
        this.server.setFlushmode(FlushMode.ASYNC);
    }

    /**
     * FixedThreadPool ?  Console?   Notice 
     */
    private void getXNDiscNotice() {
        if (WORKER_POOL_TYPE.equals("F")
                && XNDiscConfig.getBoolean(XNDiscConfig.MULTIPLICATION_THREAD_AVAILABLE_PROCESSORS)) {
            int worker_thread_pool = XNDiscConfig.getInt(XNDiscConfig.WORKER_POOL_THREAD_COUNT, 15);
            StringBuilder msg = new StringBuilder(LINE_SEPERATOR);
            msg.append("").append(StringUtils.center(" XNDisc Server Notice !!! ", 90, "-")).append("?")
                    .append(LINE_SEPERATOR);
            msg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
            msg.append("")
                    .append(StringUtils.rightPad("Readjust the number of the Worker Thread Pool,", 90, " "))
                    .append("").append(LINE_SEPERATOR);
            msg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
            msg.append("")
                    .append(StringUtils.rightPad("Original Thread Pool Size : " + worker_thread_pool
                            + " => Changed Thread Pool Size : " + WORKER_THREAD_POOL, 90, " "))
                    .append("").append(LINE_SEPERATOR);
            msg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
            msg.append("").append(StringUtils.rightPad("", 90, "-")).append("").append(LINE_SEPERATOR);
            logger.log(LoggerIF.LOG_INFO, msg.toString());
        }
    }

    /**
     * XNDisc  ?
     * 
     * @throws Exception
     *              ? ?
     */
    public void start() throws Exception {

        init();

        this.server.setStartUpLogMessage(getXNDiscServerStartMessage());

        try {
            logger.log(LoggerIF.LOG_INFO, this.server.getStartUpLogMessage());

            getXNDiscNotice();

            this.server.run(); // shutdown hook....

            this.server.start();

        } catch (Exception e) {
            throw new RuntimeException("*** XNDisc Server Start fail..." + XNDiscUtils.printStackTrace(e));
        }

    }

    /**
     * XNDisc  .
     * @throws Exception
     */
    public void stop() throws Exception {
        try {
            this.server.close();
        } catch (Exception e) {
            throw new RuntimeException("*** XNDisc Server Stop fail..." + XNDiscUtils.printStackTrace(e));
        }
    }

    /**
     *  
     * 
     * @throws Exception
     *               ?
     */
    private void initLogger() throws Exception {
        try {
            if (null == logger) {
                logger = (LoggerIF) DynamicClassLoader.createInstance(MTS_LOGGER);
            }
            logger.initLogger();
        } catch (Exception e) {
            e.printStackTrace();
            logger.log(LoggerIF.LOG_SEVERE,
                    "*** Fail - XNDisc Server initLogger() " + XNDiscUtils.printStackTrace(e));
            throw e;
        }
    }

    /**
     *  
     * 
     * @throws Exception
     *               ?
     */
    private void initFilter() throws Exception {
        try {
            FilterIF filterEnc = (FilterIF) DynamicClassLoader.createInstance(FILTER_ENC);
            FilterIF filterComp = (FilterIF) DynamicClassLoader.createInstance(FILTER_COMP);
            XNDiscConfig.setFilterEncrypt(filterEnc);
            XNDiscConfig.setFilterCompress(filterComp);
        } catch (Exception e) {
            e.printStackTrace();
            logger.log(LoggerIF.LOG_SEVERE,
                    "*** Fail - XNDisc Server initFilter() " + XNDiscUtils.printStackTrace(e));
            throw e;
        }
    }

    /**
     * (DB ) 
     * 
     * @throws Exception
     *               ?
     */
    private void initStorage() throws Exception {
        try {
            storage = (StorageIF) DynamicClassLoader.createInstance(MTS_STORAGE, logger);
        } catch (Exception e) {
            e.printStackTrace();
            logger.log(LoggerIF.LOG_SEVERE,
                    "*** Fail - XNDisc Server initStorage() " + XNDiscUtils.printStackTrace(e));
            throw e;
        }
    }

    /**
     * XNDisc Server ?  
     * 
     * @return ? 
     */
    private String getXNDiscServerStartMessage() {
        StringBuilder smsg = new StringBuilder(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.rightPad("", 90, "-")).append("?").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.center("XNDisc Server (Version : " + XNDISC_SERVER_VERSION + ")", 90, " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.center("Listening on " + this.server.getLocalAddress().getHostName() + "("
                        + this.server.getLocalAddress().getHostAddress() + "):" + this.server.getLocalPort(), 90,
                        " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.center("Start on " + XNDiscUtils.getStartDate(), 90, " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.center(" XNDisc Server Options ", 90, "-")).append("")
                .append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.rightPad("       Use SSL : " + Boolean.toString(USE_SSL), 90, " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.rightPad("       Dispatcher Initial Size : " + DISPATCHER_INIT_COUNT, 90, " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("").append(
                StringUtils.rightPad("       Dispatcher maximum Handle Size : " + DISPATCHER_MAX_HANDLES, 90, " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.rightPad("       Read Buffer Use Direct : " + READ_BUFFER_USEDIRECT, 90, " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.rightPad("       Worker Pool Thread Priority : "
                        + XNDiscConfig.getString(XNDiscConfig.WORKER_POOL_PRIORITY, "NORM"), 90, " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.rightPad("       Worker Pool minimun Size : " + MIN_SIZE_WORKER_POOL, 90, " "))
                .append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.rightPad("       Worker Pool maximum Size : " + SIZE_WORKER_POOL, 90, " "))
                .append("").append(LINE_SEPERATOR);
        if (WORKER_POOL_TYPE.equals("F")) {
            smsg.append("").append(StringUtils.rightPad("       Thread Pool Type : Fixed", 90, " "))
                    .append("").append(LINE_SEPERATOR);
            smsg.append("")
                    .append(StringUtils.rightPad("       Thread Pool Size : " + WORKER_THREAD_POOL, 90, " "))
                    .append("").append(LINE_SEPERATOR);
        } else if (WORKER_POOL_TYPE.equals("C")) {
            smsg.append("").append(StringUtils.rightPad("       Thread Pool Type : Cached", 90, " "))
                    .append("").append(LINE_SEPERATOR);
        }
        smsg.append("").append(StringUtils.center("", 90, " ")).append("").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.rightPad("", 90, "-")).append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.rightPad("       OS Architecture   : " + System.getProperty("os.arch"), 90, ""))
                .append("").append(LINE_SEPERATOR);
        smsg.append("")
                .append(StringUtils.rightPad("       OS Name           : " + System.getProperty("os.name"), 90, ""))
                .append("").append(LINE_SEPERATOR);
        smsg.append("").append(
                StringUtils.rightPad("       OS Version        : " + System.getProperty("os.version"), 90, ""))
                .append("").append(LINE_SEPERATOR);
        Runtime runtime = Runtime.getRuntime();
        smsg.append("").append(
                StringUtils.rightPad("       Processors        : " + runtime.availableProcessors() + "(s)", 90, ""))
                .append("").append(LINE_SEPERATOR);
        smsg.append("").append(StringUtils.rightPad("", 90, "-")).append("").append(LINE_SEPERATOR);
        return smsg.toString();
    }

    /**
     * Console clear 
     */
    private static void clearConsoleOutput() {
        try {
            String os = System.getProperty("os.name").toLowerCase();
            String ostype = (os.contains("windows")) ? "W" : "U";
            if (ostype.equals("W")) {
                CommandLine cmdLine = CommandLine.parse("cls");
                DefaultExecutor executor = new DefaultExecutor();
                executor.execute(cmdLine);
                System.out.printf("%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n", new Object[0]);
            } else {
                CommandLine cmdLine = CommandLine.parse("clear");
                DefaultExecutor executor = new DefaultExecutor();
                executor.execute(cmdLine);
                System.out.print(CLEAR_TERMINAL_ANSI_CMD);
                System.out.flush();
            }
        } catch (IOException e) {
        }
    }

    /**
     * XNDisc Server  ? ?  ?
     * 
     * @return ?? true,  false
     */
    private static boolean isXNDiscServerAlive() {
        boolean isAlive = false;

        String HOST = XNDiscConfig.getString(XNDiscConfig.HOST, XNDiscConfig.LOCAL_HOST);
        String PORT = XNDiscConfig.getString(XNDiscConfig.PORT);

        Scanner scanner = null;
        ByteArrayOutputStream baos = null;
        try {
            String os = System.getProperty("os.name").toLowerCase();
            String ostype = (os.contains("windows")) ? "W" : "U";
            CommandLine cmdline = new CommandLine("netstat");
            cmdline.addArgument("-an");
            if (ostype.equals("W")) {
                cmdline.addArgument("-p");
                cmdline.addArgument("\"TCP\"");
            } else { // UNIX ? ? -an ? ?  ?  
                if (XNDiscUtils.isSolaris()) {
                    cmdline.addArgument("-P");
                    cmdline.addArgument("tcp");
                } else if (XNDiscUtils.isAix()) {
                    cmdline.addArgument("-p");
                    cmdline.addArgument("TCP");
                }
            }
            DefaultExecutor executor = new DefaultExecutor();
            executor.setExitValue(0);
            baos = new ByteArrayOutputStream();
            PumpStreamHandler sh = new PumpStreamHandler(baos);
            executor.setStreamHandler(sh);
            executor.execute(cmdline);
            String str = baos.toString();
            if (str != null && str.length() > 0) { // ?  XNDisc alive ?(XNDisc Server ? ?)
                scanner = new Scanner(str);
                while (scanner.hasNextLine()) {
                    String readline = scanner.nextLine();
                    if (readline.contains(HOST) && readline.contains(PORT)
                            && readline.contains(XNDISC_LISTEN_STATUS)) {
                        isAlive = true;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            isAlive = false;
        } finally {
            try {
                if (scanner != null) {
                    scanner.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return isAlive;
    }

    public static void main(String[] args) throws Exception {

        if (XNDiscServer.isXNDiscServerAlive()) {
            XNDiscServer.clearConsoleOutput();
            System.out.println(
                    "*** XNDisc Server is already started, this XNDisc Server stop and restart or just use the current XNDisc Server !!!");
            System.exit(-1);
        }

        XNDiscServer.clearConsoleOutput();
        final XNDiscServer xnds = new XNDiscServer();
        try {
            xnds.start();
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

                @Override
                public void run() {
                    try {
                        System.out.println("*** XNDisc Server Stopping.");
                        xnds.stop();
                    } catch (Exception ignored) {
                    }
                }
            }));
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }

}