SkillAgentSearch skills...

Tnm4j

A simplified SNMP API for Java, based on Jürgen Schönwälder's Tnm extension for Tcl.

Install / Use

/learn @soulwing/Tnm4j
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

tnm4j

Build Status Maven Central

A simplified SNMP API for Java, inspired by Jürgen Schönwälder's Tnm extension for Tcl.

The original Tnm made it easy to write network management applications using simple Tcl scripts. Tnm4j attempts to bring this same simplicity to the task of writing network management applications in Java or in Java-based scripting languages such as Groovy.

Running the Examples Using Docker

The src/examples/java subdirectory contains several examples.

Running the examples is easy if you have Maven and if you have or (or are willing to install) Docker Desktop and Docker Compose on your workstation.

The src/examples/docker subdirectory contains a Dockerfile that can be used to create a Linux-based container image that runs Net-SNMP, with configuration that matches up with the src/examples/java/ExampleTargets. At the base directory for this project, there is a docker-compose.yml that can build and run the container for you.

Steps for running the examples:

  1. Install Docker Desktop

  2. Install Docker Compose

  3. Open a shell and navigate to the base directory for this project.

  4. Run Docker Compose in the base directory.

    docker-compose up --build
    

    The first time you start up, you'll see the container image being built. Subsequently, when you run docker-compose up --build it should reuse the cached image.

    After the image is built, it will run and you'll see the Net-SNMP console output.

  5. In another shell, navigate to the base directory for this project. In this shell you'll run an example using Maven as follows.

    mvn -Pexamples clean compile exec:java -Dexec.mainClass=Example01_GetAndGetNext
    

    Maven will build the project and run the example class you specified. You can run any of the examples in src/examples/java in this same manner.

  6. After you're done playing with the examples, go back to the first shell, hit Ctrl-C on the keyboard and then

    docker-compose down
    
  7. You can save a little disk space by getting rid of the container image, too.

    docker image rm tnm4j-netsnmp
    

Architecture

Tnm4j provides a lightweight façade over an SNMP adapter and a MIB parser adapter. These adapters each implement a Tnm4j service provider interface to adapt a third-party library for use with Tnm4j. The JDK's ServiceLoader mechanism is used to locate adapters for SNMP and MIB parsing support.

The default SNMP adapter uses Snmp4j by Frank Fock and Jochen Katz. Snmp4j is an outstanding library providing comprehensive support for SNMP communications in Java.

The default MIB adapter uses Per Cederberg's excellent Mibble MIB parser.

Other SNMP providers or MIB parsers could be easily adapted for use with Tnm4j by implementing the necessary SPI.

Trivial Example

The following example illustrates just a few of the features of Tnm4j. This snippet retrieves and displays the name, description, and up time of an SNMP-enabled network device.

MIB mib = MIBFactory.getInstance().newMib();
mib.load("RFC1213-MIB");

SnmpV2cContext snmp = SnmpFactory.getInstance().newSnmpV2cContext(mib);
snmp.setAddress("10.0.0.1");
snmp.setCommunity("public");

VarbindCollection varbinds = snmp.getNext("sysName", "sysDescr", "sysUpTime").get();
for (Varbind varbind : varbinds) {
  System.out.format("%s=%s\n", varbind.getName(), varbind.toString());
}

Notice how the MIB and SNMP context objects are designed to work together? This is arguably the most salient concept of Tnm4j. Tnm4j fully exploits the MIB to make it easy for the developer to access management objects in an SNMP agent. The developer can use MIB object names (instead of SNMP object identifiers) when getting or setting object values, reducing the time and effort required to get the desired management information.

The syntax and textual convention details from the MIB are used when converting object values to strings. This is illustrated in the preceding example -- converting a retrieved value to a string in the appropriate format is as simple as calling Varbind.toString().

Getting Started: Targets, Contexts, and Operations

In using Tnm4j, there are three fundamental objects you will use to interact with SNMP agents: targets, contexts, and operations.

