//
// This file is part of the OpenNMS(R) Application.
//
// OpenNMS(R) is Copyright (C) 2002-2009 The OpenNMS Group, Inc. All rights reserved.
// OpenNMS(R) is a derivative work, containing both original code, included code and modified
// code that was published under the GNU General Public License. Copyrights for modified
// and included code are below.
//
// OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
//
// Modifications:
//
// 2009 Oct 01: test for null interface in handleInerfaceDeleted. - ayres@opennms.org
// 2003 Oct 21: Fixed typo in variable name.
// 2003 Jan 31: Cleaned up some unused imports.
//
// Original code base Copyright (C) 1999-2001 Oculan Corp. All rights reserved.
//
// This program 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 2 of the License, or
// (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// For more information contact:
// OpenNMS Licensing <license@opennms.org>
// http://www.opennms.org/
// http://www.opennms.com/
//
// Tab Size = 8
//
package org.infosec.ismp.discovery;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.ValidationException;
import org.infosec.ismp.daemon.AbstractServiceDaemon;
import org.infosec.ismp.eventd.EventIpcManagerFactory;
import org.infosec.ismp.model.event.Event;
import org.infosec.ismp.model.event.EventBuilder;
import org.infosec.ismp.model.event.EventConstants;
import org.infosec.ismp.model.event.EventForwarder;
import org.infosec.ismp.ping.Pinger;
import org.springframework.util.Assert;
/**
*
* @author <a href="mailto:lianglin1979@sjtu.edu.cn">lianglin</a>
*
*/
public class Discovery extends AbstractServiceDaemon {
/**
* The callback that sends newSuspect events upon successful ping response.
*/
private static final DiscoveryPingResponseCallback cb = new DiscoveryPingResponseCallback();
private static final int PING_IDLE = 0;
private static final int PING_RUNNING = 1;
private static final int PING_FINISHING = 2;
/**
* The SQL query used to get the list of managed IP addresses from the database
*/
private static final String ALL_IP_ADDRS_SQL = "SELECT DISTINCT ipAddr FROM ipInterface WHERE isManaged <> 'D'";
/**
* a set of devices to skip discovery on
*/
private final Set<String> m_alreadyDiscovered = Collections
.synchronizedSet(new HashSet<String>());
private Timer m_timer;
private int m_xstatus = PING_IDLE;
private volatile EventForwarder m_eventForwarder;
public void setEventForwarder(EventForwarder eventForwarder) {
m_eventForwarder = eventForwarder;
}
public EventForwarder getEventForwarder() {
return m_eventForwarder;
}
/**
* Constructs a new discovery instance.
*/
public Discovery() {
super("OpenNMS.Discovery");
}
@Override
protected void onInit() throws IllegalStateException {
Assert.state(m_eventForwarder != null,
"must set the eventForwarder property");
try {
initializeConfiguration();
EventIpcManagerFactory.init();
} catch (Exception e) {
log().debug("onInit: initialization failed: " + e, e);
throw new IllegalStateException(
"Could not initialize discovery configuration.", e);
}
}
private void initializeConfiguration() throws MarshalException,
ValidationException, IOException {
// TODO
}
private void doPings() {
debugf("starting ping sweep");
try {
initializeConfiguration();
} catch (Exception e) {
log().error(
"doPings: could not re-init configuration, continuing with in memory configuration."
+ e, e);
}
m_xstatus = PING_RUNNING;
for (IPPollAddress pollAddress : getDiscoveryFactory()
.getConfiguredAddresses()) {
if (m_xstatus == PING_FINISHING || m_timer == null) {
m_xstatus = PING_IDLE;
return;
}
ping(pollAddress);
try {
// FIXME
Thread.sleep(100);
} catch (InterruptedException e) {
break;
}
}
debugf("finished discovery sweep");
m_xstatus = PING_IDLE;
}
private void ping(IPPollAddress pollAddress) {
InetAddress address = pollAddress.getAddress();
if (address != null) {
if (!isAlreadyDiscovered(address)) {
try {
Pinger.ping(address, pollAddress.getTimeout(),
pollAddress.getRetries(), (short) 1, cb);
} catch (Exception e) {
debugf(e, "error pinging %s", address.getAddress());
}
}
}
}
private boolean isAlreadyDiscovered(InetAddress address) {
if (m_alreadyDiscovered.contains(address.getHostAddress())) {
return true;
}
return false;
}
private void startTimer() {
if (m_timer != null) {
debugf("startTimer() called, but a previous timer exists; making sure it's cleaned up");
m_xstatus = PING_FINISHING;
m_timer.cancel();
}
debugf("scheduling new discovery timer");
m_timer = new Timer("Discovery.Pinger", true);
TimerTask task = new TimerTask() {
@Override
public void run() {
doPings();
}
};
// FIXME
m_timer.scheduleAtFixedRate(task, 1000, 60 * 1000);
}
private void stopTimer() {
if (m_timer != null) {
debugf("stopping existing timer");
m_xstatus = PING_FINISHING;
m_timer.cancel();
m_timer = null;
} else {
debugf("stopTimer() called, but there is no existing timer");
}
}
@Override
protected void onStart() {
syncAlreadyDiscovered();
startTimer();
}
@Override
protected void onStop() {
stopTimer();
}
@Override
protected void onPause() {
stopTimer();
}
@Override
protected void onResume() {
startTimer();
}
protected void syncAlreadyDiscovered() {
// 从数据库中读取已知节点
log().info(
"syncAlreadyDiscovered initialized list of managed IP addresses with "
+ m_alreadyDiscovered.size() + " members");
}
public void handleDiscoveryConfigurationChanged(Event event) {
log().info(
"handleDiscoveryConfigurationChanged: handling message that a change to configuration happened...");
reloadAndReStart();
}
private void reloadAndReStart() {
EventBuilder ebldr = null;
try {
initializeConfiguration();
ebldr = new EventBuilder(
EventConstants.RELOAD_DAEMON_CONFIG_SUCCESSFUL_UEI,
getName());
ebldr.addParam(EventConstants.PARM_DAEMON_NAME, "Discovery");
this.stop();
this.start();
} catch (MarshalException e) {
fatalf(e,
"Unable to initialize the discovery configuration factory");
ebldr = new EventBuilder(
EventConstants.RELOAD_DAEMON_CONFIG_FAILED_UEI, getName());
ebldr.addParam(EventConstants.PARM_DAEMON_NAME, "Discovery");
ebldr.addParam(EventConstants.PARM_REASON, e.getLocalizedMessage()
.substring(0, 128));
} catch (ValidationException e) {
fatalf(e,
"Unable to initialize the discovery configuration factory");
ebldr = new EventBuilder(
EventConstants.RELOAD_DAEMON_CONFIG_FAILED_UEI, getName());
ebldr.addParam(EventConstants.PARM_DAEMON_NAME, "Discovery");
ebldr.addParam(EventConstants.PARM_REASON, e.getLocalizedMessage()
.substring(0, 128));
} catch (IOException e) {
fatalf(e,
"Unable to initialize the discovery configuration factory");
ebldr = new EventBuilder(
EventConstants.RELOAD_DAEMON_CONFIG_FAILED_UEI, getName());
ebldr.addParam(EventConstants.PARM_DAEMON_NAME, "Discovery");
ebldr.addParam(EventConstants.PARM_REASON, e.getLocalizedMessage()
.substring(0, 128));
}
m_eventForwarder.sendNow(ebldr.getEvent());
}
public void reloadDaemonConfig(Event e) {
log().info("reloadDaemonConfig: processing reload daemon event...");
if (isReloadConfigEventTarget(e)) {
reloadAndReStart();
}
log().info("reloadDaemonConfig: reload daemon event processed.");
}
private boolean isReloadConfigEventTarget(Event event) {
boolean isTarget = false;
Map<String, String> params = event.getParams();
for (Map.Entry<String, String> parm : params.entrySet()) {
if (EventConstants.PARM_DAEMON_NAME.equals(parm.getKey())
&& "Discovery".equalsIgnoreCase(parm.getValue())) {
isTarget = true;
break;
}
}
log().debug(
"isReloadConfigEventTarget: discovery was target of reload event: "
+ isTarget);
return isTarget;
}
public void handleInterfaceDeleted(Event event) {
if (event.getNetInterface() != null) {
// remove from known nodes
m_alreadyDiscovered.remove(event.getNetInterface());
debugf("Removed %s from known node list", event.getNetInterface());
}
}
public void handleDiscoveryResume(Event event) {
try {
resume();
} catch (IllegalStateException ex) {
}
}
public void handleDiscoveryPause(Event event) {
try {
pause();
} catch (IllegalStateException ex) {
}
}
public void handleNodeGainedInterface(Event event) {
// add to known nodes
m_alreadyDiscovered.add(event.getNetInterface());
debugf("Added %s as discovered", event.getNetInterface());
}
}