The Java Management extensions specify the SNMP manager API for implementing an SNMP manager application in the Java programming language. This API is covered in the JMX specification and in the Javadoc API provided with the Java Dynamic Management Kit (see "Related Books" in the preface for more information). Here we explain the example applications that use this API.
The SNMP manager API can be used to access any SNMP agent, not just those developed with the Java Dynamic Management Kit. The manager only requires a definition of the MIB that it will access. We generate the class representing the OID table from the MIB file using the mibgen tool.
The complete source code for these applications is available in the Snmp/Manager example directory located in the main examplesDir (see "Directories and Classpath" in the preface).
Contents:
"The Synchronous Manager Example" shows the simplest way to program an SNMP manager in the Java programming language
"The Asynchronous Manager Example" demonstrates the more advanced features of the SNMP manager API
The synchronous SNMP manager is the simplest to program. The manager sends a request to an agent (peer) and waits a given timeout period for the answer. During the wait, the manager is blocked, and when the timeout delay expires, the manager can see if the request was answered or not.
A manager issues requests on variables identified by their full OID. If it has initialized the OID table description of the MIB it will access, it can also refer to the variables by their name. To do this, the manager should call the setSnmpOidTable method of the static SnmpOid object. It should pass in the OID table object instantiated from the SnmpOidTableSupport sub-class generated by the mibgen tool when "compiling" the MIB.
The SNMP manager API specifies the SnmpPeer object for describing an agent, and the SnmpParameters object for describing its read-write communities and its protocol version (SNMPv1 or SNMPv2). The SnmpSession is an object for sending requests and we can associate a default peer to it. The session instance has an SnmpOptions field which we can use to set multiplexing and error fixing behavior.
The objects specified by the SNMP manager API are not MBeans and cannot be registered in an MBean server to create a manager that could be controlled remotely. However, you could write an MBean that uses these classes to retrieve and expose information from SNMP agents.
A manager can contain any number of peers, one for each agent it wishes to access, and any number of sessions, one for each type of behavior it wishes to implement. Once the peers and the sessions are initialized, the manager can build lists of variables and send session requests to operate on them. The session returns a request object, and the manager calls its waitForCompletion method with the desired timeout delay.
Finally, the manager analyzes the result of the request, first to see if there were any errors, then to extract the data returned by the request.
Here is the code of the main method of the SimpleManager application. It performs all of the above steps to perform a very simple management operation.
// read the command line parameters String host = argv[0]; String port = argv[1]; // Specify the OidTable containing all the MIB II knowledge // Use the OidTable generated by mibgen when compiling MIB II // SnmpOidTableSupport oidTable = new RFC1213_MIBOidTable(); SnmpOid.setSnmpOidTable(oidTable); SnmpPeer agent = new SnmpPeer(host, Integer.parseInt(port)); // When creating the parameter object, you can specify the // read and write community to be used when querying the agent. SnmpParameters params = new SnmpParameters("public", "private"); agent.setSnmpParam(params); SnmpSession session = new SnmpSession("SimpleManager session"); // When invoking a service provided by the SnmpSession, it // will use the default peer if none is specified explicitly session.setDefaultPeer(agent); // Build the list of variables you want to query. // For debugging, you can associate a name to your list. SnmpVarbindList list= new SnmpVarbindList( "SimpleManager varbind list"); // We want to read the "sysDescr" variable. list.addVariable("sysDescr.0"); // Make the SNMP get request and wait for the result. SnmpRequest request = session.snmpGet(null, list); boolean completed = request.waitForCompletion(10000); // Check for a timeout of the request. if (completed == false) { java.lang.System.out.println( "Request timed out. Check reachability of agent"); java.lang.System.exit(0); } // Check if the response contains an error. int errorStatus = request.getErrorStatus(); if (errorStatus != SnmpDefinitions.snmpRspNoError) { java.lang.System.out.println("Error status = " + SnmpRequest.snmpErrorToString(errorStatus)); java.lang.System.out.println("Error index = " + request.getErrorIndex()); java.lang.System.exit(0); } // Now we can extract the content of the result. SnmpVarbindList result = request.getResponseVbList(); java.lang.System.out.println("Result: \n" + result); // End the session properly and we're done session.destroySession(); java.lang.System.exit(0); |
In the examplesDir/Snmp/Manager directory, we first need to generate the OID table description of MIB-II that our manager will access. Then we compile the example classes. To set up your environment, see "Directories and Classpath" in the preface.
$ mibgen -mo -d . mib_II.txt [output omitted] $ javac -classpath classpath -d . *.java |
Make sure that no other agent is running on port 8085, and launch the simple SNMP agent in examplesDir/Snmp/Agent. See "MIB Development Process" if you have not already built and run this example.
Here we give commands for launching the applications from the same terminal window running the Korn shell. On the Windows NT platform, you will have to launch each application in a separate window. We redirect the output messages since this agent sends traps periodically.
$ cd examplesDir/Snmp/Agent $ java -classpath classpath Agent > Agent.out & |
Now we can launch the manager application to connect to this agent. If you wish to run the manager on a different host, replace localhost with the name of the machine where you launched the agent.
$ cd examplesDir/Snmp/Manager $ java -classpath classpath SimpleManager localhost 8085 SimpleManager::main: Send get request to SNMP agent on localhost port 8085 Result: [Object ID : 1.3.6.1.2.1.1.1.0 (Syntax : String) Value : SunOS sparc 5.7] |
Here we see the output of the SNMP request, it is the value of the sysDescr on the agent.
Leave the agent running if you are going on to the next example, otherwise remember to stop it with the following commands:
$ fg java [...] Agent > agent.out <Control-C> ^C$ rm examplesDir/Snmp/Agent/agent.out |
The asynchronous SNMP manager lets you handle more requests in the same amount of time because the manager is not blocked waiting for responses. Instead it creates a request handler object which runs as a separate thread and processes several responses concurrently. Otherwise, the initialization of peers, parameters, sessions and options is identical to that of a synchronous manager.
In this example application, we also demonstrate how to implement and enable a trap listener for the traps sent by the agent. First we need to instantiate an SnmpEventReportDispatcher object. Then we add our listener implementation through its addEventReportListener method, and finally we start its thread. Trap listeners can be implemented in any manager using the SNMP manager API, not only asynchronous managers.
// read the command line parameters String host = argv[0]; String port = argv[1]; // Use the OidTable generated by migen when compiling MIB II. SnmpOidTableSupport oidTable = new RFC1213_MIBOidTable(); // Sample use of the OidTable. SnmpOidRecord record = oidTable.resolveVarName("udpLocalPort"); java.lang.System.out.println( "AsyncManager::main: variable = " + record.getName() + " oid = " + record.getOid() + " type = " + record.getType()); // Initialize the SNMP Manager API. SnmpOid.setSnmpOidTable(oidTable); // Create an SnmpPeer object for representing the agent SnmpPeer agent = new SnmpPeer(host, Integer.parseInt(port)); // Create parameters for communicating with the agent SnmpParameters params = new SnmpParameters("public", "private"); agent.setSnmpParam(params); // Build the session and assign its default peer SnmpSession session = new SnmpSession("AsyncManager session"); session.setDefaultPeer(agent); // Create a listener and dispatcher for SNMP traps: // SnmpEventReportDispatcher will run as a thread and // listens for traps in UDP port = agent port + 1 SnmpEventReportDispatcher trapAgent = new SnmpEventReportDispatcher(Integer.parseInt(port)+1); // TrapListenerImpl will receive a callback // when a valid trap PDU is received. trapAgent.addEventReportListener(new TrapListenerImpl()); new Thread(trapAgent).start(); // Build the list of variables to query SnmpVarbindList list = new SnmpVarbindList("AsyncManager varbind list"); list.addVariable("sysDescr.0"); // Create a simple implementation of an SnmpHandler. AsyncRspHandler handler = new AsyncRspHandler(); // Make the SNMP walk request with our handler SnmpRequest request = session.snmpWalkUntil( handler, list, new SnmpOid("sysServices")); // Here you could do whatever processing you need. // In the context of the example, we are just going to wait // 5 seconds so that we can receive trap PDUs. Thread.sleep(5000); // Here the handle should have resume the activity of the thread // so the request is over java.lang.System.out.println("done"); // End the session properly and we're done. // session.destroySession(); java.lang.System.exit(0); |
In this example, the manager performs an snmpWalkUntil request which will give a response for each variable that it gets. The response handler will be called every time to process the response.
A trap handler for the SNMP manager is an object that implements the SnmpEventReportListener interface in the javax.management.snmp.manager package. When this object is bound as a listener of an SnmpEventReportDispatcher object, its methods will be called to handle trap PDUs.
The interface defines two methods, one for processing SNMPv1 traps and the other for SNMPv2 traps. Trap PDUs have already been decoded by the dispatcher: the v1 handler must process an SnmpPduTrap object, and the v2 handler must process an SnmpPduRequest object representing a trap. In our implementation, we are only interested in v1 traps, and we just print out the trap information fields.
public class TrapListenerImpl implements SnmpEventReportListener { public void processSnmpTrapV1(SnmpPduTrap trap) { java.lang.System.out.println( "NOTE: TrapListenerImpl received trap :"); java.lang.System.out.println( "\tGeneric " + trap.genericTrap); java.lang.System.out.println( "\tSpecific " + trap.specificTrap); java.lang.System.out.println( "\tTimeStamp " + trap.timeStamp); java.lang.System.out.println( "\tAgent address " + trap.agentAddr.stringValue()); } public void processSnmpTrapV2(SnmpPduRequest trap) { java.lang.System.out.println("NOTE: Trap V2 ignored"); } } |
A request handler for an asynchronous manager is an implementation of the SnmpHandler interface. When a handler object is associated with a request, its methods are called when the agent returns an answer or fails to return an answer. In these methods, you implement whatever actions you wish for processing the results of a request.
The timeout used by the request handler is the one specified by the SnmpPeer object representing the agent. The handler is also called to process any errors caused by the request in the session. This insures that the manager application is never interrupted after issue a request.
public class AsyncRspHandler implements SnmpHandler { // Empty constructor public AsyncRspHandler() { } // Called when the agent responds to a request public void processSnmpPollData( SnmpRequest request, int errStatus, int errIndex, SnmpVarbindList vblist) { java.lang.System.out.println( "Processing response: " + request.toString()); java.lang.System.out.println( "errStatus = " + SnmpRequest.snmpErrorToString(errStatus) + " errIndex = " + errIndex); // Check if a result is available. if (request.getRequestStatus() == SnmpRequest.stResultsAvailable) { // Extract the result for display SnmpVarbindList result = request.getResponseVbList(); java.lang.System.out.println( "Result = " + result.vbListToString()); } } // Called when the agent fails to respond to a request public void processSnmpPollTimeout(SnmpRequest request) { java.lang.System.out.println( "Request timed out: " + request.toString()); if (request.getRequestStatus() == SnmpRequest.stResultsAvailable) { // The result is empty and will display an error message SnmpVarbindList result = request.getResponseVbList(); java.lang.System.out.println( "Result = " + result.vbListToString()); } } // Called when there is an error in the session public void processSnmpInternalError(SnmpRequest request, String errmsg) { java.lang.System.out.println( "Session error: " + request.toString()); java.lang.System.out.println("Error is: " + errmsg); } } |
These example applications do not cover the security features in the SNMP manager. However, security can be implemented at the message level with a custom PDU factory, in the same way that it is for SNMP agents (see "Message-Level Security"). The hook for using your own implementation of the PDU factory is the setPduFactory method of an SnmpPeer instance.
Message-level security can be implemented in this manner in both synchronous and asynchronous managers. See the Java Management Extensions SNMP Manager API document and its Javadoc API for more details.
If you have not done so already, launch the simple SNMP agent in examplesDir/Snmp/Agent, after making sure that no other agent is running on port 8085. The manager also requires the same OID table description that we generated for the synchronous manager. See "Running the SimpleManager Example" for instructions to do this.
Here we give commands for launching the agent and manager from the same terminal window running the Korn shell. On the Windows NT platform, you will have to launch each application in a separate window. We redirect the output messages since this agent sends traps periodically.
$ cd examplesDir/Snmp/Agent $ java -classpath classpath Agent > Agent.out & |
Now we can launch the manager application to connect to this agent. If you wish to run the manager on a different host, replace localhost with the name of the machine where you launched the agent.
$ cd examplesDir/Snmp/Manager $ java -classpath classpath AsyncManager localhost 8085 |
You should then see the output of the SnmpWalkUntil request: the response handler method is called for each variable that is returned. Since this manager also has a trap listener running in a different thread, the output may be interspersed with trap reports.
When you are done with the agent, don't forget to stop it with the following commands:
$ fg java [...] Agent > agent.out <Control-C> ^C$ rm examplesDir/Snmp/Agent/agent.out |