A target is a simple object that describes the relevant characteristics of a remote agent necessary for communication. A target implements either the SnmpV3Target, SnmpV2cTarget, or SnmpV1Target interface, depending on whether the remote agent supports the SNMPv3, SNMPv2c, or SNMPv1 protocol, respectively. These interfaces describe properties such as network address and security characteristics of the remote agent. Tnm4j provides simple concrete target implementations -- SimpleSnmpV3Target, SimpleSnmpV2cTarget, and SimpleV1Target -- that your application can construct and configure directly. Alternatively, your domain model objects representing network devices could easily implement these interfaces, allowing your model objects to be used directly as targets.

A context provides the ability to invoke SNMP operations on a given target. You create a context using SnmpFactory and providing the target to the factory method:

import org.soulwing.snmp4j.*;

SimpleSnmpV2cTarget target = new SimpleSnmpV2cTarget();
target.setAddress("10.0.0.1");
target.setCommunity("public");

SnmpContext context = SnmpFactory.getInstance().newContext(target);
try {
  // perform some SNMP operations
}
finally {
  context.close();
}

As shown in the preceding snippet, a context must (eventually) be closed, in order to avoid a resource leak. Contexts are, however, lightweight objects and it is quite reasonable to create and retain a context for as long as you need to continue communicating with the target SNMP agent. Depending on the needs of your application, this could be as short as the time needed to perform a few SNMP operations, or perhaps for as long as the remote agent exists and your application continues running. Tnm4j is used in applications that retain thousands of context objects on the heap.

If you neglect to close a context, it will eventually be closed when your code no longer holds any references to it -- the underlying implementation implements finalize to close the context if necessary. However, as it is difficult to predict when a discarded context will be reclaimed by the JVM's garbage collector, it is a best practice to close a context before you discard the last reference to it.

Performing SNMP Operations

Once you have a context for a given target, you can use the context to perform SNMP operations on the targeted SNMP agent:

SnmpContext context = SnmpFactory.getInstance().newContext(target);
try {
  VarbindCollection result = context.get("1.3.6.1.2.1.1.3.0").get();
  System.out.println(result.get(0));
}
finally {
  context.close();
}

The preceding snippet uses the context to invoke a GET operation on the remote agent and stores a reference to the retrieved variable bindings -- varbinds in SNMP speak. The numeric object ID used here (in case you didn't recognize it) is the SNMP sysUpTime object. When invoking an operation, we can request an arbitrary number of SNMP objects; the operation methods include variants which take a variable number of arguments or a List.

If you're wondering why we're using numeric OIDs here instead of names, just hang on... we'll get there shortly!

In addition to the get, the context provides methods to support all of the fundamental SNMP operations: GET, GETNEXT, GETBULK, and SET. Moreover, it provides methods to support easy and efficient SNMP table walks, which we'll cover later. See the javadoc for the full details.

You might have noticed there are quite a few gets in those two lines of code inside of the try block. The snippet is written in the idiomatic style recommended for Tnm4j, which is lean on syntax, and hides a lot of the underlying details. Let's break it down a little more to help you understand what's going on. We could rewrite the snippet a little more verbosely, like this:

SnmpContext context = SnmpFactory.getInstance().newContext(target);
try {
  SnmpResponse<VarbindCollection> response = context.get("1.3.6.1.2.1.1.3.0");
  VarbindCollection result = response.get();
  Varbind sysUpTime = result.get(0);
  System.out.println(sysUpTime);
}
finally {
  context.close();
}

Now we can see that when we use get to perform a GET operation, the return value is an SnmpResponse. If you check out the javadoc for SnmpResponse you'll see that it has a single method (get) that retrieves the result of the SNMP operation. The response object is patterned after the JDK's Future object -- the get method will block until the result of the operation is available. If the operation fails, the relevant exception will be thrown when you try to get the result from the response object.

Assuming that the operation succeeds, the result we retrieve from the response object is a VarbindCollection. This object is not a subtype of the JDK's Collection type.

View on GitHub
GitHub Stars44
CategoryDevelopment
Updated8d ago
Forks18

Languages

Java

Security Score

95/100

Audited on Mar 21, 2026

No findings