/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2008-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.vmmgr; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; import java.net.URL; import java.util.List; import java.util.Properties; import java.util.TreeMap; import java.util.Map.Entry; import javax.management.MBeanServer; import org.apache.commons.io.IOUtils; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.DOMConfigurator; import org.opennms.core.utils.LogUtils; import org.opennms.core.utils.ThreadCategory; import org.opennms.netmgt.config.service.Service; import org.opennms.netmgt.config.service.types.InvokeAtType; /** * <p> * The Manager is reponsible for launching/starting all services in the VM * that it is started for. The Manager operates in two modes, normal and * server * </p> * <p> * normal mode: In the normal mode, the Manager starts all services configured * for its VM in the service-configuration.xml and starts listening for * control events on the 'control-broadcast' JMS topic for stop control * messages for itself * </p> * <p> * server mode: In the server mode, the Manager starts up and listens on the * 'control-broadcast' JMS topic for 'start' control messages for services in * its VM and a stop control messge for itself. When a start for a service is * received, it launches only that service and sends a successful 'running' or * an 'error' response to the Controller * </p> * <p> * <strong>Note: </strong>The Manager is NOT intelligent - if it receives a * stop control event, it will exit - does not check to see if the services * its started are all stopped * <p> * * @author <a href="mailto:weave@oculan.com">Brian Weaver</a> * @author <a href="mailto:sowmya@opennms.org">Sowmya Nataraj</a> * @author <a href="http://www.opennms.org">OpenNMS.org</a> * @author <a href="mailto:weave@oculan.com">Brian Weaver</a> * @author <a href="mailto:sowmya@opennms.org">Sowmya Nataraj</a> * @author <a href="http://www.opennms.org">OpenNMS.org</a> * @author <a href="mailto:weave@oculan.com">Brian Weaver</a> * @author <a href="mailto:sowmya@opennms.org">Sowmya Nataraj</a> * @author <a href="http://www.opennms.org">OpenNMS.org</a> * @version $Id: $ */ public class Starter { /** * The log4j category used to log debug messsages and statements. */ private static final String LOG4J_CATEGORY = "OpenNMS.Manager"; private void setLogPrefix() { ThreadCategory.setPrefix(LOG4J_CATEGORY); } private ThreadCategory log() { return ThreadCategory.getInstance(getClass()); } /** * <p>startDaemon</p> */ public void startDaemon() { configureLog4j(); setLogPrefix(); setupMx4jLogger(); loadGlobalProperties(); setDefaultProperties(); start(); } private void setupMx4jLogger() { mx4j.log.Log.redirectTo(new mx4j.log.Log4JLogger()); } private void configureLog4j() { File homeDir = new File(System.getProperty("opennms.home")); File etcDir = new File(homeDir, "etc"); File xmlFile = new File(etcDir, "log4j.xml"); if (xmlFile.exists()) { DOMConfigurator.configureAndWatch(xmlFile.getAbsolutePath()); } else { File propertiesFile = new File(etcDir, "log4j.properties"); if (propertiesFile.exists()) { PropertyConfigurator.configureAndWatch(propertiesFile.getAbsolutePath()); } else { die("Could not find a Log4j configuration file at " + xmlFile.getAbsolutePath() + " or " + propertiesFile.getAbsolutePath() + ". Exiting."); } } /* * This is causing infinite recursion on exit * CaptchaStds.captchaStdOut(); */ } private void setDefaultProperties() { setupFileResourceProperty("opennms.library.jicmp", System.mapLibraryName("jicmp"), "Initialization of ICMP socket will likely fail."); setupFileResourceProperty("opennms.library.jrrd", System.mapLibraryName("jrrd"), "Initialization of RRD code will likely fail if the JniRrdStrategy is used."); setupFileResourceProperty("jcifs.properties", "jcifs.properties", "Initialization of JCIFS will likely fail or may be improperly configured."); } private void setupFileResourceProperty(String propertyName, String file, String notFoundWarning) { if (System.getProperty(propertyName) == null) { log().debug("System property '" + propertyName + "' not set. Searching for file '" + file + "' in the class path."); URL url = getClass().getClassLoader().getResource(file); if (url != null) { log().info("Found file '" + file + "' at '" + url.getPath() + "'. Setting '" + propertyName + "' to this path."); System.setProperty(propertyName, url.getPath()); } else { log().warn("Did not find file '" + file + "' in the class path. " + notFoundWarning + " Set the property '" + propertyName + "' to the location of the file."); } } else { log().debug("System property '" + propertyName + "' already set to '" + System.getProperty(propertyName) + "'."); } } private void loadGlobalProperties() { // Log system properties, sorted by property name TreeMap<Object, Object> sortedProps = new TreeMap<Object, Object>(System.getProperties()); for (Entry<Object, Object> entry : sortedProps.entrySet()) { log().debug("System property '" + entry.getKey() + "' already set to value '" + entry.getValue() + "'."); } File propertiesFile = getPropertiesFile(); if (!propertiesFile.exists()) { // don't require the file return; } Properties props = new Properties(); InputStream in = null; try { in = new FileInputStream(propertiesFile); props.load(in); } catch (IOException e) { die("Error trying to read properties file '" + propertiesFile + "': " + e, e); } finally { IOUtils.closeQuietly(in); } for (Entry<Object, Object> entry : props.entrySet()) { String systemValue = System.getProperty(entry.getKey().toString()); if (systemValue != null) { log().debug("Property '" + entry.getKey() + "' from " + propertiesFile + " already exists as a system property (with value '" + systemValue + "'). Not overridding existing system property."); } else { log().debug("Setting system property '" + entry.getKey() + "' to '" + entry.getValue() + "' from " + propertiesFile + "."); System.setProperty(entry.getKey().toString(), entry.getValue().toString()); } } if (props.containsKey("networkaddress.cache.ttl")) { java.security.Security.setProperty("networkaddress.cache.ttl", props.getProperty("networkaddress.cache.ttl")); } else { java.security.Security.setProperty("networkaddress.cache.ttl", "120"); } } /** * Print out a message and stack trace and then exit. * This method does not return. * * @param message message to print to System.err * @param t Throwable for which to print a stack trace */ private void die(String message, Throwable t) { LogUtils.errorf(this, t, message); System.exit(1); } private void die(String message) { die(message, null); } private File getPropertiesFile() { String homeDir = System.getProperty("opennms.home"); File etcDir = new File(homeDir, "etc"); File propertiesFile = new File(etcDir, "opennms.properties"); return propertiesFile; } private void start() { log().debug("Beginning startup"); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); Invoker invoker = new Invoker(); invoker.setServer(server); invoker.setAtType(InvokeAtType.START); List<InvokerService> services = InvokerService.createServiceList(Invoker.getDefaultServiceConfigFactory().getServices()); invoker.setServices(services); invoker.instantiateClasses(); List<InvokerResult> resultInfo = invoker.invokeMethods(); for (InvokerResult result : resultInfo) { if (result != null && result.getThrowable() != null) { Service service = result.getService(); String name = service.getName(); String className = service.getClassName(); String message = "An error occurred while attempting to start the \"" + name + "\" service (class " + className + "). " + "Shutting down and exiting."; log().fatal(message, result.getThrowable()); System.err.println(message); result.getThrowable().printStackTrace(); Manager manager = new Manager(); manager.stop(); manager.doSystemExit(); // Shouldn't get here return; } } log().debug("Startup complete"); } }