/* * Copyright MapR Technologies, 2013 * * 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.mapr.franz.simple; import com.googlecode.protobuf.pro.duplex.PeerInfo; import com.googlecode.protobuf.pro.duplex.execute.ThreadPoolCallExecutor; import com.googlecode.protobuf.pro.duplex.server.DuplexTcpServerBootstrap; import com.mapr.franz.catcher.wire.Catcher; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.FileNotFoundException; import java.net.SocketException; import java.util.concurrent.Executors; /** * Single machine process for catching log messages. * <p/> * This server is required to do a number of things: * <p/> * a) catch messages for topics it is handling. * <p/> * b) respond to hello messages with a list containing our own network addresses * <p/> * c) report traffic statistics on topics every few seconds * <p/> * d) clean up old queue files when starting a new file. * <p/> * Tasks (a), and (b) are handled by the server implementation. * <p/> * Task (c) by the statistics reporter. * <p/> * Task (d) is handled as part of the message appender. */ public class SimpleCatcher { private static Logger logger = LoggerFactory.getLogger(SimpleCatcher.class); public static void main(String[] args) throws FileNotFoundException, SocketException { run(parseOptions(args)); } public static void run(Options opts) throws SocketException, FileNotFoundException { logger.warn("Starting server {}", opts); SimpleCatcherService service; try { service = new SimpleCatcherService(opts.port, opts.basePath); } catch (FileNotFoundException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. return; } DuplexTcpServerBootstrap bootstrap = startProtoServer(opts.port); bootstrap.getRpcServiceRegistry().registerBlockingService( Catcher.CatcherService.newReflectiveBlockingService(service)); try { bootstrap.bind(); } catch (ChannelException e) { // releasing resources allows the server to exit bootstrap.releaseExternalResources(); throw e; } } private static DuplexTcpServerBootstrap startProtoServer(int port) { PeerInfo serverInfo = new PeerInfo("0.0.0.0", port); DuplexTcpServerBootstrap bootstrap = new DuplexTcpServerBootstrap( serverInfo, new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool()) ); ThreadPoolCallExecutor pool = new ThreadPoolCallExecutor(10, 10); bootstrap.setRpcServerCallExecutor(pool); return bootstrap; } private static Options parseOptions(String[] args) { Options opts = new Options(); CmdLineParser parser = new CmdLineParser(opts); try { parser.parseArgument(args); } catch (CmdLineException e) { e.printStackTrace(System.err); parser.printUsage(System.err); System.exit(1); } return opts; } public static class Options { public Options base(String basePath) { this.basePath = basePath; return this; } public Options port(int port) { this.port = port; return this; } @Option(name = "-port", usage = "Port number for the catcher server to listen to") int port = 5900; @Option(name = "-base", usage = "Home directory for recording topics") String basePath = "/tmp/mapr-spout"; @Override public String toString() { return "Options{" + "basePath='" + basePath + '\'' + ", port=" + port + '}'; } } }