340N/A/*
340N/A * CDDL HEADER START
340N/A *
340N/A * The contents of this file are subject to the terms of the
340N/A * Common Development and Distribution License (the "License").
340N/A * You may not use this file except in compliance with the License.
340N/A *
340N/A * See LICENSE.txt included in this distribution for the specific
340N/A * language governing permissions and limitations under the License.
340N/A *
340N/A * When distributing Covered Code, include this CDDL HEADER in each
340N/A * file and include the License file at LICENSE.txt.
340N/A * If applicable, add the following below this CDDL HEADER, with the
340N/A * fields enclosed by brackets "[]" replaced with your own identifying
340N/A * information: Portions Copyright [yyyy] [name of copyright owner]
340N/A *
340N/A * CDDL HEADER END
340N/A */
340N/A
340N/A/*
1043N/A * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
340N/A */
1043N/A
340N/Apackage org.opensolaris.opengrok.management;
340N/A
682N/Aimport java.io.File;
340N/Aimport java.io.FileInputStream;
340N/Aimport java.io.IOException;
340N/Aimport java.io.InputStream;
420N/Aimport java.net.MalformedURLException;
682N/Aimport java.net.URI;
682N/Aimport java.net.URISyntaxException;
1043N/Aimport java.rmi.registry.LocateRegistry;
340N/Aimport java.util.ArrayList;
340N/Aimport java.util.Date;
394N/Aimport java.util.HashMap;
394N/Aimport java.util.Properties;
394N/Aimport java.util.logging.Level;
394N/Aimport java.util.logging.Logger;
459N/Aimport javax.management.JMException;
394N/Aimport javax.management.MBeanServer;
394N/Aimport javax.management.MBeanServerFactory;
340N/Aimport javax.management.NotificationFilter;
394N/Aimport javax.management.ObjectName;
394N/Aimport javax.management.remote.JMXConnectorServer;
1035N/Aimport javax.management.remote.JMXConnectorServerFactory;
394N/Aimport javax.management.remote.JMXServiceURL;
340N/Aimport javax.management.timer.Timer;
340N/Aimport org.opensolaris.opengrok.Info;
340N/Aimport org.opensolaris.opengrok.OpenGrokLogger;
340N/A
1462N/Aimport org.opensolaris.opengrok.configuration.Configuration;
1043N/A// PMD thinks this import is unused (confused because it's static?)
1195N/Aimport org.opensolaris.opengrok.util.IOUtils;
1043N/Aimport static org.opensolaris.opengrok.management.Constants.*; // NOPMD
1043N/A
340N/A/**
340N/A * OG Agent main class.
340N/A * Class for starting the basic components:
340N/A * Monitor and JMX and HTTP Connectors.
340N/A * @author Jan S Berg
340N/A */
689N/Afinal public class OGAgent {
682N/A Properties props;
340N/A
1327N/A private static final Logger log = Logger.getLogger(OGAgent.class.getName());
340N/A private MBeanServer server = null;
682N/A
682N/A
1462N/A @SuppressWarnings({ "PMD.SystemPrintln", "resource" })
682N/A private static boolean loadProperties(File file, InputStream in, Properties props) {
682N/A boolean ret = false;
689N/A InputStream stream = in;
682N/A try {
682N/A if (file != null) {
689N/A stream = new FileInputStream(file);
682N/A }
689N/A props.load(stream);
682N/A ret = true;
682N/A } catch (IOException e) {
1327N/A log.warning("Failed to read configuration: " + e.getMessage());
1327N/A log.log(Level.FINE, "loadProperties", e);
682N/A ret = false;
682N/A } finally {
1195N/A IOUtils.close(stream);
682N/A }
682N/A return ret;
682N/A }
340N/A
1462N/A /**
1462N/A * Startup method. Uses {@code /etc/opengrok/opengrok.properties} as
1462N/A * defaults if available.
1462N/A * @param args .. --agent=... --config=...
1462N/A */
434N/A @SuppressWarnings("PMD.SystemPrintln")
340N/A public static void main(final String args[]) {
340N/A
682N/A Properties props = new Properties();
682N/A // Load default values
1462N/A boolean success = loadProperties(null,
1462N/A OGAgent.class.getResourceAsStream("oga.properties"), props);
682N/A
682N/A File file = new File("/etc/opengrok/opengrok.properties");
682N/A if (file.exists()) {
682N/A success = loadProperties(file, null, props);
682N/A }
682N/A
682N/A // System properties should override default properties
682N/A props.putAll(System.getProperties());
682N/A
682N/A // @todo Add support for longopts!!
682N/A for (int i = 0; success && i < args.length; i++) {
682N/A if (args[i].startsWith("--agent=")) {
682N/A props.setProperty("agent", args[i].substring("--agent=".length()));
682N/A } else if (args[i].startsWith("--config=")) {
682N/A file = new File(args[i].substring("--config=".length()));
682N/A if (file.exists()) {
682N/A success = loadProperties(file, null, props);
340N/A } else {
682N/A success = false;
1462N/A log.severe("Cannot load file '" + file.getAbsolutePath()
1462N/A + "': No such file");
340N/A }
340N/A }
340N/A }
340N/A
682N/A URI uri = null;
682N/A if (success) {
682N/A try {
682N/A uri = new URI(props.getProperty("agent"));
682N/A } catch (URISyntaxException ex) {
682N/A success = false;
1327N/A log.severe("Failed to decode agent url: " + ex.getMessage());
1327N/A log.log(Level.FINE, "main", ex);
682N/A }
682N/A }
682N/A
1462N/A if (uri != null) {
1043N/A setIfNotSet(props, LOG_PATH, uri.getPath() + "/log");
684N/A
1043N/A setIfNotSet(props, CONFIG_FILE,
1043N/A uri.getPath() + "/etc/configuration.xml");
1043N/A
1043N/A setIfNotSet(props, JMX_HOST, uri.getHost());
682N/A
1043N/A setIfNotSet(props, JMX_PORT, String.valueOf(uri.getPort()));
1043N/A
1043N/A setIfNotSet(props, RMI_PORT, String.valueOf(uri.getPort() + 1));
682N/A
1043N/A setIfNotSet(props, JMX_URL,
1043N/A "service:jmx:rmi://" + props.getProperty(JMX_HOST) + ":" +
1043N/A props.getProperty(JMX_PORT) + "/jndi/rmi://" +
1043N/A props.getProperty(JMX_HOST) + ":" +
1043N/A props.getProperty(RMI_PORT) + "/opengrok");
682N/A
682N/A success = createLogger(props);
682N/A }
682N/A
682N/A if (success) {
682N/A
682N/A OGAgent oga = new OGAgent(props);
682N/A try {
682N/A oga.runOGA();
682N/A } catch (MalformedURLException e) {
1327N/A log.severe("Could not create connector server: " + e.getMessage());
1327N/A log.log(Level.FINE, "main", e);
682N/A System.exit(1);
682N/A } catch (IOException e) {
1327N/A log.severe("Could not start connector server: " + e.getMessage());
1327N/A log.log(Level.FINE, "main", e);
682N/A System.exit(2);
682N/A } catch (Exception ex) {
1327N/A log.severe(ex.getMessage());
1327N/A log.log(Level.FINE, "main", ex);
682N/A System.exit(1);
682N/A }
682N/A } else {
340N/A System.exit(1);
340N/A }
340N/A }
340N/A
682N/A private OGAgent(Properties props) {
682N/A this.props = props;
682N/A }
682N/A
1043N/A /**
1043N/A * Set a property if it is not already set to some value.
1043N/A */
1043N/A private static void setIfNotSet(Properties props, String key, String val) {
1043N/A if (!props.keySet().contains(key)) {
1043N/A props.setProperty(key, val);
1043N/A }
1043N/A }
1043N/A
1462N/A @SuppressWarnings("boxing")
1462N/A private void runOGA() throws MalformedURLException, IOException, JMException {
340N/A String javaver = System.getProperty("java.version");
340N/A
340N/A
340N/A log.info("Starting " + Info.getFullVersion() +
340N/A " JMX Agent, with java version " + javaver);
340N/A //create mbeanserver
340N/A
1185N/A ArrayList<MBeanServer> mbservs = MBeanServerFactory.findMBeanServer(null);
459N/A log.fine("Finding MBeanservers, size " + mbservs.size());
460N/A if (mbservs.isEmpty()) {
460N/A server = MBeanServerFactory.createMBeanServer();
460N/A } else {
1185N/A server = mbservs.get(0);
459N/A }
340N/A
459N/A //instantiate and register OGAManagement
459N/A ObjectName manager = new ObjectName("OGA:name=Management");
459N/A server.registerMBean(Management.getInstance(props), manager);
682N/A
639N/A //instantiate and register OGA:JMXConfiguration
639N/A ObjectName config = new ObjectName("OGA:name=JMXConfiguration");
639N/A JMXConfiguration jc = new JMXConfiguration();
639N/A server.registerMBean(jc, config);
340N/A
459N/A //instantiate and register Timer service and resource purger
459N/A createIndexTimer(props);
459N/A log.info("MBeans registered");
340N/A
340N/A // Create and start connector server
1043N/A String urlString = props.getProperty(JMX_URL);
420N/A HashMap<String, Object> env = new HashMap<String, Object>();
1043N/A JMXServiceURL url = new JMXServiceURL(urlString);
1043N/A
1043N/A // If the protocol is RMI we need to have an RMI registry running.
1043N/A // Start an embedded registry if so requested.
1043N/A if (url.getProtocol().equals(RMI_PROTOCOL) &&
1184N/A Boolean.parseBoolean(props.getProperty(RMI_START))) {
1184N/A int rmiport = Integer.parseInt(props.getProperty(RMI_PORT));
1043N/A log.log(Level.FINE, "Starting RMI registry on port {0}", rmiport);
1043N/A LocateRegistry.createRegistry(rmiport);
1043N/A }
1043N/A
1043N/A log.log(Level.FINE, "Starting JMX connector on {0}", urlString);
1035N/A JMXConnectorServer connectorServer =
1035N/A JMXConnectorServerFactory.newJMXConnectorServer(url, env, server);
340N/A
420N/A connectorServer.start();
340N/A
340N/A log.info("OGA is ready and running...");
340N/A }
340N/A
1185N/A private void createIndexTimer(Properties properties) throws JMException {
340N/A
340N/A //instantiate, register and start the Timer service
340N/A ObjectName timer = new ObjectName("service:name=timer");
340N/A server.registerMBean(new Timer(), timer);
340N/A server.invoke(timer, "start", null, null);
340N/A log.info("Started timer service");
340N/A
1462N/A boolean enabled = Boolean.parseBoolean(properties
1462N/A .getProperty(Configuration.PROPERTY_KEY_PREFIX + "management.indexer.enabled"));
1462N/A int period = Integer.parseInt(properties
1462N/A .getProperty(Configuration.PROPERTY_KEY_PREFIX + "management.indexer.sleeptime"));
340N/A log.fine("Indexer enabled: " + enabled);
340N/A log.fine("Indexer period: " + period + " seconds");
340N/A //instantiate and register resource purger
340N/A ObjectName indexRunner = new ObjectName("OGA:name=AgentIndexRunner," + "source=timer");
340N/A server.registerMBean(AgentIndexRunner.getInstance(enabled), indexRunner);
1462N/A // Add index notification to timer (read from
1462N/A // Configuration.PROPERTY_KEY_PREFIX + management.indexer.sleeptime property).
340N/A Date date = new Date(System.currentTimeMillis() + Timer.ONE_SECOND * 5);
340N/A Long longPeriod = Long.valueOf(period * Timer.ONE_SECOND);
340N/A Integer id = (Integer) server.invoke(timer, "addNotification",
340N/A new Object[]{"timer.notification", // Type
340N/A "Time to index again", // Message
340N/A null, // user data
340N/A date, // Start time
340N/A longPeriod, // Period
340N/A },
340N/A new String[]{String.class.getName(),
340N/A String.class.getName(),
340N/A Object.class.getName(),
340N/A Date.class.getName(),
682N/A "long",});
340N/A
340N/A // Add indexer as listener to index notifications
340N/A NotificationFilter filter = new TimerFilter(id);
340N/A server.addNotificationListener(timer, indexRunner, filter, null);
340N/A }
340N/A
657N/A @SuppressWarnings("PMD.SystemPrintln")
682N/A private static boolean createLogger(Properties props) {
682N/A boolean ret = true;
1462N/A String OGAlogpath = props
1462N/A .getProperty(Configuration.PROPERTY_KEY_PREFIX + "management.logging.path");
340N/A
340N/A Level loglevel = null;
340N/A try {
1462N/A loglevel = Level.parse(props
1462N/A .getProperty(Configuration.PROPERTY_KEY_PREFIX + "management.logging.filelevel"));
340N/A } catch (Exception exll) {
340N/A loglevel = Level.FINE;
340N/A }
340N/A Level consoleloglevel = null;
340N/A try {
1462N/A consoleloglevel = Level.parse(props
1462N/A .getProperty(Configuration.PROPERTY_KEY_PREFIX + "management.logging.consolelevel"));
340N/A } catch (Exception excl) {
340N/A consoleloglevel = Level.INFO;
340N/A }
657N/A try {
657N/A OpenGrokLogger.setupLogger(OGAlogpath, loglevel, consoleloglevel);
657N/A } catch (IOException ex) {
1327N/A log.warning("OGAgent failed set up logging: " + ex.getMessage());
682N/A ret = false;
657N/A }
682N/A
682N/A return ret;
340N/A }
340N/A}