All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snmp4j.agent.io.prop.PropertyMOInput Maven / Gradle / Ivy

There is a newer version: 3.8.1
Show newest version
/*_############################################################################
  _## 
  _##  SNMP4J-Agent 3 - PropertyMOInput.java  
  _## 
  _##  Copyright (C) 2005-2018  Frank Fock (SNMP4J.org)
  _##  
  _##  Licensed under the Apache License, Version 2.0 (the "License");
  _##  you may not use this file except in compliance with the License.
  _##  You may obtain a copy of the License at
  _##  
  _##      http://www.apache.org/licenses/LICENSE-2.0
  _##  
  _##  Unless required by applicable law or agreed to in writing, software
  _##  distributed under the License is distributed on an "AS IS" BASIS,
  _##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  _##  See the License for the specific language governing permissions and
  _##  limitations under the License.
  _##  
  _##########################################################################*/

package org.snmp4j.agent.io.prop;

import java.io.*;
import java.text.ParseException;
import java.util.*;
import java.util.Map.Entry;

import org.snmp4j.agent.io.*;
import org.snmp4j.smi.*;
import org.snmp4j.agent.mo.util.VariableProvider;
import org.snmp4j.log.LogAdapter;
import org.snmp4j.log.LogFactory;
import org.snmp4j.util.OIDTextFormat;
import org.snmp4j.util.SimpleOIDTextFormat;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 * The PropertyMOInput can be used to load MIB data from a properties file.
 * 

* The format of the properties file is as follows: *

*
 *   snmp4j.agent.cfg.contexts={s|x}<context1>[,{s|x}<context2>...]
 *   snmp4j.agent.cfg.oid[.ctx.<context>].<oid>=[<numRows>:<numCols>]
 *   snmp4j.agent.cfg.oid[.ctx.<context>].<oid>=[{<format>}<value>]
 *   snmp4j.agent.cfg.index[.ctx.<context>].oid.<rowIndex>={o}<index>
 *   snmp4j.agent.cfg.value[.ctx.<context>].oid.<rowIndex>.<colIndex>=[{<format>}<value>]
 * 
