In this article let’s discuss about creating a SNMP Agent using JDMK api.
Consider a scenario where you want to monitor your java application. You can do so by creating a SNMP agent and MIB. Now using the MIB you can query the SNMP agent to retrieve the status of your application. We can create the SNMP agent using JDMK (Java Dynamic Management Kit) api. We can also send SNMP traps using the same.
First let’s create a MIB and a sample SNMP agent using JDMK. Consider the following MIB.
Test-MIB.mib
IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, Counter32, enterprises
FROM SNMPv2-SMI
DisplayString, TEXTUAL-CONVENTION
FROM SNMPv2-TC
MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
FROM SNMPv2-CONF;
-- Module Identity
------------------
test-mib MODULE-IDENTITY
LAST-UPDATED "201010240000Z"
-- Format is "YYYYMMDDhhmmZ"
ORGANIZATION "techdive.in"
CONTACT-INFO "techdive.in
http://techdive.in"
::= { testAppMgt 1 }
-- Enterprise OIDs
------------------
test OBJECT IDENTIFIER ::= { enterprises 11 }
testAppMgt OBJECT IDENTIFIER ::= { test 19 }
-- Textual Conventions
----------------------
SysTimeMillis64TC ::= TEXTUAL-CONVENTION
STATUS current
DESCRIPTION
"An elapsed time, expressed in milli-seconds (ms).
This type is based on Counter64.
"
SYNTAX Counter64
-- OBJECT-TYPE OID tree
-----------------------
testMgtMIBInfo
OBJECT IDENTIFIER ::= { test-mib 1 }
testMgtMIBDBStatus
OBJECT IDENTIFIER ::= { test-mib 2 }
testMgtMIBDBNotifs
OBJECT IDENTIFIER ::= { test-mib 3 }
--
-- Server Informations
--
appVersion OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Sytem Version"
::= { testMgtMIBInfo 2 }
sysUpTime OBJECT-TYPE
SYNTAX TimeTicks
ACCESS read-only
STATUS mandatory
DESCRIPTION
"The time since the
network management portion of the system was last
re-initialized."
::= { testMgtMIBInfo 3 }
userCount OBJECT-TYPE
SYNTAX Counter32
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Number of registered users in the system"
::= { testMgtMIBInfo 4 }
dbStatus OBJECT-TYPE
SYNTAX INTEGER { started(1), shutdown(2)}
MAX-ACCESS read-only
STATUS current
DESCRIPTION
" Database Status 1 - Started, 2 - Shutdown "
::= { testMgtMIBDBStatus 1 }
--
-- NOTIFICATIONS
--
dbStartNotification NOTIFICATION-TYPE
OBJECTS { dbStatus}
STATUS current
DESCRIPTION
"DB Started"
::= { testMgtMIBDBNotifs 1 }
dbDownNotification NOTIFICATION-TYPE
OBJECTS { dbStatus }
STATUS current
DESCRIPTION
"DB down"
::= { testMgtMIBDBNotifs 2 }
END
The above MIB is contains details such as appVersion, sysUpTime, userCount which are to be provided by the SNMP agent when queried (SNMP get, SNMP getNext) by the SNMP manager. It is also provides details of what are all the notifications which are to be sent based on certain events. Whenever the database is started or shutdown the application can send SNMP traps to the configured trap receiver.
Now download JDMK api binary version from net. You will find a tool mibgen inside the downloaded package. We need to create corresponding Java classes for the above mib Test-MIB.mib. We can create those classes using the following command
The following classes will be autogenerated
Test_MIB.java
Test_MIBOidTable.java
TestMgtMIBDBStatus.java
TestMgtMIBDBStatusMBean.java
TestMgtMIBDBStatusMeta.java
TestMgtMIBInfo.java
TestMgtMIBInfoMBean.java
TestMgtMIBInfoMeta.java
Out of the above java classes we need to extend Test_MIB.java, TestMgtMIBDBStatus.java and TestMgtMIBInfo.java.
Consider the following class ApplMgtMIBInfoImpl.java which extends from TestMgtMIBInfo.
ApplMgtMIBInfoImpl.java
import com.sun.management.snmp.SnmpStatusException;
import com.sun.management.snmp.agent.SnmpMib;
public class ApplMgtMIBInfoImpl extends TestMgtMIBInfo
{
/*
* (non-Javadoc)
* @see com.sn.TestMgtMIBInfo#getUserCount()
*/
@Override
public Long getUserCount() throws SnmpStatusException
{
return 20L;
}
/*
* (non-Javadoc)
* @see com.sn.TestMgtMIBInfo#getSysUpTime()
*/
@Override
public Long getSysUpTime() throws SnmpStatusException
{
return 5000L;
}
/*
* (non-Javadoc)
* @see com.sn.TestMgtMIBInfo#getAppVersion()
*/
@Override
public String getAppVersion() throws SnmpStatusException
{
return "2.0";
}
public ApplMgtMIBInfoImpl()
{
this(null);
}
/**
* @param myMib
*/
public ApplMgtMIBInfoImpl(SnmpMib myMib)
{
super(myMib);
}
/**
* @param myMib
* @param server
*/
public ApplMgtMIBInfoImpl(SnmpMib myMib, MBeanServer server)
{
super(myMib, server);
}
}
The above class provides customized implementation for appVersion, userCount and sysUptime SNMP variables.
Consider the class ApplMgtMIBDBStatusImpl as follows.
ApplMgtMIBDBStatusImpl.java
import javax.management.MBeanServer;
import com.sun.management.snmp.SnmpInt;
import com.sun.management.snmp.SnmpOid;
import com.sun.management.snmp.SnmpOidRecord;
import com.sun.management.snmp.SnmpStatusException;
import com.sun.management.snmp.SnmpVarBind;
import com.sun.management.snmp.SnmpVarBindList;
import com.sun.management.snmp.agent.SnmpMib;
public class ApplMgtMIBDBStatusImpl extends TestMgtMIBDBStatus
{
private static final long serialVersionUID = -7094115679131109484L;
private static boolean dbFlag = false;
private String inetAddress = "127.0.0.1";
/**
* @return the inetAddress
*/
public String getInetAddress()
{
return inetAddress;
}
/**
* @param inetAddress
* the inetAddress to set
*/
public void setInetAddress(String inetAddress)
{
this.inetAddress = inetAddress;
}
public ApplMgtMIBDBStatusImpl()
{
this(null);
}
/**
* @param myMib
*/
public ApplMgtMIBDBStatusImpl(SnmpMib myMib)
{
super(myMib);
}
/**
* @param myMib
* @param server
*/
public ApplMgtMIBDBStatusImpl(SnmpMib myMib, MBeanServer server)
{
super(myMib, server);
}
/*
* (non-Javadoc)
* @see com.sn.TestMgtMIBDBStatus#getDbStatus()
*/
@Override
public EnumDbStatus getDbStatus() throws SnmpStatusException
{
if (dbFlag == false)
{
dbFlag = true;
return new EnumDbStatus(2);
}
else
{
dbFlag = false;
return new EnumDbStatus(1);
}
}
/**
* This method should be called to send notification snmp trap for DB startup
*/
public void sendTrapDBStarted()
{
System.out.println("Sending SNMP Trap to indicate DB startup");
sendTrap("dbStartNotification", new EnumDbStatus(1));
}
/**
* This method should be called to send notification snmp trap for DB Shutdown
*/
public void sendTrapDBDown()
{
System.out.println("Sending SNMP Trap to indicate DB Shutdown");
sendTrap("dbDownNotification", new EnumDbStatus(2));
}
/**
* Send SNMP v2 traps with the generic number of the trap
*/
private void sendTrap(String snmpVarName, EnumDbStatus snmpVarValue)
{
if (TestSNMPAgent.getSnmpAdaptor() == null)
{
return;
}
SnmpVarBindList varBindList = new SnmpVarBindList();
Test_MIBOidTable oidTable = new Test_MIBOidTable();
SnmpOidRecord oid;
try
{
oid = oidTable.resolveVarName(snmpVarName);
SnmpOid oid1 = new SnmpOid(oid.getOid());
SnmpVarBind varBind1 = new SnmpVarBind(oid1, new SnmpInt(snmpVarValue));
varBindList.addVarBind(varBind1);
try
{
System.out.println("Calling TestSNMPAgent for sending Trap to " + inetAddress + " with "
+ varBindList.toString());
// sending snmpV2 trap
TestSNMPAgent.getSnmpAdaptor().snmpV2Trap(InetAddress.getByName(inetAddress), "public", oid1,
varBindList);
}
catch (Exception e3)
{
System.out.println("Error sending SNMP v2 trap." + e3);
}
}
catch (SnmpStatusException e)
{
System.out.println("Error : SnmpStatusException " + e);
}
}
}
It contains customized implementation for providing DB status and also methods to send SNMP trap notifications whenever there is DB startup and shutdown event.
Now let’s see the custom implementation for Test_MIB.java, using the following class Test_MIBImpl.
Test_MIBImpl.java
import javax.management.ObjectName;
public class Test_MibImpl extends Test_MIB
{
private ApplMgtMIBDBStatusImpl applMgtMIBDBStatusImpl;
private ApplMgtMIBInfoImpl applMgtMIBInfoImpl;
public Test_MibImpl()
{
}
public Test_MibImpl(ApplMgtMIBDBStatusImpl applMgtMIBDBStatusImpl, ApplMgtMIBInfoImpl applMgtMIBInfoImpl)
{
super();
this.applMgtMIBDBStatusImpl = applMgtMIBDBStatusImpl;
this.applMgtMIBInfoImpl = applMgtMIBInfoImpl;
}
protected Object createTestMgtMIBDBStatusMBean(String groupName, String groupOid, ObjectName groupObjname,
MBeanServer server)
{
return applMgtMIBDBStatusImpl;
}
protected Object createTestMgtMIBInfoMBean(String groupName, String groupOid, ObjectName groupObjname,
MBeanServer server)
{
return applMgtMIBInfoImpl;
}
}
The above class overrides api methods to return custom class instances which we have implemented like ApplMgtMIBInfoImpl and ApplMgtMIBDBStatusImpl. Now its time to create the SNMP agent using the auto generated classes by JDMK api and the above classes implemented by us.
TestSNMPAgent.java
import java.sql.Connection;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import com.sun.management.comm.SnmpAdaptorServer;
public class TestSNMPAgent
{
static SnmpAdaptorServer snmpAdaptor = null;
/**
* @return the snmpAdaptor
*/
public static SnmpAdaptorServer getSnmpAdaptor()
{
return snmpAdaptor;
}
/**
* @param snmpAdaptor
* the snmpAdaptor to set
*/
public static void setSnmpAdaptor(SnmpAdaptorServer snmpAdaptor)
{
TestSNMPAgent.snmpAdaptor = snmpAdaptor;
}
private Test_MIB test_mib;
/**
* @return the test_mib
*/
public Test_MIB getTest_mib()
{
return test_mib;
}
/**
* @param test_mib
* the test_mib to set
*/
public void setTest_mib(Test_MIB test_mib)
{
this.test_mib = test_mib;
}
public TestSNMPAgent()
{
}
public TestSNMPAgent(Test_MIB test_mib)
{
this.test_mib = test_mib;
}
/**
* @param args
*/
public void init()
{
System.out.println("into snmpagent");
final MBeanServer server;
final ObjectName snmpObjName;
final ObjectName mibObjName;
int snmpPort = 161;
try
{
server = MBeanServerFactory.createMBeanServer();
String domain = server.getDefaultDomain();
// Create and start the SNMP adaptor.
snmpObjName = new ObjectName(domain + ":class=SnmpAdaptorServer,protocol=snmp,port=" + snmpPort);
snmpAdaptor = new SnmpAdaptorServer(snmpPort);
server.registerMBean(snmpAdaptor, snmpObjName);
snmpAdaptor.start();
// The rest of the code is specific to our SNMP agent
// Send a coldStart SNMP Trap (use port = snmpPort+1)
// Trap communities are defined in the ACL file
snmpAdaptor.setTrapPort(new Integer(snmpPort + 1));
snmpAdaptor.snmpV1Trap(0, 0, null);
// Create the Test_MIB and add it to the MBean server.
mibObjName = new ObjectName("snmp:class=Test_MIB");
Test_MIB mib2 = new Test_MIB();
// The MBean will register all group and table entry MBeans
// during its pre-registration
server.registerMBean(test_mib, mibObjName);
// Bind the SNMP adaptor to the MIB
// snmpAdaptor.addMib(test_mib);
test_mib.setSnmpAdaptor(snmpAdaptor);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
In the above class, consider the init method, it creates a snmpAdaptor and registers it with MBeanServer. Then it starts the SNMP adaptor, sends a SNMP trap to the trap receiver as a part of initialization. It then creates an instance of Test_MIB and registers the same with MBeanServer.
Since snmpdaptor is registered with MBeanServer it can be accessed through JMX. Ok its time to start the SNMP agent, so that it can be accessed externally from an SNMP manager.
ApplMonitor.java
public class ApplMonitor
{
public ApplMonitor()
{
}
/**
* @param args
*/
public static void main(String[] args)
{
ApplMgtMIBDBStatusImpl applMgtMIBDBStatusImpl =
new ApplMgtMIBDBStatusImpl();
ApplMgtMIBInfoImpl applMgtMIBInfoImpl = new ApplMgtMIBInfoImpl();
TestSNMPAgent testSn =
new TestSNMPAgent
(new Test_MibImpl(applMgtMIBDBStatusImpl,applMgtMIBInfoImpl));
testSn.init();
sleep();
applMgtMIBDBStatusImpl.sendTrapDBStarted();
sleep();
applMgtMIBDBStatusImpl.sendTrapDBDown();
}
public static void sleep()
{
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
The main method in the above class initiates the SNMP agent using the Test_MibImpl.init() method. It also calls sendTrapDBStarted() and sendTrapDBDown() methods in ApplMgtMIBDBStatusImpl class to send SNMP trap notifications for db startup and shutdown events.
You can use any MIB browser by downloading from net to do SNMP operations for the given MIB. Also download any trap receiver tool to receive traps for db events.