alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (SnmpMibTable.java)

This example Java source code file (SnmpMibTable.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

calling, can\'t, delta, hashtable, jmx, log, logging, management, mbeannotificationinfo, object, objectname, override, rowstatus, setting, snmp, snmpoid, snmpstatusexception, snmpvarbind, util, vector

The SnmpMibTable.java Java example source code

/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.jmx.snmp.agent;

import java.io.Serializable;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.logging.Level;

import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;

import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
import com.sun.jmx.snmp.EnumRowStatus;
import com.sun.jmx.snmp.SnmpInt;
import com.sun.jmx.snmp.SnmpOid;
import com.sun.jmx.snmp.SnmpStatusException;
import com.sun.jmx.snmp.SnmpValue;
import com.sun.jmx.snmp.SnmpVarBind;

/**
 * This class is the base class for SNMP table metadata.
 * <p>
 * Its responsibility is to manage a sorted array of OID indexes
 * according to the SNMP indexing scheme over the "real" table.
 * Each object of this class can be bound to an
 * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} to which it will
 * forward remote entry creation requests, and invoke callbacks
 * when an entry has been successfully added to / removed from
 * the OID index array.
 * </p>
 *
 * <p>
 * For each table defined in the MIB, mibgen will generate a specific
 * class called Table<i>TableName that will implement the
 * SnmpTableEntryFactory interface, and a corresponding
 * <i>TableNameMeta class that will extend this class. 
* The Table<i>TableName class corresponds to the MBean view of the * table while the <i>TableNameMeta class corresponds to the * MIB metadata view of the same table. * </p> * * <p> * Objects of this class are instantiated by the generated * whole MIB class extending {@link com.sun.jmx.snmp.agent.SnmpMib} * You should never need to instantiate this class directly. * </p> * * <p>This API is a Sun Microsystems internal API and is subject * to change without notice.</b>

* @see com.sun.jmx.snmp.agent.SnmpMib * @see com.sun.jmx.snmp.agent.SnmpMibEntry * @see com.sun.jmx.snmp.agent.SnmpTableEntryFactory * @see com.sun.jmx.snmp.agent.SnmpTableSupport * */ public abstract class SnmpMibTable extends SnmpMibNode implements NotificationBroadcaster, Serializable { /** * Create a new <CODE>SnmpMibTable metadata node. * * <p> * @param mib The SNMP MIB to which the metadata will be linked. */ public SnmpMibTable(SnmpMib mib) { this.theMib= mib; setCreationEnabled(false); } // ------------------------------------------------------------------- // PUBLIC METHODS // ------------------------------------------------------------------- /** * This method is invoked when the creation of a new entry is requested * by a remote SNMP manager. * <br>By default, remote entry creation is disabled - and this method * will not be called. You can dynamically switch the entry creation * policy by calling <code>setCreationEnabled(true) and * setCreationEnabled(false)</code> on this object. * <p> * This method is called internally by the SNMP runtime and you * should never need to call it directly. </b>However you might want * to extend it in order to implement your own specific application * behaviour, should the default behaviour not be at your convenience. * </p> * <p> * @param req The SNMP subrequest requesting this creation * @param rowOid The OID indexing the conceptual row (entry) for which * the creation was requested. * @param depth The position of the columnar object arc in the OIDs * from the varbind list. * * @exception SnmpStatusException if the entry cannot be created. */ public abstract void createNewEntry(SnmpMibSubRequest req, SnmpOid rowOid, int depth) throws SnmpStatusException; /** * Tell whether the specific version of this metadata generated * by <code>mibgen requires entries to be registered with * the MBeanServer. In this case an ObjectName will have to be * passed to addEntry() in order for the table to behave correctly * (case of the generic metadata). * <p> * If that version of the metadata does not require entry to be * registered, then passing an ObjectName becomes optional (null * can be passed instead). * * @return <code>true if registration is required by this * version of the metadata. */ public abstract boolean isRegistrationRequired(); /** * Tell whether a new entry should be created when a SET operation * is received for an entry that does not exist yet. * * @return true if a new entry must be created, false otherwise.<br> * [default: returns <CODE>false] **/ public boolean isCreationEnabled() { return creationEnabled; } /** * This method lets you dynamically switch the creation policy. * * <p> * @param remoteCreationFlag Tells whether remote entry creation must * be enabled or disabled. * <ul>
  • * <CODE>setCreationEnabled(true) will enable remote entry * creation via SET operations.</li> * <li> * <CODE>setCreationEnabled(false) will disable remote entry * creation via SET operations.</li> * <p> By default remote entry creation via SET operation is disabled. * </p> * </ul> **/ public void setCreationEnabled(boolean remoteCreationFlag) { creationEnabled = remoteCreationFlag; } /** * Return <code>true if the conceptual row contains a columnar * object used to control creation/deletion of rows in this table. * <p> * This columnar object can be either a variable with RowStatus * syntax as defined by RFC 2579, or a plain variable whose * semantics is table specific. * <p> * By default, this function returns <code>false, and it is * assumed that the table has no such control variable.<br> * When <code>mibgen is used over SMIv2 MIBs, it will generate * an <code>hasRowStatus() method returning true * for each table containing an object with RowStatus syntax. * <p> * When this method returns <code>false the default mechanism * for remote entry creation is used. * Otherwise, creation/deletion is performed as specified * by the control variable (see getRowAction() for more details). * <p> * This method is called internally when a SET request involving * this table is processed. * <p> * If you need to implement a control variable which do not use * the RowStatus convention as defined by RFC 2579, you should * subclass the generated table metadata class in order to redefine * this method and make it returns <code>true.
    * You will then have to redefine the isRowStatus(), mapRowStatus(), * isRowReady(), and setRowStatus() methods to suit your specific * implementation. * <p> * @return <li>true if this table contains a control * variable (eg: a variable with RFC 2579 RowStatus syntax), * </li> * <li>false if this table does not contain * any control variable.</li> * **/ public boolean hasRowStatus() { return false; } // --------------------------------------------------------------------- // // Implements the method defined in SnmpMibNode. // // --------------------------------------------------------------------- /** * Generic handling of the <CODE>get operation. * <p> The default implementation of this method is to * <ul> * <li> check whether the entry exists, and if not register an * exception for each varbind in the list. * <li> call the generated * <CODE>get(req,oid,depth+1) method.
  • * </ul> * <p> * <pre> * public void get(SnmpMibSubRequest req, int depth) * throws SnmpStatusException { * boolean isnew = req.isNewEntry(); * * // if the entry does not exists, then registers an error for * // each varbind involved (nb: this should not happen, since * // the error should already have been detected earlier) * // * if (isnew) { * SnmpVarBind var = null; * for (Enumeration e= req.getElements(); e.hasMoreElements();) { * var = (SnmpVarBind) e.nextElement(); * req.registerGetException(var,noSuchNameException); * } * } * * final SnmpOid oid = req.getEntryOid(); * get(req,oid,depth+1); * } * </pre> * <p> You should not need to override this method in any cases, because * it will eventually call * <CODE>get(SnmpMibSubRequest req, int depth) on the generated * derivative of <CODE>SnmpMibEntry. If you need to implement * specific policies for minimizing the accesses made to some remote * underlying resources, or if you need to implement some consistency * checks between the different values provided in the varbind list, * you should then rather override * <CODE>get(SnmpMibSubRequest req, int depth) on the generated * derivative of <CODE>SnmpMibEntry. * <p> * */ @Override public void get(SnmpMibSubRequest req, int depth) throws SnmpStatusException { final boolean isnew = req.isNewEntry(); final SnmpMibSubRequest r = req; // if the entry does not exists, then registers an error for // each varbind involved (nb: should not happen, the error // should have been registered earlier) if (isnew) { SnmpVarBind var; for (Enumeration<SnmpVarBind> e= r.getElements(); e.hasMoreElements();) { var = e.nextElement(); r.registerGetException(var,new SnmpStatusException(SnmpStatusException.noSuchInstance)); } } final SnmpOid oid = r.getEntryOid(); // SnmpIndex index = buildSnmpIndex(oid.longValue(false), 0); // get(req,index,depth+1); // get(req,oid,depth+1); } // --------------------------------------------------------------------- // // Implements the method defined in SnmpMibNode. // // --------------------------------------------------------------------- /** * Generic handling of the <CODE>check operation. * <p> The default implementation of this method is to * <ul> * <li> check whether a new entry must be created, and if remote * creation of entries is enabled, create it. </li> * <li> call the generated * <CODE>check(req,oid,depth+1) method. * </ul> * <p> * <pre> * public void check(SnmpMibSubRequest req, int depth) * throws SnmpStatusException { * final SnmpOid oid = req.getEntryOid(); * final int action = getRowAction(req,oid,depth+1); * * beginRowAction(req,oid,depth+1,action); * check(req,oid,depth+1); * } * </pre> * <p> You should not need to override this method in any cases, because * it will eventually call * <CODE>check(SnmpMibSubRequest req, int depth) on the generated * derivative of <CODE>SnmpMibEntry. If you need to implement * specific policies for minimizing the accesses made to some remote * underlying resources, or if you need to implement some consistency * checks between the different values provided in the varbind list, * you should then rather override * <CODE>check(SnmpMibSubRequest req, int depth) on the generated * derivative of <CODE>SnmpMibEntry. * <p> * */ @Override public void check(SnmpMibSubRequest req, int depth) throws SnmpStatusException { final SnmpOid oid = req.getEntryOid(); final int action = getRowAction(req,oid,depth+1); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "check", "Calling beginRowAction"); } beginRowAction(req,oid,depth+1,action); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "check", "Calling check for " + req.getSize() + " varbinds"); } check(req,oid,depth+1); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "check", "check finished"); } } // --------------------------------------------------------------------- // // Implements the method defined in SnmpMibNode. // // --------------------------------------------------------------------- /** * Generic handling of the <CODE>set operation. * <p> The default implementation of this method is to * call the generated * <CODE>set(req,oid,depth+1) method. * <p> * <pre> * public void set(SnmpMibSubRequest req, int depth) * throws SnmpStatusException { * final SnmpOid oid = req.getEntryOid(); * final int action = getRowAction(req,oid,depth+1); * * set(req,oid,depth+1); * endRowAction(req,oid,depth+1,action); * } * </pre> * <p> You should not need to override this method in any cases, because * it will eventually call * <CODE>set(SnmpMibSubRequest req, int depth) on the generated * derivative of <CODE>SnmpMibEntry. If you need to implement * specific policies for minimizing the accesses made to some remote * underlying resources, or if you need to implement some consistency * checks between the different values provided in the varbind list, * you should then rather override * <CODE>set(SnmpMibSubRequest req, int depth) on the generated * derivative of <CODE>SnmpMibEntry. * <p> * */ @Override public void set(SnmpMibSubRequest req, int depth) throws SnmpStatusException { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "set", "Entering set"); } final SnmpOid oid = req.getEntryOid(); final int action = getRowAction(req,oid,depth+1); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "set", "Calling set for " + req.getSize() + " varbinds"); } set(req,oid,depth+1); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "set", "Calling endRowAction"); } endRowAction(req,oid,depth+1,action); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "set", "RowAction finished"); } } /** * Add a new entry in this <CODE>SnmpMibTable. * Also triggers the addEntryCB() callback of the * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface * if this node is bound to a factory. * * This method assumes that the given entry will not be registered. * If the entry is going to be registered, or if ObjectName's are * required, then * {@link com.sun.jmx.snmp.agent.SnmpMibTable#addEntry(SnmpOid, * ObjectName, Object)} should be preferred. * <br> This function is mainly provided for backward compatibility. * * <p> * @param rowOid The <CODE>SnmpOid identifying the table * row to be added. * @param entry The entry to add. * * @exception SnmpStatusException The entry couldn't be added * at the position identified by the given * <code>rowOid, or this version of the metadata * requires ObjectName's. */ // public void addEntry(SnmpIndex index, Object entry) public void addEntry(SnmpOid rowOid, Object entry) throws SnmpStatusException { addEntry(rowOid, null, entry); } /** * Add a new entry in this <CODE>SnmpMibTable. * Also triggers the addEntryCB() callback of the * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface * if this node is bound to a factory. * * <p> * @param oid The <CODE>SnmpOid identifying the table * row to be added. * * @param name The ObjectName with which this entry is registered. * This parameter can be omitted if isRegistrationRequired() * return false. * * @param entry The entry to add. * * @exception SnmpStatusException The entry couldn't be added * at the position identified by the given * <code>rowOid, or if this version of the metadata * requires ObjectName's, and the given name is null. */ // protected synchronized void addEntry(SnmpIndex index, ObjectName name, // Object entry) public synchronized void addEntry(SnmpOid oid, ObjectName name, Object entry) throws SnmpStatusException { if (isRegistrationRequired() == true && name == null) throw new SnmpStatusException(SnmpStatusException.badValue); if (size == 0) { // indexes.addElement(index); // XX oids.addElement(oid); insertOid(0,oid); if (entries != null) entries.addElement(entry); if (entrynames != null) entrynames.addElement(name); size++; // triggers callbacks on the entry factory // if (factory != null) { try { factory.addEntryCb(0,oid,name,entry,this); } catch (SnmpStatusException x) { removeOid(0); if (entries != null) entries.removeElementAt(0); if (entrynames != null) entrynames.removeElementAt(0); throw x; } } // sends the notifications // sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_ADDED, (new Date()).getTime(), entry, name); return; } // Get the insertion position ... // int pos= 0; // bug jaw.00356.B : use oid rather than index to get the // insertion point. // pos= getInsertionPoint(oid,true); if (pos == size) { // Add a new element in the vectors ... // // indexes.addElement(index); // XX oids.addElement(oid); insertOid(tablecount,oid); if (entries != null) entries.addElement(entry); if (entrynames != null) entrynames.addElement(name); size++; } else { // Insert new element ... // try { // indexes.insertElementAt(index, pos); // XX oids.insertElementAt(oid, pos); insertOid(pos,oid); if (entries != null) entries.insertElementAt(entry, pos); if (entrynames != null) entrynames.insertElementAt(name,pos); size++; } catch(ArrayIndexOutOfBoundsException e) { } } // triggers callbacks on the entry factory // if (factory != null) { try { factory.addEntryCb(pos,oid,name,entry,this); } catch (SnmpStatusException x) { removeOid(pos); if (entries != null) entries.removeElementAt(pos); if (entrynames != null) entrynames.removeElementAt(pos); throw x; } } // sends the notifications // sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_ADDED, (new Date()).getTime(), entry, name); } /** * Remove the specified entry from the table. * Also triggers the removeEntryCB() callback of the * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface * if this node is bound to a factory. * * <p> * @param rowOid The <CODE>SnmpOid identifying the table * row to remove. * * @param entry The entry to be removed. This parameter is not used * internally, it is simply passed along to the * removeEntryCB() callback. * * @exception SnmpStatusException if the specified entry couldn't * be removed (if the given <code>rowOid is not * valid for instance). */ public synchronized void removeEntry(SnmpOid rowOid, Object entry) throws SnmpStatusException { int pos = findObject(rowOid); if (pos == -1) return; removeEntry(pos,entry); } /** * Remove the specified entry from the table. * Also triggers the removeEntryCB() callback of the * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface * if this node is bound to a factory. * * <p> * @param rowOid The <CODE>SnmpOid identifying the table * row to remove. * * @exception SnmpStatusException if the specified entry couldn't * be removed (if the given <code>rowOid is not * valid for instance). */ public void removeEntry(SnmpOid rowOid) throws SnmpStatusException { int pos = findObject(rowOid); if (pos == -1) return; removeEntry(pos,null); } /** * Remove the specified entry from the table. * Also triggers the removeEntryCB() callback of the * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface * if this node is bound to a factory. * * <p> * @param pos The position of the entry in the table. * * @param entry The entry to be removed. This parameter is not used * internally, it is simply passed along to the * removeEntryCB() callback. * * @exception SnmpStatusException if the specified entry couldn't * be removed. */ public synchronized void removeEntry(int pos, Object entry) throws SnmpStatusException { if (pos == -1) return; if (pos >= size) return; Object obj = entry; if (entries != null && entries.size() > pos) { obj = entries.elementAt(pos); entries.removeElementAt(pos); } ObjectName name = null; if (entrynames != null && entrynames.size() > pos) { name = entrynames.elementAt(pos); entrynames.removeElementAt(pos); } final SnmpOid rowOid = tableoids[pos]; removeOid(pos); size --; if (obj == null) obj = entry; if (factory != null) factory.removeEntryCb(pos,rowOid,name,obj,this); sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_REMOVED, (new Date()).getTime(), obj, name); } /** * Get the entry corresponding to the specified rowOid. * * <p> * @param rowOid The <CODE>SnmpOid identifying the * row to be retrieved. * * @return The entry. * * @exception SnmpStatusException There is no entry with the specified * <code>rowOid in the table. */ public synchronized Object getEntry(SnmpOid rowOid) throws SnmpStatusException { int pos= findObject(rowOid); if (pos == -1) throw new SnmpStatusException(SnmpStatusException.noSuchInstance); return entries.elementAt(pos); } /** * Get the ObjectName of the entry corresponding to the * specified rowOid. * The result of this method is only meaningful if * isRegistrationRequired() yields true. * * <p> * @param rowOid The <CODE>SnmpOid identifying the table * row whose ObjectName we want to retrieve. * * @return The object name of the entry. * * @exception SnmpStatusException There is no entry with the specified * <code>rowOid in the table. */ public synchronized ObjectName getEntryName(SnmpOid rowOid) throws SnmpStatusException { int pos = findObject(rowOid); if (entrynames == null) return null; if (pos == -1 || pos >= entrynames.size()) throw new SnmpStatusException(SnmpStatusException.noSuchInstance); return entrynames.elementAt(pos); } /** * Return the entries stored in this table <CODE>SnmpMibTable. * <p> * If the subclass generated by mibgen uses the generic way to access * the entries (i.e. if it goes through the MBeanServer) then some of * the entries may be <code>null. It all depends whether a non * <code>null entry was passed to addEntry().
    * Otherwise, if it uses the standard way (access the entry directly * through their standard MBean interface) this array will contain all * the entries. * <p> * @return The entries array. */ public Object[] getBasicEntries() { Object[] array= new Object[size]; entries.copyInto(array); return array; } /** * Get the size of the table. * * @return The number of entries currently registered in this table. */ public int getSize() { return size; } // EVENT STUFF //------------ /** * Enable to add an SNMP entry listener to this * <CODE>SnmpMibTable. * * <p> * @param listener The listener object which will handle the * notifications emitted by the registered MBean. * * @param filter The filter object. If filter is null, no filtering * will be performed before handling notifications. * * @param handback The context to be sent to the listener when a * notification is emitted. * * @exception IllegalArgumentException Listener parameter is null. */ @Override public synchronized void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) { // Check listener // if (listener == null) { throw new java.lang.IllegalArgumentException ("Listener can't be null") ; } // looking for listener in handbackTable // Vector<Object> handbackList = handbackTable.get(listener) ; Vector<NotificationFilter> filterList = filterTable.get(listener) ; if ( handbackList == null ) { handbackList = new Vector<>() ; filterList = new Vector<>() ; handbackTable.put(listener, handbackList) ; filterTable.put(listener, filterList) ; } // Add the handback and the filter // handbackList.addElement(handback) ; filterList.addElement(filter) ; } /** * Enable to remove an SNMP entry listener from this * <CODE>SnmpMibTable. * * @param listener The listener object which will handle the * notifications emitted by the registered MBean. * This method will remove all the information related to this * listener. * * @exception ListenerNotFoundException The listener is not registered * in the MBean. */ @Override public synchronized void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { // looking for listener in handbackTable // java.util.Vector<?> handbackList = handbackTable.get(listener) ; if ( handbackList == null ) { throw new ListenerNotFoundException("listener"); } // If handback is null, remove the listener entry // handbackTable.remove(listener) ; filterTable.remove(listener) ; } /** * Return a <CODE>NotificationInfo object containing the * notification class and the notification type sent by the * <CODE>SnmpMibTable. */ @Override public MBeanNotificationInfo[] getNotificationInfo() { String[] types = {SnmpTableEntryNotification.SNMP_ENTRY_ADDED, SnmpTableEntryNotification.SNMP_ENTRY_REMOVED}; MBeanNotificationInfo[] notifsInfo = { new MBeanNotificationInfo (types, "com.sun.jmx.snmp.agent.SnmpTableEntryNotification", "Notifications sent by the SnmpMibTable") }; return notifsInfo; } /** * Register the factory through which table entries should * be created when remote entry creation is enabled. * * <p> * @param factory The * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} through * which entries will be created when a remote SNMP manager * request the creation of a new entry via an SNMP SET request. */ public void registerEntryFactory(SnmpTableEntryFactory factory) { this.factory = factory; } // ---------------------------------------------------------------------- // PROTECTED METHODS - RowStatus // ---------------------------------------------------------------------- /** * Return true if the columnar object identified by <code>var * is used to control the addition/deletion of rows in this table. * * <p> * By default, this method assumes that there is no control variable * and always return <code>false * <p> * If this table was defined using SMIv2, and if it contains a * control variable with RowStatus syntax, <code>mibgen * will generate a non default implementation for this method * that will identify the RowStatus control variable. * <p> * You will have to redefine this method if you need to implement * control variables that do not conform to RFC 2579 RowStatus * TEXTUAL-CONVENTION. * <p> * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param var The OID arc identifying the involved columnar object. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * **/ protected boolean isRowStatus(SnmpOid rowOid, long var, Object userData) { return false; } /** * Return the RowStatus code value specified in this request. * <p> * The RowStatus code value should be one of the values defined * by {@link com.sun.jmx.snmp.EnumRowStatus}. These codes correspond * to RowStatus codes as defined in RFC 2579, plus the <i>unspecified * value which is SNMP Runtime specific. * <p> * * @param req The sub-request that must be handled by this node. * * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param depth The depth reached in the OID tree. * * @return The RowStatus code specified in this request, if any: * <ul> * <li>If the specified row does not exist and this table do * not use any variable to control creation/deletion of * rows, then default creation mechanism is assumed and * <i>createAndGo is returned * <li>Otherwise, if the row exists and this table do not use any * variable to control creation/deletion of rows, * <i>unspecified is returned. * <li>Otherwise, if the request does not contain the control variable, * <i>unspecified is returned. * <li>Otherwise, mapRowStatus() is called to extract the RowStatus * code from the SnmpVarBind that contains the control variable.</li> * </ul> * * @exception SnmpStatusException if the value of the control variable * could not be mapped to a RowStatus code. * * @see com.sun.jmx.snmp.EnumRowStatus **/ protected int getRowAction(SnmpMibSubRequest req, SnmpOid rowOid, int depth) throws SnmpStatusException { final boolean isnew = req.isNewEntry(); final SnmpVarBind vb = req.getRowStatusVarBind(); if (vb == null) { if (isnew && ! hasRowStatus()) return EnumRowStatus.createAndGo; else return EnumRowStatus.unspecified; } try { return mapRowStatus(rowOid, vb, req.getUserData()); } catch( SnmpStatusException x) { checkRowStatusFail(req, x.getStatus()); } return EnumRowStatus.unspecified; } /** * Map the value of the <code>vbstatus varbind to the * corresponding RowStatus code defined in * {@link com.sun.jmx.snmp.EnumRowStatus}. * These codes correspond to RowStatus codes as defined in RFC 2579, * plus the <i>unspecified value which is SNMP Runtime specific. * <p> * By default, this method assumes that the control variable is * an Integer, and it simply returns its value without further * analysis. * <p> * If this table was defined using SMIv2, and if it contains a * control variable with RowStatus syntax, <code>mibgen * will generate a non default implementation for this method. * <p> * You will have to redefine this method if you need to implement * control variables that do not conform to RFC 2579 RowStatus * TEXTUAL-CONVENTION. * * <p> * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param vbstatus The SnmpVarBind containing the value of the control * variable, as identified by the isRowStatus() method. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @return The RowStatus code mapped from the value contained * in <code>vbstatus. * * @exception SnmpStatusException if the value of the control variable * could not be mapped to a RowStatus code. * * @see com.sun.jmx.snmp.EnumRowStatus **/ protected int mapRowStatus(SnmpOid rowOid, SnmpVarBind vbstatus, Object userData) throws SnmpStatusException { final SnmpValue rsvalue = vbstatus.value; if (rsvalue instanceof SnmpInt) return ((SnmpInt)rsvalue).intValue(); else throw new SnmpStatusException( SnmpStatusException.snmpRspInconsistentValue); } /** * Set the control variable to the specified <code>newStatus * value. * * <p> * This method maps the given <code>newStatus to the appropriate * value for the control variable, then sets the control variable in * the entry identified by <code>rowOid. It returns the new * value of the control variable. * <p> * By default, it is assumed that there is no control variable so this * method does nothing and simply returns <code>null. * <p> * If this table was defined using SMIv2, and if it contains a * control variable with RowStatus syntax, <code>mibgen * will generate a non default implementation for this method. * <p> * You will have to redefine this method if you need to implement * control variables that do not conform to RFC 2579 RowStatus * TEXTUAL-CONVENTION. * * <p> * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param newStatus The new status for the row: one of the * RowStatus code defined in * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes * correspond to RowStatus codes as defined in RFC 2579, * plus the <i>unspecified value which is SNMP Runtime specific. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @return The new value of the control variable (usually * <code>new SnmpInt(newStatus)) or null * if the table do not have any control variable. * * @exception SnmpStatusException If the given <code>newStatus * could not be set on the specified entry, or if the * given <code>newStatus is not valid. * * @see com.sun.jmx.snmp.EnumRowStatus **/ protected SnmpValue setRowStatus(SnmpOid rowOid, int newStatus, Object userData) throws SnmpStatusException { return null; } /** * Tell whether the specified row is ready and can be put in the * <i>notInService state. * <p> * This method is called only once, after all the varbind have been * set on a new entry for which <i>createAndWait was specified. * <p> * If the entry is not yet ready, this method should return false. * It will then be the responsibility of the entry to switch its * own state to <i>notInService when it becomes ready. * No further call to <code>isRowReady() will be made. * <p> * By default, this method always return true. <br> * <code>mibgen will not generate any specific implementation * for this method - meaning that by default, a row created using * <i>createAndWait will always be placed in notInService * state at the end of the request. * <p> * If this table was defined using SMIv2, and if it contains a * control variable with RowStatus syntax, <code>mibgen * will generate an implementation for this method that will * delegate the work to the metadata class modelling the conceptual * row, so that you can override the default behaviour by subclassing * that metadata class. * <p> * You will have to redefine this method if this default mechanism * does not suit your needs. * * <p> * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @return <code>true if the row can be placed in * <i>notInService state. * * @exception SnmpStatusException An error occurred while trying * to retrieve the row status, and the operation should * be aborted. * * @see com.sun.jmx.snmp.EnumRowStatus **/ protected boolean isRowReady(SnmpOid rowOid, Object userData) throws SnmpStatusException { return true; } /** * Check whether the control variable of the given row can be * switched to the new specified <code>newStatus. * <p> * This method is called during the <i>check phase of a SET * request when the control variable specifies <i>active or * <i>notInService. * <p> * By default it is assumed that nothing prevents putting the * row in the requested state, and this method does nothing. * It is simply provided as a hook so that specific checks can * be implemented. * <p> * Note that if the actual row deletion fails afterward, the * atomicity of the request is no longer guaranteed. * * <p> * @param req The sub-request that must be handled by this node. * * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param depth The depth reached in the OID tree. * * @param newStatus The new status for the row: one of the * RowStatus code defined in * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes * correspond to RowStatus codes as defined in RFC 2579, * plus the <i>unspecified value which is SNMP Runtime specific. * * @exception SnmpStatusException if switching to this new state * would fail. * **/ protected void checkRowStatusChange(SnmpMibSubRequest req, SnmpOid rowOid, int depth, int newStatus) throws SnmpStatusException { } /** * Check whether the specified row can be removed from the table. * <p> * This method is called during the <i>check phase of a SET * request when the control variable specifies <i>destroy * <p> * By default it is assumed that nothing prevents row deletion * and this method does nothing. It is simply provided as a hook * so that specific checks can be implemented. * <p> * Note that if the actual row deletion fails afterward, the * atomicity of the request is no longer guaranteed. * * <p> * @param req The sub-request that must be handled by this node. * * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param depth The depth reached in the OID tree. * * @exception SnmpStatusException if the row deletion must be * rejected. **/ protected void checkRemoveTableRow(SnmpMibSubRequest req, SnmpOid rowOid, int depth) throws SnmpStatusException { } /** * Remove a table row upon a remote manager request. * * This method is called internally when <code>getRowAction() * yields <i>destroy - i.e.: it is only called when a remote * manager requests the removal of a table row.<br> * You should never need to call this function directly. * <p> * By default, this method simply calls <code>removeEntry(rowOid) * </code>. * <p> * You can redefine this method if you need to implement some * specific behaviour when a remote row deletion is invoked. * <p> * Note that specific checks should not be implemented in this * method, but rather in <code>checkRemoveTableRow(). * If <code>checkRemoveTableRow() succeeds and this method * fails afterward, the atomicity of the original SET request can no * longer be guaranteed. * <p> * * @param req The sub-request that must be handled by this node. * * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param depth The depth reached in the OID tree. * * @exception SnmpStatusException if the actual row deletion fails. * This should not happen since it would break the * atomicity of the SET request. Specific checks should * be implemented in <code>checkRemoveTableRow() * if needed. If the entry does not exists, no exception * is generated and the method simply returns. * **/ protected void removeTableRow(SnmpMibSubRequest req, SnmpOid rowOid, int depth) throws SnmpStatusException { removeEntry(rowOid); } /** * This method takes care of initial RowStatus handling during the * check() phase of a SET request. * * In particular it will: * <ul>
  • check that the given rowAction returned by * <code>getRowAction() is valid.
  • * <li>Then depending on the rowAction specified it will: * <ul>
  • either call createNewEntry() ( * rowAction = <i>createAndGo or createAndWait * </code>),
  • * <li>or call checkRemoveTableRow() ( * rowAction = <i>destroy), * <li>or call checkRowStatusChange() ( * rowAction = <i>active or notInService), * <li>or generate a SnmpStatusException if the passed * rowAction</code> is not correct. * </ul> * <p> * In principle, you should not need to redefine this method. * <p> * <code>beginRowAction() is called during the check phase * of a SET request, before actual checking on the varbind list * is performed. * * <p> * @param req The sub-request that must be handled by this node. * * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param depth The depth reached in the OID tree. * * @param rowAction The requested action as returned by <code> * getRowAction()</code>: one of the RowStatus codes defined in * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes * correspond to RowStatus codes as defined in RFC 2579, * plus the <i>unspecified value which is SNMP Runtime specific. * * @exception SnmpStatusException if the specified <code>rowAction * is not valid or cannot be executed. * This should not happen since it would break the * atomicity of the SET request. Specific checks should * be implemented in <code>beginRowAction() if needed. * * @see com.sun.jmx.snmp.EnumRowStatus **/ protected synchronized void beginRowAction(SnmpMibSubRequest req, SnmpOid rowOid, int depth, int rowAction) throws SnmpStatusException { final boolean isnew = req.isNewEntry(); final SnmpOid oid = rowOid; final int action = rowAction; switch (action) { case EnumRowStatus.unspecified: if (isnew) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "beginRowAction", "Failed to create row[" + rowOid + "] : RowStatus = unspecified"); } checkRowStatusFail(req,SnmpStatusException.snmpRspNoAccess); } break; case EnumRowStatus.createAndGo: case EnumRowStatus.createAndWait: if (isnew) { if (isCreationEnabled()) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "beginRowAction", "Creating row[" + rowOid + "] : RowStatus = createAndGo | createAndWait"); } createNewEntry(req,oid,depth); } else { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "beginRowAction", "Can't create row[" + rowOid + "] : RowStatus = createAndGo | createAndWait " + "but creation is disabled"); } checkRowStatusFail(req, SnmpStatusException.snmpRspNoAccess); } } else { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "beginRowAction", "Can't create row[" + rowOid + "] : RowStatus = createAndGo | createAndWait " + "but row already exists"); } checkRowStatusFail(req, SnmpStatusException.snmpRspInconsistentValue); } break; case EnumRowStatus.destroy: if (isnew) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "beginRowAction", "Warning: can't destroy row[" + rowOid + "] : RowStatus = destroy but row does not exist"); } } else if (!isCreationEnabled()) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "beginRowAction", "Can't destroy row[" + rowOid + "] : " + "RowStatus = destroy but creation is disabled"); } checkRowStatusFail(req,SnmpStatusException.snmpRspNoAccess); } checkRemoveTableRow(req,rowOid,depth); break; case EnumRowStatus.active: case EnumRowStatus.notInService: if (isnew) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "beginRowAction", "Can't switch state of row[" + rowOid + "] : specified RowStatus = active | " + "notInService but row does not exist"); } checkRowStatusFail(req, SnmpStatusException.snmpRspInconsistentValue); } checkRowStatusChange(req,rowOid,depth,action); break; case EnumRowStatus.notReady: default: if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "beginRowAction", "Invalid RowStatus value for row[" + rowOid + "] : specified RowStatus = " + action); } checkRowStatusFail(req, SnmpStatusException.snmpRspInconsistentValue); } } /** * This method takes care of final RowStatus handling during the * set() phase of a SET request. * * In particular it will: * <ul>
  • either call setRowStatus(active) * (<code> rowAction = createAndGo or active * </code>),
  • * <li>or call setRowStatus(notInService or * notReady</i>) depending on the result of * isRowReady()</code> (rowAction = createAndWait * </code>), * <li>or call setRowStatus(notInService) * (<code> rowAction = notInService), * <li>or call removeTableRow() ( * rowAction = <i>destroy), * <li>or generate a SnmpStatusException if the passed * rowAction</code> is not correct. This should be avoided * since it would break SET request atomicity</li> * </ul> * <p> * In principle, you should not need to redefine this method. * <p> * <code>endRowAction() is called during the set() phase * of a SET request, after the actual set() on the varbind list * has been performed. The varbind containing the control variable * is updated with the value returned by setRowStatus() (if it is * not <code>null). * * <p> * @param req The sub-request that must be handled by this node. * * @param rowOid The <CODE>SnmpOid identifying the table * row involved in the operation. * * @param depth The depth reached in the OID tree. * * @param rowAction The requested action as returned by <code> * getRowAction()</code>: one of the RowStatus codes defined in * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes * correspond to RowStatus codes as defined in RFC 2579, * plus the <i>unspecified value which is SNMP Runtime specific. * * @exception SnmpStatusException if the specified <code>rowAction * is not valid. * * @see com.sun.jmx.snmp.EnumRowStatus **/ protected void endRowAction(SnmpMibSubRequest req, SnmpOid rowOid, int depth, int rowAction) throws SnmpStatusException { final boolean isnew = req.isNewEntry(); final SnmpOid oid = rowOid; final int action = rowAction; final Object data = req.getUserData(); SnmpValue value = null; switch (action) { case EnumRowStatus.unspecified: break; case EnumRowStatus.createAndGo: if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "endRowAction", "Setting RowStatus to 'active' " + "for row[" + rowOid + "] : requested RowStatus = " + "createAndGo"); } value = setRowStatus(oid,EnumRowStatus.active,data); break; case EnumRowStatus.createAndWait: if (isRowReady(oid,data)) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "endRowAction", "Setting RowStatus to 'notInService' for row[" + rowOid + "] : requested RowStatus = createAndWait"); } value = setRowStatus(oid,EnumRowStatus.notInService,data); } else { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "endRowAction", "Setting RowStatus to 'notReady' " + "for row[" + rowOid + "] : requested RowStatus = " + "createAndWait"); } value = setRowStatus(oid,EnumRowStatus.notReady,data); } break; case EnumRowStatus.destroy: if (isnew) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "endRowAction", "Warning: requested RowStatus = destroy, " + "but row[" + rowOid + "] does not exist"); } } else { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "endRowAction", "Destroying row[" + rowOid + "] : requested RowStatus = destroy"); } } removeTableRow(req,oid,depth); break; case EnumRowStatus.active: if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "endRowAction", "Setting RowStatus to 'active' for row[" + rowOid + "] : requested RowStatus = active"); } value = setRowStatus(oid,EnumRowStatus.active,data); break; case EnumRowStatus.notInService: if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "endRowAction", "Setting RowStatus to 'notInService' for row[" + rowOid + "] : requested RowStatus = notInService"); } value = setRowStatus(oid,EnumRowStatus.notInService,data); break; case EnumRowStatus.notReady: default: if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMibTable.class.getName(), "endRowAction", "Invalid RowStatus value for row[" + rowOid + "] : specified RowStatus = " + action); } setRowStatusFail(req, SnmpStatusException.snmpRspInconsistentValue); } if (value != null) { final SnmpVarBind vb = req.getRowStatusVarBind(); if (vb != null) vb.value = value; } } // ------------------------------------------------------------------- // PROTECTED METHODS - get next // ------------------------------------------------------------------- /** * Return the next OID arc corresponding to a readable columnar * object in the underlying entry OBJECT-TYPE, possibly skipping over * those objects that must not or cannot be returned. * Calls {@link * #getNextVarEntryId(com.sun.jmx.snmp.SnmpOid,long,java.lang.Object)}, * until * {@link #skipEntryVariable(com.sun.jmx.snmp.SnmpOid,long, * java.lang.Object,int)} returns false. * * * @param rowOid The OID index of the row involved in the operation. * * @param var Id of the variable we start from, looking for the next. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @param pduVersion Protocol version of the original request PDU. * * @return The next columnar object id which can be returned using * the given PDU's protocol version. * * @exception SnmpStatusException If no id is found after the given id. * **/ protected long getNextVarEntryId(SnmpOid rowOid, long var, Object userData, int pduVersion) throws SnmpStatusException { long varid=var; do { varid = getNextVarEntryId(rowOid,varid,userData); } while (skipEntryVariable(rowOid,varid,userData,pduVersion)); return varid; } /** * Hook for subclasses. * The default implementation of this method is to always return * false. Subclasses should redefine this method so that it returns * true when: * <ul>
  • the variable is a leaf that is not instantiated,
  • * <li>or the variable is a leaf whose type cannot be returned by that * version of the protocol (e.g. an Counter64 with SNMPv1).</li> * </ul> * * @param rowOid The OID index of the row involved in the operation. * * @param var Id of the variable we start from, looking for the next. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @param pduVersion Protocol version of the original request PDU. * * @return true if the variable must be skipped by the get-next * algorithm. */ protected boolean skipEntryVariable(SnmpOid rowOid, long var, Object userData, int pduVersion) { return false; } /** * Get the <CODE>SnmpOid index of the row that follows * the given <CODE>oid in the table. The given * oid</CODE> does not need to be a valid row OID index. * * <p> * @param oid The OID from which the search will begin. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @return The next <CODE>SnmpOid index. * * @exception SnmpStatusException There is no index following the * specified <CODE>oid in the table. */ protected SnmpOid getNextOid(SnmpOid oid, Object userData) throws SnmpStatusException { if (size == 0) { throw new SnmpStatusException(SnmpStatusException.noSuchInstance); } final SnmpOid resOid = oid; // Just a simple check to speed up retrieval of last element ... // // XX SnmpOid last= (SnmpOid) oids.lastElement(); SnmpOid last= tableoids[tablecount-1]; if (last.equals(resOid)) { // Last element of the table ... // throw new SnmpStatusException(SnmpStatusException.noSuchInstance); } // First find the oid. This will allow to speed up retrieval process // during smart discovery of table (using the getNext) as the // management station will use the valid index returned during a // previous getNext ... // // Returns the position following the position at which resOid // is found, or the position at which resOid should be inserted. // final int newPos = getInsertionPoint(resOid,false); // If the position returned is not out of bound, we will find // the next element in the array. // if (newPos > -1 && newPos < size) { try { // XX last = (SnmpOid) oids.elementAt(newPos); last = tableoids[newPos]; } catch(ArrayIndexOutOfBoundsException e) { throw new SnmpStatusException(SnmpStatusException.noSuchInstance); } } else { // We are dealing with the last element of the table .. // throw new SnmpStatusException(SnmpStatusException.noSuchInstance); } return last; } /** * Return the first entry OID registered in the table. * * <p> * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @return The <CODE>SnmpOid of the first entry in the table. * * @exception SnmpStatusException If the table is empty. */ protected SnmpOid getNextOid(Object userData) throws SnmpStatusException { if (size == 0) { throw new SnmpStatusException(SnmpStatusException.noSuchInstance); } // XX return (SnmpOid) oids.firstElement(); return tableoids[0]; } // ------------------------------------------------------------------- // Abstract Protected Methods // ------------------------------------------------------------------- /** * This method is used internally and is implemented by the * <CODE>SnmpMibTable subclasses generated by mibgen. * * <p> Return the next OID arc corresponding to a readable columnar * object in the underlying entry OBJECT-TYPE.</p> * * <p> * @param rowOid The OID index of the row involved in the operation. * * @param var Id of the variable we start from, looking for the next. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @return The next columnar object id. * * @exception SnmpStatusException If no id is found after the given id. * **/ abstract protected long getNextVarEntryId(SnmpOid rowOid, long var, Object userData) throws SnmpStatusException; /** * This method is used internally and is implemented by the * <CODE>SnmpMibTable subclasses generated by mibgen. * * <p> * @param rowOid The OID index of the row involved in the operation. * * @param var The var we want to validate. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @exception SnmpStatusException If this id is not valid. * */ abstract protected void validateVarEntryId(SnmpOid rowOid, long var, Object userData) throws SnmpStatusException; /** * * This method is used internally and is implemented by the * <CODE>SnmpMibTable subclasses generated by mibgen. * * <p> * @param rowOid The OID index of the row involved in the operation. * * @param var The OID arc. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @exception SnmpStatusException If this id is not valid. * */ abstract protected boolean isReadableEntryId(SnmpOid rowOid, long var, Object userData) throws SnmpStatusException; /** * This method is used internally and is implemented by the * <CODE>SnmpMibTable subclasses generated by mibgen. */ abstract protected void get(SnmpMibSubRequest req, SnmpOid rowOid, int depth) throws SnmpStatusException; /** * This method is used internally and is implemented by the * <CODE>SnmpMibTable subclasses generated by mibgen. */ abstract protected void check(SnmpMibSubRequest req, SnmpOid rowOid, int depth) throws SnmpStatusException; /** * This method is used internally and is implemented by the * <CODE>SnmpMibTable subclasses generated by mibgen. */ abstract protected void set(SnmpMibSubRequest req, SnmpOid rowOid, int depth) throws SnmpStatusException; // ---------------------------------------------------------------------- // PACKAGE METHODS // ---------------------------------------------------------------------- /** * Get the <CODE>SnmpOid index of the row that follows the * index extracted from the specified OID array. * Builds the SnmpOid corresponding to the row OID and calls * <code>getNextOid(oid,userData); * * <p> * @param oid The OID array. * * @param pos The position in the OID array at which the index starts. * * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @return The next <CODE>SnmpOid. * * @exception SnmpStatusException There is no index following the * specified one in the table. */ SnmpOid getNextOid(long[] oid, int pos, Object userData) throws SnmpStatusException { // Construct the sub-oid starting at pos. // This sub-oid correspond to the oid part just after the entry // variable oid. // final SnmpOid resOid = new SnmpEntryOid(oid,pos); return getNextOid(resOid,userData); } // --------------------------------------------------------------------- // // Register an exception when checking the RowStatus variable // // --------------------------------------------------------------------- static void checkRowStatusFail(SnmpMibSubRequest req, int errorStatus) throws SnmpStatusException { final SnmpVarBind statusvb = req.getRowStatusVarBind(); final SnmpStatusException x = new SnmpStatusException(errorStatus); req.registerCheckException(statusvb,x); } // --------------------------------------------------------------------- // // Register an exception when checking the RowStatus variable // // --------------------------------------------------------------------- static void setRowStatusFail(SnmpMibSubRequest req, int errorStatus) throws SnmpStatusException { final SnmpVarBind statusvb = req.getRowStatusVarBind(); final SnmpStatusException x = new SnmpStatusException(errorStatus); req.registerSetException(statusvb,x); } // --------------------------------------------------------------------- // // Implements the method defined in SnmpMibNode. // // --------------------------------------------------------------------- @Override final synchronized void findHandlingNode(SnmpVarBind varbind, long[] oid, int depth, SnmpRequestTree handlers) throws SnmpStatusException { final int length = oid.length; if (handlers == null) throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr); if (depth >= length) throw new SnmpStatusException(SnmpStatusException.noAccess); if (oid[depth] != nodeId) throw new SnmpStatusException(SnmpStatusException.noAccess); if (depth+2 >= length) throw new SnmpStatusException(SnmpStatusException.noAccess); // Checks that the oid is valid // validateOid(oid,depth); // Gets the part of the OID that identifies the entry final SnmpOid entryoid = new SnmpEntryOid(oid, depth+2); // Finds the entry: false means that the entry does not exists final Object data = handlers.getUserData(); final boolean hasEntry = contains(entryoid, data); // Fails if the entry is not found and the table does not // not support creation. // We know that the entry does not exists if (isentry == false). if (!hasEntry) { if (!handlers.isCreationAllowed()) { // we're not doing a set throw new SnmpStatusException(SnmpStatusException.noSuchInstance); } else if (!isCreationEnabled()) // we're doing a set but creation is disabled. throw new SnmpStatusException(SnmpStatusException.snmpRspNoAccess); } final long var = oid[depth+1]; // Validate the entry id if (hasEntry) { // The entry already exists - validate the id validateVarEntryId(entryoid,var,data); } // Registers this node for the identified entry. // if (handlers.isSetRequest() && isRowStatus(entryoid,var,data)) // We only try to identify the RowStatus for SET operations // handlers.add(this,depth,entryoid,varbind,(!hasEntry),varbind); else handlers.add(this,depth,entryoid,varbind,(!hasEntry)); } // --------------------------------------------------------------------- // // Implements the method defined in SnmpMibNode. The algorithm is very // largely inspired from the original getNext() method. // // --------------------------------------------------------------------- @Override final synchronized long[] findNextHandlingNode(SnmpVarBind varbind, long[] oid, int pos, int depth, SnmpRequestTree handlers, AcmChecker checker) throws SnmpStatusException { int length = oid.length; if (handlers == null) { // This should be considered as a genErr, but we do not want to // abort the whole request, so we're going to throw // a noSuchObject... // throw new SnmpStatusException(SnmpStatusException.noSuchObject); } final Object data = handlers.getUserData(); final int pduVersion = handlers.getRequestPduVersion(); long var= -1; // If the querried oid contains less arcs than the OID of the // xxxEntry object, we must return the first leaf under the // first columnar object: the best way to do that is to reset // the queried oid: // oid[0] = nodeId (arc of the xxxEntry object) // pos = 0 (points to the arc of the xxxEntry object) // then we just have to proceed... // if (pos >= length) { // this will have the side effect to set // oid[pos] = nodeId // and // (pos+1) = length // so we won't fall into the "else if" cases below - // so using "else if" rather than "if ..." is guaranteed // to be safe. // oid = new long[1]; oid[0] = nodeId; pos = 0; length = 1; } else if (oid[pos] > nodeId) { // oid[pos] is expected to be the id of the xxxEntry ... // The id requested is greater than the id of the xxxEntry, // so we won't find the next element in this table... (any // element in this table will have a smaller OID) // throw new SnmpStatusException(SnmpStatusException.noSuchObject); } else if (oid[pos] < nodeId) { // we must return the first leaf under the first columnar // object, so we are back to our first case where pos was // out of bounds... => reset the oid to contain only the // arc of the xxxEntry object. // oid = new long[1]; oid[0] = nodeId; pos = 0; length = 0; } else if ((pos + 1) < length) { // The arc at the position "pos+1" is the id of the columnar // object (ie: the id of the variable in the table entry) // var = oid[pos+1]; } // Now that we've got everything right we can begin. SnmpOid entryoid; if (pos == (length - 1)) { // pos points to the last arc in the oid, and this arc is // guaranteed to be the xxxEntry id (we have handled all // the other possibilities before) // // We must therefore return the first leaf below the first // columnar object in the table. // // Get the first index. If an exception is raised, // then it means that the table is empty. We thus do not // have to catch the exception - we let it propagate to // the caller. // entryoid = getNextOid(data); var = getNextVarEntryId(entryoid,var,data,pduVersion); } else if ( pos == (length-2)) { // In that case we have (pos+1) = (length-1), so pos // points to the arc of the querried variable (columnar object). // Since the requested oid stops there, it means we have // to return the first leaf under this columnar object. // // So we first get the first index: // Note: if this raises an exception, this means that the table // is empty, so we can let the exception propagate to the caller. // entryoid = getNextOid(data); // XXX revisit: not exactly perfect: // a specific row could be empty.. But we don't know // how to make the difference! => tradeoff holes // in tables can't be properly supported (all rows // must have the same holes) // if (skipEntryVariable(entryoid,var,data,pduVersion)) { var = getNextVarEntryId(entryoid,var,data,pduVersion); } } else { // So now there remain one last case, namely: some part of the // index is provided by the oid... // We build a possibly incomplete and invalid index from // the OID. // The piece of index provided should begin at pos+2 // oid[pos] = id of the xxxEntry object, // oid[pos+1] = id of the columnar object, // oid[pos+2] ... oid[length-1] = piece of index. // // We get the next index following the provided index. // If this raises an exception, then it means that we have // reached the last index in the table, and we must then // try with the next columnar object. // // Bug fix 4269251 // The SnmpIndex is defined to contain a valid oid: // this is not an SNMP requirement for the getNext request. // So we no more use the SnmpIndex but directly the SnmpOid. // try { entryoid = getNextOid(oid, pos + 2, data); // If the variable must ne skipped, fall through... // // XXX revisit: not exactly perfect: // a specific row could be empty.. But we don't know // how to make the difference! => tradeoff holes // in tables can't be properly supported (all rows // must have the same holes) // if (skipEntryVariable(entryoid,var,data,pduVersion)) { throw new SnmpStatusException(SnmpStatusException.noSuchObject); } } catch(SnmpStatusException se) { entryoid = getNextOid(data); var = getNextVarEntryId(entryoid,var,data,pduVersion); } } return findNextAccessibleOid(entryoid, varbind, oid, depth, handlers, checker, data, var); } private long[] findNextAccessibleOid(SnmpOid entryoid, SnmpVarBind varbind,long[] oid, int depth, SnmpRequestTree handlers, AcmChecker checker, Object data, long var) throws SnmpStatusException { final int pduVersion = handlers.getRequestPduVersion(); // Loop on each var (column) while(true) { // This should not happen. If it happens, (bug, or customized // methods returning garbage instead of raising an exception), // it probably means that there is nothing to return anyway. // So we throw the exception. // => will skip to next node in the MIB tree. // if (entryoid == null || var == -1 ) { throw new SnmpStatusException(SnmpStatusException.noSuchObject); } // So here we know both the row (entryoid) and the column (var) // try { // Raising an exception here will make the catch() clause // switch to the next variable. If `var' is not readable // for this specific entry, it is not readable for any // other entry => skip to next column. // if (!isReadableEntryId(entryoid,var,data)) { throw new SnmpStatusException(SnmpStatusException.noSuchObject); } // Prepare the result and the ACM checker. // final long[] etable = entryoid.longValue(false); final int elength = etable.length; final long[] result = new long[depth + 2 + elength]; result[0] = -1 ; // Bug detector! // Copy the entryOid at the end of `result' // java.lang.System.arraycopy(etable, 0, result, depth+2, elength); // Set the node Id and var Id in result. // result[depth] = nodeId; result[depth+1] = var; // Append nodeId.varId.<rowOid> to ACM checker. // checker.add(depth,result,depth,elength+2); // No we're going to ACM check our OID. try { checker.checkCurrentOid(); // No exception thrown by checker => this is all OK! // we have it: register the handler and return the // result. // handlers.add(this,depth,entryoid,varbind,false); return result; } catch(SnmpStatusException e) { // Skip to the next entry. If an exception is // thrown, will be catch by enclosing catch // and a skip is done to the next var. // entryoid = getNextOid(entryoid, data); } finally { // Clean the checker. // checker.remove(depth,elength+2); } } catch(SnmpStatusException e) { // Catching an exception here means we have to skip to the // next column. // // Back to the first row. entryoid = getNextOid(data); // Find out the next column. // var = getNextVarEntryId(entryoid,var,data,pduVersion); } // This should not happen. If it happens, (bug, or customized // methods returning garbage instead of raising an exception), // it probably means that there is nothing to return anyway. // No need to continue, we throw an exception. // => will skip to next node in the MIB tree. // if (entryoid == null || var == -1 ) { throw new SnmpStatusException(SnmpStatusException.noSuchObject); } } } /** * Validate the specified OID. * * <p> * @param oid The OID array. * * @param pos The position in the array. * * @exception SnmpStatusException If the validation fails. */ final void validateOid(long[] oid, int pos) throws SnmpStatusException { final int length= oid.length; // Control the length of the oid // if (pos +2 >= length) { throw new SnmpStatusException(SnmpStatusException.noSuchInstance); } // Check that the entry identifier is specified // if (oid[pos] != nodeId) { throw new SnmpStatusException(SnmpStatusException.noSuchObject); } } // ---------------------------------------------------------------------- // PRIVATE METHODS // ---------------------------------------------------------------------- /** * Enable this <CODE>SnmpMibTable to send a notification. * * <p> * @param notification The notification to send. */ private synchronized void sendNotification(Notification notification) { // loop on listener // for(java.util.Enumeration<NotificationListener> k = handbackTable.keys(); k.hasMoreElements(); ) { NotificationListener listener = k.nextElement(); // Get the associated handback list and the associated filter list // java.util.Vector<?> handbackList = handbackTable.get(listener) ; java.util.Vector<NotificationFilter> filterList = filterTable.get(listener) ; // loop on handback // java.util.Enumeration<NotificationFilter> f = filterList.elements(); for(java.util.Enumeration<?> h = handbackList.elements(); h.hasMoreElements(); ) { Object handback = h.nextElement(); NotificationFilter filter = f.nextElement(); if ((filter == null) || (filter.isNotificationEnabled(notification))) { listener.handleNotification(notification,handback) ; } } } } /** * This method is used by the SnmpMibTable to create and send a table * entry notification to all the listeners registered for this kind of * notification. * * <p> * @param type The notification type. * * @param timeStamp The notification emission date. * * @param entry The entry object. */ private void sendNotification(String type, long timeStamp, Object entry, ObjectName name) { synchronized(this) { sequenceNumber = sequenceNumber + 1; } SnmpTableEntryNotification notif = new SnmpTableEntryNotification(type, this, sequenceNumber, timeStamp, entry, name); this.sendNotification(notif) ; } /** * Return true if the entry identified by the given OID index * is contained in this table. * <p> * <b>Do not call this method directly
    . * <p> * This method is provided has a hook for subclasses. * It is called when a get/set request is received in order to * determine whether the specified entry is contained in the table. * You may want to override this method if you need to perform e.g. * lazy evaluation of tables (you need to update the table when a * request is received) or if your table is virtual. * <p> * Note that this method is called by the Runtime from within a * synchronized block. * * @param oid The index part of the OID we're looking for. * @param userData A contextual object containing user-data. * This object is allocated through the <code> * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code> * for each incoming SNMP request. * * @return <code>true if the entry is found, false * otherwise. * * @since 1.5 **/ protected boolean contains(SnmpOid oid, Object userData) { return (findObject(oid) > -1); } /** * Look for the given oid in the OID table (tableoids) and returns * its position. * * <p> * @param oid The OID we're looking for. * * @return The position of the OID in the table. -1 if the given * OID was not found. * **/ private int findObject(SnmpOid oid) { int low= 0; int max= size - 1; SnmpOid pos; int comp; int curr= low + (max-low)/2; //System.out.println("Try to retrieve: " + oid.toString()); while (low <= max) { // XX pos = (SnmpOid) oids.elementAt(curr); pos = tableoids[curr]; //System.out.println("Compare with" + pos.toString()); // never know ...we might find something ... // comp = oid.compareTo(pos); if (comp == 0) return curr; if (oid.equals(pos) == true) { return curr; } if (comp > 0) { low = curr + 1; } else { max = curr - 1; } curr = low + (max-low)/2; } return -1; } /** * Search the position at which the given oid should be inserted * in the OID table (tableoids). * * <p> * @param oid The OID we would like to insert. * * @param fail Tells whether a SnmpStatusException must be generated * if the given OID is already present in the table. * * @return The position at which the OID should be inserted in * the table. When the OID is found, it returns the next * position. Note that it is not valid to insert twice the * same OID. This feature is only an optimization to improve * the getNextOid() behaviour. * * @exception SnmpStatusException if the OID is already present in the * table and <code>fail is true. * **/ private int getInsertionPoint(SnmpOid oid, boolean fail) throws SnmpStatusException { final int failStatus = SnmpStatusException.snmpRspNotWritable; int low= 0; int max= size - 1; SnmpOid pos; int comp; int curr= low + (max-low)/2; while (low <= max) { // XX pos= (SnmpOid) oids.elementAt(curr); pos= tableoids[curr]; // never know ...we might find something ... // comp= oid.compareTo(pos); if (comp == 0) { if (fail) throw new SnmpStatusException(failStatus,curr); else return curr+1; } if (comp>0) { low= curr +1; } else { max= curr -1; } curr= low + (max-low)/2; } return curr; } /** * Remove the OID located at the given position. * * <p> * @param pos The position at which the OID to be removed is located. * **/ private void removeOid(int pos) { if (pos >= tablecount) return; if (pos < 0) return; final int l1 = --tablecount-pos; tableoids[pos] = null; if (l1 > 0) java.lang.System.arraycopy(tableoids,pos+1,tableoids,pos,l1); tableoids[tablecount] = null; } /** * Insert an OID at the given position. * * <p> * @param oid The OID to be inserted in the table * @param pos The position at which the OID to be added is located. * **/ private void insertOid(int pos, SnmpOid oid) { if (pos >= tablesize || tablecount == tablesize) { // Vector must be enlarged // Save old vector final SnmpOid[] olde = tableoids; // Allocate larger vectors tablesize += Delta; tableoids = new SnmpOid[tablesize]; // Check pos validity if (pos > tablecount) pos = tablecount; if (pos < 0) pos = 0; final int l1 = pos; final int l2 = tablecount - pos; // Copy original vector up to `pos' if (l1 > 0) java.lang.System.arraycopy(olde,0,tableoids,0,l1); // Copy original vector from `pos' to end, leaving // an empty room at `pos' in the new vector. if (l2 > 0) java.lang.System.arraycopy(olde,l1,tableoids, l1+1,l2); } else if (pos < tablecount) { // Vector is large enough to accommodate one additional // entry. // // Shift vector, making an empty room at `pos' java.lang.System.arraycopy(tableoids,pos,tableoids, pos+1,tablecount-pos); } // Fill the gap at `pos' tableoids[pos] = oid; tablecount++; } // ---------------------------------------------------------------------- // PROTECTED VARIABLES // ---------------------------------------------------------------------- /** * The id of the contained entry object. * @serial */ protected int nodeId=1; /** * The MIB to which the metadata is linked. * @serial */ protected SnmpMib theMib; /** * <CODE>true if remote creation of entries via SET operations * is enabled. * [default value is <CODE>false] * @serial */ protected boolean creationEnabled = false; /** * The entry factory */ protected SnmpTableEntryFactory factory = null; // ---------------------------------------------------------------------- // PRIVATE VARIABLES // ---------------------------------------------------------------------- /** * The number of elements in the table. * @serial */ private int size=0; /** * The list of indexes. * @serial */ // private Vector indexes= new Vector(); /** * The list of OIDs. * @serial */ // private Vector oids= new Vector(); private final static int Delta = 16; private int tablecount = 0; private int tablesize = Delta; private SnmpOid tableoids[] = new SnmpOid[tablesize]; /** * The list of entries. * @serial */ private final Vector<Object> entries= new Vector<>(); /** * The list of object names. * @serial */ private final Vector<ObjectName> entrynames= new Vector<>(); /** * Callback handlers */ // final Vector callbacks = new Vector(); /** * Listener hashtable containing the hand-back objects. */ private Hashtable<NotificationListener, Vector handbackTable = new Hashtable<>(); /** * Listener hashtable containing the filter objects. */ private Hashtable<NotificationListener, Vector filterTable = new Hashtable<>(); // PACKAGE VARIABLES //------------------ /** * SNMP table sequence number. * The default value is set to 0. */ transient long sequenceNumber = 0; }

    Other Java examples (source code examples)

    Here is a short list of links related to this Java SnmpMibTable.java source code file:

    ... this post is sponsored by my books ...

    #1 New Release!

    FP Best Seller

     

    new blog posts

     

    Copyright 1998-2021 Alvin Alexander, alvinalexander.com
    All Rights Reserved.

    A percentage of advertising revenue from
    pages under the /java/jwarehouse URI on this website is
    paid back to open source projects.