Package org.jboss.jmx.adaptor.snmp.agent

Source Code of org.jboss.jmx.adaptor.snmp.agent.RequestHandlerImpl$BindEntry

/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.jmx.adaptor.snmp.agent;

import java.io.InputStream;
import java.net.InetAddress;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.management.Attribute;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.jboss.jmx.adaptor.snmp.config.attribute.AttributeMappings;
import org.jboss.jmx.adaptor.snmp.config.attribute.ManagedBean;
import org.jboss.jmx.adaptor.snmp.config.attribute.MappedAttribute;
import org.jboss.logging.Logger;
import org.jboss.xb.binding.ObjectModelFactory;
import org.jboss.xb.binding.Unmarshaller;
import org.jboss.xb.binding.UnmarshallerFactory;
import org.opennms.protocols.snmp.*;

/**
* Implement RequestHandler with mapping of snmp get/set requests
* to JMX mbean attribute gets/sets
*
* @author <a href="mailto:hwr@pilhuhn.de>">Heiko W. Rupp</a>
* @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
* @version $Revision: 95976 $
*/
public class RequestHandlerImpl extends RequestHandlerSupport
   implements Reconfigurable
{
  // Protected Data ------------------------------------------------

  private static final String NO_ENTRY_FOUND_FOR_OID = "No entry found for oid ";
  private static final String SKIP_ENTRY = " - skipping entry";


  /** Bindings from oid to mbean */
  protected SortedMap bindings = new TreeMap();

  private SortedSet oidKeys = null;

  /** Has this RequestHandler instance been initialized? */
  private boolean initialized = false;

  // Constructors --------------------------------------------------

  /**
   * Default CTOR
   */
  public RequestHandlerImpl()
  {
    bindings = new TreeMap();
    oidKeys = new TreeSet();
  }

  // RequestHandler Implementation ---------------------------------

  /**
   * Initialize
   *
   * @param resourceName A file containing get/set mappings
   * @param server Our MBean-Server
   * @param log The logger we use
   * @param uptime The uptime of the snmp-agent subsystem.
   */
  public void initialize(String resourceName, MBeanServer server, Logger log, Clock uptime)
      throws Exception
   {
      log.debug("initialize() with res=" + resourceName);
     super.initialize(resourceName, server, log, uptime);
    if (resourceName != null)
      initializeBindings();
    else
      log.warn("No RequestHandlerResName configured, disabling snmp-get");

    initialized = true;
  }

   // Reconfigurable Implementation ---------------------------------
   /**
    * Reconfigures the RequestHandler
    */
   public void reconfigure(String resName) throws Exception
   {
      if (resName == null || resName.equals(""))
         throw new IllegalArgumentException("Null or empty resName, cannot reconfigure");

      if (initialized == false)
         throw new IllegalStateException("Cannot reconfigure, not initialized yet");
     
      this.resourceName = resName;
  
      // Wipe out old entries
      bindings.clear();
     
      // Fetch them again
      initializeBindings();
   }
  
  // SnmpAgentHandler Implementation -------------------------------

  /**
   * <P>
   * This method is defined to handle SNMP Get requests that are received by
   * the session. The request has already been validated by the system. This
   * routine will build a response and pass it back to the caller.
   * </P>
   *
   * @param pdu
   *            The SNMP pdu
   * @param getNext
   *            The agent is requesting the lexically NEXT item after each
   *            item in the pdu.
   *
   * @return SnmpPduRequest filled in with the proper response, or null if
   *         cannot process NOTE: this might be changed to throw an exception.
   */
  public SnmpPduRequest snmpReceivedGet(SnmpPduPacket pdu, boolean getNext)
  {
    try
    {
      SnmpPduRequest response = null;
      int pduLength = pdu.getLength();
      final boolean trace = log.isTraceEnabled();

      if (trace)
        log.trace("requestId=" + pdu.getRequestId() + ", pduLength="
            + pduLength + ", getNext=" + getNext);

      SnmpVarBind[] vblist = new SnmpVarBind[pduLength];
      int errorStatus = SnmpPduPacket.ErrNoError;
      int errorIndex = 0;

      // Process for each varibind in the request
      for (int i = 0; i < pduLength; i++)
      {
        boolean good = true;
        SnmpVarBind vb = pdu.getVarBindAt(i);
        SnmpObjectId oid = vb.getName();
        if (getNext)
        {
          /*
           * We call getNextOid() to find out what is the next valid OID
           * instance in the supported MIB (sub-)tree. Assign that OID to the
           * VB List and then proceed same as that of get request. If the
           * passed oid is already the last, we flag it.
           */
          ComparableSnmpObjectId coid = new ComparableSnmpObjectId(oid);
          oid = getNextOid(coid, true);
          if (oid == null)
          {
            good = false;
          }
          else
          {
            pdu.setVarBindAt(i, new SnmpVarBind(oid));
          }
        }
        if (oid!=null)
          vblist[i] = new SnmpVarBind(oid);
        else
          vblist[i] = new SnmpVarBind(vb.getName()); // oid passed in
       

        if (trace)
          log.trace("oid=" + oid);

        SnmpSyntax result = null;
        if (good && bindings != null)
          result = getValueFor(oid);

        if (trace)
          log.trace("got result of " + result);

        if (result == null || !good)
        {
          errorStatus = SnmpPduPacket.ErrNoSuchName;
          errorIndex = i + 1;
          log.debug("Error Occured " + vb.getName().toString());
        }
        else
        {
          vblist[i].setValue(result);
          log.debug("Varbind[" + i + "] := "
                  + vblist[i].getName().toString());
          log.debug(" --> " + vblist[i].getValue().toString());
        }
      } // for ...
      response = new SnmpPduRequest(SnmpPduPacket.RESPONSE, vblist);
      response.setErrorStatus(errorStatus);
      response.setErrorIndex(errorIndex);
      return response;
    } catch (Exception e)
    {
      // TODO Auto-generated catch block
      e.printStackTrace();
      return null;
    }
  }

  /**
   * <P>
   * This method is defined to handle SNMP Set requests that are received by
   * the session. The request has already been validated by the system. This
   * routine will build a response and pass it back to the caller.
   * </P>
   *
   * @param pdu
   *           The SNMP pdu
   *
   * @return SnmpPduRequest filled in with the proper response, or null if
   *         cannot process NOTE: this might be changed to throw an exception.
   */
  public SnmpPduRequest snmpReceivedSet(SnmpPduPacket pdu)
   {
    final boolean trace = log.isTraceEnabled();
    SnmpPduRequest response = null;
    int errorStatus = SnmpPduPacket.ErrNoError;
    int errorIndex = 0;
    int k = pdu.getLength();
    SnmpVarBind[] vblist = new SnmpVarBind[k];

    for (int i = 0; i < k; i++)
      {
      SnmpVarBind vb = pdu.getVarBindAt(i);
      vblist[i] = new SnmpVarBind(vb);
      SnmpObjectId oid = vb.getName();
      SnmpSyntax newVal = vb.getValue();
      if (trace)
        log.trace("set: received oid " + oid.toString() + " with value " + newVal.toString());
      SnmpSyntax result = null;
      try
         {
        result = setValueFor(oid,newVal);
      }
         catch (ReadOnlyException e)
         {
        errorStatus = SnmpPduPacket.ErrReadOnly;
        errorIndex = i + 1;
      }

       if (result != null)
       {
        errorStatus = SnmpPduPacket.ErrReadOnly;
        errorIndex = i + 1;
        log.debug("Error occured " + vb.getName().toString());
       }

       if (trace)
          {
         log.trace("Varbind[" + i + "] := " + vb.getName().toString());
         log.trace(" --> " + vb.getValue().toString());
       }
    }
    response = new SnmpPduRequest(SnmpPduPacket.RESPONSE, vblist);
    response.setErrorStatus(errorStatus);
    response.setErrorIndex(errorIndex);

    return response;
  }

  /**
   * <P>
   * This method is defined to handle SNMP requests that are received by the
   * session. The parameters allow the handler to determine the host, port,
   * and community string of the received PDU
   * </P>
   *
   * @param session
   *            The SNMP session
   * @param manager
   *            The remote sender
   * @param port
   *            The remote senders port
   * @param community
   *            The community string
   * @param pdu
   *            The SNMP pdu
   *
   */
  public void snmpReceivedPdu(SnmpAgentSession session, InetAddress manager,
      int port, SnmpOctetString community, SnmpPduPacket pdu)
   {
    log.error("Message from manager " + manager.toString() + " on port " + port);
    int cmd = pdu.getCommand();
    log.error("Unsupported PDU command......... " + cmd);
  }

  /**
   * <P>
   * This method is invoked if an error occurs in the session. The error code
   * that represents the failure will be passed in the second parameter,
   * 'error'. The error codes can be found in the class SnmpAgentSession
   * class.
   * </P>
   *
   * <P>
   * If a particular PDU is part of the error condition it will be passed in
   * the third parameter, 'pdu'. The pdu will be of the type SnmpPduRequest or
   * SnmpPduTrap object. The handler should use the "instanceof" operator to
   * determine which type the object is. Also, the object may be null if the
   * error condition is not associated with a particular PDU.
   * </P>
   *
   * @param session
   *            The SNMP Session
   * @param error
   *            The error condition value.
   * @param ref
   *            The PDU reference, or potentially null. It may also be an
   *            exception.
   */
  public void SnmpAgentSessionError(SnmpAgentSession session, int error, Object ref)
   {
    log.error("An error occured in the trap session");
    log.error("Session error code = " + error);
    if (ref != null)
      {
      log.error("Session error reference: " + ref.toString());
    }

    if (error == SnmpAgentSession.ERROR_EXCEPTION)
      {
      synchronized (session)
         {
        session.notify(); // close the session
      }
    }
  }

   // Private -------------------------------------------------------
  
  /**
   * Initialize the bindings from the file given in resourceName
   */
  private void initializeBindings() throws Exception
   {
      log.debug("Reading resource: '" + resourceName + "'");
     
      ObjectModelFactory omf = new AttributeMappingsBinding();
      InputStream is = null;
      AttributeMappings mappings = null;
      try
      {
         // locate resource
         is = SecurityActions.getThreadContextClassLoaderResource(resourceName);
        
         // create unmarshaller
         Unmarshaller unmarshaller = UnmarshallerFactory.newInstance().newUnmarshaller();

         // let JBossXB do it's magic using the AttributeMappingsBinding
         mappings = (AttributeMappings)unmarshaller.unmarshal(is, omf, null);        
      }
      catch (Exception e)
      {
         log.error("Accessing resource '" + resourceName + "'");
         throw e;
      }
      finally
      {
         if (is != null)
         {
            // close the XML stream
            is.close();           
         }
      }
      if (mappings == null)
      {
         log.warn("No bindings found in " + resourceName);
         return;        
      }
      log.debug("Found " + mappings.size() + " attribute mappings");    
    /**
     * We have the MBeans now. Put them into the bindungs.
     */

    Iterator it = mappings.iterator();
    while (it.hasNext())
      {
       ManagedBean mmb = (ManagedBean)it.next();
       String oidPrefix = mmb.getOidPrefix();
       List attrs = mmb.getAttributes();
       Iterator aIt = attrs.iterator();
       while (aIt.hasNext())
       {
          MappedAttribute ma = (MappedAttribute)aIt.next();
          String oid;
          if (oidPrefix != null)
             oid = oidPrefix + ma.getOid();
          else
             oid = ma.getOid();
          
          BindEntry be = new BindEntry(oid, mmb.getName(), ma.getName());
          be.isReadWrite = ma.isReadWrite();
         
          ComparableSnmpObjectId coid = new ComparableSnmpObjectId(oid);
         
          if (log.isTraceEnabled())
             log.trace("New bind entry   " + be);
          if (bindings.containsKey(coid)) {
             log.info("Duplicate oid " + oid + SKIP_ENTRY);
             continue;
          }
          if (mmb.getName() == null || mmb.getName().equals(""))
          {
             log.info("Invalid mbean name for oid " + oid + SKIP_ENTRY);
             continue;
          }
          if (ma.getName() == null || ma.getName().equals(""))
          {
             log.info("Invalid attribute name " + ma.getName() + " for oid " + oid + SKIP_ENTRY);
             continue;
          }
          bindings.put(coid, be);
          oidKeys.add(coid);
         
       }
      }
   }

  /**
   * Return the current value for the given oid
   *
   * @param oid
   *            The oid we want a value for
   * @return SnmpNull if no value present
   */
  private SnmpSyntax getValueFor(final SnmpObjectId oid) {

    BindEntry be = findBindEntryForOid(oid);
    SnmpSyntax ssy = null;
    if (be != null)
      {
      if (log.isTraceEnabled())
        log.trace("Found entry " + be.toString() + " for oid " + oid);
        
      try
         {
         Object val = server.getAttribute(be.mbean, be.attr.getName());

        if (val instanceof Long)
            {
          Long uin = (Long) val;
          ssy = new SnmpUInt32(uin);
        }
            else if (val instanceof String)
            {
          String in = (String) val;
          ssy = new SnmpOctetString(in.getBytes());
        }
            else if (val instanceof Integer)
            {
          Integer in = (Integer) val;
          ssy = new SnmpInt32(in);
        }
            else if (val instanceof SnmpObjectId)
            {
          ssy = (SnmpObjectId)val;
        }
            else if (val instanceof SnmpTimeTicks)
            {
               ssy = (SnmpTimeTicks)val;
            }
            else
          log.info("Unknown type for " + be);
      }
         catch (Exception e)
         {
        log.warn("getValueFor (" + be.mbean.toString() + ", "
            + be.attr.getName() + ": " + e.toString());
         }
      }
      else
      {
      ssy = new SnmpNull();
      log.info(NO_ENTRY_FOUND_FOR_OID + oid);
    }
    return ssy;
  }
 
  /**
   * Set a jmx attribute
   * @param oid The oid to set. This is translated into a mbean / attribute pair
   * @param newVal The new value to set
   * @return null on success, non-null on failure
   * @throws ReadOnlyException If the referred entry is read only.
   */
  private SnmpSyntax setValueFor(final SnmpObjectId oid, final SnmpSyntax newVal) throws ReadOnlyException
   {
    final boolean trace = log.isTraceEnabled();
   
    BindEntry be = findBindEntryForOid(oid);
   
    if (trace)
      log.trace("setValueFor: found bind entry for " + oid);
   
    SnmpSyntax ssy = null;
    if (be != null)
      {
      if (trace)
        log.trace("setValueFor: " + be.toString());
        
      if (be.isReadWrite == false)
         {
        if (trace)
          log.trace("setValueFor: this is marked read only");
           
        throw new ReadOnlyException(oid);
      }
      try
         {
        Object val = null;
        if (newVal instanceof SnmpOctetString)
            {
          val = newVal.toString();
        }
        else if (newVal instanceof SnmpInt32)
            {
          val = new Integer(((SnmpInt32)newVal).getValue());
        }
        else if (newVal instanceof SnmpUInt32)
            {
          val = new Long(((SnmpUInt32)newVal).getValue());
        }
        // TODO do more mumbo jumbo for type casting / changing
       
        if (val != null)
            {
          Attribute at = new Attribute(be.attr.getName(), val);
          server.setAttribute(be.mbean, at);
          if (trace)
            log.trace("setValueFor: set attribute in mbean-Server");
        }
        else
            {
          log.debug("Did not find a suitable data type for newVal " + newVal);
          ssy = new SnmpNull();
        }
        // TODO
      }
      catch (Exception e )
         {
        log.debug("setValueFor: exception " + e.getMessage());
        ssy = new SnmpNull();
      }
    }
    else
      {
      ssy = new SnmpNull();
      log.info(NO_ENTRY_FOUND_FOR_OID + oid);
    }
    return ssy;
  }


  /**
   * Lookup a BinEntry on the given oid. If the oid ends in .0,
   * then the .0 will be stripped of before the search.
   * @param oid The oid look up.
   * @return a bind entry or null.
   */
  private BindEntry findBindEntryForOid(final SnmpObjectId oid) {
   
    ComparableSnmpObjectId coid= new ComparableSnmpObjectId(oid);
   
    if (coid.isLeaf())
    {
      coid = coid.removeLastPart();
    }
    BindEntry be = (BindEntry)bindings.get(coid);

    return be;
  }

  /**
   * Return the next oid that is larger than ours.
   * @param oid the starting oid
   * @param stayInSubtree if true, the next oid will not have a different prefix than the one of oid.
   * @return the next oid or null if none found.
   */
  private ComparableSnmpObjectId getNextOid(final ComparableSnmpObjectId oid, boolean stayInSubtree) {
    ComparableSnmpObjectId coid = new ComparableSnmpObjectId(oid);


    if (coid.isLeaf())
      coid = coid.removeLastPart();

    SortedSet ret;
    ret= oidKeys.tailSet(oid)// get oids >= oid
    Iterator it = ret.iterator();
    ComparableSnmpObjectId roid=null;
   
    /*
     * If there are elements in the tail set, then
     * - get first one.
     * - if first is input (which it is supposed to be according to the contract of
     *   SortedSet.tailSet() , then get next, which is the
     *   one we look for.
     */
    if (it.hasNext())
    {
      roid = (ComparableSnmpObjectId)it.next(); // oid
    }
   
    if (roid == null)
    {
      return null; // roid is null,
    }
   
    if (roid.compareTo(coid)==0) // input elment
    {
      // if there is a next element, then it is ours.
      if (it.hasNext())
      {
        roid = (ComparableSnmpObjectId)it.next();
      }
      else
      {
        roid = null; // end of list
      }
    }
     
    /*
     * Check if still in subtree if requested to stay within
     */
    if (stayInSubtree && roid != null)
    {
      ComparableSnmpObjectId parent = coid.removeLastPart();
      if (!parent.isRootOf(roid))
        roid = null;
    }

    return roid;
  }


   // Inner Class ---------------------------------------------------
  
  /**
   * An entry containing the mapping between oid and mbean/attribute
   *
   * @author <a href="mailto:pilhuhn@user.sf.net>">Heiko W. Rupp</a>
   */
  private class BindEntry implements Comparable {
    private final ComparableSnmpObjectId oid;

    private ObjectName mbean;
      private Attribute attr;
    private String mName;
      private String aName;     
    private boolean isReadWrite = false;

    /**
     * Constructs a new BindEntry
     *
     * @param oid
     *            The SNMP-oid, this entry will use.
     * @param mbName
     *            The name of an MBean with attribute to query
     * @param attrName
     *            The name of the attribute to query
     */
    BindEntry(final String oidString, final String mbName, final String attrName) {
      this(new ComparableSnmpObjectId(oidString),
          mbName,
          attrName);
    }
   
    /**
     * Constructs a new BindEntry.
     * @param coid The SNMP-oid, this entry will use.
     * @param mbName The name of an MBean with attribute to query
     * @param attrName The name of the attribute to query
     */
    BindEntry(final ComparableSnmpObjectId coid, final String mbName, final String attrName) {
      oid = coid;
      this.mName = mbName;
      this.aName = attrName;
      try
         {
         mbean = new ObjectName(mbName);
        attr = new Attribute(attrName, null);

      }
         catch (Exception e)
         {
            log.warn(e.toString());
        mName = "-unset-";
        aName = "-unset-";
      }
    }

    /**
     * A string representation of this BindEntry
     */
    public String toString() {
      StringBuffer buf = new StringBuffer();
      buf.append("[oid=");
      buf.append(oid).append(", mbean=");
      buf.append(mName).append(", attr=");
      buf.append(aName).append(", rw=");
      buf.append(isReadWrite).append("]");

      return buf.toString();
    }

    public Attribute getAttr() {
      return attr;
    }

    public ObjectName getMbean()
      {
      return mbean;
    }

    public ComparableSnmpObjectId getOid()
      {
      return oid;
    }


    /**
     * Compare two BindEntries. Ordering is defined at oid-level.
     *
     * @param other
     *            The BindEntry to compare to.
     * @return 0 on equals, 1 if this is bigger than other
     */
    public int compareTo(Object other)
      {
      if (other == null)
        throw new NullPointerException("Can't compare to NULL");

      if (!(other instanceof BindEntry))
        throw new ClassCastException("Parameter is no BindEntry");

      // trivial case
      if (this.equals(other))
        return 0;
        
      BindEntry obe = (BindEntry) other;
      if (getOid().equals(obe.getOid()))
        return 0;

      int res =oid.compare(obe.getOid());
      return res;
    }

  }

}
TOP

Related Classes of org.jboss.jmx.adaptor.snmp.agent.RequestHandlerImpl$BindEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.