* where text enclosed in [] is optional and *
    *
  • context1 - is a SNMPv3 context name as UTF-8 string (format {s}) or * a hexadecimal string (format {x}). *
  • *
  • context - is a SNMPv3 context name as UTF-8 string if that string does * not contain any ISO control characters, otherwise a hexdecimal representation separated by a colon (:). *
  • *
  • format - one of *
      *
    • u - an Unsigned32 value.
    • *
    • i - an Integer32 value.
    • *
    • s - an OctetString value.
    • *
    • x - an OctetString value in hexadecimal format (separated by :).
    • *
    • d - an OctetString value in decimal format (separated by .).
    • *
    • b - an OctetString value in decimal format (separated by ' ' per byte).
    • *
    • n - a Null value.
    • *
    • o - an OID value as dotted string where string parts may be specified * directly enclosed in single quotes (') and the to an OID converted value of a variable/oid instance may be specified * in the format {@code [#]{<name/oid>}}. The value of the variable will be included into the OID with prependend * length if the # is used in the format string otherwise no length will be included.
    • *
    • t - a TimeTicks value as an unsigned long value.
    • *
    • a - a IpAddress value.
    • *
    • $ - gets the value from the variable or object instance specified by the * name/oid following the $.
    • *
    *
  • *
  • value - a variable value in the format specified by {@code format}. *
  • *
  • numRows - the number of rows in the table.
  • *
  • numCols - the number of columns in the table.
  • *
  • rowIndex - the row index as a zero based unsigned integer.
  • *
  • colIndex - the column index as a zero based unsigned integer.
  • *
  • index - the OID value of the row's index.
  • *
*

* An example properties file is: *

*
 * snmp4j.agent.cfg.contexts=
 * snmp4j.agent.cfg.oid.1.3.6.1.2.1.1.2.0={o}1.3.6.1.4.1.4976
 * snmp4j.agent.cfg.oid.1.3.6.1.2.1.1.4.0={s}System Administrator
 * snmp4j.agent.cfg.oid.1.3.6.1.2.1.1.6.0={s}<edit location>
 * snmp4j.agent.cfg.oid.1.3.6.1.2.1.1.7.0={i}10
 * snmp4j.agent.cfg.oid.1.3.6.1.2.1.1.9.1=1:2
 * snmp4j.agent.cfg.index.1.3.6.1.2.1.1.9.1.0={o}1
 * snmp4j.agent.cfg.value.1.3.6.1.2.1.1.9.1.0.0={o}1.3.6.1.4.1.4976.10.1.1.100.4.1
 * snmp4j.agent.cfg.value.1.3.6.1.2.1.1.9.1.0.1=
 * ## VACM MIB
 * # security2Group
 * snmp4j.agent.cfg.oid.1.3.6.1.6.3.16.1.2.1=2:3
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.16.1.2.1.0={o}2.6.'public'
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.2.1.0.0={s}v1v2cgroup
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.2.1.0.1={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.2.1.0.2={i}1
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.16.1.2.1.1={o}3.6.'SHADES'
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.2.1.1.0={s}v3group
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.2.1.1.1={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.2.1.1.2={i}1
 * # access
 * snmp4j.agent.cfg.oid.1.3.6.1.6.3.16.1.4.1=2:6
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.16.1.4.1.0={o}10.'v1v2cgroup'.0.2.1
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.0.0={i}1
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.0.1={s}unrestrictedReadView
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.0.2={s}unrestrictedWriteView
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.0.3={s}unrestrictedNotifyView
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.0.4={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.0.5={i}1
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.16.1.4.1.1={o}7.'v3group'.0.3.3
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.1.0={i}1
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.1.1={s}unrestrictedReadView
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.1.2={s}unrestrictedWriteView
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.1.3={s}unrestrictedNotifyView
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.1.4={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.4.1.1.5={i}1
 * # view trees
 * snmp4j.agent.cfg.oid.1.3.6.1.6.3.16.1.5.2.1=3:4
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.16.1.5.2.1.0={o}20.'unrestrictedReadView'.3.1.3.6
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.0.0={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.0.1={i}1
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.0.2={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.0.3={i}1
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.16.1.5.2.1.1={o}21.'unrestrictedWriteView'.3.1.3.6
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.1.0={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.1.1={i}1
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.1.2={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.1.3={i}1
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.16.1.5.2.1.2={o}22.'unrestrictedNotifyView'.3.1.3.6
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.2.0={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.2.1={i}1
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.2.2={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.16.1.5.2.1.2.3={i}1
 * ## SNMP community MIB
 * snmp4j.agent.cfg.oid.1.3.6.1.6.3.18.1.1.1=1:7
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.18.1.1.1.0={o}'public'
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.18.1.1.1.0.0={s}public
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.18.1.1.1.0.1={s}public
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.18.1.1.1.0.2={$1.3.6.1.6.3.10.2.1.1.0}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.18.1.1.1.0.3={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.18.1.1.1.0.4={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.18.1.1.1.0.5={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.18.1.1.1.0.6={i}1
 * ## USM MIB
 * snmp4j.agent.cfg.oid.1.3.6.1.6.3.15.1.2.2.1=1:14
 * snmp4j.agent.cfg.index.1.3.6.1.6.3.15.1.2.2.1.0={o}$#{1.3.6.1.6.3.10.2.1.1.0}.6.'SHADES'
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.0={s}SHADES
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.1={o}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.2={o}1.3.6.1.6.3.10.1.1.3
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.3={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.4={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.5={o}1.3.6.1.6.3.10.1.2.2
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.6={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.7={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.8={s}
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.9={i}4
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.10={i}1
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.11={s}SHADESAuthPassword
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.12={s}SHADESPrivPassword
 * snmp4j.agent.cfg.value.1.3.6.1.6.3.15.1.2.2.1.0.13=
 *
 * 
* * @author Frank Fock * @version 1.2 */ public class PropertyMOInput implements MOInput { private static final LogAdapter logger = LogFactory.getLogger(PropertyMOInput.class); public static final String CONFIG_PREFIX = "snmp4j.agent.cfg."; public static final String CONTEXTS_ID = "contexts"; public static final String OID_ID = "oid."; public static final String INDEX_ID = "index."; public static final String VERSION_ID = "version."; public static final String CTX_ID = "ctx."; public static final String VALUE_ID = "value."; private static final int STATE_ALL_CTX_DATA_SEQ = 0; private static final int STATE_ALL_CTX_DATA = 1; private static final int STATE_CTX_SEQ = 2; private static final int STATE_CTX_DATA_SEQ = 3; private static final int STATE_CTX_DATA = 4; private int importMode = ImportMode.RESTORE_CHANGES; private int state = STATE_ALL_CTX_DATA_SEQ; private SortedMap properties; private ContextInfo contexts; private OIDInfo oids; private DataInfo data; private VariableProvider variables; private OIDTextFormat oidTextFormat = new SimpleOIDTextFormat(); public PropertyMOInput(Properties props) { properties = scanProperties(props); contexts = scanContexts(properties); } public PropertyMOInput(Properties props, VariableProvider variables) { this(props); this.variables = variables; } public PropertyMOInput(Properties props, VariableProvider variables, OIDTextFormat oidTextFormat) { this(props, variables); this.oidTextFormat = oidTextFormat; } private ContextInfo scanContexts(Map properties) { String ctx = properties.get(CONFIG_PREFIX + CONTEXTS_ID); StringTokenizer st = new StringTokenizer(ctx, ","); ArrayList l = new ArrayList<>(st.countTokens()); while (st.hasMoreTokens()) { String token = st.nextToken(); OctetString s = (OctetString) createVariableFromString(token, OctetString.class); l.add(new Context(s)); } return new ContextInfo(l.size(), l.iterator()); } private OIDInfo scanOIDs(SortedMap properties, OctetString ctx) { String prefix = CONFIG_PREFIX + OID_ID; String ctxSuffix = ""; if (ctx != null) { ctxSuffix = CTX_ID + ctx.toString() + "."; } prefix += ctxSuffix; SortedMap oids = properties.tailMap(prefix); ArrayList l = new ArrayList(); for (Entry stringStringEntry : oids.entrySet()) { Entry e = stringStringEntry; String k = e.getKey(); if (k.startsWith(prefix)) { String oid; oid = k.substring(prefix.length()); String version = properties.get(CONFIG_PREFIX + VERSION_ID + ctxSuffix); l.add(new MOInfo(parseOID(oid), version)); } else { break; } } return new OIDInfo(ctx, l.size(), l.iterator()); } private OID parseOID(String oid) { try { return new OID(oidTextFormat.parse(oid)); } catch (ParseException pex) { throw new RuntimeException("OID '" + oid + "' cannot be parsed", pex); } } private void scanDataVariable(SortedMap properties, OID oid, DataInfo dataInfo) { String prefix = CONFIG_PREFIX; String ctxSuffix = ""; if (dataInfo.context != null) { ctxSuffix = CTX_ID + dataInfo.context; } prefix += ctxSuffix; prefix += OID_ID + oid.toDottedString(); String value = properties.get(prefix); Variable v = createVariableFromString(value, Variable.class); dataInfo.add(v); } private void scanDataIndexVariables(SortedMap properties, OID oid, DataInfo dataInfo) { String prefix = CONFIG_PREFIX; String ctxSuffix = ""; if (dataInfo.context != null) { ctxSuffix = CTX_ID + dataInfo.context; } prefix += ctxSuffix; prefix += OID_ID + oid.toDottedString(); String dimension = properties.get(prefix); if (dimension == null) { return; } StringTokenizer st = new StringTokenizer(dimension, ": "); int rows = Integer.parseInt(st.nextToken()); int cols = Integer.parseInt(st.nextToken()); String indexPrefix = CONFIG_PREFIX + ctxSuffix + INDEX_ID + oid.toDottedString(); String valuePrefix = CONFIG_PREFIX + ctxSuffix + VALUE_ID + oid.toDottedString(); for (int i = 0; i < rows; i++) { String indexString = properties.get(indexPrefix + "." + i); OID index = (OID) createVariableFromString(indexString, OID.class); Variable[] v = new Variable[cols]; for (int j = 0; j < cols; j++) { String val = properties.get(valuePrefix + "." + i + "." + j); if (val != null) { v[j] = createVariableFromString(val, Variable.class); } } dataInfo.add(new IndexedVariables(index, v)); } } /** * Scans the supplied properties for config relevant properties and stores them into the returned LinkedHashMap. * * @param props * a set of properties. * * @return a LinkedHashMap with properties whose key starts with {@link #CONFIG_PREFIX}. */ private static SortedMap scanProperties(Properties props) { SortedMap map = new TreeMap(); for (Entry e : props.entrySet()) { if (e.getKey().toString().startsWith(CONFIG_PREFIX)) { map.put(e.getKey().toString(), e.getValue().toString()); } } return map; } /** * Returns the update mode, which might be one of the constants defined by {@link ImportMode}. By default, {@link * ImportMode#RESTORE_CHANGES} is returned. * * @return the constant denoting the update mode that should be used by a * SerializableManagedObject to import its content from * persistent storage. */ public int getImportMode() { return importMode; } public Context readContext() throws IOException { if ((state <= STATE_CTX_SEQ) && (contexts != null)) { if (state < STATE_CTX_SEQ) { state = STATE_CTX_SEQ; } return contexts.iterator.next(); } else { throw new IOException(); } } public IndexedVariables readIndexedVariables() throws IOException { if (data == null) { DataInfo indexedVariablesDataInfo = new DataInfo(oids.curContext); data = indexedVariablesDataInfo; scanDataIndexVariables(properties, oids.curOID.getOID(), indexedVariablesDataInfo); } IndexedVariables ivar = (IndexedVariables) data.next(); if (logger.isDebugEnabled()) { logger.debug("Read indexed variables " + ivar + " for OID " + oids.curOID.getOID() + " in context " + oids.curContext); } return ivar; } public MOInfo readManagedObject() throws IOException { MOInfo info = oids.next(); data = null; if (logger.isDebugEnabled()) { logger.debug("Read MO " + info); } return info; } public Sequence readSequence() throws IOException { switch (state) { case STATE_ALL_CTX_DATA_SEQ: { state++; oids = scanOIDs(properties, null); return new Sequence(oids.numElements); } case STATE_ALL_CTX_DATA: if (data != null && !oids.iterator.hasNext()) { state++; // fall through } else { DataInfo indexedVariablesDataInfo = new DataInfo(oids.curContext); data = indexedVariablesDataInfo; scanDataIndexVariables(properties, oids.curOID.getOID(), indexedVariablesDataInfo); return new Sequence(data.size()); } case STATE_CTX_SEQ: { state++; return new Sequence(contexts.numContexts); } } return null; } public Variable readVariable() throws IOException { if (data == null) { DataInfo variableDataInfo = new DataInfo(oids.curContext); data = variableDataInfo; scanDataVariable(properties, oids.curOID.getOID(), variableDataInfo); } Variable v = (Variable) data.next(); if (logger.isDebugEnabled()) { logger.debug("Read variable " + v + " for OID " + oids.curOID.getOID() + " in context " + oids.curContext); } return v; } public void skipContext(Context context) throws IOException { } public void skipManagedObject(MOInfo mo) throws IOException { } /** * Parses a string of the format *
     * OID={type}value where <type> is one of
     * the following single characters enclosed by '{' and '}':
     *  i                     Integer32
     *  u                     UnsignedInteger32, Gauge32
     *  s                     OCTET STRING
     *  x                     OCTET STRING specified as hex string where
     *                        bytes separated by colons (':').
     *  d                     OCTET STRING specified as decimal string
     *                        where bytes are separated by dots ('.').
     *  n                     Null
     *  o                     OBJECT IDENTIFIER
     *  t                     TimeTicks
     *  a                     IpAddress
     *  b                     OCTET STRING specified as binary string where
     *                        bytes are separated by spaces.
     *  $<variableName>     where <variableName> is the name of a predefined
     *                        variable or the OID of a variable of the agent's
     *                        MIB.
     * 
* and returns the corresponding variable. * * @param value * the variable value string. * @param returnType * the expected Variable class to return. * * @return {@code null} if {@code value} is {@code null} and the {@code Variable} corresponding to {@code value} * otherwise. */ public Variable createVariableFromString(String value, Class returnType) { if (value != null) { char type = ' '; String varName = null; if (value.length() >= 3) { type = value.charAt(1); int pos = value.indexOf('}'); if (type == '$') { varName = value.substring(2, pos); } value = value.substring(pos + 1); } Variable variable; switch (type) { case 'i': variable = new Integer32(Integer.parseInt(value)); break; case 'u': variable = new UnsignedInteger32(Long.parseLong(value)); break; case 's': variable = new OctetString(value); break; case 'x': variable = OctetString.fromString(value, ':', 16); break; case 'd': variable = OctetString.fromString(value, '.', 10); break; case 'b': variable = OctetString.fromString(value, ' ', 2); break; case 'n': variable = new Null(); break; case 'o': try { variable = parseOID(value); } catch (Exception ex) { // does oid contain variable reference? Pattern p = Pattern.compile("(\\$#?\\{[^\\}]*\\})"); Matcher m = p.matcher(value); StringBuffer result = new StringBuffer(); while (m.find()) { String group = m.group(); boolean impliedLength = true; if (group.charAt(1) == '#') { impliedLength = false; } group = group.substring(group.indexOf('{') + 1, group.length() - 1); Variable replacementValue = (this.variables == null) ? new OID() : this.variables.getVariable(group); if (replacementValue != null) { OID oid = replacementValue.toSubIndex(impliedLength); m.appendReplacement(result, oid.toDottedString()); } } m.appendTail(result); variable = parseOID(result.toString()); } break; case 't': variable = new TimeTicks(Long.parseLong(value)); break; case 'a': variable = new IpAddress(value); break; case '$': variable = (this.variables == null) ? null : this.variables.getVariable(varName); break; case ' ': return null; default: throw new IllegalArgumentException("Variable type " + type + " not supported"); } if (!returnType.isInstance(variable)) { /**@todo make conversion*/ } return variable; } return null; } public void close() throws IOException { } private class ContextInfo implements Iterator { int numContexts; Context curContext; Iterator iterator; ContextInfo(int numContexts, Iterator contexts) { this.numContexts = numContexts; this.iterator = contexts; } public void remove() { throw new UnsupportedOperationException(); } public boolean hasNext() { return iterator.hasNext(); } public Context next() { curContext = iterator.next(); return curContext; } } private class OIDInfo implements Iterator { int numElements; MOInfo curOID; OctetString curContext; Iterator iterator; OIDInfo(OctetString context, int numElements, Iterator data) { this.numElements = numElements; this.iterator = data; this.curContext = context; } public void remove() { throw new UnsupportedOperationException(); } public boolean hasNext() { return iterator.hasNext(); } public MOInfo next() { curOID = iterator.next(); return curOID; } } private class DataInfo implements Iterator { OctetString context; List data = new ArrayList(); Iterator iterator; DataInfo(OctetString context) { this.context = context; } public void add(T element) { data.add(element); } public void remove() { throw new UnsupportedOperationException(); } private void initIterator() { if (iterator == null) { iterator = data.iterator(); } } public boolean hasNext() { initIterator(); return iterator.hasNext(); } public T next() { initIterator(); return iterator.next(); } public int size() { return data.size(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy