Skip to content
Permalink
 
 
Cannot retrieve contributors at this time
362 lines (335 sloc) 12.1 KB
package com.apple.iad.rhq.snmp;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.percederberg.mibble.Mib;
import net.percederberg.mibble.MibLoader;
import net.percederberg.mibble.MibLoaderException;
import net.percederberg.mibble.MibSymbol;
import net.percederberg.mibble.MibType;
import net.percederberg.mibble.MibTypeSymbol;
import net.percederberg.mibble.MibValue;
import net.percederberg.mibble.MibValueSymbol;
import net.percederberg.mibble.snmp.SnmpAccess;
import net.percederberg.mibble.snmp.SnmpIndex;
import net.percederberg.mibble.snmp.SnmpNotificationType;
import net.percederberg.mibble.snmp.SnmpObjectType;
import net.percederberg.mibble.snmp.SnmpStatus;
import net.percederberg.mibble.snmp.SnmpTrapType;
import net.percederberg.mibble.snmp.SnmpType;
import net.percederberg.mibble.type.ElementType;
import net.percederberg.mibble.type.SequenceOfType;
import net.percederberg.mibble.type.SequenceType;
import net.percederberg.mibble.value.ObjectIdentifierValue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.util.TableEvent;
/**
* Provides mappings of the SNMP name and OID; tracks interesting data from the MIB to use at runtime.
*/
public class MibIndex {
public static final Pattern NAME_OID = Pattern.compile("(\\p{Alpha}+)(\\.\\d+)*");
public static final String MIB_DIR = "mibs";
private static final Log log = LogFactory.getLog(MibIndex.class);
private static final boolean debug = log.isDebugEnabled();
final NavigableMap<OID, String> oids = new TreeMap<OID, String>();
final Map<String, NameRecord> names = new LinkedHashMap<String, NameRecord>();
private final Map<String, TableRecord> tables = new LinkedHashMap<String, TableRecord>();
private final MibLoader loader;
private boolean extra;
/**
* Constructs a new instance.
*/
public MibIndex() {
loader = new MibLoader();
loader.addResourceDir(MIB_DIR);
}
/**
* Set to 'true' to store extra information from the MIB.
* Currently this only includes the description.
*/
public void setExtra(boolean extra) {
this.extra = extra;
}
/**
* Load a MIB file, then build an index based on the SNMP object symbols.
* Builds a name to OID and name to type reference.
*/
public void load(String mibFile) throws IOException {
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
log.debug("load mib file " + mibFile + " class loader" + cl);
Mib mib;
File file = new File(mibFile);
URL url = cl.getResource(MIB_DIR + "/" + mibFile);
if (file.canRead()) {
mib = loader.load(file);
} else if (url != null) {
log.debug("found using URL");
mib = loader.load(url);
} else {
try {
url = new URL(mibFile);
log.debug("loading using URL");
mib = loader.load(url);
} catch (MalformedURLException e) {
log.debug("not found using URL; load using loader class");
mib = loader.load(mibFile);
}
}
Collection<MibSymbol> symbols = mib.getAllSymbols();
for (MibSymbol s : symbols) {
if (s instanceof MibValueSymbol) {
MibValueSymbol v = (MibValueSymbol) s;
MibType t = v.getType();
if (t instanceof SnmpType) {
SnmpType ot = (SnmpType) t;
symbol(v, ot);
}
}
}
initTables();
} catch (IOException e) {
throw e;
} catch (MibLoaderException e) {
StringWriter sw = new StringWriter();
e.getLog().printTo(new PrintWriter(sw));
throw new IOException(sw.toString());
}
}
private void symbol(MibValueSymbol v, SnmpType ot) {
if (obsolete(ot)) {
return;
}
String name = v.getName();
MibTypeSymbol mts = null;
MibType type = v.getType();
MibType syntax = null;
List<OID> index = Collections.emptyList();
debug("symbol", name, type.getClass(), v.getValue());
if (type instanceof SnmpObjectType) {
SnmpObjectType sot = (SnmpObjectType) type;
syntax = sot.getSyntax();
if (syntax instanceof SequenceOfType) {
table(name, (SequenceOfType) syntax);
} else if (syntax instanceof SequenceType) {
if (!sot.getIndex().isEmpty()) {
index = new ArrayList<OID>();
for (SnmpIndex i : (List<SnmpIndex>)sot.getIndex()) {
ObjectIdentifierValue oiv = (ObjectIdentifierValue) i.getValue();
index.add(new OID(oiv.toString()));
}
}
}
mts = syntax.getReferenceSymbol();
}
debug("mts", mts, "type", type);
String desc = extra ? ot.getDescription() : null;
debug("name", name);
SnmpAccess access = null;
if (ot instanceof SnmpObjectType) {
access = ((SnmpObjectType) ot).getAccess();
}
OID oid;
if (ot instanceof SnmpTrapType) {
MibValue mv = ((SnmpTrapType) ot).getEnterprise();
debug("mv", mv);
oid = new OID(mv.toString());
} else {
oid = new OID(v.getValue().toString());
}
names.put(name, new NameRecord(oid, syntax, access, mts, index, desc));
oids.put(oid, name);
}
/**
* Tables are 'sequence of type' containing entry instances which are 'sequence type'.
*/
private void table(String name, SequenceOfType sot) {
debug("table", name, sot);
MibType et = sot.getElementType();
if (et instanceof SequenceType) {
SequenceType st = (SequenceType) et;
// syntax name, not entry name; rely on entry OID being table OID + 1
// String entry = st.getReferenceSymbol().getName();
List<String> cols = new ArrayList<String>();
for (ElementType et2 : st.getAllElements()) {
String cname = et2.getName();
cols.add(cname);
}
tables.put(name, new TableRecord(this, cols));
}
}
private boolean obsolete(SnmpType type) {
if (type instanceof SnmpNotificationType)
return ((SnmpNotificationType)type).getStatus() == SnmpStatus.OBSOLETE;
if (type instanceof SnmpObjectType)
return ((SnmpObjectType)type).getStatus() == SnmpStatus.OBSOLETE;
return false;
}
/**
* Returns a name record.
* @throws IndexException if name is not found
*/
public NameRecord getNameRecord(String name) {
if (name == null)
throw new NullPointerException("name");
NameRecord nr = names.get(name);
if (nr == null)
throw new IndexException("name " + name + " not found");
return nr;
}
/**
* Returns a name record by exact OID.
* @throws IndexException if OID is not found
* @see #toName(OID) to convert to name plus suffix
*/
public String getName(OID oid) {
String name = oids.get(oid);
if (name == null)
throw new IndexException("oid " + oid + " not found");
return name;
}
/**
* Returns true if {@link #getName(OID)} will return a value.
*/
public boolean hasName(OID oid) {
return oids.containsKey(oid);
}
/**
* Returns a map of integers to value by name.
* Returns null if no mapping exists.
*/
public Map<Integer, String> getMapping(String name) {
NameRecord nameRecord = names.get(name);
if (nameRecord == null)
return null;
return nameRecord.getMapping();
}
/**
* Remove unknown columns from tables, set up OID columns, indexes.
*/
private void initTables() {
for (Entry<String, TableRecord> me : tables.entrySet()) {
TableRecord tr = me.getValue();
tr.init(me.getKey());
}
}
/**
* Returns the OID columns for this table.
* @throws IndexException if table is unknown
*/
public TableRecord getTableRecord(String tableName) {
TableRecord tableRecord = tables.get(tableName);
if (tableRecord == null)
throw new IndexException("unknown table " + tableName + " have " + tables.keySet());
return tableRecord;
}
/**
* Decode a table event for a table, assuming the columns are as ordered in the
* call to {@link #getTable(String)}.
*
* @param tableName
* @param te
* @return
*/
public Map<String, Variable> decode(String tableName, TableEvent te) {
HashMap<String, Variable> hm = new HashMap<String, Variable>();
log.debug(te);
for (VariableBinding vb : te.getColumns()) {
String key = oids.get(vb.getOid());
Variable var = vb.getVariable();
hm.put(key, var);
}
return hm;
}
private void debug(Object... objs) {
if (debug)
log.debug(Arrays.toString(objs));
}
/**
* Returns a mapping of names to name records.
*/
public Map<String, NameRecord> getNames() {
return Collections.unmodifiableMap(names);
}
/**
* Returns the OID for the given string value.
* Note the name can be an OID, or a textual name, include suffixes.
* Examples:
* <ul>
* <li>someName - will return the OID of 'someName'
* <li>someName.2 - will return the OID of 'someName' suffixed with '2'
* <li>1.3.6.1.6.3.1.1.5 - will parse the OID
* </ul>
* @throws IndexException if name cannot be resolved
*/
public OID toOid(String value) {
if (value == null)
throw new NullPointerException("value");
Matcher m = NAME_OID.matcher(value);
if (m.matches()) {
String name = m.group(1);
String remain = m.group(2);
if (remain == null) {
return getNameRecord(name).getOid();
} else {
remain = remain.substring(1);
return new OID(getNameRecord(name).getOid()).append(new OID(remain));
}
}
return new OID(value);
}
/**
* Inverse operation of {@link #toOid(String)}.
* Returns the exact matching name part suffixed with the remainder OID.
*/
public String toName(OID oid) {
if (oid == null)
throw new NullPointerException("value");
String name = this.oids.get(oid);
if (name != null)
return name;
Entry<OID, String> lowerEntry = this.oids.lowerEntry(oid);
if (lowerEntry != null && oid.startsWith(lowerEntry.getKey())) {
OID parent = lowerEntry.getKey();
OID suffix = new OID(oid.getValue(), parent.size(), oid.size() - parent.size());
return lowerEntry.getValue() + "." + suffix;
}
return oid.toString();
}
/**
* Returns a mapping of names to table records.
*/
public Map<String, TableRecord> getTables() {
return Collections.unmodifiableMap(tables);
}
/**
* Returns a debug string.
*/
@Override
public String toString() {
return "MibIndex [loader=" + loader +
",\n names=" + names +
",\n tables=" + tables +
"]";
}
}
You can’t perform that action at this time.