/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2010-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.mock.snmp; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.UndeclaredThrowableException; import java.net.URL; import java.util.Collections; import java.util.List; import java.util.Map.Entry; import java.util.Properties; import java.util.SortedMap; import java.util.TreeMap; import org.snmp4j.agent.DefaultMOScope; import org.snmp4j.agent.MOAccess; import org.snmp4j.agent.MOScope; import org.snmp4j.agent.ManagedObject; import org.snmp4j.agent.request.RequestStatus; import org.snmp4j.agent.request.SubRequest; import org.snmp4j.log.LogAdapter; import org.snmp4j.log.LogFactory; import org.snmp4j.mp.SnmpConstants; import org.snmp4j.smi.Counter32; import org.snmp4j.smi.Counter64; import org.snmp4j.smi.Gauge32; import org.snmp4j.smi.Integer32; import org.snmp4j.smi.IpAddress; import org.snmp4j.smi.Null; import org.snmp4j.smi.OID; import org.snmp4j.smi.OctetString; import org.snmp4j.smi.TimeTicks; import org.snmp4j.smi.Variable; import org.snmp4j.smi.VariableBinding; /** * <p>PropertiesBackedManagedObject class.</p> * * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a> * @author <a href="mailto:jeffg@opennms.org">Jeff Gehlbach</a> */ public class PropertiesBackedManagedObject implements ManagedObject, MockSnmpMOLoader, Updatable, MOAccess { private static final LogAdapter s_log = LogFactory.getLogger(PropertiesBackedManagedObject.class); private TreeMap<OID, Object> m_vars = null; private MOScope m_scope = null; private Object m_oldValue; /** {@inheritDoc} */ public List<ManagedObject> loadMOs(URL moFile) { final Properties props = loadProperties(moFile); m_vars = new TreeMap<OID, Object>(); for(final Entry<Object, Object> e : props.entrySet()) { final String key = (String)e.getKey(); final Object value = e.getValue(); if (!key.startsWith(".")) { s_log.debug(String.format("key does not start with '.', probably a linewrap issue in snmpwalk: %s = %s", key, value)); continue; } try { m_vars.put(new OID(key), value); } catch (final Throwable ex) { // Catch any malformed OIDs and create a more descriptive error message final IllegalArgumentException nfe = new IllegalArgumentException("Could not load OID value: [" + key + "] [" + value + "]"); nfe.initCause(ex); throw nfe; } } m_scope = new DefaultMOScope(m_vars.firstKey(), true, m_vars.lastKey(), true); return Collections.singletonList((ManagedObject)this); } private Properties loadProperties(URL moFile) { final Properties moProps = new Properties(); InputStream inStream = null; try { inStream = moFile.openStream(); moProps.load( inStream ); } catch (final Exception ex) { s_log.error("Unable to read property file " + moFile, ex); return null; } finally { closeQuietly(inStream); } return moProps; } private void closeQuietly(InputStream in) { try { in.close(); } catch (IOException e) { // ignore this -- hence the quietly } } /** {@inheritDoc} */ public OID find(final MOScope range) { if (!m_scope.isOverlapping(range)) { return null; } OID first = range.getLowerBound(); if (range.isLowerIncluded()) { first = first.successor(); } final SortedMap<OID, Object> tail = m_vars.tailMap(first); if (tail.isEmpty()) { return null; } return tail.firstKey(); // skip the leading '.' } /** * <p>findNextOid</p> * * @param given a {@link org.snmp4j.smi.OID} object. * @return a {@link org.snmp4j.smi.OID} object. */ public OID findNextOid(final OID given) { final OID next = given.successor(); final SortedMap<OID, Object> tail = m_vars.tailMap(next); if (tail.isEmpty()) { return null; } return tail.firstKey(); } private Variable findValueForOID(final OID oid) { final Object val = m_vars.get(oid); if (val == null) { return null; } else if (val instanceof Variable) { return (Variable)val; } return getVariableFromValueString(oid.toString(), (String)val); } /** {@inheritDoc} */ public void get(final SubRequest request) { getVariable(request, request.getVariableBinding().getOid()); } private void getVariable(final SubRequest request, final OID oid) { Variable value = findValueForOID(oid); VariableBinding vb = request.getVariableBinding(); vb.setOid(oid); vb.setVariable(value == null ? Null.noSuchObject : value); request.completed(); } /** * <p>getScope</p> * * @return a {@link org.snmp4j.agent.MOScope} object. */ public MOScope getScope() { return m_scope; } /** {@inheritDoc} */ public boolean next(final SubRequest request) { final OID nextOid = findNextOid(request.getVariableBinding().getOid()); if (nextOid == null) { return false; } getVariable(request, nextOid); return true; } /** {@inheritDoc} */ public void prepare(final SubRequest request) { // store the old value, in case we undo it final VariableBinding vb = request.getVariableBinding(); m_oldValue = m_vars.get(vb.getOid()); final RequestStatus status = request.getStatus(); status.setErrorStatus(SnmpConstants.SNMP_ERROR_SUCCESS); status.setPhaseComplete(true); } /** {@inheritDoc} */ public void commit(final SubRequest request) { final VariableBinding vb = request.getVariableBinding(); final Variable v = vb.getVariable(); m_vars.put(vb.getOid(), v); final RequestStatus status = request.getStatus(); status.setPhaseComplete(true); } /** {@inheritDoc} */ public void cleanup(final SubRequest request) { m_oldValue = null; final RequestStatus status = request.getStatus(); status.setPhaseComplete(true); } /** {@inheritDoc} */ public void undo(final SubRequest request) { m_vars.put(request.getVariableBinding().getOid(), m_oldValue); m_oldValue = null; final RequestStatus status = request.getStatus(); status.setErrorStatus(SnmpConstants.SNMP_ERROR_SUCCESS); status.setPhaseComplete(true); } /** {@inheritDoc} */ public void updateValue(final OID oid, final Variable value) { m_vars.put(oid, value); } /** * <p>isAccessibleForCreate</p> * * @return a boolean. */ public boolean isAccessibleForCreate() { return false; } /** * <p>isAccessibleForNotify</p> * * @return a boolean. */ public boolean isAccessibleForNotify() { return false; } /** * <p>isAccessibleForRead</p> * * @return a boolean. */ public boolean isAccessibleForRead() { return true; } /** * <p>isAccessibleForWrite</p> * * @return a boolean. */ public boolean isAccessibleForWrite() { return false; } /** * <p>getVariableFromValueString</p> * * @param oidStr a {@link java.lang.String} object. * @param valStr a {@link java.lang.String} object. * @return a {@link org.snmp4j.smi.Variable} object. */ private Variable getVariableFromValueString(String oidStr, String valStr) { Variable newVar; if ("\"\"".equals(valStr)) { newVar = new Null(); } else { String moTypeStr = valStr.substring(0, valStr.indexOf(":")); String moValStr = valStr.substring(valStr.indexOf(":") + 2); try { if (moTypeStr.equals("STRING")) { newVar = new OctetString(moValStr); } else if (moTypeStr.equals("Hex-STRING")) { newVar = OctetString.fromHexString(moValStr.trim().replace(' ', ':')); } else if (moTypeStr.equals("INTEGER")) { newVar = new Integer32(Integer.parseInt(moValStr)); } else if (moTypeStr.equals("Gauge32")) { newVar = new Gauge32(Long.parseLong(moValStr)); } else if (moTypeStr.equals("Counter32")) { newVar = new Counter32(Long.parseLong(moValStr)); // a 32 bit counter can be > 2 ^ 31, which is > INTEGER_MAX } else if (moTypeStr.equals("Counter64")) { newVar = new Counter64(Long.parseLong(moValStr)); } else if (moTypeStr.equals("Timeticks")) { Integer ticksInt = Integer.parseInt( moValStr.substring( moValStr.indexOf("(") + 1, moValStr.indexOf(")") ) ); newVar = new TimeTicks(ticksInt); } else if (moTypeStr.equals("OID")) { newVar = new OID(moValStr); } else if (moTypeStr.equals("IpAddress")) { newVar = new IpAddress(moValStr.trim()); } else if (moTypeStr.equals("Network Address")) { newVar = OctetString.fromHexString(moValStr.trim()); } else { // Punt, assume it's a String //newVar = new OctetString(moValStr); throw new IllegalArgumentException("Unrecognized SNMP Type "+moTypeStr); } } catch (Throwable t) { throw new UndeclaredThrowableException(t, "Could not convert value '" + moValStr + "' of type '" + moTypeStr + "' to SNMP object for OID " + oidStr); } } return newVar; } }