/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-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.capsd;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.concurrent.ExecutorService;
import org.opennms.core.utils.BeanUtils;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.daemon.AbstractServiceDaemon;
import org.opennms.netmgt.model.events.StoppableEventListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
/**
* <P>
* The Capability daemon - it is notified by the discovery process when a new
* node is discovered - it then polls for all the capabilities for this node and
* is responsible for loading the data collecte1d into the database.
* </P>
*
* <P>
* Once a node is added to the database, its sends an indication back to the
* discovery which then flags this node as 'known'.
* </P>
*
* @author <A HREF="mailto:mike@opennms.org">Mike Davidson </A>
* @author <A HREF="http://www.opennms.org/">OpenNMS </A>
*/
public class Capsd extends AbstractServiceDaemon {
/**
* Database synchronization lock for synchronizing write access to the
* database between the SuspectEventProcessor and RescanProcessor thread
* pools
*/
private static Object m_dbSyncLock = new Object();
/**
* <P>
* Contains dotted-decimal representation of the IP address where Capsd is
* running. Used when capsd sends events out
* </P>
*/
private static String m_address = null;
/**
* Rescan scheduler thread
*/
@Autowired
private Scheduler m_scheduler;
/**
* Event receiver.
*/
private StoppableEventListener m_eventListener;
/**
* The pool of threads that are used to executed the SuspectEventProcessor
* instances queued by the event processor (BroadcastEventProcessor).
*/
private ExecutorService m_suspectRunner;
/**
* The pool of threads that are used to executed RescanProcessor instances
* queued by the rescan scheduler thread.
*/
private ExecutorService m_rescanRunner;
/*
* Injected properties, the should be asserted in onInit
*/
@Autowired
private SuspectEventProcessorFactory m_suspectEventProcessorFactory;
@Autowired
private CapsdDbSyncer m_capsdDbSyncer;
/**
* <P>
* Static initialization
* </P>
*/
static {
m_address = InetAddressUtils.getLocalHostAddressAsString();
} // end static class initialization
/**
* Constructs the Capsd objec
*/
public Capsd() {
super("OpenNMS.Capsd");
m_scheduler = null;
}
/**
* <p>onStop</p>
*/
protected void onStop() {
// System.err.println("Capsd onStop() dumping stack");
// Thread.dumpStack();
// Stop the broadcast event receiver
m_eventListener.stop();
// Stop the Suspect Event Processor thread pool
m_suspectRunner.shutdown();
// Stop the Rescan Processor thread pool
m_rescanRunner.shutdown();
if (m_scheduler != null) m_scheduler.stop();
}
/**
* <p>onInit</p>
*/
protected void onInit() {
BeanUtils.assertAutowiring(this);
Assert.state(m_suspectRunner != null, "must set the suspectRunner property");
Assert.state(m_rescanRunner != null, "must set the rescanRunner property");
Assert.state(m_eventListener != null, "must set the eventListener property");
if (System.getProperty("org.opennms.provisiond.enableDiscovery", "false").equalsIgnoreCase("true")) {
throw new IllegalStateException("Provisiond is configured to handle discovery events. " +
"Please disable Capsd in service-configuration.xml, or set " +
"org.opennms.provisiond.enableDiscovery=false in opennms.properties!");
}
/*
* First any new services are added to the services table
* with a call to syncServices().
*
* Secondly the management state of interfaces and services
* in the database is updated based on the latest configuration
* information with a call to syncManagementState()
*
* Lastly the primary snmp interface state ('isSnmpPrimary')
* of all interfaces which support SNMP is updated based on
* the latest configuration information via a call to
* syncSnmpPrimaryState()
*/
log().debug("init: Loading services into database...");
m_capsdDbSyncer.syncServices();
log().debug("init: Syncing management state...");
m_capsdDbSyncer.syncManagementState();
log().debug("init: Syncing primary SNMP interface state...");
m_capsdDbSyncer.syncSnmpPrimaryState();
}
/**
* <p>onStart</p>
*/
protected void onStart() {
// System.err.println("Capsd onStart() dumping stack");
// Thread.dumpStack();
// Set the Set that SuspectEventProcessor will use to track
// suspect scans that are in progress
SuspectEventProcessor.setQueuedSuspectsTracker(new HashSet<String>());
// Likewise, a separate Set for the RescanProcessor
RescanProcessor.setQueuedRescansTracker(new HashSet<Integer>());
// Start the rescan scheduler
log().debug("start: Starting rescan scheduler");
m_scheduler.start();
}
/**
* <p>onPause</p>
*/
protected void onPause() {
// XXX Pause all threads?
}
/**
* <p>onResume</p>
*/
protected void onResume() {
// XXX Resume all threads?
}
/**
* Used to retrieve the local host name/address. The name/address of the
* machine on which Capsd is running.
*
* @return a {@link java.lang.String} object.
*/
public static String getLocalHostAddress() {
return m_address;
}
static Object getDbSyncLock() {
return m_dbSyncLock;
}
/**
* This method is used by other managed beans to forward an IP Address for
* capability scanning. The If the interface converts properly then it is
* scanned as a suspect interface for the discovery of all the services and
* other interfaces that exists on the node.
*
* @param ifAddr
* The address of the suspect interface.
* @throws java.net.UnknownHostException
* Thrown if the address cannot be converted to aa proper
* internet address.
*/
public void scanSuspectInterface(final String ifAddr) throws UnknownHostException {
final String prefix = ThreadCategory.getPrefix();
try {
ThreadCategory.setPrefix(getName());
final InetAddress addr = InetAddressUtils.addr(ifAddr);
final SuspectEventProcessor proc = m_suspectEventProcessorFactory.createSuspectEventProcessor(InetAddressUtils.str(addr));
proc.run();
} finally {
ThreadCategory.setPrefix(prefix);
}
}
/**
* This method is used to force an existing node to be capability rescanned.
* The main reason for its existence is as a hook for JMX managed beans to
* invoke forced rescans allowing the main rescan logic to remain in the
* capsd agent.
*
* @param nodeId
* The node identifier from the database.
*/
public void rescanInterfaceParent(Integer nodeId) {
String prefix = ThreadCategory.getPrefix();
try {
ThreadCategory.setPrefix(getName());
m_scheduler.forceRescan(nodeId.intValue());
} finally {
ThreadCategory.setPrefix(prefix);
}
}
/**
* <p>setSuspectRunner</p>
*
* @param suspectRunner a {@link java.util.concurrent.ExecutorService} object.
*/
public void setSuspectRunner(ExecutorService suspectRunner) {
m_suspectRunner = suspectRunner;
}
/**
* <p>setRescanRunner</p>
*
* @param rescanRunner a {@link java.util.concurrent.ExecutorService} object.
*/
public void setRescanRunner(ExecutorService rescanRunner) {
m_rescanRunner = rescanRunner;
}
/**
* <p>setEventListener</p>
*
* @param eventListener a {@link org.opennms.netmgt.model.events.StoppableEventListener} object.
*/
public void setEventListener(StoppableEventListener eventListener) {
m_eventListener = eventListener;
}
} // end Capsd class