package org.opennms.netmgt.snmp.mock;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.opennms.core.concurrent.LogPreservingThreadFactory;
import org.opennms.core.utils.LogUtils;
import org.opennms.netmgt.snmp.CollectionTracker;
import org.opennms.netmgt.snmp.SnmpAgentAddress;
import org.opennms.netmgt.snmp.SnmpAgentConfig;
import org.opennms.netmgt.snmp.SnmpObjId;
import org.opennms.netmgt.snmp.SnmpValue;
import org.opennms.netmgt.snmp.SnmpWalker;
public class MockSnmpWalker extends SnmpWalker {
private static class MockPduBuilder extends WalkerPduBuilder {
private List<SnmpObjId> m_oids = new ArrayList<SnmpObjId>();
public MockPduBuilder(final int maxVarsPerPdu) {
super(maxVarsPerPdu);
reset();
}
@Override
public void reset() {
m_oids.clear();
}
public List<SnmpObjId> getOids() {
return new ArrayList<SnmpObjId>(m_oids);
}
@Override
public void addOid(final SnmpObjId snmpObjId) {
m_oids.add(snmpObjId);
}
@Override
public void setNonRepeaters(final int numNonRepeaters) {
}
@Override
public void setMaxRepetitions(final int maxRepetitions) {
}
}
private static class MockVarBind {
SnmpObjId m_oid;
SnmpValue m_value;
public MockVarBind(SnmpObjId oid, SnmpValue value) {
m_oid = oid;
m_value = value;
}
public SnmpObjId getOid() {
return m_oid;
}
public SnmpValue getValue() {
return m_value;
}
}
private final SnmpAgentAddress m_agentAddress;
private final int m_snmpVersion;
private final PropertyOidContainer m_container;
private final ExecutorService m_executor;
public MockSnmpWalker(final SnmpAgentAddress agentAddress, int snmpVersion, final PropertyOidContainer container, final String name, final CollectionTracker tracker, int maxVarsPerPdu) {
super(agentAddress.getAddress(), name, maxVarsPerPdu, 1, tracker);
m_agentAddress = agentAddress;
m_snmpVersion = snmpVersion;
m_container = container;
m_executor = Executors.newSingleThreadExecutor(
new LogPreservingThreadFactory(getClass().getSimpleName(), 1, false)
);
}
@Override
protected WalkerPduBuilder createPduBuilder(final int maxVarsPerPdu) {
return new MockPduBuilder(maxVarsPerPdu);
}
@Override
protected void sendNextPdu(final WalkerPduBuilder pduBuilder) throws IOException {
final MockPduBuilder builder = (MockPduBuilder)pduBuilder;
final List<SnmpObjId> oids = builder.getOids();
LogUtils.debugf(this, "'Sending' tracker PDU of size " + oids.size());
m_executor.submit(new ResponseHandler(oids));
}
@Override
protected void handleDone() {
LogUtils.debugf(this, "handleDone()");
super.handleDone();
}
@Override
protected void handleAuthError(final String msg) {
LogUtils.debugf(this, "handleAuthError(%s)", msg);
super.handleAuthError(msg);
}
@Override
protected void handleError(final String msg) {
LogUtils.debugf(this, "handleError(%s)", msg);
super.handleError(msg);
}
@Override
protected void handleError(final String msg, final Throwable t) {
LogUtils.debugf(this, t, "handleError(%s, %s)", msg, t.getLocalizedMessage());
super.handleError(msg, t);
}
@Override
protected void handleFatalError(final Throwable e) {
LogUtils.debugf(this, e, "handleFatalError(%s)", e.getLocalizedMessage());
super.handleFatalError(e);
}
@Override
protected void handleTimeout(final String msg) {
LogUtils.debugf(this, "handleTimeout(%s)", msg);
super.handleTimeout(msg);
}
@Override
protected void close() throws IOException {
m_executor.shutdown();
}
@Override
protected void buildAndSendNextPdu() throws IOException {
LogUtils.debugf(this, "buildAndSendNextPdu()");
super.buildAndSendNextPdu();
}
private final class ResponseHandler implements Runnable {
private final List<SnmpObjId> m_oids;
private ResponseHandler(final List<SnmpObjId> oids) {
m_oids = oids;
}
@Override
public void run() {
handleResponses();
}
protected void handleResponses() {
LogUtils.debugf(this, "handleResponses(%s)", m_oids);
try {
if (m_container == null) {
LogUtils.infof(this, "No SNMP response data configured for %s; pretending we've timed out.", m_agentAddress);
Thread.sleep(100);
handleTimeout("No MockSnmpAgent data configured for '" + m_agentAddress + "'.");
return;
}
List<MockVarBind> responses = new ArrayList<MockVarBind>(m_oids.size());
int errorStatus = 0;
int errorIndex = 0;
int index = 1; // snmp index start at 1
for (final SnmpObjId oid : m_oids) {
SnmpObjId nextOid = m_container.findNextOidForOid(oid);
if (nextOid == null) {
LogUtils.debugf(this, "No OID following %s", oid);
if (m_snmpVersion == SnmpAgentConfig.VERSION1) {
if (errorStatus == 0) { // for V1 only record the index of the first failing varbind
errorStatus = CollectionTracker.NO_SUCH_NAME_ERR;
errorIndex = index;
}
}
responses.add(new MockVarBind(oid, MockSnmpValue.END_OF_MIB));
} else {
responses.add(new MockVarBind(nextOid, m_container.findValueForOid(nextOid)));
}
index++;
}
if (!processErrors(errorStatus, errorIndex)) {
LogUtils.debugf(this, "Responding with PDU of size %d.", responses.size());
for(MockVarBind vb : responses) {
processResponse(vb.getOid(), vb.getValue());
}
}
buildAndSendNextPdu();
} catch (final Throwable t) {
handleFatalError(t);
}
}
}
}