/******************************************************************************* * Copyright 2013-2015 alladin-IT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package at.alladin.rmbt.qos.testserver; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import at.alladin.rmbt.qos.testserver.plugin.rest.RestService; /** * * @author lb * */ public class ServerPreferences { public static enum TestServerServiceEnum { TEST_SERVER("TEST SERVER"), TCP_SERVICE("TCP MONITOR"), UDP_SERVICE("UDP MONITOR"), RUNTIME_GUARD_SERVICE("RUNTIME GUARD SERVICE"); protected String name; private TestServerServiceEnum(String name) { this.name = name; } public String getName() { return name; } } public class UdpPort { final boolean isNio; final int port; public UdpPort(final boolean isNio, final int port) { this.isNio = isNio; this.port = port; } @Override public String toString() { return "UdpPort [isNio=" + isNio + ", port=" + port + "]"; } } public final static int TEST_SERVER_ID = 0; public final static int TCP_SERVICE_ID = 1; public final static int UDP_SERVICE_ID = 2; public static final String ARG_SERVER_PORT = "-P"; public static final String ARG_UDP_PORT_RANGE = "-U"; public static final String ARG_MAX_THREADS = "-T"; public static final String ARG_HELP = "-H"; public static final String ARG_IP_CHECK = "-IC"; public static final String ARG_IP = "-IP"; public static final String ARG_CONFIG_FILE = "-F"; public static final String ARG_SECRET_KEY = "-K"; public static final String ARG_USE_SSL = "-S"; public static final String ARG_VERBOSE = "-V"; public static final String ARG_VERBOSE2 = "-VV"; public static final String ARG_LOG = "-L"; public static final String PARAM_SERVER_PORT = "server.port"; public static final String PARAM_SERVER_THREADS = "server.threads"; public static final String PARAM_SERVER_SECRET_KEY = "server.secret"; public static final String PARAM_SERVER_USE_SSL = "server.ssl"; public static final String PARAM_SERVER_VERBOSE = "server.verbose"; public static final String PARAM_SERVER_UDP_MIN_PORT = "server.udp.minport"; public static final String PARAM_SERVER_UDP_MAX_PORT = "server.udp.maxport"; public static final String PARAM_SERVER_UDP_PORT_LIST = "server.udp.ports"; public static final String PARAM_SERVER_UDP_NIO_PORT_LIST = "server.udp.nio.ports"; public static final String PARAM_SERVER_LOGGING = "server.logging"; public static final String PARAM_SERVER_LOGGING_PATTERN = "server.log.pattern"; public static final String PARAM_SERVER_SYSLOG = "server.syslog"; public static final String PARAM_SERVER_SYSLOG_HOST = "server.syslog.host"; public static final String PARAM_SERVER_SYSLOG_PATTERN = "server.syslog.pattern"; public static final String PARAM_SERVER_LOG_CONSOLE = "server.log.console"; public static final String PARAM_SERVER_COMMAND_CONSOLE = "server.console"; public static final String PARAM_SERVER_LOG_FILE = "server.log"; public static final String PARAM_SERVER_UDP_SERVICE_LOG_FILE = "server.log.udp"; public static final String PARAM_SERVER_TCP_SERVICE_LOG_FILE = "server.log.tcp"; public static final String PARAM_SERVER_TCP_IP_CHECK = "server.ip.check"; public static final String PARAM_SERVER_IP = "server.ip"; public static final String REGEX_PORT_LIST = "([0-9]+)[,]?"; public static final String REGEX_IP_LIST = "([a-fA-F0-9.:]+)[,]?"; private int serverPort = 5234; private int udpPortMin = 0; private int udpPortMax = 0; private final Set<UdpPort> udpPortSet = new TreeSet<>(new Comparator<UdpPort>() { @Override public int compare(UdpPort o1, UdpPort o2) { return Integer.compare(o1.port, o2.port); } }); private int maxThreads = 100; private boolean useSsl = false; private int verboseLevel = 0; private String secretKey = null; private boolean isIpCheck = false; private boolean isLoggingEnabled = true; private String loggingPattern = "%p %d{ISO8601} - %m%n"; private boolean isSyslogEnabled = true; private String syslogHost = "localhost"; private String syslogPattern = "%p %d{ISO8601} %c - %m%n"; private boolean isConsoleLog = false; private boolean isCommandConsoleEnabled = false; private final TreeMap<TestServerServiceEnum, String> logFileMap = new TreeMap<>(); private final Set<InetAddress> inetAddrBindToSet = new HashSet<>(); private final long startTimestamp = System.currentTimeMillis(); /////////////////////////// // Plugins/Services: /////////////////////////// public final static String PLUGIN_REST_SERVICE = "REST"; private final Map<String, ServiceSetting> pluginMap = new HashMap<>(); /** * * @throws TestServerException * @throws UnknownHostException */ public ServerPreferences() throws TestServerException { loadFromConfigFile("config.properties"); setUdpPortSet(); checkConstraints(); } /** * * @param args * @throws TestServerException * @throws UnknownHostException */ public ServerPreferences(String[] args) throws TestServerException { loadFromConfigFile("config.properties"); try { for (int i = 0; i < args.length; i++) { String arg = args[i].toUpperCase(); if (arg.equals(ARG_SERVER_PORT)) { serverPort = Integer.parseInt(args[++i]); } else if (arg.equals(ARG_IP)) { inetAddrBindToSet.add(InetAddress.getByName(args[++i])); } else if (arg.equals(ARG_IP_CHECK)) { isIpCheck = true; } else if (arg.equals(ARG_UDP_PORT_RANGE)) { udpPortMin = Integer.parseInt(args[++i]); udpPortMax = Integer.parseInt(args[++i]); } else if (arg.equals(ARG_MAX_THREADS)) { maxThreads = Integer.parseInt(args[++i]); if (maxThreads <= 10) { writeWarningNumThreadsTooLowString(maxThreads); } } else if (arg.equals(ARG_CONFIG_FILE)) { loadFromConfigFile(args[++i]); } else if (arg.equals(ARG_SECRET_KEY)) { secretKey = args[++i]; } else if (arg.equals(ARG_USE_SSL)) { useSsl = true; } else if (arg.equals(ARG_VERBOSE)) { verboseLevel = 1; } else if (arg.equals(ARG_VERBOSE2)) { verboseLevel = 2; } else if (arg.equals(ARG_HELP)) { writeErrorString(); } else if (arg.equals(ARG_LOG)) { logFileMap.put(TestServerServiceEnum.TEST_SERVER, args[++i]); } else { throw new TestServerException("UNKNOWN PARAMETER: " + arg, null); } } setUdpPortSet(); } catch (Exception e) { throw new TestServerException("TEST SERVER EXCEPTION", e); } checkConstraints(); } /** * */ private void setUdpPortSet() { if (udpPortMin > 0) { for (int port = udpPortMin; port <= udpPortMax; port++) { udpPortSet.add(new UdpPort(false, port)); } } } /** * * @param fileName * @throws TestServerException */ private void loadFromConfigFile(String fileName) throws TestServerException { Properties prop = new Properties(); try { prop.load(new FileInputStream(fileName)); String param = prop.getProperty(PARAM_SERVER_PORT); if (param!=null) { serverPort = Integer.parseInt(param.trim()); } param = prop.getProperty(PARAM_SERVER_IP); if (param!=null) { Pattern p = Pattern.compile(REGEX_IP_LIST); Matcher m = p.matcher(param); while (m.find()) { inetAddrBindToSet.add(InetAddress.getByName(m.group(1))); } } param = prop.getProperty(PARAM_SERVER_TCP_IP_CHECK); if (param!=null) { isIpCheck = Boolean.parseBoolean(param.trim()); } param = prop.getProperty(PARAM_SERVER_THREADS); if (param!=null) { maxThreads = Integer.parseInt(param.trim()); } param = prop.getProperty(PARAM_SERVER_UDP_MIN_PORT); if (param!=null) { udpPortMin = Integer.parseInt(param.trim()); } param = prop.getProperty(PARAM_SERVER_UDP_MAX_PORT); if (param!=null) { udpPortMax = Integer.parseInt(param.trim()); } param = prop.getProperty(PARAM_SERVER_USE_SSL); if (param!=null) { useSsl = Boolean.parseBoolean(param.trim()); } param = prop.getProperty(PARAM_SERVER_VERBOSE); if (param!=null) { verboseLevel = Integer.parseInt(param.trim()); } param = prop.getProperty(PARAM_SERVER_SECRET_KEY); if (param!=null) { secretKey = param.trim(); } param = prop.getProperty(PARAM_SERVER_COMMAND_CONSOLE); if (param!=null) { isCommandConsoleEnabled = Boolean.parseBoolean(param.trim()); } param = prop.getProperty(PARAM_SERVER_SYSLOG); if (param!=null) { isSyslogEnabled = Boolean.parseBoolean(param.trim()); } param = prop.getProperty(PARAM_SERVER_SYSLOG_HOST); if (param!=null) { syslogHost = param.trim(); } param = prop.getProperty(PARAM_SERVER_SYSLOG_PATTERN); if (param!=null) { syslogPattern = param.trim(); } param = prop.getProperty(PARAM_SERVER_LOGGING); if (param!=null) { isLoggingEnabled = Boolean.parseBoolean(param.trim()); } param = prop.getProperty(PARAM_SERVER_LOGGING_PATTERN); if (param!=null) { loggingPattern = param.trim(); } param = prop.getProperty(PARAM_SERVER_LOG_CONSOLE); if (param!=null) { isConsoleLog = Boolean.parseBoolean(param.trim()); } param = prop.getProperty(PARAM_SERVER_LOG_FILE); if (param!=null) { logFileMap.put(TestServerServiceEnum.TEST_SERVER, param.trim()); } param = prop.getProperty(PARAM_SERVER_UDP_SERVICE_LOG_FILE); if (param!=null) { logFileMap.put(TestServerServiceEnum.UDP_SERVICE, param.trim()); } param = prop.getProperty(PARAM_SERVER_TCP_SERVICE_LOG_FILE); if (param!=null) { logFileMap.put(TestServerServiceEnum.TCP_SERVICE, param.trim()); } param = prop.getProperty(PARAM_SERVER_UDP_PORT_LIST); if (param!=null) { Pattern p = Pattern.compile(REGEX_PORT_LIST); Matcher m = p.matcher(param); while (m.find()) { udpPortSet.add(new UdpPort(false, Integer.valueOf(m.group(1)))); } } param = prop.getProperty(PARAM_SERVER_UDP_NIO_PORT_LIST); if (param!=null) { Pattern p = Pattern.compile(REGEX_PORT_LIST); Matcher m = p.matcher(param); while (m.find()) { final UdpPort udpPort = new UdpPort(true, Integer.valueOf(m.group(1))); if (udpPortSet.contains(udpPort)) { throw new TestServerException("Cannot create non blocking datagram channel. UDP port: " + udpPort.port + " already defined as blocking.", null); } else { udpPortSet.add(udpPort); } } } ///////////////////////////////// // Services/Plugins: ///////////////////////////////// pluginMap.put("REST", new RestService(prop, this)); } catch (IOException ex) { ex.printStackTrace(); throw new TestServerException("TEST SERVER EXCEPTION", ex); } } /** * * @throws TestServerException * @throws UnknownHostException */ private void checkConstraints() throws TestServerException { if (udpPortMin > udpPortMax) { throw new TestServerException("UDP MIN PORT (=" + udpPortMin + ") MUST BE LOWER THAN UDP MAX PORT (=" + udpPortMax + ")", null); } if (maxThreads < 5) { throw new TestServerException("NUMBER OF THREADS TOO LOW (" + maxThreads + ")", null); } //create log paths: for (String fileName : logFileMap.values()) { File f = new File(fileName); File dir = new File(f.getParent()); if (!dir.exists()) { dir.mkdir(); } } if (inetAddrBindToSet.isEmpty()) { try { inetAddrBindToSet.add(InetAddress.getByName("0.0.0.0")); } catch (Exception e) { throw new TestServerException(e.getLocalizedMessage(), e); } } } /** * * @return */ public int getServerPort() { return serverPort; } /** * * @param serverPort */ public void setServerPort(int serverPort) { this.serverPort = serverPort; } /** * * @return */ public int getUdpPortMin() { return udpPortMin; } /** * * @param udpPortMin */ public void setUdpPortMin(int udpPortMin) { this.udpPortMin = udpPortMin; } /** * * @return */ public int getMaxThreads() { return maxThreads; } /** * * @param maxThreads */ public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } /** * * @return */ public int getUdpPortMax() { return udpPortMax; } /** * * @param udpPortMax */ public void setUdpPortMax(int udpPortMax) { this.udpPortMax = udpPortMax; } /** * * @return */ public String getSecretKey() { return secretKey; } /** * * @param secretKey */ public void setSecretKey(String secretKey) { this.secretKey = secretKey; } /** * * @return */ public boolean useSsl() { return useSsl; } /** * * @param useSsl */ public void setUseSsl(boolean useSsl) { this.useSsl = useSsl; } /** * * @return */ public int getVerboseLevel() { return verboseLevel; } /** * * @param verboseLevel */ public void setVerboseLevel(int verboseLevel) { this.verboseLevel = verboseLevel; } /** * * @return */ public boolean isLoggingEnabled() { return isLoggingEnabled; } /** * * @param isLoggingEnabled */ public void setLoggingEnabled(boolean isLoggingEnabled) { this.isLoggingEnabled = isLoggingEnabled; } /** * * @return */ public Map<String, ServiceSetting> getPluginMap() { return pluginMap; } /** * */ public static void writeErrorString() { System.out.println("---------------------------------------------"); System.out.println("Error initializing QoS TestServer\n"); System.out.println("Supported parameters:"); System.out.println("-h => shows this help."); System.out.println("-s => ssl connection."); System.out.println("-ip => the ip, the test server will be bound to."); System.out.println("-ic => register all TCP test candidates and make an ip check before responding."); System.out.println("-v => verbose level 1, more debug output."); System.out.println("-vv => verbose level 2, even more debug output."); System.out.println("-f [file_name] => initilizes the server by using a config file (default: config.properties)."); System.out.println("-p [port_number] => initilizes the server on this port number (default: 5233)."); System.out.println("-u [min_port_number] [max_port_number] => supported udp port range by this server: from min_port_number (inclusive) to max_port_number (exclusive)."); System.out.println("-t [max_threads] => The max number of threads (clients) this server can hanle at the same time (default: 100)."); System.out.println("-k [secret_key] => The secret key used for client-server communication."); System.out.println("\nExample: -p 5233 -u 10000 20000 => makes the server listen on port 5233 for incoming test requests and let it accept udp test connections on ports 10000 to 20000."); System.out.println("\nIf no parameter is set then the default config file config.properties is beeing used. If this file isn't found, the default values are beeing used."); System.out.println("---------------------------------------------"); } /** * * @param threads */ public void writeWarningNumThreadsTooLowString(int threads) { System.out.println("---------------------------------------------"); System.out.println("Warning: number of threads is low (" + threads + ")\nThe TestServer can handle only this amount of clients at the same time. Waiting times may occure."); System.out.println("---------------------------------------------\n"); } /** * * @return */ public Set<UdpPort> getUdpPortSet() { return udpPortSet; } /** * * @return */ public TreeMap<TestServerServiceEnum, String> getLogFileMap() { return logFileMap; } /** * * @return */ public Set<InetAddress> getInetAddrBindToSet() { return inetAddrBindToSet; } /** * * @return */ public boolean isIpCheck() { return isIpCheck; } /** * * @param isIpCheck */ public void setIpCheck(boolean isIpCheck) { this.isIpCheck = isIpCheck; } public boolean isConsoleLog() { return isConsoleLog; } public void setConsoleLog(boolean isConsoleLog) { this.isConsoleLog = isConsoleLog; } public boolean isCommandConsoleEnabled() { return isCommandConsoleEnabled; } public void setCommandConsoleEnabled(boolean isCommandConsoleEnabled) { this.isCommandConsoleEnabled = isCommandConsoleEnabled; } public long getStartTimestamp() { return startTimestamp; } public boolean isSyslogEnabled() { return isSyslogEnabled; } public void setSyslogEnabled(boolean isSyslogEnabled) { this.isSyslogEnabled = isSyslogEnabled; } public String getSyslogHost() { return syslogHost; } public void setSyslogHost(String syslogHost) { this.syslogHost = syslogHost; } public String getSyslogPattern() { return syslogPattern; } public void setSyslogPattern(String syslogPattern) { this.syslogPattern = syslogPattern; } public String getLoggingPattern() { return loggingPattern; } public void setLoggingPattern(String loggingPattern) { this.loggingPattern = loggingPattern; } @Override public String toString() { return "ServerPreferences [serverPort=" + serverPort + ", udpPortMin=" + udpPortMin + ", udpPortMax=" + udpPortMax + ", udpPortSet=" + udpPortSet + ", maxThreads=" + maxThreads + ", useSsl=" + useSsl + ", verboseLevel=" + verboseLevel + ", secretKey=" + secretKey + ", isIpCheck=" + isIpCheck + ", isLoggingEnabled=" + isLoggingEnabled + ", loggingPattern=" + loggingPattern + ", isSyslogEnabled=" + isSyslogEnabled + ", syslogHost=" + syslogHost + ", syslogPattern=" + syslogPattern + ", isConsoleLog=" + isConsoleLog + ", isCommandConsoleEnabled=" + isCommandConsoleEnabled + ", logFileMap=" + logFileMap + ", inetAddrBindToSet=" + inetAddrBindToSet + ", startTimestamp=" + startTimestamp + ", pluginMap=" + pluginMap + "]" + "\n\tOnline since: " + (new java.util.Date(startTimestamp)).toString(); } ///////////////////////////////////////////////////////// // // Server Services // ///////////////////////////////////////////////////////// public static abstract class ServiceSetting { protected boolean isEnabled; protected final String name; public ServiceSetting(String name, boolean isEnabled) { this.isEnabled = isEnabled; this.name = name; } public boolean isEnabled() { return isEnabled; } public void setEnabled(boolean isEnabled) { this.isEnabled = isEnabled; } public String getName() { return name; } public abstract void start() throws UnknownHostException; public abstract void stop(); public abstract void setParam(Properties properties); } }