ProductClient.java
- /*
- * Main
- */
- package gov.usgs.earthquake.distribution;
- import gov.usgs.earthquake.indexer.SearchCLI;
- import gov.usgs.util.Config;
- import gov.usgs.util.DefaultConfigurable;
- import gov.usgs.util.StringUtils;
- import java.lang.management.ManagementFactory;
- import java.util.Iterator;
- import java.util.List;
- import java.util.LinkedList;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import javax.management.MBeanServer;
- import javax.management.ObjectName;
- /**
- * The entry point to product distribution.
- *
- * The ProductClient implements the Configurable interface and can use the
- * following configuration parameters:
- *
- * <dl>
- *
- * <dt>receivers</dt>
- * <dd>(Required) A comma separated list of section names that should be loaded
- * as NotificationReceiver objects. Each receiver is a source of notifications
- * for listeners.</dd>
- *
- * <dt>listeners</dt>
- * <dd>(Required) A comma separated list of section names that should be loaded
- * as NotificationListener objects. Each listener receives notifications from
- * receivers.</dd>
- *
- * <dt>logdirectory</dt>
- * <dd>(Optional) Log directory. Default is "log", relative to the current
- * working directory. Log files using a naming convention
- * <code>ProductClient_YYYYMMDD.log</code>.</dd>
- *
- * <dt>loglevel</dt> <dd>(Optional) Default is INFO. One of SEVERE, WARNING,
- * INFO, CONFIG, FINE, FINER, FINEST</dd>
- *
- * <dt>enableTracker</dt> <dd>(Optional) Default is false. Whether or not to
- * send tracker updates to a product tracker. This is generally desirable, but
- * is disabled by default for the paranoid.</dd>
- *
- * <dt>redirectconsole</dt> <dd>(Optional) Default is false. Whether or not to
- * redirect console output to the log file.</dd>
- *
- * </dl>
- *
- * <p>
- * All listeners listen to all receivers for notifications.
- * </p>
- *
- */
- public class ProductClient extends DefaultConfigurable implements
- ProductClientMBean, Bootstrappable {
- /** The "release" version number. */
- public static final String RELEASE_VERSION = "Version 2.8.0 2022-10-11";
- /** Property name used on products for current RELEASE_VERSION. */
- public static final String PDL_CLIENT_VERSION_PROPERTY = "pdl-client-version";
- /** SVN Id property. */
- public static final String SVN_VERSION = "$Id$";
- /** SVN Revision property. */
- public static final String SVN_REVISION = "$Revision$";
- /** SVN LastChangedDate property. */
- public static final String SVN_LAST_CHANGED_DATE = "$LastChangedDate$";
- /** Logging object. */
- private static final Logger LOGGER = Logger.getLogger(ProductClient.class
- .getName());
- /** Defaults are loaded from inside the jar file. */
- public static final String JAR_CONFIG_FILE = "etc/config/config.ini";
- /** Default location of config file. */
- public static final String DEFAULT_CONFIG_FILE = "config.ini";
- /** Custom config file locations. */
- public static final String CONFIG_FILE_ARGUMENT = "--configFile=";
- /** Run the builder. */
- public static final String BUILD_ARGUMENT = "--build";
- /** Run the tracker. */
- public static final String TRACK_ARGUMENT = "--track";
- /** Run the builder. */
- public static final String SEND_ARGUMENT = "--send";
- /** Run the client. */
- public static final String RECEIVE_ARGUMENT = "--receive";
- /** Run the search. */
- public static final String SEARCH_ARGUMENT = "--search";
- /** Show usage. */
- public static final String USAGE_ARGUMENT = "--help";
- /** Property containing list of receivers. */
- public static final String RECEIVERS_PROPERTY_NAME = "receivers";
- /** Property containing list of senders. */
- public static final String LISTENERS_PROPERTY_NAME = "listeners";
- /** Log level property name. */
- public static final String LOGLEVEL_PROPERTY_NAME = "loglevel";
- /** Default log level is INFO. */
- public static final String DEFAULT_LOGLEVEL = "INFO";
- /** Property with location for log directory. */
- public static final String LOGDIRECTORY_PROPERTY_NAME = "logdirectory";
- /** Default directory for logging. */
- public static final String DEFAULT_LOGDIRECTORY = "log";
- /** Default location for log file. */
- public static final String DEFAULT_LOGFILE = "'ProductClient'_yyyyMMdd'.log'";
- /** Whether or not to redirect stdout and stderr to log file. */
- public static final String CONSOLE_REDIRECT_PROPERTY_NAME = "redirectconsole";
- /** Default console redirect value (don't redirect). */
- public static final String DEFAULT_CONSOLE_REDIRECT = "false";
- /** Property used to disable tracker updates. */
- public static final String ENABLE_TRACKER_PROPERTY_NAME = "enableTracker";
- /** Property used to enable Admin Socket */
- public static final String ENABLE_ADMIN_SOCKET = "enableAdminSocket";
- /** Default bool for admin socket property */
- public static final String DEFAULT_ENABLE_ADMIN_SOCKET = "false";
- /** List of receivers that generate notifications. */
- private List<NotificationReceiver> receivers = new LinkedList<NotificationReceiver>();
- /** List of listeners that receive notifications. */
- private List<NotificationListener> listeners = new LinkedList<NotificationListener>();
- /** Whether to start a zabbix agent. */
- private boolean enableAdminSocket = false;
- private boolean enableJMX = true;
- private AdminSocketServer adminSocketServer = null;
- public void configure(Config config) throws Exception {
- loadListeners(config);
- loadReceivers(config);
- // connect all listeners to all receivers
- Iterator<NotificationReceiver> iter = receivers.iterator();
- while (iter.hasNext()) {
- NotificationReceiver receiver = iter.next();
- Iterator<NotificationListener> iter2 = listeners.iterator();
- while (iter2.hasNext()) {
- NotificationListener listener = iter2.next();
- receiver.addNotificationListener(listener);
- }
- }
- enableAdminSocket = Boolean.valueOf(config.getProperty(
- ENABLE_ADMIN_SOCKET, DEFAULT_ENABLE_ADMIN_SOCKET));
- }
- /**
- * Load listeners from a Config object.
- *
- * @param config
- * the configuration.
- * @throws Exception if error occurs
- */
- public void loadListeners(final Config config) throws Exception {
- Iterator<String> iter = StringUtils.split(
- config.getProperty(LISTENERS_PROPERTY_NAME, ""), ",")
- .iterator();
- while (iter.hasNext()) {
- String listenerName = iter.next();
- LOGGER.config("Loading listener '" + listenerName + "'");
- NotificationListener listener = (NotificationListener) Config
- .getConfig().getObject(listenerName);
- if (listener == null) {
- throw new ConfigurationException("Unable to load listener '"
- + listenerName
- + "', make sure it is properly configured.");
- }
- // listenerName references an object in the global configuration
- listeners.add(listener);
- }
- }
- /**
- * Load NotificationReceivers from a Config object.
- *
- * @param config
- * the configuration
- * @throws Exception if error occurs
- */
- public void loadReceivers(final Config config) throws Exception {
- Iterator<String> iter = StringUtils.split(
- config.getProperty(RECEIVERS_PROPERTY_NAME), ",").iterator();
- while (iter.hasNext()) {
- String receiverName = iter.next();
- LOGGER.config("Loading receiver '" + receiverName + "'");
- NotificationReceiver receiver = (NotificationReceiver) Config
- .getConfig().getObject(receiverName);
- if (receiver == null) {
- throw new ConfigurationException("Unable to load receiver '"
- + receiverName
- + "', make sure it is properly configured.");
- }
- // receiverName references an object in the global configuration
- receivers.add(receiver);
- }
- }
- /**
- * Start up all listeners and receivers.
- */
- public void startup() throws Exception {
- Iterator<NotificationListener> iter = listeners.iterator();
- while (iter.hasNext()) {
- iter.next().startup();
- }
- Iterator<NotificationReceiver> iter2 = receivers.iterator();
- while (iter2.hasNext()) {
- iter2.next().startup();
- }
- if (enableAdminSocket) {
- LOGGER.info("Starting AdminSocketServer on port 11111");
- adminSocketServer = new AdminSocketServer();
- adminSocketServer.setClient(this);
- adminSocketServer.startup();
- }
- if (enableJMX) {
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- ObjectName clientName = new ObjectName("ProductClient:name=jmx");
- mbs.registerMBean(this, clientName);
- }
- }
- /**
- * Shut down all receivers and listeners.
- */
- public void shutdown() throws Exception {
- if (receivers.size() > 0) {
- Iterator<NotificationReceiver> iter2 = receivers.iterator();
- while (iter2.hasNext()) {
- try {
- iter2.next().shutdown();
- } catch (Exception e) {
- // ignore
- }
- }
- }
- if (listeners.size() > 0) {
- Iterator<NotificationListener> iter = listeners.iterator();
- while (iter.hasNext()) {
- try {
- iter.next().shutdown();
- } catch (Exception e) {
- // ignore
- }
- }
- }
- if (adminSocketServer != null) {
- try {
- adminSocketServer.shutdown();
- } catch (Exception e) {
- }
- adminSocketServer = null;
- }
- }
- /**
- * Entry point into Product Distribution.
- *
- * @param args argument
- */
- public void run(final String[] args) throws Exception {
- try {
- // default is show usage
- boolean receiveProducts = false;
- boolean buildProduct = false;
- boolean trackProduct = false;
- boolean searchProduct = false;
- boolean showUsage = false;
- // parse arguments
- for (String arg : args) {
- if (arg.equals(SEND_ARGUMENT) || arg.equals(BUILD_ARGUMENT)) {
- buildProduct = true;
- } else if (arg.equals(RECEIVE_ARGUMENT)) {
- receiveProducts = true;
- } else if (arg.equals(TRACK_ARGUMENT)) {
- trackProduct = true;
- } else if (arg.equals(SEARCH_ARGUMENT)) {
- searchProduct = true;
- } else if (arg.equals(USAGE_ARGUMENT)) {
- showUsage = true;
- }
- }
- // output current version
- System.err.println("Product Distribution Client");
- System.err.println(RELEASE_VERSION);
- System.err.println();
- if (buildProduct) {
- if (showUsage) {
- System.err.println("Usage: ");
- System.err
- .println(" java -jar ProductClient.jar --build [BUILD ARGUMENTS]");
- System.err.println();
- System.err.println(CLIProductBuilder.getUsage());
- System.exit(0);
- }
- LOGGER.info("Running Product Builder");
- // run builder main
- CLIProductBuilder.main(args);
- System.exit(0);
- } else if (trackProduct) {
- if (showUsage) {
- System.err.println("Usage: ");
- System.err
- .println(" java -jar ProductClient.jar --track [TRACK ARGUMENTS]");
- System.err.println();
- System.err.println(ProductTracker.getUsage());
- System.exit(0);
- }
- LOGGER.info("Running Product Tracker");
- ProductTracker.main(args);
- System.exit(0);
- } else if (searchProduct) {
- // search needs to happen after track, since track also uses a
- // --search argument
- if (showUsage) {
- System.err.println("Usage: ");
- System.err
- .println(" java -jar ProductClient.jar --search [SEARCH ARGUMENTS]");
- System.err.println();
- System.err.println(SearchCLI.getUsage());
- System.exit(0);
- }
- LOGGER.info("Running Product Search");
- SearchCLI.main(args);
- System.exit(0);
- } else if (receiveProducts && !showUsage) {
- // start processing
- LOGGER.info("Starting");
- try {
- startup();
- } catch (Exception e) {
- LOGGER.log(Level.SEVERE,
- "Exceptions while starting, shutting down", e);
- try {
- // this has been throwing exceptions, move into try
- shutdown();
- } finally {
- // exit no matter what
- System.exit(1);
- }
- }
- LOGGER.info("Started");
- // shutdown threads when control-c is pressed
- // otherwise, would continue running
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void run() {
- try {
- LOGGER.info("Shutting down");
- shutdown();
- LOGGER.info("Shutdown complete");
- } catch (Exception e) {
- LOGGER.log(Level.WARNING,
- "Exception while shutting down", e);
- }
- }
- });
- } else {
- System.err.println("Usage: ");
- System.err
- .println(" java -jar ProductClient.jar [ARGUMENTS]");
- System.err.println();
- System.err.println(getUsage());
- System.exit(1);
- }
- } catch (Exception e) {
- LOGGER.log(Level.SEVERE, "Exception in main", e);
- }
- }
- /**
- * @return The list of receivers
- */
- public List<NotificationReceiver> getReceivers() {
- return receivers;
- }
- /**
- *
- * @return The list of listeners
- */
- public List<NotificationListener> getListeners() {
- return listeners;
- }
- /** @return Product usage */
- public static String getUsage() {
- StringBuffer buf = new StringBuffer();
- buf.append("[--configFile=FILE] override the default config file location\n");
- buf.append(" default is config.ini in CWD\n");
- buf.append("[--help] show this message and exit\n");
- buf.append("[--version] show the version and exit\n");
- buf.append("[--configTest] load configuration and exit\n");
- buf.append("\n");
- buf.append("[--send] create and send a product\n");
- buf.append(" try --send --help for more information\n");
- buf.append("[--receive] receive products\n");
- buf.append("[--track] check or update product status\n");
- buf.append(" try --track --help for more information\n");
- buf.append("\n");
- buf.append("You must use one of \"--send\", \"--receive\", or \"--track\"\n");
- buf.append("\n");
- return buf.toString();
- }
- @Override
- public String getListenerQueueStatus() {
- StringBuffer buf = new StringBuffer();
- Iterator<NotificationReceiver> iter = receivers.iterator();
- while (iter.hasNext()) {
- NotificationReceiver receiver = iter.next();
- if (receiver instanceof DefaultNotificationReceiver) {
- buf.append(((DefaultNotificationReceiver) receiver)
- .getListenerQueueStatus());
- }
- }
- return buf.toString();
- }
- @Override
- public String getVersion() {
- return RELEASE_VERSION;
- }
- @Override
- public long getMaxMemory() {
- return Runtime.getRuntime().maxMemory();
- }
- @Override
- public long getFreeMemory() {
- return Runtime.getRuntime().freeMemory();
- }
- }