package com.linkedin.databus.client.generic; /* * * Copyright 2013 LinkedIn Corp. All rights reserved * * 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. * */ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.log4j.Logger; import com.linkedin.databus.client.DatabusHttpClientImpl; import com.linkedin.databus.client.consumer.LoggingConsumer; import com.linkedin.databus.client.pub.DatabusRegistration; import com.linkedin.databus.client.pub.DbusClusterConsumerFactory; import com.linkedin.databus.client.pub.DbusPartitionListener; import com.linkedin.databus.client.pub.DbusServerSideFilterFactory; import com.linkedin.databus.client.pub.ServerInfo.ServerInfoBuilder; import com.linkedin.databus.core.util.ConfigLoader; import com.linkedin.databus2.core.container.netty.ServerContainer; import com.linkedin.databus2.core.container.request.ContainerOperationProcessor; import com.linkedin.databus2.core.container.request.ProcessorRegistrationConflictException; public abstract class ClusterFileLoggingClient { public static final String MODULE = SimpleFileLoggingConsumer.class.getName(); public static final Logger LOG = Logger.getLogger(MODULE); public static final String RELAY_HOST_OPT_NAME = "relay_host"; public static final String RELAY_PORT_OPT_NAME = "relay_port"; public static final String EVENT_DUMP_FILE_OPT_NAME = "f"; public static final String VALUE_DUMP_FILE_OPT_NAME = "value_file"; public static final String HTTP_PORT_OPT_NAME = "http_port"; public static final String JMX_SERVICE_PORT_OPT_NAME = "jmx_service_port"; public static final String BOOTSTRAP_HOST_OPT_NAME = "bootstrap_host"; public static final String BOOTSTRAP_PORT_OPT_NAME = "bootstrap_port"; public static final String EVENT_PATTERN_OPT_NAME = "event_pattern"; public static final String CLUSTER_NAME_OPT_NAME = "cluster_name"; private static String _eventDumpFile = null; private static String _valueDumpFile = null; private static String _relayHost = null; private static String _relayPort = null; private static String _bootstrapHost = null; private static String _bootstrapPort = null; private static String _httpPort = null; private static String _jmxServicePort = null; private static String _checkpointFileRootDir = null; private static String _eventPattern = null; private static boolean _enableBootStrap = false; private static List<String> _clusters = null; protected static Options constructCommandLineOptions() { Options options = new Options(); options.addOption(CLUSTER_NAME_OPT_NAME, true, "Cluster Name"); options.addOption(RELAY_HOST_OPT_NAME, true, "Relay Host Name"); options.addOption(RELAY_PORT_OPT_NAME, true, "Relay Port"); options.addOption(EVENT_DUMP_FILE_OPT_NAME, true, "File to dump event"); options.addOption(VALUE_DUMP_FILE_OPT_NAME, true, "File to dump deserilized values"); options.addOption(HTTP_PORT_OPT_NAME, true, "Consumer http port"); options.addOption(JMX_SERVICE_PORT_OPT_NAME, true, "Consumer jmx service port"); options.addOption(BOOTSTRAP_HOST_OPT_NAME, true, "Bootstrap server Name"); options.addOption(BOOTSTRAP_PORT_OPT_NAME, true, "Bootstrap server Port"); options.addOption(EVENT_PATTERN_OPT_NAME, true, "Event Pattern Name to Check"); return options; } protected static String[] processLocalArgs(String[] cliArgs) throws IOException, ParseException { CommandLineParser cliParser = new GnuParser(); Options cliOptions = constructCommandLineOptions(); CommandLine cmd = cliParser.parse(cliOptions, cliArgs, true); // Options here has to be up front if (cmd.hasOption(CLUSTER_NAME_OPT_NAME)) { String cluster = cmd.getOptionValue(CLUSTER_NAME_OPT_NAME); String[] clusters = cluster.split(","); _clusters = Arrays.asList(clusters); LOG.info("Cluster Name = " + _clusters); } if (cmd.hasOption(RELAY_HOST_OPT_NAME)) { _relayHost = cmd.getOptionValue(RELAY_HOST_OPT_NAME); LOG.info("Relay Host = " + _relayHost); } if (cmd.hasOption(RELAY_PORT_OPT_NAME)) { _relayPort = cmd.getOptionValue(RELAY_PORT_OPT_NAME); LOG.info("Relay Port = " + _relayPort); } if (cmd.hasOption(EVENT_DUMP_FILE_OPT_NAME)) { _eventDumpFile = cmd.getOptionValue(EVENT_DUMP_FILE_OPT_NAME); LOG.info("Saving event dump to file: " + _eventDumpFile); } if (cmd.hasOption(VALUE_DUMP_FILE_OPT_NAME)) { _valueDumpFile = cmd.getOptionValue(VALUE_DUMP_FILE_OPT_NAME); LOG.info("Saving event value dump to file: " + _valueDumpFile); } if (cmd.hasOption(HTTP_PORT_OPT_NAME)) { _httpPort = cmd.getOptionValue(HTTP_PORT_OPT_NAME); LOG.info("Consumer http port = " + _httpPort); } if (cmd.hasOption(JMX_SERVICE_PORT_OPT_NAME)) { _jmxServicePort = cmd.getOptionValue(JMX_SERVICE_PORT_OPT_NAME); LOG.info("Consumer JMX Service port = " + _jmxServicePort); } if (cmd.hasOption(BOOTSTRAP_HOST_OPT_NAME)) { _bootstrapHost = cmd.getOptionValue(BOOTSTRAP_HOST_OPT_NAME); LOG.info("Bootstrap Server = " + _bootstrapHost); } if (cmd.hasOption(BOOTSTRAP_PORT_OPT_NAME)) { _bootstrapPort = cmd.getOptionValue(BOOTSTRAP_PORT_OPT_NAME); LOG.info("Bootstrap Server Port = " + _bootstrapPort); } if (cmd.hasOption(EVENT_PATTERN_OPT_NAME)) { _eventPattern = cmd.getOptionValue(EVENT_PATTERN_OPT_NAME); LOG.info("Event pattern = " + _eventPattern); } if (_bootstrapHost != null || _bootstrapPort != null) { _enableBootStrap = true; } // return what left over args return cmd.getArgs(); } protected abstract String[] getSources(); protected DatabusFileLoggingConsumer createTypedConsumer(String valueDumpFile) throws IOException { return new DatabusFileLoggingConsumer(valueDumpFile, false); } public void mainFunction(String args[]) throws Exception { String [] leftOverArgs = processLocalArgs(args); Properties startupProps = DatabusHttpClientImpl.processCommandLineArgs(leftOverArgs); DatabusHttpClientImpl.Config clientConfigBuilder = new DatabusHttpClientImpl.Config(); clientConfigBuilder.getContainer().setIdFromName(MODULE + ".localhost"); if (_enableBootStrap) { clientConfigBuilder.getRuntime().getBootstrap().setEnabled(true); } ConfigLoader<DatabusHttpClientImpl.StaticConfig> configLoader = new ConfigLoader<DatabusHttpClientImpl.StaticConfig>("databus.client.", clientConfigBuilder); String[] sources = getSources(); StringBuilder sourcesString = new StringBuilder(); boolean firstSrc = true; for (String source: sources) { if (! firstSrc) sourcesString.append(","); firstSrc = false; sourcesString.append(source); } if (_httpPort != null) { startupProps.put("databus.client.container.httpPort", _httpPort); } if (_jmxServicePort != null) { startupProps.put("databus.client.container.jmx.jmxServicePort", _jmxServicePort); } if (_checkpointFileRootDir != null) { startupProps.put("databus.client.checkpointPersistence.fileSystem.rootDirectory", _checkpointFileRootDir); } DatabusHttpClientImpl.StaticConfig clientConfig = configLoader.loadConfig(startupProps); // set up relay ServerInfoBuilder relayBuilder = clientConfig.getRuntime().getRelay("1"); relayBuilder.setName("DefaultRelay"); if (_relayHost != null) { relayBuilder.setHost(_relayHost); } if (_relayPort != null) { relayBuilder.setPort(Integer.parseInt(_relayPort)); } relayBuilder.setSources(sourcesString.toString()); // set up bootstrap if (_enableBootStrap) { ServerInfoBuilder bootstrapBuilder = clientConfig.getRuntime().getBootstrap().getService("2"); bootstrapBuilder.setName("DefaultBootstrapServices"); if (_bootstrapHost != null) { bootstrapBuilder.setHost(_bootstrapHost); } if (_bootstrapPort != null) { bootstrapBuilder.setPort(Integer.parseInt(_bootstrapPort)); } bootstrapBuilder.setSources(sourcesString.toString()); } // set up listeners DatabusHttpClientImpl client = new DatabusHttpClientImpl(clientConfig); List<DatabusRegistration> regs = new ArrayList<DatabusRegistration>(); for (String cluster : _clusters) { DatabusRegistration reg = client.registerCluster(cluster, createConsumerFactory(cluster, _valueDumpFile, _eventDumpFile), createServerSideFactory(cluster), createPartitionListener(cluster), sources); regs.add(reg); } // add pause processor try { client.getProcessorRegistry().register(ContainerOperationProcessor.COMMAND_NAME, new ContainerOperationProcessor(null, client)); } catch (ProcessorRegistrationConflictException e) { LOG.error("Failed to register " + ConsumerPauseRequestProcessor.COMMAND_NAME); } DatabusClientShutdownThread shutdownThread = new DatabusClientShutdownThread(client); Runtime.getRuntime().addShutdownHook(shutdownThread); client.startAndBlock(); } protected abstract DbusClusterConsumerFactory createConsumerFactory(String cluster, String valueFilePrefix, String eventDumpPrefix); protected abstract DbusServerSideFilterFactory createServerSideFactory(String cluster); protected abstract DbusPartitionListener createPartitionListener(String cluster); static class DatabusClientShutdownThread extends Thread { public static final String MODULE = DatabusClientShutdownThread.class.getName(); public static final Logger LOG = Logger.getLogger(MODULE); private final ServerContainer _serverContainer; public DatabusClientShutdownThread(ServerContainer serverContainer) { super("ServerContainer Shutdown Thread"); _serverContainer = serverContainer; } @Override public void run() { LOG.info("Starting shutdown procedure for server container..."); try { if (null != _serverContainer && _serverContainer.isRunningStatus()) { _serverContainer.shutdownUninteruptibly(); } LOG.info("Server Container shutdown."); } catch (Exception e) { LOG.error("Error shutting down Server Container", e); } } } }