Java tutorial
/* * <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); } } }