Java tutorial
/** * Copyright 2015 Otto (GmbH & Co KG) * * 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 com.ottogroup.bi.spqr.websocket.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import com.fasterxml.jackson.databind.ObjectMapper; import com.ottogroup.bi.spqr.websocket.server.cfg.SPQRWebSocketServerConfiguration; /** * Ramps up the web socket server which provides access to pipelines results. As SPQR uses kafka by default * to interconnect pipelines and emit results the server currently supports to read content from * kafka topics accordingly. <br/><br/> * In contrast to spqr node and resource management server this one is based on netty as it provides * support for web sockets. * * @author mnxfst * @since Apr 17, 2015 */ public class SPQRWebSocketServer { /** our faithful logging facility ... ;-) */ private static final Logger logger = Logger.getLogger(SPQRWebSocketServer.class); public static final String CFG_HELP = "help"; public static final String CFG_HELP_SHORT = "h"; public static final String CFG_CONFIGURATION_FILE = "config"; public static final String CFG_CONFIGURATION_FILE_SHORT = "c"; /** * Initializes and executes the server components * @param configurationFile reference to configuration file * @throws IOException * @throws InterruptedException */ protected void run(final String configurationFile) throws IOException, InterruptedException { /////////////////////////////////////////////////////////////////// // lookup configuration file and create handle File cfgFile = new File(StringUtils.trim(configurationFile)); if (!cfgFile.isFile()) throw new FileNotFoundException("No configuration file found at '" + configurationFile + "'"); // /////////////////////////////////////////////////////////////////// run(new FileInputStream(cfgFile)); } /** * Initializes and executes the server components. Although the other {@link SPQRWebSocketServer#run(String)} * could do the same work this one allows better testing as the {@link InputStream} parameter allows * to inject a variable which may be controlled much better. In the case it would be necessary to * provide a reference to a temporary file which is controlled by the use case ... somehow too much work ;-) * This one is easier. * @param configurationFileStream stream holding configuration file content * @throws IOException * @throws InterruptedException */ protected void run(final InputStream configurationFileStream) throws IOException, InterruptedException { /////////////////////////////////////////////////////////////////// // parse out configuration from provided input stream ObjectMapper jsonMapper = new ObjectMapper(); SPQRWebSocketServerConfiguration cfg = jsonMapper.readValue(configurationFileStream, SPQRWebSocketServerConfiguration.class); // /////////////////////////////////////////////////////////////////// PropertyConfigurator.configure(cfg.getLog4jConfigurationFile()); EventLoopGroup bossGroup = new NioEventLoopGroup(cfg.getBossEventGroupThreads()); EventLoopGroup workerGroup = new NioEventLoopGroup(cfg.getWorkerEventGroupThreads()); logger.info( "websocket server [port=" + cfg.getPort() + ", bossGroupThreads=" + cfg.getBossEventGroupThreads() + ", workerGroupThreads=" + cfg.getWorkerEventGroupThreads() + "]"); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new SPQRWebSocketServerInitializer()); Channel channel = bootstrap.bind(cfg.getPort()).sync().channel(); channel.closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } /** * Returns the available command-line options * @return */ public static Options getOptions() { Options options = new Options(); options.addOption(CFG_CONFIGURATION_FILE_SHORT, CFG_CONFIGURATION_FILE, true, "Configuration file"); options.addOption(CFG_HELP_SHORT, CFG_HELP, false, "Help"); return options; } /** * Checks the command-line settings and ramps up the server * @param args arguments passed from command-line * @throws ParseException indicates that parsing the command-line failed for any reason * @throws InterruptedException * @throws IOException */ public static void main(String[] args) throws ParseException, IOException, InterruptedException { //////////////////////////////////////////////////////////////////////// // evaluate command-line and ensure that it provides valid input CommandLineParser parser = new PosixParser(); CommandLine commandLine = parser.parse(getOptions(), args); if (commandLine.hasOption(CFG_HELP)) { new HelpFormatter().printHelp("spqr-websocket-server", getOptions()); return; } if (!commandLine.hasOption(CFG_CONFIGURATION_FILE)) { new HelpFormatter().printHelp("spqr-websocket-server", "", getOptions(), "Missing required configuration file"); return; } // //////////////////////////////////////////////////////////////////////// new SPQRWebSocketServer().run(commandLine.getOptionValue(CFG_CONFIGURATION_FILE)); } }