SnmpClient.java

package eu.linuxengineering.snmp.client;

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.DefaultPDUFactory;
import org.snmp4j.util.TreeEvent;
import org.snmp4j.util.TreeUtils;

import eu.javaexperience.log.JavaExperienceLoggingFacility;
import eu.javaexperience.log.LogLevel;
import eu.javaexperience.log.Loggable;
import eu.javaexperience.log.Logger;
import eu.javaexperience.log.LoggingTools;

/**
 * Based on:
 * https://www.jitendrazaa.com/blog/java/snmp/create-snmp-client-in-java-using-snmp4j/
 * */
public class SnmpClient implements Closeable
{
	protected static final Logger LOG = JavaExperienceLoggingFacility.getLogger(new Loggable("SnmpClient"));
	
	protected String address = null;
	protected TransportMapping<UdpAddress> transport;
	protected Snmp snmp = null;
	
	/**
	 * address like: udp:127.0.0.1/161
	 */
	public SnmpClient(String address)
	{
		this.address = address;
	}

	public SnmpClient(InetSocketAddress sa)
	{
		this.address = "udp:"+sa.getHostString()+"/"+sa.getPort();
	}
	
	public void start() throws IOException
	{
		transport = new DefaultUdpTransportMapping();
		snmp = new Snmp(transport);
		transport.listen();
	}

	@Override
	public void close() throws IOException
	{
		transport.close();
	}
	
	/**
	 * Method which takes a single OID and returns the response from the agent as a
	 * String.
	 * 
	 * @param oid
	 * @return
	 * @throws IOException
	 */
	public String getAsString(OID oid) throws IOException
	{
		ResponseEvent event = get(new OID[]{oid});
		Variable var = event.getResponse().get(0).getVariable();
		if(var instanceof Null)
		{
			return null;
		}
		return var.toString();
	}

	/**
	 * This method is capable of handling multiple OIDs
	 * 
	 * @param oids
	 * @return
	 * @throws IOException
	 */
	public ResponseEvent get(OID oids[]) throws IOException
	{
		PDU pdu = new PDU();
		for(OID oid:oids)
		{
			pdu.add(new VariableBinding(oid));
		}
		
		pdu.setType(PDU.GET);
		ResponseEvent event = snmp.send(pdu, getTarget(), null);
		if(event != null)
		{
			return event;
		}
		throw new RuntimeException("GET timed out");
	}

	/**
	 * This method returns a Target, which contains information about where the data
	 * should be fetched and how.
	 * 
	 * @return
	 */
	protected Target getTarget()
	{
		Address targetAddress = GenericAddress.parse(address);
		CommunityTarget target = new CommunityTarget();
		target.setCommunity(new OctetString("public"));
		target.setAddress(targetAddress);
		target.setRetries(2);
		target.setTimeout(1500);
		target.setVersion(SnmpConstants.version2c);
		return target;
	}
	
	public int walkSubtree(OID oid, Map<OID, Variable> result) throws IOException
	{
		int add = 0;
		TransportMapping<? extends Address> transport = new DefaultUdpTransportMapping();
		Snmp snmp = new Snmp(transport);
		try
		{
			transport.listen();
			
			TreeUtils treeUtils = new TreeUtils(snmp, new DefaultPDUFactory());
			List<TreeEvent> events = treeUtils.getSubtree(getTarget(), oid);
			if (events == null || events.size() == 0)
			{
				LoggingTools.tryLogFormat(LOG, LogLevel.WARNING, "Unable to read table `%s`", oid);
				throw new RuntimeException("Unable to read table at "+oid);
			}
	
			for(TreeEvent event : events)
			{
				if(event == null)
				{
					continue;
				}
				
				if(event.isError())
				{
					LoggingTools.tryLogFormat(LOG, LogLevel.WARNING, "table OID `%s` message: `%s`", oid, event.getErrorMessage());
					continue;
				}
				
				VariableBinding[] varBindings = event.getVariableBindings();
				if(varBindings == null || varBindings.length == 0)
				{
					continue;
				}
				
				for(VariableBinding varBinding : varBindings)
				{
					if (varBinding == null)
					{
						continue;
					}
					
					++add;
					result.put(varBinding.getOid(), varBinding.getVariable());
				}
			}
		}
		finally
		{
			snmp.close();
		}
		
		return add;
	}

}