Initial load
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpEntryOid.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpEntryOid.java
new file mode 100644
index 0000000..809a42b
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpEntryOid.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.jmx.snmp.agent;
+
+import com.sun.jmx.snmp.SnmpOid;
+
+/**
+ * This class only adds a new constructor to SnmpOid...
+ *
+ **/
+class SnmpEntryOid extends SnmpOid {
+ private static final long serialVersionUID = 9212653887791059564L;
+
+ /**
+ * Constructs a new <CODE>SnmpOid</CODE> from the specified
+ * component array, starting at given position.
+ *
+ * @param oid The original OID array
+ * @param start The position at which to begin.
+ *
+ **/
+ public SnmpEntryOid(long[] oid, int start) {
+ final int subLength = oid.length - start;
+ final long[] subOid = new long[subLength];
+ java.lang.System.arraycopy(oid, start, subOid, 0, subLength) ;
+ components = subOid;
+ componentCount = subLength;
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpErrorHandlerAgent.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpErrorHandlerAgent.java
new file mode 100644
index 0000000..e887eab
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpErrorHandlerAgent.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2001-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.logging.Level;
+
+import javax.management.ObjectName;
+import javax.management.MBeanServer;
+
+import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
+import com.sun.jmx.snmp.SnmpStatusException;
+import com.sun.jmx.snmp.SnmpDefinitions;
+import com.sun.jmx.snmp.SnmpVarBind;
+
+/**
+ * A simple MIB agent that implements SNMP calls (get, set, getnext and getbulk) in a way that only errors or exceptions are returned. Every call done on this agent fails. Error handling is done according to the manager's SNMP protocol version.
+ * <P>It is used by <CODE>SnmpAdaptorServer</CODE> for its default agent behavior. When a received Oid doesn't match, this agent is called to fill the result list with errors.</P>
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ * @since 1.5
+ *
+ */
+
+public class SnmpErrorHandlerAgent extends SnmpMibAgent
+ implements Serializable {
+ private static final long serialVersionUID = 7751082923508885650L;
+
+ public SnmpErrorHandlerAgent() {}
+
+ /**
+ * Initializes the MIB (with no registration of the MBeans into the
+ * MBean server). Does nothing.
+ *
+ * @exception IllegalAccessException The MIB cannot be initialized.
+ */
+
+ public void init() throws IllegalAccessException {
+ }
+
+ /**
+ * Initializes the MIB but each single MBean representing the MIB
+ * is inserted into the MBean server.
+ *
+ * @param server The MBean server to register the service with.
+ * @param name The object name.
+ *
+ * @return The passed name paramter.
+ *
+ * @exception java.lang.Exception
+ */
+
+ public ObjectName preRegister(MBeanServer server, ObjectName name)
+ throws Exception {
+ return name;
+ }
+
+ /**
+ * Gets the root object identifier of the MIB.
+ * <P>The root object identifier is the object identifier uniquely
+ * identifying the MIB.
+ *
+ * @return The returned oid is null.
+ */
+
+ public long[] getRootOid() {
+ return null;
+ }
+
+ /**
+ * Processes a <CODE>get</CODE> operation. It will throw an exception for V1 requests or it will set exceptions within the list for V2 requests.
+ *
+ * @param inRequest The SnmpMibRequest object holding the list of variable to be retrieved.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ */
+
+ public void get(SnmpMibRequest inRequest) throws SnmpStatusException {
+
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpErrorHandlerAgent.class.getName(),
+ "get", "Get in Exception");
+
+ if(inRequest.getVersion() == SnmpDefinitions.snmpVersionOne)
+ throw new SnmpStatusException(SnmpStatusException.noSuchName);
+
+ Enumeration l = inRequest.getElements();
+ while(l.hasMoreElements()) {
+ SnmpVarBind varbind = (SnmpVarBind) l.nextElement();
+ varbind.setNoSuchObject();
+ }
+ }
+
+ /**
+ * Checks if a <CODE>set</CODE> operation can be performed.
+ * If the operation can not be performed, the method should emit a
+ * <CODE>SnmpStatusException</CODE>.
+ *
+ * @param inRequest The SnmpMibRequest object holding the list of variables to
+ * be set. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException The <CODE>set</CODE> operation
+ * cannot be performed.
+ */
+
+ public void check(SnmpMibRequest inRequest) throws SnmpStatusException {
+
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpErrorHandlerAgent.class.getName(),
+ "check", "Check in Exception");
+
+ throw new SnmpStatusException(SnmpDefinitions.snmpRspNotWritable);
+ }
+
+ /**
+ * Processes a <CODE>set</CODE> operation. Should never be called (check previously called having failed).
+ *
+ * @param inRequest The SnmpMibRequest object holding the list of variable to be set.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ */
+
+ public void set(SnmpMibRequest inRequest) throws SnmpStatusException {
+
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpErrorHandlerAgent.class.getName(),
+ "set", "Set in Exception, CANNOT be called");
+
+ throw new SnmpStatusException(SnmpDefinitions.snmpRspNotWritable);
+ }
+
+ /**
+ * Processes a <CODE>getNext</CODE> operation. It will throw an exception for V1 requests or it will set exceptions within the list for V2 requests..
+ *
+ * @param inRequest The SnmpMibRequest object holding the list of variables to be retrieved.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ */
+
+ public void getNext(SnmpMibRequest inRequest) throws SnmpStatusException {
+
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpErrorHandlerAgent.class.getName(),
+ "getNext", "GetNext in Exception");
+
+ if(inRequest.getVersion() == SnmpDefinitions.snmpVersionOne)
+ throw new SnmpStatusException(SnmpStatusException.noSuchName);
+
+ Enumeration l = inRequest.getElements();
+ while(l.hasMoreElements()) {
+ SnmpVarBind varbind = (SnmpVarBind) l.nextElement();
+ varbind.setEndOfMibView();
+ }
+ }
+
+ /**
+ * Processes a <CODE>getBulk</CODE> operation. It will throw an exception if the request is a V1 one or it will set exceptions within the list for V2 ones.
+ *
+ * @param inRequest The SnmpMibRequest object holding the list of variable to be retrieved.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ */
+
+ public void getBulk(SnmpMibRequest inRequest, int nonRepeat, int maxRepeat)
+ throws SnmpStatusException {
+
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpErrorHandlerAgent.class.getName(),
+ "getBulk", "GetBulk in Exception");
+
+ if(inRequest.getVersion() == SnmpDefinitions.snmpVersionOne)
+ throw new SnmpStatusException(SnmpDefinitions.snmpRspGenErr, 0);
+
+ Enumeration l = inRequest.getElements();
+ while(l.hasMoreElements()) {
+ SnmpVarBind varbind = (SnmpVarBind) l.nextElement();
+ varbind.setEndOfMibView();
+ }
+ }
+
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpGenericMetaServer.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpGenericMetaServer.java
new file mode 100644
index 0000000..58aecdb
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpGenericMetaServer.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+/**
+ * <p>
+ * This interface defines the methods that must be implemented by an
+ * SNMP metadata object that needs to interact with an
+ * {@link com.sun.jmx.snmp.agent.SnmpGenericObjectServer} object.
+ * </p>
+ *
+ * <p>
+ * All these methods are usually generated by <code>mibgen</code> when
+ * run in generic-metadata mode.
+ * </p>
+ *
+ * <p><b><i>
+ * This interface is used internally between the generated Metadata and
+ * the SNMP runtime and you shouldn't need to worry about it, because
+ * you will never have to use it directly.
+ * </b></i></p>
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ **/
+public interface SnmpGenericMetaServer {
+
+ /**
+ * Construct an attribute value (as returned by Attribute::getValue())
+ * from an SnmpValue. The returned attribute value can be used to
+ * construct an Attribute object.
+ *
+ * @param id The OID arc identifying the variable for which the
+ * value is constructed.
+ * @param value The SnmpValue from which the Attribute::value will be
+ * constructed.
+ * @return The attribute value built from the given <code>value</code>.
+ * @exception SnmpStatusException if the attribute value cannot be built
+ * from the given SnmpValue <code>value</code>.
+ *
+ */
+ Object buildAttributeValue(long id, SnmpValue value)
+ throws SnmpStatusException;
+
+ /**
+ * Construct an SnmpValue from an Attribute value as returned by
+ * Attribute::getValue().
+ *
+ * @param id The OID arc identifying the variable for which the
+ * value is constructed.
+ * @param value The attribute value as returned by Attribute::getValue().
+ *
+ * @return The SnmpValue built from the given <code>value</code>.
+ * @exception SnmpStatusException if the SnmpValue cannot be built from
+ * the given <code>value</code>.
+ **/
+ SnmpValue buildSnmpValue(long id, Object value)
+ throws SnmpStatusException;
+
+ /**
+ * Return the name of the attribute corresponding to the
+ * SNMP variable identified by the given <code>id</code>.
+ *
+ * @param id The OID arc identifying the variable.
+ *
+ * @return The name of the variable identified by the given
+ * <code>id</code>.
+ *
+ * @exception SnmpStatusException if the given <code>id</code> does not
+ * correspond to a known variable.
+ */
+ String getAttributeName(long id)
+ throws SnmpStatusException;
+
+ /**
+ * Check the access rights for a SET operation.
+ *
+ * @param x The new requested value.
+ * @param id The OID arc identifying the variable for which the SET is
+ * requested.
+ * @param data 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 the SET operation must be rejected.
+ */
+ void checkSetAccess(SnmpValue x, long id, Object data)
+ throws SnmpStatusException;
+
+ /**
+ * Check the access rights for a GET operation.
+ *
+ * @param id The OID arc identifying the variable for which the SET is
+ * requested.
+ * @param data 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 the SET operation must be rejected.
+ */
+ void checkGetAccess(long id, Object data)
+ throws SnmpStatusException;
+
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpGenericObjectServer.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpGenericObjectServer.java
new file mode 100644
index 0000000..8b78b26
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpGenericObjectServer.java
@@ -0,0 +1,573 @@
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+
+// java imports
+//
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+// jmx imports
+//
+import javax.management.AttributeList;
+import javax.management.Attribute;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.InstanceNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.RuntimeOperationsException;
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+
+/**
+ * <p>
+ * This class is a utility class that transforms SNMP GET / SET requests
+ * into standard JMX getAttributes() setAttributes() requests.
+ * </p>
+ *
+ * <p>
+ * The transformation relies on the metadata information provided by the
+ * {@link com.sun.jmx.snmp.agent.SnmpGenericMetaServer} object which is
+ * passed as the first parameter to every method. This SnmpGenericMetaServer
+ * object is usually a Metadata object generated by <code>mibgen</code>.
+ * </p>
+ *
+ * <p><b><i>
+ * This class is used internally by mibgen generated metadata objects and
+ * you should never need to use it directly.
+ * </b></i></p>
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ **/
+
+public class SnmpGenericObjectServer {
+
+ // ----------------------------------------------------------------------
+ //
+ // Protected variables
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * The MBean server through which the MBeans will be accessed.
+ **/
+ protected final MBeanServer server;
+
+ // ----------------------------------------------------------------------
+ //
+ // Constructors
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Builds a new SnmpGenericObjectServer. Usually there will be a single
+ * object of this type per MIB.
+ *
+ * @param server The MBeanServer in which the MBean accessed by this
+ * MIB are registered.
+ **/
+ public SnmpGenericObjectServer(MBeanServer server) {
+ this.server = server;
+ }
+
+ /**
+ * Execute an SNMP GET request.
+ *
+ * <p>
+ * This method first builds the list of attributes that need to be
+ * retrieved from the MBean and then calls getAttributes() on the
+ * MBean server. Then it updates the SnmpMibSubRequest with the values
+ * retrieved from the MBean.
+ * </p>
+ *
+ * <p>
+ * The SNMP metadata information is obtained through the given
+ * <code>meta</code> object, which usually is an instance of a
+ * <code>mibgen</code> generated class.
+ * </p>
+ *
+ * <p><b><i>
+ * This method is called internally by <code>mibgen</code> generated
+ * objects and you should never need to call it directly.
+ * </i></b></p>
+ *
+ * @param meta The metadata object impacted by the subrequest
+ * @param name The ObjectName of the MBean impacted by this subrequest
+ * @param req The SNMP subrequest to execute on the MBean
+ * @param depth The depth of the SNMP object in the OID tree.
+ *
+ * @exception SnmpStatusException whenever an SNMP exception must be
+ * raised. Raising an exception will abort the request.<br>
+ * Exceptions should never be raised directly, but only by means of
+ * <code>
+ * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
+ * </code>
+ **/
+ public void get(SnmpGenericMetaServer meta, ObjectName name,
+ SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException {
+
+ // java.lang.System.out.println(">>>>>>>>> GET " + name);
+
+ final int size = req.getSize();
+ final Object data = req.getUserData();
+ final String[] nameList = new String[size];
+ final SnmpVarBind[] varList = new SnmpVarBind[size];
+ final long[] idList = new long[size];
+ int i = 0;
+
+ for (Enumeration e=req.getElements(); e.hasMoreElements();) {
+ final SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ try {
+ final long id = var.oid.getOidArc(depth);
+ nameList[i] = meta.getAttributeName(id);
+ varList[i] = var;
+ idList[i] = id;
+
+ // Check the access rights according to the MIB.
+ // The MBean might be less restrictive (have a getter
+ // while the MIB defines the variable as AFN)
+ //
+ meta.checkGetAccess(id,data);
+
+ //java.lang.System.out.println(nameList[i] + " added.");
+ i++;
+ } catch(SnmpStatusException x) {
+ //java.lang.System.out.println("exception for " + nameList[i]);
+ //x.printStackTrace();
+ req.registerGetException(var,x);
+ }
+ }
+
+ AttributeList result = null;
+ int errorCode = SnmpStatusException.noSuchInstance;
+
+ try {
+ result = server.getAttributes(name,nameList);
+ } catch (InstanceNotFoundException f) {
+ //java.lang.System.out.println(name + ": instance not found.");
+ //f.printStackTrace();
+ result = new AttributeList();
+ } catch (ReflectionException r) {
+ //java.lang.System.out.println(name + ": reflexion error.");
+ //r.printStackTrace();
+ result = new AttributeList();
+ } catch (Exception x) {
+ result = new AttributeList();
+ }
+
+
+ final Iterator it = result.iterator();
+
+ for (int j=0; j < i; j++) {
+ if (!it.hasNext()) {
+ //java.lang.System.out.println(name + "variable[" + j +
+ // "] absent");
+ final SnmpStatusException x =
+ new SnmpStatusException(errorCode);
+ req.registerGetException(varList[j],x);
+ continue;
+ }
+
+ final Attribute att = (Attribute) it.next();
+
+ while ((j < i) && (! nameList[j].equals(att.getName()))) {
+ //java.lang.System.out.println(name + "variable[" +j +
+ // "] not found");
+ final SnmpStatusException x =
+ new SnmpStatusException(errorCode);
+ req.registerGetException(varList[j],x);
+ j++;
+ }
+
+ if ( j == i) break;
+
+ try {
+ varList[j].value =
+ meta.buildSnmpValue(idList[j],att.getValue());
+ } catch (SnmpStatusException x) {
+ req.registerGetException(varList[j],x);
+ }
+ //java.lang.System.out.println(att.getName() + " retrieved.");
+ }
+ //java.lang.System.out.println(">>>>>>>>> END GET");
+ }
+
+ /**
+ * Get the value of an SNMP variable.
+ *
+ * <p><b><i>
+ * You should never need to use this method directly.
+ * </i></b></p>
+ *
+ * @param meta The impacted metadata object
+ * @param name The ObjectName of the impacted MBean
+ * @param id The OID arc identifying the variable we're trying to set.
+ * @param data User contextual data allocated through the
+ * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
+ *
+ * @return The value of the variable.
+ *
+ * @exception SnmpStatusException whenever an SNMP exception must be
+ * raised. Raising an exception will abort the request. <br>
+ * Exceptions should never be raised directly, but only by means of
+ * <code>
+ * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
+ * </code>
+ **/
+ public SnmpValue get(SnmpGenericMetaServer meta, ObjectName name,
+ long id, Object data)
+ throws SnmpStatusException {
+ final String attname = meta.getAttributeName(id);
+ Object result = null;
+
+ try {
+ result = server.getAttribute(name,attname);
+ } catch (MBeanException m) {
+ Exception t = m.getTargetException();
+ if (t instanceof SnmpStatusException)
+ throw (SnmpStatusException) t;
+ throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
+ } catch (Exception e) {
+ throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
+ }
+
+ return meta.buildSnmpValue(id,result);
+ }
+
+ /**
+ * Execute an SNMP SET request.
+ *
+ * <p>
+ * This method first builds the list of attributes that need to be
+ * set on the MBean and then calls setAttributes() on the
+ * MBean server. Then it updates the SnmpMibSubRequest with the new
+ * values retrieved from the MBean.
+ * </p>
+ *
+ * <p>
+ * The SNMP metadata information is obtained through the given
+ * <code>meta</code> object, which usually is an instance of a
+ * <code>mibgen</code> generated class.
+ * </p>
+ *
+ * <p><b><i>
+ * This method is called internally by <code>mibgen</code> generated
+ * objects and you should never need to call it directly.
+ * </i></b></p>
+ *
+ * @param meta The metadata object impacted by the subrequest
+ * @param name The ObjectName of the MBean impacted by this subrequest
+ * @param req The SNMP subrequest to execute on the MBean
+ * @param depth The depth of the SNMP object in the OID tree.
+ *
+ * @exception SnmpStatusException whenever an SNMP exception must be
+ * raised. Raising an exception will abort the request. <br>
+ * Exceptions should never be raised directly, but only by means of
+ * <code>
+ * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
+ * </code>
+ **/
+ public void set(SnmpGenericMetaServer meta, ObjectName name,
+ SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException {
+
+ final int size = req.getSize();
+ final AttributeList attList = new AttributeList(size);
+ final String[] nameList = new String[size];
+ final SnmpVarBind[] varList = new SnmpVarBind[size];
+ final long[] idList = new long[size];
+ int i = 0;
+
+ for (Enumeration e=req.getElements(); e.hasMoreElements();) {
+ final SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ try {
+ final long id = var.oid.getOidArc(depth);
+ final String attname = meta.getAttributeName(id);
+ final Object attvalue=
+ meta.buildAttributeValue(id,var.value);
+ final Attribute att = new Attribute(attname,attvalue);
+ attList.add(att);
+ nameList[i] = attname;
+ varList[i] = var;
+ idList[i] = id;
+ i++;
+ } catch(SnmpStatusException x) {
+ req.registerSetException(var,x);
+ }
+ }
+
+ AttributeList result = null;
+ int errorCode = SnmpStatusException.noAccess;
+
+ try {
+ result = server.setAttributes(name,attList);
+ } catch (InstanceNotFoundException f) {
+ result = new AttributeList();
+ errorCode = SnmpStatusException.snmpRspInconsistentName;
+ } catch (ReflectionException r) {
+ errorCode = SnmpStatusException.snmpRspInconsistentName;
+ result = new AttributeList();
+ } catch (Exception x) {
+ result = new AttributeList();
+ }
+
+ final Iterator it = result.iterator();
+
+ for (int j=0; j < i; j++) {
+ if (!it.hasNext()) {
+ final SnmpStatusException x =
+ new SnmpStatusException(errorCode);
+ req.registerSetException(varList[j],x);
+ continue;
+ }
+
+ final Attribute att = (Attribute) it.next();
+
+ while ((j < i) && (! nameList[j].equals(att.getName()))) {
+ final SnmpStatusException x =
+ new SnmpStatusException(SnmpStatusException.noAccess);
+ req.registerSetException(varList[j],x);
+ j++;
+ }
+
+ if ( j == i) break;
+
+ try {
+ varList[j].value =
+ meta.buildSnmpValue(idList[j],att.getValue());
+ } catch (SnmpStatusException x) {
+ req.registerSetException(varList[j],x);
+ }
+
+ }
+ }
+
+ /**
+ * Set the value of an SNMP variable.
+ *
+ * <p><b><i>
+ * You should never need to use this method directly.
+ * </i></b></p>
+ *
+ * @param meta The impacted metadata object
+ * @param name The ObjectName of the impacted MBean
+ * @param x The new requested SnmpValue
+ * @param id The OID arc identifying the variable we're trying to set.
+ * @param data User contextual data allocated through the
+ * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
+ *
+ * @return The new value of the variable after the operation.
+ *
+ * @exception SnmpStatusException whenever an SNMP exception must be
+ * raised. Raising an exception will abort the request. <br>
+ * Exceptions should never be raised directly, but only by means of
+ * <code>
+ * req.registerSetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
+ * </code>
+ **/
+ public SnmpValue set(SnmpGenericMetaServer meta, ObjectName name,
+ SnmpValue x, long id, Object data)
+ throws SnmpStatusException {
+ final String attname = meta.getAttributeName(id);
+ final Object attvalue=
+ meta.buildAttributeValue(id,x);
+ final Attribute att = new Attribute(attname,attvalue);
+
+ Object result = null;
+
+ try {
+ server.setAttribute(name,att);
+ result = server.getAttribute(name,attname);
+ } catch(InvalidAttributeValueException iv) {
+ throw new
+ SnmpStatusException(SnmpStatusException.snmpRspWrongValue);
+ } catch (InstanceNotFoundException f) {
+ throw new
+ SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
+ } catch (ReflectionException r) {
+ throw new
+ SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
+ } catch (MBeanException m) {
+ Exception t = m.getTargetException();
+ if (t instanceof SnmpStatusException)
+ throw (SnmpStatusException) t;
+ throw new
+ SnmpStatusException(SnmpStatusException.noAccess);
+ } catch (Exception e) {
+ throw new
+ SnmpStatusException(SnmpStatusException.noAccess);
+ }
+
+ return meta.buildSnmpValue(id,result);
+ }
+
+ /**
+ * Checks whether an SNMP SET request can be successfully performed.
+ *
+ * <p>
+ * For each variable in the subrequest, this method calls
+ * checkSetAccess() on the meta object, and then tries to invoke the
+ * check<i>AttributeName</i>() method on the MBean. If this method
+ * is not defined then it is assumed that the SET won't fail.
+ * </p>
+ *
+ * <p><b><i>
+ * This method is called internally by <code>mibgen</code> generated
+ * objects and you should never need to call it directly.
+ * </i></b></p>
+ *
+ * @param meta The metadata object impacted by the subrequest
+ * @param name The ObjectName of the MBean impacted by this subrequest
+ * @param req The SNMP subrequest to execute on the MBean
+ * @param depth The depth of the SNMP object in the OID tree.
+ *
+ * @exception SnmpStatusException if the requested SET operation must
+ * be rejected. Raising an exception will abort the request. <br>
+ * Exceptions should never be raised directly, but only by means of
+ * <code>
+ * req.registerCheckException(<i>VariableId</i>,<i>SnmpStatusException</i>)
+ * </code>
+ *
+ **/
+ public void check(SnmpGenericMetaServer meta, ObjectName name,
+ SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException {
+
+ final Object data = req.getUserData();
+
+ for (Enumeration e=req.getElements(); e.hasMoreElements();) {
+ final SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ try {
+ final long id = var.oid.getOidArc(depth);
+ // call meta.check() here, and meta.check will call check()
+ check(meta,name,var.value,id,data);
+ } catch(SnmpStatusException x) {
+ req.registerCheckException(var,x);
+ }
+ }
+ }
+
+ /**
+ * Checks whether a SET operation can be performed on a given SNMP
+ * variable.
+ *
+ * @param meta The impacted metadata object
+ * @param name The ObjectName of the impacted MBean
+ * @param x The new requested SnmpValue
+ * @param id The OID arc identifying the variable we're trying to set.
+ * @param data User contextual data allocated through the
+ * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
+ *
+ * <p>
+ * This method calls checkSetAccess() on the meta object, and then
+ * tries to invoke the check<i>AttributeName</i>() method on the MBean.
+ * If this method is not defined then it is assumed that the SET
+ * won't fail.
+ * </p>
+ *
+ * <p><b><i>
+ * This method is called internally by <code>mibgen</code> generated
+ * objects and you should never need to call it directly.
+ * </i></b></p>
+ *
+ * @exception SnmpStatusException if the requested SET operation must
+ * be rejected. Raising an exception will abort the request. <br>
+ * Exceptions should never be raised directly, but only by means of
+ * <code>
+ * req.registerCheckException(<i>VariableId</i>,<i>SnmpStatusException</i>)
+ * </code>
+ *
+ **/
+ // XXX xxx ZZZ zzz Maybe we should go through the MBeanInfo here?
+ public void check(SnmpGenericMetaServer meta, ObjectName name,
+ SnmpValue x, long id, Object data)
+ throws SnmpStatusException {
+
+ meta.checkSetAccess(x,id,data);
+ try {
+ final String attname = meta.getAttributeName(id);
+ final Object attvalue= meta.buildAttributeValue(id,x);
+ final Object[] params = new Object[1];
+ final String[] signature = new String[1];
+
+ params[0] = attvalue;
+ signature[0] = attvalue.getClass().getName();
+ server.invoke(name,"check"+attname,params,signature);
+
+ } catch( SnmpStatusException e) {
+ throw e;
+ }
+ catch (InstanceNotFoundException i) {
+ throw new
+ SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
+ } catch (ReflectionException r) {
+ // checkXXXX() not defined => do nothing
+ } catch (MBeanException m) {
+ Exception t = m.getTargetException();
+ if (t instanceof SnmpStatusException)
+ throw (SnmpStatusException) t;
+ throw new SnmpStatusException(SnmpStatusException.noAccess);
+ } catch (Exception e) {
+ throw new
+ SnmpStatusException(SnmpStatusException.noAccess);
+ }
+ }
+
+ public void registerTableEntry(SnmpMibTable meta, SnmpOid rowOid,
+ ObjectName objname, Object entry)
+ throws SnmpStatusException {
+ if (objname == null)
+ throw new
+ SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
+ try {
+ if (entry != null && !server.isRegistered(objname))
+ server.registerMBean(entry, objname);
+ } catch (InstanceAlreadyExistsException e) {
+ throw new
+ SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
+ } catch (MBeanRegistrationException e) {
+ throw new SnmpStatusException(SnmpStatusException.snmpRspNoAccess);
+ } catch (NotCompliantMBeanException e) {
+ throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
+ } catch (RuntimeOperationsException e) {
+ throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
+ } catch(Exception e) {
+ throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
+ }
+ }
+
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpIndex.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpIndex.java
new file mode 100644
index 0000000..d2511ba
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpIndex.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package com.sun.jmx.snmp.agent;
+
+
+
+// java imports
+//
+import java.io.Serializable;
+import java.util.Vector;
+import java.util.Enumeration;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpOid;
+
+/**
+ * Represents a SNMP index.
+ * An <CODE>SnmpIndex</CODE> is represented as a <CODE>Vector</CODE> of <CODE>SnmpOid</CODE>.
+ * <P>
+ * This class is used internally and by the classes generated by <CODE>mibgen</CODE>.
+ * You should not need to use this class directly.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public class SnmpIndex implements Serializable {
+ private static final long serialVersionUID = 8712159739982192146L;
+
+ /**
+ * Initializes an <CODE>SnmpIndex</CODE> using a vector of object identifiers.
+ * <P>Following the RFC recommendations, every syntax that is used as a
+ * table index should have an object identifier representation. There are
+ * some guidelines on how to map the different syntaxes into an object identifier.
+ * In the different <CODE>SnmpValue</CODE> classes provided, there is a <CODE>toOid</CODE> method to get
+ * the object identifier of the value.
+ *
+ * @param oidList The list of Object Identifiers.
+ */
+ public SnmpIndex(SnmpOid[] oidList) {
+ size= oidList.length;
+ for(int i= 0; i <size; i++) {
+ // The order is important ...
+ //
+ oids.addElement(oidList[i]);
+ }
+ }
+
+ /**
+ * Initializes an <CODE>SnmpIndex</CODE> using the specified Object Identifier.
+ *
+ * @param oid The Object Identifier.
+ */
+ public SnmpIndex(SnmpOid oid) {
+ oids.addElement(oid);
+ size= 1;
+ }
+
+ /**
+ * Gets the number of Object Identifiers the index is made of.
+ *
+ * @return The number of Object Identifiers.
+ */
+ public int getNbComponents() {
+ return size;
+ }
+
+ /**
+ * Gets the index as a vector of Object Identifiers.
+ *
+ * @return The index as a vector.
+ */
+ public Vector<SnmpOid> getComponents() {
+ return oids;
+ }
+
+ /**
+ * Compares two indexes for equality.
+ *
+ * @param index The index to compare <CODE>this</CODE> with.
+ *
+ * @return <CODE>true</CODE> if the two indexes are equal, <CODE>false</CODE> otherwise.
+ */
+ public boolean equals(SnmpIndex index) {
+
+ if (size != index.getNbComponents())
+ return false;
+
+ // The two vectors have the same length.
+ // Compare each single element ...
+ //
+ SnmpOid oid1;
+ SnmpOid oid2;
+ Vector<SnmpOid> components= index.getComponents();
+ for(int i=0; i <size; i++) {
+ oid1= oids.elementAt(i);
+ oid2= components.elementAt(i);
+ if (oid1.equals(oid2) == false)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Compares two indexes.
+ *
+ * @param index The index to compare <CODE>this</CODE> with.
+ *
+ * @return The value 0 if the two OID vectors have the same elements, another value otherwise.
+ */
+ public int compareTo(SnmpIndex index) {
+
+ int length= index.getNbComponents();
+ Vector<SnmpOid> components= index.getComponents();
+ SnmpOid oid1;
+ SnmpOid oid2;
+ int comp;
+ for(int i=0; i < size; i++) {
+ if ( i > length) {
+ // There is no more element in the index
+ //
+ return 1;
+ }
+ // Access the element ...
+ //
+ oid1= oids.elementAt(i);
+ oid2= components.elementAt(i);
+ comp= oid1.compareTo(oid2);
+ if (comp == 0)
+ continue;
+ return comp;
+ }
+ return 0;
+ }
+
+ /**
+ * Returns a <CODE>String</CODE> representation of the index.
+ * The different elements are separated by "//".
+ *
+ * @return A string representation of the index.
+ */
+ public String toString() {
+ StringBuffer msg= new StringBuffer();
+ for(Enumeration e= oids.elements(); e.hasMoreElements(); ) {
+ SnmpOid val= (SnmpOid) e.nextElement();
+ msg.append( "//" + val.toString());
+ }
+ return msg.toString();
+ }
+
+ // PRIVATE VARIABLES
+ //------------------
+
+ /**
+ * The list of OIDs.
+ * @serial
+ */
+ private Vector<SnmpOid> oids = new Vector<SnmpOid>();
+
+ /**
+ * The number of elements in the index.
+ * @serial
+ */
+ private int size = 0;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMib.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMib.java
new file mode 100644
index 0000000..b5c96ff
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMib.java
@@ -0,0 +1,1026 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.logging.Level;
+import java.util.Vector;
+
+import javax.management.ObjectName;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.NotCompliantMBeanException;
+
+import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpDefinitions;
+import com.sun.jmx.snmp.SnmpStatusException;
+import com.sun.jmx.snmp.SnmpEngine;
+import com.sun.jmx.snmp.SnmpUnknownModelException;
+import com.sun.jmx.snmp.internal.SnmpAccessControlModel;
+import com.sun.jmx.snmp.internal.SnmpEngineImpl;
+
+/**
+ * This list is used in order to construct the OID during the getnext.
+ * The constructed oid is checked by the checker AcmChecker.
+ */
+final class LongList {
+
+ public static int DEFAULT_CAPACITY = 10;
+
+ public static int DEFAULT_INCREMENT = 10;
+
+
+ private final int DELTA;
+ private int size;
+
+ /**
+ * The list content. Any access to this variable must be protected
+ * by a synchronized block on the LongList object.
+ * Only read-only action should be performed on this object.
+ **/
+ public long[] list;
+
+ LongList() {
+ this(DEFAULT_CAPACITY,DEFAULT_INCREMENT);
+ }
+
+ LongList(int initialCapacity) {
+ this(initialCapacity,DEFAULT_INCREMENT);
+ }
+
+ LongList(int initialCapacity, int delta) {
+ size = 0;
+ DELTA = delta;
+ list = allocate(initialCapacity);
+ }
+
+ /**
+ * Same behaviour than size() in {@link java.util.List}.
+ **/
+ public final int size() { return size;}
+
+ /**
+ * Same behaviour than add(long o) in {@link java.util.List}.
+ * Any access to this method should be protected in a synchronized
+ * block on the LongList object.
+ **/
+ public final boolean add(final long o) {
+ if (size >= list.length)
+ resize();
+ list[size++]=o;
+ return true;
+ }
+
+ /**
+ * Same behaviour than add(int index, long o) in
+ * {@link java.util.List}.
+ * Any access to this method should be protected in a synchronized
+ * block on the LongList object.
+ **/
+ public final void add(final int index, final long o) {
+ if (index > size) throw new IndexOutOfBoundsException();
+ if (index >= list.length) resize();
+ if (index == size) {
+ list[size++]=o;
+ return;
+ }
+
+ java.lang.System.arraycopy(list,index,list,index+1,size-index);
+ list[index]=o;
+ size++;
+ }
+
+ /**
+ * Adds <var>count</var> elements to the list.
+ * @param at index at which the elements must be inserted. The
+ * first element will be inserted at this index.
+ * @param src An array containing the elements we want to insert.
+ * @param from Index of the first element from <var>src</var> that
+ * must be inserted.
+ * @param count number of elements to insert.
+ * Any access to this method should be protected in a synchronized
+ * block on the LongList object.
+ **/
+ public final void add(final int at,final long[] src, final int from,
+ final int count) {
+ if (count <= 0) return;
+ if (at > size) throw new IndexOutOfBoundsException();
+ ensure(size+count);
+ if (at < size) {
+ java.lang.System.arraycopy(list,at,list,at+count,size-at);
+ }
+ java.lang.System.arraycopy(src,from,list,at,count);
+ size+=count;
+ }
+
+ /**
+ * Any access to this method should be protected in a synchronized
+ * block on the LongList object.
+ **/
+ public final long remove(final int from, final int count) {
+ if (count < 1 || from < 0) return -1;
+ if (from+count > size) return -1;
+
+ final long o = list[from];
+ final int oldsize = size;
+ size = size - count;
+
+ if (from == size) return o;
+
+ java.lang.System.arraycopy(list,from+count,list,from,
+ size-from);
+ return o;
+ }
+
+ /**
+ * Same behaviour than remove(int index) in {@link java.util.List}.
+ * Any access to this method should be protected in a synchronized
+ * block on the LongList object.
+ **/
+ public final long remove(final int index) {
+ if (index >= size) return -1;
+ final long o = list[index];
+ list[index]=0;
+ if (index == --size) return o;
+
+ java.lang.System.arraycopy(list,index+1,list,index,
+ size-index);
+ return o;
+ }
+
+ /**
+ * Same behaviour than the toArray(long[] a) method in
+ * {@link java.util.List}.
+ * Any access to this method should be protected in a synchronized
+ * block on the LongList object.
+ **/
+ public final long[] toArray(long[] a) {
+ java.lang.System.arraycopy(list,0,a,0,size);
+ return a;
+ }
+
+ /**
+ * Same behaviour than the toArray() method in
+ * {@link java.util.List}.
+ * Any access to this method should be protected in a synchronized
+ * block on the LongList object.
+ **/
+ public final long[] toArray() {
+ return toArray(new long[size]);
+ }
+
+ /**
+ * Resize the list. Increase its capacity by DELTA elements.
+ * Any call to this method must be protected by a synchronized
+ * block on this LongList.
+ **/
+ private final void resize() {
+ final long[] newlist = allocate(list.length + DELTA);
+ java.lang.System.arraycopy(list,0,newlist,0,size);
+ list = newlist;
+ }
+
+ /**
+ * Resize the list. Insure that the new length will be at
+ * least equal to <var>length</var>.
+ * @param length new minimal length requested.
+ * Any call to this method must be protected by a synchronized
+ * block on this LongList.
+ **/
+ private final void ensure(int length) {
+ if (list.length < length) {
+ final int min = list.length+DELTA;
+ length=(length<min)?min:length;
+ final long[] newlist = allocate(length);
+ java.lang.System.arraycopy(list,0,newlist,0,size);
+ list = newlist;
+ }
+ }
+
+ /**
+ * Allocate a new array of object of specified length.
+ **/
+ private final long[] allocate(final int length) {
+ return new long[length];
+ }
+
+}
+
+/**
+ * Oid Checker makes use of ACM to check each OID during the getnext process.
+ */
+class AcmChecker {
+
+
+ SnmpAccessControlModel model = null;
+ String principal = null;
+ int securityLevel = -1;
+ int version = -1;
+ int pduType = -1;
+ int securityModel = -1;
+ byte[] contextName = null;
+ SnmpEngineImpl engine = null;
+ LongList l = null;
+ AcmChecker(SnmpMibRequest req) {
+ engine = (SnmpEngineImpl) req.getEngine();
+ //We are in V3 architecture, ACM is in the picture.
+ if(engine != null) {
+ if(engine.isCheckOidActivated()) {
+ try {
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "AcmChecker(SnmpMibRequest)",
+ "SNMP V3 Access Control to be done");
+ }
+ model = (SnmpAccessControlModel)
+ engine.getAccessControlSubSystem().
+ getModel(SnmpDefinitions.snmpVersionThree);
+ principal = req.getPrincipal();
+ securityLevel = req.getSecurityLevel();
+ pduType = req.getPdu().type;
+ version = req.getRequestPduVersion();
+ securityModel = req.getSecurityModel();
+ contextName = req.getAccessContextName();
+ l = new LongList();
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ final StringBuilder strb = new StringBuilder()
+ .append("Will check oid for : principal : ")
+ .append(principal)
+ .append("; securityLevel : ").append(securityLevel)
+ .append("; pduType : ").append(pduType)
+ .append("; version : ").append(version)
+ .append("; securityModel : ").append(securityModel)
+ .append("; contextName : ").append(contextName);
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "AcmChecker(SnmpMibRequest)", strb.toString());
+ }
+
+ }catch(SnmpUnknownModelException e) {
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "AcmChecker(SnmpMibRequest)",
+ "Unknown Model, no ACM check.");
+ }
+ }
+ }
+ }
+ }
+
+ void add(int index, long arc) {
+ if(model != null)
+ l.add(index, arc);
+ }
+
+ void remove(int index) {
+ if(model != null)
+ l.remove(index);
+ }
+
+ void add(final int at,final long[] src, final int from,
+ final int count) {
+ if(model != null)
+ l.add(at,src,from,count);
+ }
+
+ void remove(final int from, final int count) {
+ if(model != null)
+ l.remove(from,count);
+ }
+
+ void checkCurrentOid() throws SnmpStatusException {
+ if(model != null) {
+ SnmpOid oid = new SnmpOid(l.toArray());
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
+ "checkCurrentOid", "Checking access for : " + oid);
+ }
+ model.checkAccess(version,
+ principal,
+ securityLevel,
+ pduType,
+ securityModel,
+ contextName,
+ oid);
+ }
+ }
+
+}
+
+/**
+ * Abstract class for representing an SNMP MIB.
+ * <P>
+ * When compiling a SNMP MIB, among all the classes generated by
+ * <CODE>mibgen</CODE>, there is one which extends <CODE>SnmpMib</CODE>
+ * for representing a whole MIB.
+ * <BR>The class is used by the SNMP protocol adaptor as the entry point in
+ * the MIB.
+ *
+ * <p>This generated class can be subclassed in your code in order to
+ * plug in your own specific behaviour.
+ * </p>
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+public abstract class SnmpMib extends SnmpMibAgent implements Serializable {
+
+ /**
+ * Default constructor.
+ * Initializes the OID tree.
+ */
+ public SnmpMib() {
+ root= new SnmpMibOid();
+ }
+
+
+ // --------------------------------------------------------------------
+ // POLYMORHIC METHODS
+ // --------------------------------------------------------------------
+
+ /**
+ * <p>
+ * This callback should return the OID associated to the group
+ * identified by the given <code>groupName</code>.
+ * </p>
+ *
+ * <p>
+ * This method is provided as a hook to plug-in some custom
+ * specific behavior. Although doing so is discouraged you might
+ * want to subclass this method in order to store & provide more metadata
+ * information (mapping OID <-> symbolic name) within the agent,
+ * or to "change" the root of the MIB OID by prefixing the
+ * defaultOid by an application dependant OID string, for instance.
+ * </p>
+ *
+ * <p>
+ * The default implementation of this method is to return the given
+ * <code>defaultOid</code>
+ * </p>
+ *
+ * @param groupName The java-ized name of the SNMP group.
+ * @param defaultOid The OID defined in the MIB for that group
+ * (in dot notation).
+ *
+ * @return The OID of the group identified by <code>groupName</code>,
+ * in dot-notation.
+ */
+ protected String getGroupOid(String groupName, String defaultOid) {
+ return defaultOid;
+ }
+
+ /**
+ * <p>
+ * This callback should return the ObjectName associated to the
+ * group identified by the given <code>groupName</code>.
+ * </p>
+ *
+ * <p>
+ * This method is provided as a hook to plug-in some custom
+ * specific behavior. You might want to override this method
+ * in order to provide a different object naming scheme than
+ * that proposed by default by <code>mibgen</code>.
+ * </p>
+ *
+ * <p>
+ * This method is only meaningful if the MIB is registered
+ * in the MBeanServer, otherwise, it will not be called.
+ * </p>
+ *
+ * <p>
+ * The default implementation of this method is to return an ObjectName
+ * built from the given <code>defaultName</code>.
+ * </p>
+ *
+ * @param name The java-ized name of the SNMP group.
+ * @param oid The OID returned by getGroupOid() - in dot notation.
+ * @param defaultName The name by default generated by <code>
+ * mibgen</code>
+ *
+ * @return The ObjectName of the group identified by <code>name</code>
+ */
+ protected ObjectName getGroupObjectName(String name, String oid,
+ String defaultName)
+ throws MalformedObjectNameException {
+ return new ObjectName(defaultName);
+ }
+
+ /**
+ * <p>
+ * Register an SNMP group and its metadata node in the MIB.
+ * </p>
+ *
+ * <p>
+ * This method is provided as a hook to plug-in some custom
+ * specific behavior. You might want to override this method
+ * if you want to set special links between the MBean, its metadata
+ * node, its OID or ObjectName etc..
+ * </p>
+ *
+ * <p>
+ * If the MIB is not registered in the MBeanServer, the <code>
+ * server</code> and <code>groupObjName</code> parameters will be
+ * <code>null</code>.<br>
+ * If the given group MBean is not <code>null</code>, and if the
+ * <code>server</code> and <code>groupObjName</code> parameters are
+ * not null, then this method will also automatically register the
+ * group MBean with the given MBeanServer <code>server</code>.
+ * </p>
+ *
+ * @param groupName The java-ized name of the SNMP group.
+ * @param groupOid The OID as returned by getGroupOid() - in dot
+ * notation.
+ * @param groupObjName The ObjectName as returned by getGroupObjectName().
+ * This parameter may be <code>null</code> if the
+ * MIB is not registered in the MBeanServer.
+ * @param node The metadata node, as returned by the metadata
+ * factory method for this group.
+ * @param group The MBean for this group, as returned by the
+ * MBean factory method for this group.
+ * @param server The MBeanServer in which the groups are to be
+ * registered. This parameter will be <code>null</code>
+ * if the MIB is not registered, otherwise it is a
+ * reference to the MBeanServer in which the MIB is
+ * registered.
+ *
+ */
+ protected void registerGroupNode(String groupName, String groupOid,
+ ObjectName groupObjName, SnmpMibNode node,
+ Object group, MBeanServer server)
+ throws NotCompliantMBeanException, MBeanRegistrationException,
+ InstanceAlreadyExistsException, IllegalAccessException {
+ root.registerNode(groupOid,node);
+ if (server != null && groupObjName != null && group != null)
+ server.registerMBean(group,groupObjName);
+ }
+
+ /**
+ * <p>
+ * Register an SNMP Table metadata node in the MIB.
+ * </p>
+ *
+ * <p>
+ * <b><i>
+ * This method is used internally and you should never need to
+ * call it directly.</i></b><br> It is used to establish the link
+ * between an SNMP table metadata node and its bean-like counterpart.
+ * <br>
+ * The group metadata nodes will create and register their
+ * underlying table metadata nodes in the MIB using this
+ * method. <br>
+ * The metadata nodes will be later retrieved from the MIB by the
+ * bean-like table objects using the getRegisterTableMeta() method.
+ * </p>
+ *
+ * @param name The java-ized name of the SNMP table.
+ * @param table The SNMP table metadata node - usually this
+ * corresponds to a <code>mibgen</code> generated
+ * object.
+ */
+ public abstract void registerTableMeta(String name, SnmpMibTable table);
+
+ /**
+ * Returns a registered SNMP Table metadata node.
+ *
+ * <p><b><i>
+ * This method is used internally and you should never need to
+ * call it directly.
+ * </i></b></p>
+ *
+ */
+ public abstract SnmpMibTable getRegisteredTableMeta(String name);
+
+ // --------------------------------------------------------------------
+ // PUBLIC METHODS
+ // --------------------------------------------------------------------
+
+ /**
+ * Processes a <CODE>get</CODE> operation.
+ *
+ **/
+ // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
+ // for java-doc
+ //
+ public void get(SnmpMibRequest req) throws SnmpStatusException {
+
+ // Builds the request tree: creation is not allowed, operation
+ // is not atomic.
+
+ final int reqType = SnmpDefinitions.pduGetRequestPdu;
+ SnmpRequestTree handlers = getHandlers(req,false,false,reqType);
+
+ SnmpRequestTree.Handler h = null;
+ SnmpMibNode meta = null;
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
+ "get", "Processing handlers for GET... ");
+ }
+
+ // For each sub-request stored in the request-tree, invoke the
+ // get() method.
+ for (Enumeration eh=handlers.getHandlers();eh.hasMoreElements();) {
+ h = (SnmpRequestTree.Handler) eh.nextElement();
+
+ // Gets the Meta node. It can be either a Group Meta or a
+ // Table Meta.
+ //
+ meta = handlers.getMetaNode(h);
+
+ // Gets the depth of the Meta node in the OID tree
+ final int depth = handlers.getOidDepth(h);
+
+ for (Enumeration rqs=handlers.getSubRequests(h);
+ rqs.hasMoreElements();) {
+
+ // Invoke the get() operation.
+ meta.get((SnmpMibSubRequest)rqs.nextElement(),depth);
+ }
+ }
+ }
+
+ /**
+ * Processes a <CODE>set</CODE> operation.
+ *
+ */
+ // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
+ // for java-doc
+ //
+ public void set(SnmpMibRequest req) throws SnmpStatusException {
+
+ SnmpRequestTree handlers = null;
+
+ // Optimization: we're going to get the whole SnmpRequestTree
+ // built in the "check" method, so that we don't have to rebuild
+ // it here.
+ //
+ if (req instanceof SnmpMibRequestImpl)
+ handlers = ((SnmpMibRequestImpl)req).getRequestTree();
+
+ // Optimization didn't work: we have to rebuild the tree.
+ //
+ // Builds the request tree: creation is not allowed, operation
+ // is atomic.
+ //
+ final int reqType = SnmpDefinitions.pduSetRequestPdu;
+ if (handlers == null) handlers = getHandlers(req,false,true,reqType);
+ handlers.switchCreationFlag(false);
+ handlers.setPduType(reqType);
+
+ SnmpRequestTree.Handler h = null;
+ SnmpMibNode meta = null;
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
+ "set", "Processing handlers for SET... ");
+ }
+
+ // For each sub-request stored in the request-tree, invoke the
+ // get() method.
+ for (Enumeration eh=handlers.getHandlers();eh.hasMoreElements();) {
+ h = (SnmpRequestTree.Handler) eh.nextElement();
+
+ // Gets the Meta node. It can be either a Group Meta or a
+ // Table Meta.
+ //
+ meta = handlers.getMetaNode(h);
+
+ // Gets the depth of the Meta node in the OID tree
+ final int depth = handlers.getOidDepth(h);
+
+ for (Enumeration rqs=handlers.getSubRequests(h);
+ rqs.hasMoreElements();) {
+
+ // Invoke the set() operation
+ meta.set((SnmpMibSubRequest)rqs.nextElement(),depth);
+ }
+ }
+ }
+
+ /**
+ * Checks if a <CODE>set</CODE> operation can be performed.
+ * If the operation cannot be performed, the method will raise a
+ * <CODE>SnmpStatusException</CODE>.
+ *
+ */
+ // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
+ // for java-doc
+ //
+ public void check(SnmpMibRequest req) throws SnmpStatusException {
+
+ final int reqType = SnmpDefinitions.pduWalkRequest;
+ // Builds the request tree: creation is allowed, operation
+ // is atomic.
+ SnmpRequestTree handlers = getHandlers(req,true,true,reqType);
+
+ SnmpRequestTree.Handler h = null;
+ SnmpMibNode meta = null;
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
+ "check", "Processing handlers for CHECK... ");
+ }
+
+ // For each sub-request stored in the request-tree, invoke the
+ // check() method.
+ for (Enumeration eh=handlers.getHandlers();eh.hasMoreElements();) {
+ h = (SnmpRequestTree.Handler) eh.nextElement();
+
+ // Gets the Meta node. It can be either a Group Meta or a
+ // Table Meta.
+ //
+ meta = handlers.getMetaNode(h);
+
+ // Gets the depth of the Meta node in the OID tree
+ final int depth = handlers.getOidDepth(h);
+
+ for (Enumeration rqs=handlers.getSubRequests(h);
+ rqs.hasMoreElements();) {
+
+ // Invoke the check() operation
+ meta.check((SnmpMibSubRequest)rqs.nextElement(),depth);
+ }
+ }
+
+ // Optimization: we're going to pass the whole SnmpRequestTree
+ // to the "set" method, so that we don't have to rebuild it there.
+ //
+ if (req instanceof SnmpMibRequestImpl) {
+ ((SnmpMibRequestImpl)req).setRequestTree(handlers);
+ }
+
+ }
+
+ /**
+ * Processes a <CODE>getNext</CODE> operation.
+ *
+ */
+ // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
+ // for java-doc
+ //
+ public void getNext(SnmpMibRequest req) throws SnmpStatusException {
+ // Build the request tree for the operation
+ // The subrequest stored in the request tree are valid GET requests
+ SnmpRequestTree handlers = getGetNextHandlers(req);
+
+ SnmpRequestTree.Handler h = null;
+ SnmpMibNode meta = null;
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
+ "getNext", "Processing handlers for GET-NEXT... ");
+ }
+
+ // Now invoke get() for each subrequest of the request tree.
+ for (Enumeration eh=handlers.getHandlers();eh.hasMoreElements();) {
+ h = (SnmpRequestTree.Handler) eh.nextElement();
+
+ // Gets the Meta node. It can be either a Group Meta or a
+ // Table Meta.
+ //
+ meta = handlers.getMetaNode(h);
+
+ // Gets the depth of the Meta node in the OID tree
+ int depth = handlers.getOidDepth(h);
+
+ for (Enumeration rqs=handlers.getSubRequests(h);
+ rqs.hasMoreElements();) {
+
+ // Invoke the get() operation
+ meta.get((SnmpMibSubRequest)rqs.nextElement(),depth);
+ }
+ }
+ }
+
+
+ /**
+ * Processes a <CODE>getBulk</CODE> operation.
+ * The method implements the <CODE>getBulk</CODE> operation by calling
+ * appropriately the <CODE>getNext</CODE> method.
+ *
+ */
+ // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
+ // for java-doc
+ //
+ public void getBulk(SnmpMibRequest req, int nonRepeat, int maxRepeat)
+ throws SnmpStatusException {
+
+ getBulkWithGetNext(req, nonRepeat, maxRepeat);
+ }
+
+ /**
+ * Gets the root object identifier of the MIB.
+ * <P>In order to be accurate, the method should be called once the
+ * MIB is fully initialized (that is, after a call to <CODE>init</CODE>
+ * or <CODE>preRegister</CODE>).
+ *
+ * @return The root object identifier.
+ */
+ public long[] getRootOid() {
+
+ if( rootOid == null) {
+ Vector<Integer> list= new Vector<Integer>(10);
+
+ // Ask the tree to do the job !
+ //
+ root.getRootOid(list);
+
+ // Now format the result
+ //
+ rootOid= new long[list.size()];
+ int i=0;
+ for(Enumeration<Integer> e= list.elements(); e.hasMoreElements(); ) {
+ Integer val= e.nextElement();
+ rootOid[i++]= val.longValue();
+ }
+ }
+ return rootOid;
+
+ }
+
+ // --------------------------------------------------------------------
+ // PRIVATE METHODS
+ //---------------------------------------------------------------------
+
+ /**
+ * This method builds the temporary request-tree that will be used to
+ * perform the SNMP request associated with the given vector of varbinds
+ * `list'.
+ *
+ * @param req The SnmpMibRequest object holding the varbind list
+ * concerning this MIB.
+ * @param createflag Indicates whether the operation allow for creation
+ * of new instances (ie: it is a SET).
+ * @param atomic Indicates whether the operation is atomic or not.
+ * @param type Request type (from SnmpDefinitions).
+ *
+ * @return The request-tree where the original varbind list has been
+ * dispatched to the appropriate nodes.
+ */
+ private SnmpRequestTree getHandlers(SnmpMibRequest req,
+ boolean createflag, boolean atomic,
+ int type)
+ throws SnmpStatusException {
+
+ // Build an empty request tree
+ SnmpRequestTree handlers =
+ new SnmpRequestTree(req,createflag,type);
+
+ int index=0;
+ SnmpVarBind var = null;
+ final int ver= req.getVersion();
+
+ // For each varbind in the list finds its handling node.
+ for (Enumeration e= req.getElements(); e.hasMoreElements(); index++) {
+
+ var= (SnmpVarBind) e.nextElement();
+
+ try {
+ // Find the handling node for this varbind.
+ root.findHandlingNode(var,var.oid.longValue(false),
+ 0,handlers);
+ } catch(SnmpStatusException x) {
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getHandlers",
+ "Couldn't find a handling node for " +
+ var.oid.toString());
+ }
+
+ // If the operation is atomic (Check/Set) or the version
+ // is V1 we must generate an exception.
+ //
+ if (ver == SnmpDefinitions.snmpVersionOne) {
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getHandlers", "\tV1: Throwing exception");
+ }
+
+ // The index in the exception must correspond to the
+ // SNMP index ...
+ //
+ final SnmpStatusException sse =
+ new SnmpStatusException(x, index + 1);
+ sse.initCause(x);
+ throw sse;
+ } else if ((type == SnmpDefinitions.pduWalkRequest) ||
+ (type == SnmpDefinitions.pduSetRequestPdu)) {
+ final int status =
+ SnmpRequestTree.mapSetException(x.getStatus(),ver);
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getHandlers", "\tSET: Throwing exception");
+ }
+
+ final SnmpStatusException sse =
+ new SnmpStatusException(status, index + 1);
+ sse.initCause(x);
+ throw sse;
+ } else if (atomic) {
+
+ // Should never come here...
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getHandlers", "\tATOMIC: Throwing exception");
+ }
+
+ final SnmpStatusException sse =
+ new SnmpStatusException(x, index + 1);
+ sse.initCause(x);
+ throw sse;
+ }
+
+ final int status =
+ SnmpRequestTree.mapGetException(x.getStatus(),ver);
+
+ if (status == SnmpStatusException.noSuchInstance) {
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getHandlers",
+ "\tGET: Registering noSuchInstance");
+ }
+
+ var.value= SnmpVarBind.noSuchInstance;
+
+ } else if (status == SnmpStatusException.noSuchObject) {
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getHandlers",
+ "\tGET: Registering noSuchObject");
+ }
+
+ var.value= SnmpVarBind.noSuchObject;
+
+ } else {
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getHandlers",
+ "\tGET: Registering global error: " + status);
+ }
+
+ final SnmpStatusException sse =
+ new SnmpStatusException(status, index + 1);
+ sse.initCause(x);
+ throw sse;
+ }
+ }
+ }
+ return handlers;
+ }
+
+ /**
+ * This method builds the temporary request-tree that will be used to
+ * perform the SNMP GET-NEXT request associated with the given vector
+ * of varbinds `list'.
+ *
+ * @param req The SnmpMibRequest object holding the varbind list
+ * concerning this MIB.
+ *
+ * @return The request-tree where the original varbind list has been
+ * dispatched to the appropriate nodes, and where the original
+ * OIDs have been replaced with the correct "next" OID.
+ */
+ private SnmpRequestTree getGetNextHandlers(SnmpMibRequest req)
+ throws SnmpStatusException {
+
+ // Creates an empty request tree, no entry creation is allowed (false)
+ SnmpRequestTree handlers = new
+ SnmpRequestTree(req,false,SnmpDefinitions.pduGetNextRequestPdu);
+
+ // Sets the getNext flag: if version=V2, status exception are
+ // transformed in endOfMibView
+ handlers.setGetNextFlag();
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
+ "getGetNextHandlers", "Received MIB request : " + req);
+ }
+ AcmChecker checker = new AcmChecker(req);
+ int index=0;
+ SnmpVarBind var = null;
+ final int ver= req.getVersion();
+ SnmpOid original = null;
+ // For each varbind, finds the handling node.
+ // This function has the side effect of transforming a GET-NEXT
+ // request into a valid GET request, replacing the OIDs in the
+ // original GET-NEXT request with the OID of the first leaf that
+ // follows.
+ for (Enumeration e= req.getElements(); e.hasMoreElements(); index++) {
+
+ var = (SnmpVarBind) e.nextElement();
+ SnmpOid result = null;
+ try {
+ // Find the node handling the OID that follows the varbind
+ // OID. `result' contains this next leaf OID.
+ //ACM loop.
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getGetNextHandlers", " Next OID of : " + var.oid);
+ }
+ result = new SnmpOid(root.findNextHandlingNode
+ (var,var.oid.longValue(false),0,
+ 0,handlers, checker));
+
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getGetNextHandlers", " is : " + result);
+ }
+ // We replace the varbind original OID with the OID of the
+ // leaf object we have to return.
+ var.oid = result;
+ } catch(SnmpStatusException x) {
+
+ // if (isDebugOn())
+ // debug("getGetNextHandlers",
+ // "Couldn't find a handling node for "
+ // + var.oid.toString());
+
+ if (ver == SnmpDefinitions.snmpVersionOne) {
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getGetNextHandlers",
+ "\tThrowing exception " + x.toString());
+ }
+ // The index in the exception must correspond to the
+ // SNMP index ...
+ //
+ throw new SnmpStatusException(x, index + 1);
+ }
+ if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpMib.class.getName(),
+ "getGetNextHandlers",
+ "Exception : " + x.getStatus());
+ }
+
+ var.setSnmpValue(SnmpVarBind.endOfMibView);
+ }
+ }
+ return handlers;
+ }
+
+ // --------------------------------------------------------------------
+ // PROTECTED VARIABLES
+ // --------------------------------------------------------------------
+
+ /**
+ * The top element in the Mib tree.
+ * @serial
+ */
+ protected SnmpMibOid root;
+
+
+ // --------------------------------------------------------------------
+ // PRIVATE VARIABLES
+ // --------------------------------------------------------------------
+
+ /**
+ * The root object identifier of the MIB.
+ */
+ private transient long[] rootOid= null;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibAgent.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibAgent.java
new file mode 100644
index 0000000..c2d48cf
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibAgent.java
@@ -0,0 +1,757 @@
+/*
+ * Copyright 1998-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package com.sun.jmx.snmp.agent;
+
+
+
+// java imports
+//
+import java.io.Serializable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Set;
+
+// jmx imports
+//
+import javax.management.MBeanServer;
+import javax.management.MBeanRegistration;
+import javax.management.ObjectName;
+import javax.management.MalformedObjectNameException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ServiceNotFoundException;
+import javax.management.ReflectionException;
+import javax.management.MBeanException;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpDefinitions;
+import com.sun.jmx.snmp.SnmpStatusException;
+import com.sun.jmx.snmp.SnmpPdu;
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpEngine;
+
+/**
+ * Abstract class for representing an SNMP agent.
+ *
+ * The class is used by the SNMP protocol adaptor as the entry point in
+ * the SNMP agent to query.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public abstract class SnmpMibAgent
+ implements SnmpMibAgentMBean, MBeanRegistration, Serializable {
+
+ /**
+ * Default constructor.
+ */
+ public SnmpMibAgent() {
+ }
+
+ // ---------------------------------------------------------------------
+ // PUBLIC METHODS
+ //----------------------------------------------------------------------
+
+ /**
+ * Initializes the MIB (with no registration of the MBeans into the
+ * MBean server).
+ *
+ * @exception IllegalAccessException The MIB can not be initialized.
+ */
+ public abstract void init() throws IllegalAccessException;
+
+ /**
+ * Initializes the MIB but each single MBean representing the MIB
+ * is inserted into the MBean server.
+ *
+ * @param server The MBean server to register the service with.
+ * @param name The object name.
+ *
+ * @return The name of the SNMP MIB registered.
+ *
+ * @exception java.lang.Exception
+ */
+ public abstract ObjectName preRegister(MBeanServer server,
+ ObjectName name)
+ throws java.lang.Exception;
+
+ /**
+ * Not used in this context.
+ */
+ public void postRegister (Boolean registrationDone) {
+ }
+
+ /**
+ * Not used in this context.
+ */
+ public void preDeregister() throws java.lang.Exception {
+ }
+
+ /**
+ * Not used in this context.
+ */
+ public void postDeregister() {
+ }
+
+ /**
+ * Processes a <CODE>get</CODE> operation.
+ * This method must update the SnmpVarBinds contained in the
+ * <var>{@link SnmpMibRequest} req</var> parameter.
+ *
+ * @param req The SnmpMibRequest object holding the list of variable to
+ * be retrieved. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ */
+ public abstract void get(SnmpMibRequest req)
+ throws SnmpStatusException;
+
+ /**
+ * Processes a <CODE>getNext</CODE> operation.
+ * This method must update the SnmpVarBinds contained in the
+ * <var>{@link SnmpMibRequest} req</var> parameter.
+ *
+ * @param req The SnmpMibRequest object holding the list of
+ * OIDs from which the next variables should be retrieved.
+ * This list is composed of <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ */
+ public abstract void getNext(SnmpMibRequest req)
+ throws SnmpStatusException;
+
+ /**
+ * Processes a <CODE>getBulk</CODE> operation.
+ * This method must update the SnmpVarBinds contained in the
+ * <var>{@link SnmpMibRequest} req</var> parameter.
+ *
+ * @param req The SnmpMibRequest object holding the list of variable to
+ * be retrieved. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @param nonRepeat The number of variables, starting with the first
+ * variable in the variable-bindings, for which a single
+ * lexicographic successor is requested.
+ *
+ * @param maxRepeat The number of lexicographic successors requested
+ * for each of the last R variables. R is the number of variables
+ * following the first <CODE>nonRepeat</CODE> variables for which
+ * multiple lexicographic successors are requested.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ */
+ public abstract void getBulk(SnmpMibRequest req, int nonRepeat,
+ int maxRepeat)
+ throws SnmpStatusException;
+
+ /**
+ * Processes a <CODE>set</CODE> operation.
+ * This method must update the SnmpVarBinds contained in the
+ * <var>{@link SnmpMibRequest} req</var> parameter.
+ * This method is called during the second phase of the SET two-phase
+ * commit.
+ *
+ * @param req The SnmpMibRequest object holding the list of variable to
+ * be set. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ * Throwing an exception in this method will break the
+ * atomicity of the SET operation. Care must be taken so that
+ * the exception is thrown in the {@link #check(SnmpMibRequest)}
+ * method instead.
+ */
+ public abstract void set(SnmpMibRequest req)
+ throws SnmpStatusException;
+
+
+ /**
+ * Checks if a <CODE>set</CODE> operation can be performed.
+ * If the operation can not be performed, the method should throw an
+ * <CODE>SnmpStatusException</CODE>.
+ * This method is called during the first phase of the SET two-phase
+ * commit.
+ *
+ * @param req The SnmpMibRequest object holding the list of variable to
+ * be set. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException The <CODE>set</CODE> operation
+ * cannot be performed.
+ */
+ public abstract void check(SnmpMibRequest req)
+ throws SnmpStatusException;
+
+ /**
+ * Gets the root object identifier of the MIB.
+ * <P>The root object identifier is the object identifier uniquely
+ * identifying the MIB.
+ *
+ * @return The root object identifier.
+ */
+ public abstract long[] getRootOid();
+
+ // ---------------------------------------------------------------------
+ // GETTERS AND SETTERS
+ // ---------------------------------------------------------------------
+
+ /**
+ * Gets the reference to the MBean server in which the SNMP MIB is
+ * registered.
+ *
+ * @return The MBean server or null if the MIB is not registered in any
+ * MBean server.
+ */
+ public MBeanServer getMBeanServer() {
+ return server;
+ }
+
+ /**
+ * Gets the reference to the SNMP protocol adaptor to which the MIB is
+ * bound.
+ *
+ * @return The SNMP MIB handler.
+ */
+ public SnmpMibHandler getSnmpAdaptor() {
+ return adaptor;
+ }
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler.
+ *
+ * @param stack The SNMP MIB handler.
+ */
+ public void setSnmpAdaptor(SnmpMibHandler stack) {
+ if (adaptor != null) {
+ adaptor.removeMib(this);
+ }
+ adaptor = stack;
+ if (adaptor != null) {
+ adaptor.addMib(this);
+ }
+ }
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler.
+ * This method is to be called to set a specific agent to a specific OID. This can be useful when dealing with MIB overlapping.
+ * Some OID can be implemented in more than one MIB. In this case, the OID nearest the agent will be used on SNMP operations.
+ * @param stack The SNMP MIB handler.
+ * @param oids The set of OIDs this agent implements.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptor(SnmpMibHandler stack, SnmpOid[] oids) {
+ if (adaptor != null) {
+ adaptor.removeMib(this);
+ }
+ adaptor = stack;
+ if (adaptor != null) {
+ adaptor.addMib(this, oids);
+ }
+ }
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and adds this new MIB in the SNMP MIB handler.
+ * Adds a new contextualized MIB in the SNMP MIB handler.
+ *
+ * @param stack The SNMP MIB handler.
+ * @param contextName The MIB context name. If null is passed, will be registered in the default context.
+ *
+ * @exception IllegalArgumentException If the parameter is null.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptor(SnmpMibHandler stack, String contextName) {
+ if (adaptor != null) {
+ adaptor.removeMib(this, contextName);
+ }
+ adaptor = stack;
+ if (adaptor != null) {
+ adaptor.addMib(this, contextName);
+ }
+ }
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and adds this new MIB in the SNMP MIB handler.
+ * Adds a new contextualized MIB in the SNMP MIB handler.
+ *
+ * @param stack The SNMP MIB handler.
+ * @param contextName The MIB context name. If null is passed, will be registered in the default context.
+ * @param oids The set of OIDs this agent implements.
+ * @exception IllegalArgumentException If the parameter is null.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptor(SnmpMibHandler stack,
+ String contextName,
+ SnmpOid[] oids) {
+ if (adaptor != null) {
+ adaptor.removeMib(this, contextName);
+ }
+ adaptor = stack;
+ if (adaptor != null) {
+ adaptor.addMib(this, contextName, oids);
+ }
+ }
+
+ /**
+ * Gets the object name of the SNMP protocol adaptor to which the MIB
+ * is bound.
+ *
+ * @return The name of the SNMP protocol adaptor.
+ */
+ public ObjectName getSnmpAdaptorName() {
+ return adaptorName;
+ }
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler
+ * associated to the specified <CODE>name</CODE>.
+ *
+ * @param name The name of the SNMP protocol adaptor.
+ *
+ * @exception InstanceNotFoundException The SNMP protocol adaptor does
+ * not exist in the MBean server.
+ *
+ * @exception ServiceNotFoundException This SNMP MIB is not registered
+ * in the MBean server or the requested service is not supported.
+ */
+ public void setSnmpAdaptorName(ObjectName name)
+ throws InstanceNotFoundException, ServiceNotFoundException {
+
+ if (server == null) {
+ throw new ServiceNotFoundException(mibName + " is not registered in the MBean server");
+ }
+ // First remove the reference on the old adaptor server.
+ //
+ if (adaptor != null) {
+ adaptor.removeMib(this);
+ }
+
+ // Then update the reference to the new adaptor server.
+ //
+ Object[] params = {this};
+ String[] signature = {"com.sun.jmx.snmp.agent.SnmpMibAgent"};
+ try {
+ adaptor = (SnmpMibHandler)(server.invoke(name, "addMib", params,
+ signature));
+ } catch (InstanceNotFoundException e) {
+ throw new InstanceNotFoundException(name.toString());
+ } catch (ReflectionException e) {
+ throw new ServiceNotFoundException(name.toString());
+ } catch (MBeanException e) {
+ // Should never occur...
+ }
+
+ adaptorName = name;
+ }
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler
+ * associated to the specified <CODE>name</CODE>.
+ * This method is to be called to set a specific agent to a specific OID. This can be useful when dealing with MIB overlapping.
+ * Some OID can be implemented in more than one MIB. In this case, the OID nearer agent will be used on SNMP operations.
+ * @param name The name of the SNMP protocol adaptor.
+ * @param oids The set of OIDs this agent implements.
+ * @exception InstanceNotFoundException The SNMP protocol adaptor does
+ * not exist in the MBean server.
+ *
+ * @exception ServiceNotFoundException This SNMP MIB is not registered
+ * in the MBean server or the requested service is not supported.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptorName(ObjectName name, SnmpOid[] oids)
+ throws InstanceNotFoundException, ServiceNotFoundException {
+
+ if (server == null) {
+ throw new ServiceNotFoundException(mibName + " is not registered in the MBean server");
+ }
+ // First remove the reference on the old adaptor server.
+ //
+ if (adaptor != null) {
+ adaptor.removeMib(this);
+ }
+
+ // Then update the reference to the new adaptor server.
+ //
+ Object[] params = {this, oids};
+ String[] signature = {"com.sun.jmx.snmp.agent.SnmpMibAgent",
+ oids.getClass().getName()};
+ try {
+ adaptor = (SnmpMibHandler)(server.invoke(name, "addMib", params,
+ signature));
+ } catch (InstanceNotFoundException e) {
+ throw new InstanceNotFoundException(name.toString());
+ } catch (ReflectionException e) {
+ throw new ServiceNotFoundException(name.toString());
+ } catch (MBeanException e) {
+ // Should never occur...
+ }
+
+ adaptorName = name;
+ }
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler
+ * associated to the specified <CODE>name</CODE>.
+ *
+ * @param name The name of the SNMP protocol adaptor.
+ * @param contextName The MIB context name. If null is passed, will be registered in the default context.
+ * @exception InstanceNotFoundException The SNMP protocol adaptor does
+ * not exist in the MBean server.
+ *
+ * @exception ServiceNotFoundException This SNMP MIB is not registered
+ * in the MBean server or the requested service is not supported.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptorName(ObjectName name, String contextName)
+ throws InstanceNotFoundException, ServiceNotFoundException {
+
+ if (server == null) {
+ throw new ServiceNotFoundException(mibName + " is not registered in the MBean server");
+ }
+
+ // First remove the reference on the old adaptor server.
+ //
+ if (adaptor != null) {
+ adaptor.removeMib(this, contextName);
+ }
+
+ // Then update the reference to the new adaptor server.
+ //
+ Object[] params = {this, contextName};
+ String[] signature = {"com.sun.jmx.snmp.agent.SnmpMibAgent", "java.lang.String"};
+ try {
+ adaptor = (SnmpMibHandler)(server.invoke(name, "addMib", params,
+ signature));
+ } catch (InstanceNotFoundException e) {
+ throw new InstanceNotFoundException(name.toString());
+ } catch (ReflectionException e) {
+ throw new ServiceNotFoundException(name.toString());
+ } catch (MBeanException e) {
+ // Should never occur...
+ }
+
+ adaptorName = name;
+ }
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler
+ * associated to the specified <CODE>name</CODE>.
+ *
+ * @param name The name of the SNMP protocol adaptor.
+ * @param contextName The MIB context name. If null is passed, will be registered in the default context.
+ * @param oids The set of OIDs this agent implements.
+ * @exception InstanceNotFoundException The SNMP protocol adaptor does
+ * not exist in the MBean server.
+ *
+ * @exception ServiceNotFoundException This SNMP MIB is not registered
+ * in the MBean server or the requested service is not supported.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptorName(ObjectName name,
+ String contextName, SnmpOid[] oids)
+ throws InstanceNotFoundException, ServiceNotFoundException {
+
+ if (server == null) {
+ throw new ServiceNotFoundException(mibName + " is not registered in the MBean server");
+ }
+
+ // First remove the reference on the old adaptor server.
+ //
+ if (adaptor != null) {
+ adaptor.removeMib(this, contextName);
+ }
+
+ // Then update the reference to the new adaptor server.
+ //
+ Object[] params = {this, contextName, oids};
+ String[] signature = {"com.sun.jmx.snmp.agent.SnmpMibAgent", "java.lang.String", oids.getClass().getName()};
+ try {
+ adaptor = (SnmpMibHandler)(server.invoke(name, "addMib", params,
+ signature));
+ } catch (InstanceNotFoundException e) {
+ throw new InstanceNotFoundException(name.toString());
+ } catch (ReflectionException e) {
+ throw new ServiceNotFoundException(name.toString());
+ } catch (MBeanException e) {
+ // Should never occur...
+ }
+
+ adaptorName = name;
+ }
+
+ /**
+ * Indicates whether or not the MIB module is bound to a SNMP protocol
+ * adaptor.
+ * As a reminder, only bound MIBs can be accessed through SNMP protocol
+ * adaptor.
+ *
+ * @return <CODE>true</CODE> if the MIB module is bound,
+ * <CODE>false</CODE> otherwise.
+ */
+ public boolean getBindingState() {
+ if (adaptor == null)
+ return false;
+ else
+ return true;
+ }
+
+ /**
+ * Gets the MIB name.
+ *
+ * @return The MIB name.
+ */
+ public String getMibName() {
+ return mibName;
+ }
+
+ /**
+ * This is a factory method for creating new SnmpMibRequest objects.
+ * @param reqPdu The received PDU.
+ * @param vblist The vector of SnmpVarBind objects in which the
+ * MIB concerned by this request is involved.
+ * @param version The protocol version of the SNMP request.
+ * @param userData User allocated contextual data.
+ *
+ * @return A new SnmpMibRequest object.
+ *
+ * @since 1.5
+ **/
+ public static SnmpMibRequest newMibRequest(SnmpPdu reqPdu,
+ Vector<SnmpVarBind> vblist,
+ int version,
+ Object userData)
+ {
+ return new SnmpMibRequestImpl(null,
+ reqPdu,
+ vblist,
+ version,
+ userData,
+ null,
+ SnmpDefinitions.noAuthNoPriv,
+ getSecurityModel(version),
+ null,null);
+ }
+ /**
+ * This is a factory method for creating new SnmpMibRequest objects.
+ * @param engine The local engine.
+ * @param reqPdu The received pdu.
+ * @param vblist The vector of SnmpVarBind objects in which the
+ * MIB concerned by this request is involved.
+ * @param version The protocol version of the SNMP request.
+ * @param userData User allocated contextual data.
+ *
+ * @return A new SnmpMibRequest object.
+ *
+ * @since 1.5
+ **/
+ public static SnmpMibRequest newMibRequest(SnmpEngine engine,
+ SnmpPdu reqPdu,
+ Vector<SnmpVarBind> vblist,
+ int version,
+ Object userData,
+ String principal,
+ int securityLevel,
+ int securityModel,
+ byte[] contextName,
+ byte[] accessContextName) {
+ return new SnmpMibRequestImpl(engine,
+ reqPdu,
+ vblist,
+ version,
+ userData,
+ principal,
+ securityLevel,
+ securityModel,
+ contextName,
+ accessContextName);
+ }
+ // ---------------------------------------------------------------------
+ // PACKAGE METHODS
+ // ---------------------------------------------------------------------
+
+ /**
+ * Processes a <CODE>getBulk</CODE> operation using call to
+ * <CODE>getNext</CODE>.
+ * The method implements the <CODE>getBulk</CODE> operation by calling
+ * appropriately the <CODE>getNext</CODE> method.
+ *
+ * @param req The SnmpMibRequest containing the variable list to be
+ * retrieved.
+ *
+ * @param nonRepeat The number of variables, starting with the first
+ * variable in the variable-bindings, for which a single lexicographic
+ * successor is requested.
+ *
+ * @param maxRepeat The number of lexicographic successors
+ * requested for each of the last R variables. R is the number of
+ * variables following the first nonRepeat variables for which
+ * multiple lexicographic successors are requested.
+ *
+ * @return The variable list containing returned values.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ */
+ void getBulkWithGetNext(SnmpMibRequest req, int nonRepeat, int maxRepeat)
+ throws SnmpStatusException {
+ final Vector<SnmpVarBind> list = req.getSubList();
+
+ // RFC 1905, Section 4.2.3, p14
+ final int L = list.size() ;
+ final int N = Math.max(Math.min(nonRepeat, L), 0) ;
+ final int M = Math.max(maxRepeat, 0) ;
+ final int R = L - N ;
+
+ // Let's build the varBindList for the response pdu
+ //
+ // int errorStatus = SnmpDefinitions.snmpRspNoError ;
+ // int errorIndex = 0 ;
+ if (L != 0) {
+
+ // Non-repeaters and first row of repeaters
+ //
+ getNext(req);
+
+ // Now the remaining repeaters
+ //
+ Vector<SnmpVarBind> repeaters= splitFrom(list, N);
+ SnmpMibRequestImpl repeatedReq =
+ new SnmpMibRequestImpl(req.getEngine(),
+ req.getPdu(),
+ repeaters,
+ SnmpDefinitions.snmpVersionTwo,
+ req.getUserData(),
+ req.getPrincipal(),
+ req.getSecurityLevel(),
+ req.getSecurityModel(),
+ req.getContextName(),
+ req.getAccessContextName());
+ for (int i = 2 ; i <= M ; i++) {
+ getNext(repeatedReq);
+ concatVector(req, repeaters);
+ }
+ }
+ }
+
+
+ // ---------------------------------------------------------------------
+ // PRIVATE METHODS
+ // ---------------------------------------------------------------------
+
+ /**
+ * This method creates a new Vector which does not contain the first
+ * element up to the specified limit.
+ *
+ * @param original The original vector.
+ * @param limit The limit.
+ */
+ private Vector<SnmpVarBind> splitFrom(Vector<SnmpVarBind> original, int limit) {
+
+ int max= original.size();
+ Vector<SnmpVarBind> result= new Vector<SnmpVarBind>(max - limit);
+ int i= limit;
+
+ // Ok the loop looks a bit strange. But in order to improve the
+ // perf, we try to avoid reference to the limit variable from
+ // within the loop ...
+ //
+ for(Enumeration<SnmpVarBind> e= original.elements(); e.hasMoreElements(); --i) {
+ SnmpVarBind var= e.nextElement();
+ if (i >0)
+ continue;
+ result.addElement(new SnmpVarBind(var.oid, var.value));
+ }
+ return result;
+ }
+
+ private void concatVector(SnmpMibRequest req, Vector source) {
+ for(Enumeration e= source.elements(); e.hasMoreElements(); ) {
+ SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ // We need to duplicate the SnmpVarBind otherwise it is going
+ // to be overloaded by the next get Next ...
+ req.addVarBind(new SnmpVarBind(var.oid, var.value));
+ }
+ }
+
+ private void concatVector(Vector<SnmpVarBind> target, Vector<SnmpVarBind> source) {
+ for(Enumeration<SnmpVarBind> e= source.elements(); e.hasMoreElements(); ) {
+ SnmpVarBind var= e.nextElement();
+ // We need to duplicate the SnmpVarBind otherwise it is going
+ // to be overloaded by the next get Next ...
+ target.addElement(new SnmpVarBind(var.oid, var.value));
+ }
+ }
+
+ private static int getSecurityModel(int version) {
+ switch(version) {
+ case SnmpDefinitions.snmpVersionOne:
+ return SnmpDefinitions.snmpV1SecurityModel;
+ default:
+ return SnmpDefinitions.snmpV2SecurityModel;
+ }
+ }
+
+ // ---------------------------------------------------------------------
+ // PROTECTED VARIABLES
+ // ---------------------------------------------------------------------
+
+ /**
+ * The object name of the MIB.
+ * @serial
+ */
+ protected String mibName;
+
+ /**
+ * The reference to the MBean server.
+ * @serial
+ */
+ protected MBeanServer server;
+
+ // ---------------------------------------------------------------------
+ // PRIVATE VARIABLES
+ // ---------------------------------------------------------------------
+
+ /**
+ * The object name of the SNMP protocol adaptor.
+ * @serial
+ */
+ private ObjectName adaptorName;
+
+ /**
+ * The reference to the SNMP stack.
+ */
+ private transient SnmpMibHandler adaptor;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibAgentMBean.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibAgentMBean.java
new file mode 100644
index 0000000..315ab02
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibAgentMBean.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package com.sun.jmx.snmp.agent;
+
+
+
+// java imports
+//
+import java.util.Vector;
+
+// jmx imports
+//
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MalformedObjectNameException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ServiceNotFoundException;
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+/**
+ * Exposes the remote management interface of the <CODE>SnmpMibAgent</CODE> MBean.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public interface SnmpMibAgentMBean {
+
+ // PUBLIC METHODS
+ //---------------
+
+ /**
+ * Processes a <CODE>get</CODE> operation.
+ * This method must not be called from remote.
+ *
+ * @param req The SnmpMibRequest object holding the list of variables to
+ * be retrieved. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ * @see SnmpMibAgent#get(SnmpMibRequest)
+ */
+ public void get(SnmpMibRequest req) throws SnmpStatusException;
+
+ /**
+ * Processes a <CODE>getNext</CODE> operation.
+ * This method must not be called from remote.
+ *
+ * @param req The SnmpMibRequest object holding the list of variables to
+ * be retrieved. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ * @see SnmpMibAgent#getNext(SnmpMibRequest)
+ */
+ public void getNext(SnmpMibRequest req) throws SnmpStatusException;
+
+ /**
+ * Processes a <CODE>getBulk</CODE> operation.
+ * This method must not be called from remote.
+ *
+ * @param req The SnmpMibRequest object holding the list of variables to
+ * be retrieved. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @param nonRepeat The number of variables, starting with the first
+ * variable in the variable-bindings, for which a single
+ * lexicographic successor is requested.
+ *
+ * @param maxRepeat The number of lexicographic successors requested
+ * for each of the last R variables. R is the number of variables
+ * following the first <CODE>nonRepeat</CODE> variables for which
+ * multiple lexicographic successors are requested.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ * @see SnmpMibAgent#getBulk(SnmpMibRequest,int,int)
+ */
+ public void getBulk(SnmpMibRequest req, int nonRepeat, int maxRepeat)
+ throws SnmpStatusException;
+
+ /**
+ * Processes a <CODE>set</CODE> operation.
+ * This method must not be called from remote.
+ *
+ * @param req The SnmpMibRequest object holding the list of variables to
+ * be set. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException An error occured during the operation.
+ * @see SnmpMibAgent#set(SnmpMibRequest)
+ */
+ public void set(SnmpMibRequest req) throws SnmpStatusException;
+
+ /**
+ * Checks if a <CODE>set</CODE> operation can be performed.
+ * If the operation cannot be performed, the method should emit a
+ * <CODE>SnmpStatusException</CODE>.
+ *
+ * @param req The SnmpMibRequest object holding the list of variables to
+ * be set. This list is composed of
+ * <CODE>SnmpVarBind</CODE> objects.
+ *
+ * @exception SnmpStatusException The <CODE>set</CODE> operation
+ * cannot be performed.
+ * @see SnmpMibAgent#check(SnmpMibRequest)
+ */
+ public void check(SnmpMibRequest req) throws SnmpStatusException;
+
+ // GETTERS AND SETTERS
+ //--------------------
+
+ /**
+ * Gets the reference to the MBean server in which the SNMP MIB is
+ * registered.
+ *
+ * @return The MBean server or null if the MIB is not registered in any
+ * MBean server.
+ */
+ public MBeanServer getMBeanServer();
+
+ /**
+ * Gets the reference to the SNMP protocol adaptor to which the MIB is
+ * bound.
+ * <BR>This method is used for accessing the SNMP MIB handler property
+ * of the SNMP MIB agent in case of a standalone agent.
+ *
+ * @return The SNMP MIB handler.
+ */
+ public SnmpMibHandler getSnmpAdaptor();
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the
+ * MIB will be SNMP accessible and add this new MIB in the SNMP MIB
+ * handler.
+ * <BR>This method is used for setting the SNMP MIB handler property of
+ * the SNMP MIB agent in case of a standalone agent.
+ *
+ * @param stack The SNMP MIB handler.
+ */
+ public void setSnmpAdaptor(SnmpMibHandler stack);
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler.
+ * This method is to be called to set a specific agent to a specific OID.
+ * This can be useful when dealing with MIB overlapping.
+ * Some OID can be implemented in more than one MIB. In this case, the
+ * OID nearer agent will be used on SNMP operations.
+ * @param stack The SNMP MIB handler.
+ * @param oids The set of OIDs this agent implements.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptor(SnmpMibHandler stack, SnmpOid[] oids);
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler.
+ * Adds a new contextualized MIB in the SNMP MIB handler.
+ *
+ * @param stack The SNMP MIB handler.
+ * @param contextName The MIB context name. If null is passed, will be
+ * registered in the default context.
+ *
+ * @exception IllegalArgumentException If the parameter is null.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptor(SnmpMibHandler stack, String contextName);
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and adds this new MIB in the SNMP MIB handler.
+ * Adds a new contextualized MIB in the SNMP MIB handler.
+ *
+ * @param stack The SNMP MIB handler.
+ * @param contextName The MIB context name. If null is passed, will be
+ * registered in the default context.
+ * @param oids The set of OIDs this agent implements.
+ * @exception IllegalArgumentException If the parameter is null.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptor(SnmpMibHandler stack,
+ String contextName,
+ SnmpOid[] oids);
+
+ /**
+ * Gets the object name of the SNMP protocol adaptor to which the MIB is
+ * bound.
+ *
+ * @return The name of the SNMP protocol adaptor.
+ */
+ public ObjectName getSnmpAdaptorName();
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler
+ * associated to the specified <CODE>name</CODE>.
+ *
+ * @param name The object name of the SNMP MIB handler.
+ *
+ * @exception InstanceNotFoundException The MBean does not exist in the
+ * MBean server.
+ * @exception ServiceNotFoundException This SNMP MIB is not registered
+ * in the MBean server or the requested service is not supported.
+ */
+ public void setSnmpAdaptorName(ObjectName name)
+ throws InstanceNotFoundException, ServiceNotFoundException;
+
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler
+ * associated to the specified <CODE>name</CODE>.
+ * This method is to be called to set a specific agent to a specific OID.
+ * This can be useful when dealing with MIB overlapping.
+ * Some OID can be implemented in more than one MIB. In this case, the
+ * OID nearer agent will be used on SNMP operations.
+ * @param name The name of the SNMP protocol adaptor.
+ * @param oids The set of OIDs this agent implements.
+ * @exception InstanceNotFoundException The SNMP protocol adaptor does
+ * not exist in the MBean server.
+ *
+ * @exception ServiceNotFoundException This SNMP MIB is not registered
+ * in the MBean server or the requested service is not supported.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptorName(ObjectName name, SnmpOid[] oids)
+ throws InstanceNotFoundException, ServiceNotFoundException;
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler
+ * associated to the specified <CODE>name</CODE>.
+ *
+ * @param name The name of the SNMP protocol adaptor.
+ * @param contextName The MIB context name. If null is passed, will be
+ * registered in the default context.
+ * @exception InstanceNotFoundException The SNMP protocol adaptor does
+ * not exist in the MBean server.
+ *
+ * @exception ServiceNotFoundException This SNMP MIB is not registered
+ * in the MBean server or the requested service is not supported.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptorName(ObjectName name, String contextName)
+ throws InstanceNotFoundException, ServiceNotFoundException;
+
+ /**
+ * Sets the reference to the SNMP protocol adaptor through which the MIB
+ * will be SNMP accessible and add this new MIB in the SNMP MIB handler
+ * associated to the specified <CODE>name</CODE>.
+ *
+ * @param name The name of the SNMP protocol adaptor.
+ * @param contextName The MIB context name. If null is passed, will be
+ * registered in the default context.
+ * @param oids The set of OIDs this agent implements.
+ * @exception InstanceNotFoundException The SNMP protocol adaptor does
+ * not exist in the MBean server.
+ *
+ * @exception ServiceNotFoundException This SNMP MIB is not registered
+ * in the MBean server or the requested service is not supported.
+ *
+ * @since 1.5
+ */
+ public void setSnmpAdaptorName(ObjectName name,
+ String contextName,
+ SnmpOid[] oids)
+ throws InstanceNotFoundException, ServiceNotFoundException;
+
+ /**
+ * Indicates whether or not the MIB module is bound to a SNMP protocol
+ * adaptor.
+ * As a reminder, only bound MIBs can be accessed through SNMP protocol
+ * adaptor.
+ *
+ * @return <CODE>true</CODE> if the MIB module is bound,
+ * <CODE>false</CODE> otherwise.
+ */
+ public boolean getBindingState();
+
+ /**
+ * Gets the MIB name.
+ *
+ * @return The MIB name.
+ */
+ public String getMibName();
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibEntry.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibEntry.java
new file mode 100644
index 0000000..2553304
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibEntry.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2000-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+// java imports
+//
+import java.io.Serializable;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpStatusException;
+import com.sun.jmx.snmp.agent.SnmpMibOid;
+import com.sun.jmx.snmp.agent.SnmpMibNode;
+
+/**
+ * Represents a node in an SNMP MIB which corresponds to a table entry
+ * meta node.
+ * <P>
+ * This class is used by the class generated by <CODE>mibgen</CODE>.
+ * You should not need to use this class directly.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public abstract class SnmpMibEntry extends SnmpMibNode
+ implements Serializable {
+
+ /**
+ * Tells whether the given arc identifies a variable (scalar object) in
+ * this entry.
+ *
+ * @param arc An OID arc.
+ *
+ * @return <CODE>true</CODE> if `arc' leads to a variable.
+ */
+ public abstract boolean isVariable(long arc);
+
+ /**
+ * Tells whether the given arc identifies a readable scalar object in
+ * this entry.
+ *
+ * @param arc An OID arc.
+ *
+ * @return <CODE>true</CODE> if `arc' leads to a readable variable.
+ */
+ public abstract boolean isReadable(long arc);
+
+ /**
+ * Get the next OID arc corresponding to a readable scalar variable.
+ *
+ */
+ public long getNextVarId(long id, Object userData)
+ throws SnmpStatusException {
+ long nextvar = super.getNextVarId(id,userData);
+ while (!isReadable(nextvar))
+ nextvar = super.getNextVarId(nextvar,userData);
+ return nextvar;
+ }
+
+ /**
+ * Checks whether the given OID arc identifies a variable (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.
+ *
+ * @exception If the given `arc' does not identify any variable in this
+ * group, throws an SnmpStatusException.
+ */
+ public void validateVarId(long arc, Object userData)
+ throws SnmpStatusException {
+ if (isVariable(arc) == false) throw noSuchNameException;
+ }
+
+ /**
+ * Generic handling of the <CODE>get</CODE> operation.
+ * <p>The actual implementation of this method will be generated
+ * by mibgen. Usually, this implementation only delegates the
+ * job to some other provided runtime class, which knows how to
+ * access the MBean. The current toolkit thus provides two
+ * implementations:
+ * <ul><li>The standard implementation will directly access the
+ * MBean through a java reference,</li>
+ * <li>The generic implementation will access the MBean through
+ * the MBean server.</li>
+ * </ul>
+ * <p>Both implementations rely upon specific - and distinct, set of
+ * mibgen generated methods.
+ * <p> You can override this method if you need to implement some
+ * specific policies for minimizing the accesses made to some remote
+ * underlying resources.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ abstract public void get(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * Generic handling of the <CODE>set</CODE> operation.
+ * <p>The actual implementation of this method will be generated
+ * by mibgen. Usually, this implementation only delegates the
+ * job to some other provided runtime class, which knows how to
+ * access the MBean. The current toolkit thus provides two
+ * implementations:
+ * <ul><li>The standard implementation will directly access the
+ * MBean through a java reference,</li>
+ * <li>The generic implementation will access the MBean through
+ * the MBean server.</li>
+ * </ul>
+ * <p>Both implementations rely upon specific - and distinct, set of
+ * mibgen generated methods.
+ * <p> You can override this method if you need to implement some
+ * specific policies for minimizing the accesses made to some remote
+ * underlying resources.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ abstract public void set(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * Generic handling of the <CODE>check</CODE> operation.
+ *
+ * <p>The actual implementation of this method will be generated
+ * by mibgen. Usually, this implementation only delegates the
+ * job to some other provided runtime class, which knows how to
+ * access the MBean. The current toolkit thus provides two
+ * implementations:
+ * <ul><li>The standard implementation will directly access the
+ * MBean through a java reference,</li>
+ * <li>The generic implementation will access the MBean through
+ * the MBean server.</li>
+ * </ul>
+ * <p>Both implementations rely upon specific - and distinct, set of
+ * mibgen generated methods.
+ * <p> You can override this method if you need to implement some
+ * 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.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ abstract public void check(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibGroup.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibGroup.java
new file mode 100644
index 0000000..bf8ffba
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibGroup.java
@@ -0,0 +1,519 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+// java imports
+//
+import java.io.Serializable;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.Vector;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+// SNMP Runtime imports
+//
+import com.sun.jmx.snmp.agent.SnmpMibOid;
+import com.sun.jmx.snmp.agent.SnmpMibNode;
+
+/**
+ * Represents a node in an SNMP MIB which corresponds to a group.
+ * This class allows subnodes to be registered below a group, providing
+ * support for nested groups. The subnodes are registered at run time
+ * when registering the nested groups in the global MIB OID tree.
+ * <P>
+ * This class is used by the class generated by <CODE>mibgen</CODE>.
+ * You should not need to use this class directly.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public abstract class SnmpMibGroup extends SnmpMibOid
+ implements Serializable {
+
+ // We will register the OID arcs leading to subgroups in this hashtable.
+ // So for each arc in varList, if the arc is also in subgroups, it leads
+ // to a subgroup, if it is not in subgroup, it leads either to a table
+ // or to a variable.
+ protected Hashtable<Long, Long> subgroups = null;
+
+ /**
+ * Tells whether the given arc identifies a table in this group.
+ *
+ * @param arc An OID arc.
+ *
+ * @return <CODE>true</CODE> if `arc' leads to a table.
+ */
+ public abstract boolean isTable(long arc);
+
+ /**
+ * Tells whether the given arc identifies a variable (scalar object) in
+ * this group.
+ *
+ * @param arc An OID arc.
+ *
+ * @return <CODE>true</CODE> if `arc' leads to a variable.
+ */
+ public abstract boolean isVariable(long arc);
+
+ /**
+ * Tells whether the given arc identifies a readable scalar object in
+ * this group.
+ *
+ * @param arc An OID arc.
+ *
+ * @return <CODE>true</CODE> if `arc' leads to a readable variable.
+ */
+ public abstract boolean isReadable(long arc);
+
+
+ /**
+ * Gets the table identified by the given `arc'.
+ *
+ * @param arc An OID arc.
+ *
+ * @return The <CODE>SnmpMibTable</CODE> identified by `arc', or
+ * <CODE>null</CODE> if `arc' does not identify any table.
+ */
+ public abstract SnmpMibTable getTable(long arc);
+
+ /**
+ * Checks whether the given OID arc identifies a variable (scalar
+ * object).
+ *
+ * @exception If the given `arc' does not identify any variable in this
+ * group, throws an SnmpStatusException.
+ */
+ public void validateVarId(long arc, Object userData)
+ throws SnmpStatusException {
+ if (isVariable(arc) == false)
+ throw noSuchObjectException;
+ }
+
+
+ // -------------------------------------------------------------------
+ // We use a hashtable (subgroup) in order to determine whether an
+ // OID arc leads to a subgroup. This implementation can be changed if
+ // needed...
+ // For instance, the subclass could provide a generated isNestedArc()
+ // method in which the subgroup OID arcs would be hardcoded.
+ // However, the generic approach was prefered because at this time
+ // groups and subgroups are dynamically registered in the MIB.
+ //
+ /**
+ * Tell whether the given OID arc identifies a sub-tree
+ * leading to a nested SNMP sub-group. This method is used internally.
+ * You shouldn't need to call it directly.
+ *
+ * @param arc An OID arc.
+ *
+ * @return <CODE>true</CODE> if the given OID arc identifies a subtree
+ * leading to a nested SNMP sub-group.
+ *
+ */
+ public boolean isNestedArc(long arc) {
+ if (subgroups == null) return false;
+ Object obj = subgroups.get(new Long(arc));
+ // if the arc is registered in the hashtable,
+ // it leads to a subgroup.
+ return (obj != null);
+ }
+
+ /**
+ * Generic handling of the <CODE>get</CODE> operation.
+ * <p>The actual implementation of this method will be generated
+ * by mibgen. Usually, this implementation only delegates the
+ * job to some other provided runtime class, which knows how to
+ * access the MBean. The current toolkit thus provides two
+ * implementations:
+ * <ul><li>The standard implementation will directly access the
+ * MBean through a java reference,</li>
+ * <li>The generic implementation will access the MBean through
+ * the MBean server.</li>
+ * </ul>
+ * <p>Both implementations rely upon specific - and distinct, set of
+ * mibgen generated methods.
+ * <p> You can override this method if you need to implement some
+ * specific policies for minimizing the accesses made to some remote
+ * underlying resources.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ abstract public void get(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * Generic handling of the <CODE>set</CODE> operation.
+ * <p>The actual implementation of this method will be generated
+ * by mibgen. Usually, this implementation only delegates the
+ * job to some other provided runtime class, which knows how to
+ * access the MBean. The current toolkit thus provides two
+ * implementations:
+ * <ul><li>The standard implementation will directly access the
+ * MBean through a java reference,</li>
+ * <li>The generic implementation will access the MBean through
+ * the MBean server.</li>
+ * </ul>
+ * <p>Both implementations rely upon specific - and distinct, set of
+ * mibgen generated methods.
+ * <p> You can override this method if you need to implement some
+ * specific policies for minimizing the accesses made to some remote
+ * underlying resources.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ abstract public void set(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * Generic handling of the <CODE>check</CODE> operation.
+ *
+ * <p>The actual implementation of this method will be generated
+ * by mibgen. Usually, this implementation only delegates the
+ * job to some other provided runtime class, which knows how to
+ * access the MBean. The current toolkit thus provides two
+ * implementations:
+ * <ul><li>The standard implementation will directly access the
+ * MBean through a java reference,</li>
+ * <li>The generic implementation will access the MBean through
+ * the MBean server.</li>
+ * </ul>
+ * <p>Both implementations rely upon specific - and distinct, set of
+ * mibgen generated methods.
+ * <p> You can override this method if you need to implement some
+ * 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.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ abstract public void check(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+ // --------------------------------------------------------------------
+ // If we reach this node, we are below the root OID, so we just
+ // return.
+ // --------------------------------------------------------------------
+ public void getRootOid(Vector result) {
+ return;
+ }
+
+ // -------------------------------------------------------------------
+ // PACKAGE METHODS
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // This method can also be overriden in a subclass to provide a
+ // different implementation of the isNestedArc() method.
+ // => if isNestedArc() is hardcoded, then registerSubArc() becomes
+ // useless and can become empty.
+ /**
+ * Register an OID arc that identifies a sub-tree
+ * leading to a nested SNMP sub-group. This method is used internally.
+ * You shouldn't ever call it directly.
+ *
+ * @param arc An OID arc.
+ *
+ */
+ void registerNestedArc(long arc) {
+ Long obj = new Long(arc);
+ if (subgroups == null) subgroups = new Hashtable<Long, Long>();
+ // registers the arc in the hashtable.
+ subgroups.put(obj,obj);
+ }
+
+ // -------------------------------------------------------------------
+ // The SnmpMibOid algorithm relies on the fact that for every arc
+ // registered in varList, there is a corresponding node at the same
+ // position in children.
+ // So the trick is to register a null node in children for each variable
+ // in varList, so that the real subgroup nodes can be inserted at the
+ // correct location.
+ // registerObject() should be called for each scalar object and each
+ // table arc by the generated subclass.
+ /**
+ * Register an OID arc that identifies a scalar object or a table.
+ * This method is used internally. You shouldn't ever call it directly.
+ *
+ * @param arc An OID arc.
+ *
+ */
+ protected void registerObject(long arc)
+ throws IllegalAccessException {
+
+ // this will register the variable in both varList and children
+ // The node registered in children will be null, so that the parent
+ // algorithm will behave as if no node were registered. This is a
+ // trick that makes the parent algorithm behave as if only subgroups
+ // were registered in varList and children.
+ long[] oid = new long[1];
+ oid[0] = arc;
+ super.registerNode(oid,0,null);
+ }
+
+ // -------------------------------------------------------------------
+ // registerNode() will be called at runtime when nested groups are
+ // registered in the MIB. So we do know that this method will only
+ // be called to register nested-groups.
+ // We trap registerNode() in order to call registerSubArc()
+ /**
+ * Register a child node of this node in the OID tree.
+ * This method is used internally. You shouldn't ever call it directly.
+ *
+ * @param oid The oid of the node being registered.
+ * @param cursor The position reached in the oid.
+ * @param node The node being registered.
+ *
+ */
+ void registerNode(long[] oid, int cursor ,SnmpMibNode node)
+ throws IllegalAccessException {
+ super.registerNode(oid,cursor,node);
+ if (cursor < 0) return;
+ if (cursor >= oid.length) return;
+ // if we get here, then it means we are registering a subgroup.
+ // We will thus register the sub arc in the subgroups hashtable.
+ registerNestedArc(oid[cursor]);
+ }
+
+ // -------------------------------------------------------------------
+ // see comments in SnmpMibNode
+ // -------------------------------------------------------------------
+ void findHandlingNode(SnmpVarBind varbind,
+ long[] oid, int depth,
+ SnmpRequestTree handlers)
+ throws SnmpStatusException {
+
+ int length = oid.length;
+ SnmpMibNode node = null;
+
+ if (handlers == null)
+ throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
+
+ final Object data = handlers.getUserData();
+
+ if (depth >= length) {
+ // Nothing is left... the oid is not valid
+ throw new SnmpStatusException(SnmpStatusException.noAccess);
+ }
+
+ long arc = oid[depth];
+
+ if (isNestedArc(arc)) {
+ // This arc leads to a subgroup: delegates the search to the
+ // method defined in SnmpMibOid
+ super.findHandlingNode(varbind,oid,depth,handlers);
+ return;
+ } else if (isTable(arc)) {
+ // This arc leads to a table: forward the search to the table.
+
+ // Gets the table
+ SnmpMibTable table = getTable(arc);
+
+ // Forward the search to the table
+ table.findHandlingNode(varbind,oid,depth+1,handlers);
+
+ } else {
+ // If it's not a variable, throws an exception
+ validateVarId(arc, data);
+
+ // The trailing .0 is missing in the OID
+ if (depth+2 > length)
+ throw noSuchInstanceException;
+
+ // There are too many arcs left in the OID (there should remain
+ // a single trailing .0)
+ if (depth+2 < length)
+ throw noSuchInstanceException;
+
+ // The last trailing arc is not .0
+ if (oid[depth+1] != 0L)
+ throw noSuchInstanceException;
+
+ // It's one of our variable, register this node.
+ handlers.add(this,depth,varbind);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // See comments in SnmpMibNode.
+ // -------------------------------------------------------------------
+ long[] findNextHandlingNode(SnmpVarBind varbind,
+ long[] oid, int pos, int depth,
+ SnmpRequestTree handlers, AcmChecker checker)
+ throws SnmpStatusException {
+
+ int length = oid.length;
+ SnmpMibNode node = null;
+
+ 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 noSuchObjectException;
+
+ final Object data = handlers.getUserData();
+ final int pduVersion = handlers.getRequestPduVersion();
+
+
+ // The generic case where the end of the OID has been reached is
+ // handled in the superclass
+ // XXX Revisit: this works but it is somewhat convoluted. Just setting
+ // arc to -1 would work too.
+ if (pos >= length)
+ return super.findNextHandlingNode(varbind,oid,pos,depth,
+ handlers, checker);
+
+ // Ok, we've got the arc.
+ long arc = oid[pos];
+
+ long[] result = null;
+
+ // We have a recursive logic. Should we have a loop instead?
+ try {
+
+ if (isTable(arc)) {
+ // If the arc identifies a table, then we need to forward
+ // the search to the table.
+
+ // Gets the table identified by `arc'
+ SnmpMibTable table = getTable(arc);
+
+ // Forward to the table
+ checker.add(depth, arc);
+ try {
+ result = table.findNextHandlingNode(varbind,oid,pos+1,
+ depth+1,handlers,
+ checker);
+ }catch(SnmpStatusException ex) {
+ throw noSuchObjectException;
+ } finally {
+ checker.remove(depth);
+ }
+ // Build up the leaf OID
+ result[depth] = arc;
+ return result;
+ } else if (isReadable(arc)) {
+ // If the arc identifies a readable variable, then two cases:
+
+ if (pos == (length - 1)) {
+ // The end of the OID is reached, so we return the leaf
+ // corresponding to the variable identified by `arc'
+
+ // Build up the OID
+ // result = new SnmpOid(0);
+ // result.insert((int)arc);
+ result = new long[depth+2];
+ result[depth+1] = 0L;
+ result[depth] = arc;
+
+ checker.add(depth, result, depth, 2);
+ try {
+ checker.checkCurrentOid();
+ } catch(SnmpStatusException e) {
+ throw noSuchObjectException;
+ } finally {
+ checker.remove(depth,2);
+ }
+
+ // Registers this node
+ handlers.add(this,depth,varbind);
+ return result;
+ }
+
+ // The end of the OID is not yet reached, so we must return
+ // the next leaf following the variable identified by `arc'.
+ // We cannot return the variable because whatever follows in
+ // the OID will be greater or equals to 0, and 0 identifies
+ // the variable itself - so we have indeed to return the
+ // next object.
+ // So we do nothing, because this case is handled at the
+ // end of the if ... else if ... else ... block.
+
+ } else if (isNestedArc(arc)) {
+ // Now if the arc leads to a subgroup, we delegate the
+ // search to the child, just as done in SnmpMibNode.
+ //
+
+ // get the child ( = nested arc node).
+ //
+ final SnmpMibNode child = getChild(arc);
+
+ if (child != null) {
+ checker.add(depth, arc);
+ try {
+ result = child.findNextHandlingNode(varbind,oid,pos+1,
+ depth+1,handlers,
+ checker);
+ result[depth] = arc;
+ return result;
+ } finally {
+ checker.remove(depth);
+ }
+ }
+ }
+
+ // The oid is not valid, we will throw an exception in order
+ // to try with the next valid identifier...
+ //
+ throw noSuchObjectException;
+
+ } catch (SnmpStatusException e) {
+ // We didn't find anything at the given arc, so we're going
+ // to try with the next valid arc
+ //
+ long[] newOid = new long[1];
+ newOid[0] = getNextVarId(arc,data,pduVersion);
+ return findNextHandlingNode(varbind,newOid,0,depth,
+ handlers,checker);
+ }
+ }
+
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibHandler.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibHandler.java
new file mode 100644
index 0000000..a6cf258
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibHandler.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 1998-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package com.sun.jmx.snmp.agent;
+
+
+
+// java imports
+//
+import java.util.Vector;
+import java.io.IOException;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+/**
+ * The logical link between an SNMP MIB and the SNMP communication stack.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public interface SnmpMibHandler {
+
+ /**
+ * Adds a new MIB in the SNMP MIB handler.
+ * This method is called automatically by {@link com.sun.jmx.snmp.agent.SnmpMibAgent#setSnmpAdaptor(SnmpMibHandler)} and
+ * {@link com.sun.jmx.snmp.agent.SnmpMibAgent#setSnmpAdaptorName(ObjectName)} and should not be called directly.
+ *
+ * @param mib The MIB to add.
+ *
+ * @return A reference on the SNMP MIB handler.
+ *
+ * @exception IllegalArgumentException If the parameter is null.
+ */
+ public SnmpMibHandler addMib(SnmpMibAgent mib) throws IllegalArgumentException;
+
+/**
+ * Adds a new MIB in the SNMP MIB handler.
+ *
+ * @param mib The MIB to add.
+ * @param oids The array of oid used to add the mib. Each oid is a root oid for the mib.
+ * @return A reference on the SNMP MIB handler.
+ *
+ * @exception IllegalArgumentException If the parameter is null.
+ *
+ * @since 1.5
+ */
+ public SnmpMibHandler addMib(SnmpMibAgent mib, SnmpOid[] oids) throws IllegalArgumentException;
+
+ /**
+ * Adds a new contextualized MIB in the SNMP MIB handler.
+ *
+ * @param mib The MIB to add.
+ * @param contextName The MIB context name. If null is passed, will be registered in the default context.
+ *
+ * @return A reference to the SNMP MIB handler.
+ *
+ * @exception IllegalArgumentException If the parameter is null.
+ *
+ * @since 1.5
+ */
+ public SnmpMibHandler addMib(SnmpMibAgent mib, String contextName)
+ throws IllegalArgumentException;
+
+ /**
+ * Adds a new contextualized MIB in the SNMP MIB handler.
+ *
+ * @param mib The MIB to add.
+ * @param contextName The MIB context name. If null is passed, will be registered in the default context.
+ * @param oids The array of oid used to add the mib. Each oid is a root oid for the mib.
+ *
+ * @return A reference to the SNMP MIB handler.
+ *
+ * @exception IllegalArgumentException If the parameter is null.
+ *
+ * @since 1.5
+ */
+ public SnmpMibHandler addMib(SnmpMibAgent mib, String contextName, SnmpOid[] oids)
+ throws IllegalArgumentException;
+
+ /**
+ * Removes the specified MIB from the SNMP protocol adaptor.
+ * This method is called automatically by {@link com.sun.jmx.snmp.agent.SnmpMibAgent#setSnmpAdaptor(SnmpMibHandler)} and
+ * {@link com.sun.jmx.snmp.agent.SnmpMibAgent#setSnmpAdaptorName(ObjectName)} and should not be called directly.
+ *
+ * @param mib The MIB to be removed.
+ *
+ * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was a MIB included in the SNMP MIB handler,
+ * <CODE>false</CODE> otherwise.
+ */
+ public boolean removeMib(SnmpMibAgent mib);
+ /**
+ * Removes the specified MIB from the SNMP protocol adaptor.
+ * This method is called automatically by {@link com.sun.jmx.snmp.agent.SnmpMibAgent#setSnmpAdaptor(SnmpMibHandler)} and
+ * {@link com.sun.jmx.snmp.agent.SnmpMibAgent#setSnmpAdaptorName(ObjectName)} and should not be called directly.
+ *
+ * @param mib The MIB to be removed.
+ * @param oids The oid the MIB was previously registered for.
+ * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was a MIB included in the SNMP MIB handler,
+ * <CODE>false</CODE> otherwise.
+ *
+ * @since 1.5
+ */
+ public boolean removeMib(SnmpMibAgent mib, SnmpOid[] oids);
+ /**
+ * Removes the specified MIB from the SNMP protocol adaptor.
+ *
+ * @param mib The MIB to be removed.
+ * @param contextName The context name used at registration time.
+ *
+ * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was a MIB included in the SNMP MIB handler,
+ * <CODE>false</CODE> otherwise.
+ *
+ * @since 1.5
+ */
+ public boolean removeMib(SnmpMibAgent mib, String contextName);
+ /**
+ * Removes the specified MIB from the SNMP protocol adaptor.
+ *
+ * @param mib The MIB to be removed.
+ * @param contextName The context name used at registration time.
+ * @param oids The oid the MIB was previously registered for.
+ * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was a MIB included in the SNMP MIB handler,
+ * <CODE>false</CODE> otherwise.
+ *
+ * @since 1.5
+ */
+ public boolean removeMib(SnmpMibAgent mib, String contextName, SnmpOid[] oids);
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibNode.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibNode.java
new file mode 100644
index 0000000..52b952e
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibNode.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package com.sun.jmx.snmp.agent;
+
+
+
+// java imports
+//
+import java.io.Serializable;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpDefinitions;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+/**
+ * The <CODE>SnmpMibNode</CODE> class represents a node in an SNMP MIB.
+ * <P>
+ * This class is used internally and by the class generated by
+ * <CODE>mibgen</CODE>.
+ * You should not need to use this class directly.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public abstract class SnmpMibNode implements Serializable {
+
+ // ---------------------------------------------------------------------
+ // PUBLIC METHODS
+ //----------------------------------------------------------------------
+
+ /**
+ * Get the next OID arc corresponding to a readable scalar variable,
+ * a branch leading to a subgroub, or a table.
+ *
+ * @param id Id 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 id in this group.
+ *
+ * @exception SnmpStatusException If no id is found after the given id.
+ */
+ public long getNextVarId(long id, Object userData)
+ throws SnmpStatusException {
+ return getNextIdentifier(varList,id);
+ }
+
+ /**
+ * Get the next OID arc corresponding to a readable scalar variable,
+ * a branch leading to a subgroub, or a table, possibly skipping over
+ * those arcs that must not or cannot be returned.
+ *
+ * Calls {@link #getNextVarId(long,java.lang.Object)} until
+ * {@link #skipVariable(long,java.lang.Object,int)} returns false.
+ *
+ * @param id Id 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 id in this group which can be returned using
+ * the given PDU's protocol version.
+ *
+ * @exception SnmpStatusException If no id is found after the given id.
+ */
+ public long getNextVarId(long id, Object userData, int pduVersion)
+ throws SnmpStatusException {
+ long varid=id;
+ do {
+ varid = getNextVarId(varid,userData);
+ } while (skipVariable(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><li>the variable is a leaf that is not instantiated,</li>
+ * <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 id Id 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 skipVariable(long id, Object userData, int pduVersion) {
+ return false;
+ }
+
+ /**
+ * Find the node which handles a varbind, and register it in the
+ * SnmpRequestTree. This method is a pure internal method. You should
+ * never try to call it directly.
+ *
+ * @param varbind The varbind to be handled
+ *
+ * @param oid The OID array extracted from the varbind
+ *
+ * @param depth The depth reached in the OID at this step of the
+ * processing.
+ *
+ * @param handlers The Hashtable in which the varbind will be registered
+ * with its handling node. This hashtable contains
+ * <CODE>SnmpRequestTree.Handler</CODE> items.
+ *
+ * @exception SnmpStatusException No handling node was found.
+ **/
+ void findHandlingNode(SnmpVarBind varbind,
+ long[] oid, int depth,
+ SnmpRequestTree handlers)
+ throws SnmpStatusException {
+ throw noSuchObjectException;
+ }
+
+ /**
+ * Find the node which handles the leaf that immediately follows the
+ * given varbind OID, and register the it in the SnmpRequestTree.
+ * This method is a pure internal method. You should never try to call
+ * it directly.
+ *
+ * @param varbind The varbind to be handled
+ *
+ * @param oid The OID array extracted from the varbind
+ *
+ * @param depth The depth reached in the OID at this step of the
+ * processing.
+ *
+ * @param handlers The Hashtable in which the varbind will be registered
+ * with its handling node. This hashtable contains
+ * SnmpRequestTree.Handler items.
+ *
+ * @return The SnmpOid of the next leaf.
+ *
+ * @exception SnmpStatusException No handling node was found.
+ **/
+ long[] findNextHandlingNode(SnmpVarBind varbind,
+ long[] oid, int pos, int depth,
+ SnmpRequestTree handlers, AcmChecker checker)
+ throws SnmpStatusException {
+ throw noSuchObjectException;
+ }
+
+ /**
+ * Generic handling of the <CODE>get</CODE> operation.
+ *
+ * <p> You can override this method if you need to implement some
+ * specific policies for minimizing the accesses made to some remote
+ * underlying resources.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ public abstract void get(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * Generic handling of the <CODE>set</CODE> operation.
+ * <p> You can override this method if you need to implement some
+ * specific policies for minimizing the accesses made to some remote
+ * underlying resources.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ public abstract void set(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * Generic handling of the <CODE>check</CODE> operation.
+ * <p> You can override this method if you need to implement some
+ * 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.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ public abstract void check(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * Sorts the specified integer array.
+ *
+ * @param array An integer array.
+ */
+ static public void sort(int array[]) {
+ QuickSort(array, 0, array.length - 1);
+ }
+
+ /**
+ * Computes the root OID of the MIB.
+ */
+ public void getRootOid(Vector<Integer> result) {
+ return;
+ }
+
+ //----------------------------------------------------------------------
+ // PACKAGE METHODS
+ //----------------------------------------------------------------------
+
+ /**
+ * This is a generic version of C.A.R Hoare's Quick Sort
+ * algorithm. This will handle arrays that are already
+ * sorted, and arrays with duplicate keys.
+ *
+ * If you think of a one dimensional array as going from
+ * the lowest index on the left to the highest index on the right
+ * then the parameters to this function are lowest index or
+ * left and highest index or right. The first time you call
+ * this function it will be with the parameters 0, a.length - 1.
+ *
+ * @param a An integer array.
+ * @param lo0 Left boundary of array partition.
+ * @param hi0 Right boundary of array partition.
+ */
+ static void QuickSort(int a[], int lo0, int hi0) {
+ int lo = lo0;
+ int hi = hi0;
+ int mid;
+
+ if ( hi0 > lo0) {
+
+ /* Arbitrarily establishing partition element as the midpoint of
+ * the array.
+ */
+ mid = a[ ( lo0 + hi0 ) / 2 ];
+
+ // loop through the array until indices cross
+ while( lo <= hi ) {
+ /* find the first element that is greater than or equal to
+ * the partition element starting from the left Index.
+ */
+ while( ( lo < hi0 ) && ( a[lo] < mid ))
+ ++lo;
+
+ /* find an element that is smaller than or equal to
+ * the partition element starting from the right Index.
+ */
+ while( ( hi > lo0 ) && ( a[hi] > mid ))
+ --hi;
+
+ // if the indexes have not crossed, swap
+ if( lo <= hi ) {
+ swap(a, lo, hi);
+ ++lo;
+ --hi;
+ }
+ }
+
+ /* If the right index has not reached the left side of array
+ * must now sort the left partition.
+ */
+ if( lo0 < hi )
+ QuickSort( a, lo0, hi );
+
+ /* If the left index has not reached the right side of array
+ * must now sort the right partition.
+ */
+ if( lo < hi0 )
+ QuickSort( a, lo, hi0 );
+
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // PROTECTED METHODS
+ //----------------------------------------------------------------------
+
+ /**
+ * This will give the first element greater than <CODE>value</CODE>
+ * in a sorted array.
+ * If there is no element of the array greater than <CODE>value</CODE>,
+ * the method will throw a <CODE>SnmpStatusException</CODE>.
+ *
+ * @param table A sorted integer array.
+ *
+ * @param value The greatest value.
+ *
+ * @exception SnmpStatusException If there is no element greater than
+ * <CODE>value</CODE>.
+ */
+ final static protected int getNextIdentifier(int table[], long value)
+ throws SnmpStatusException {
+
+ final int[] a = table;
+ final int val= (int) value;
+
+ if (a == null)
+ throw noSuchObjectException;
+
+ int low= 0;
+ int max= a.length;
+ int curr= low + (max-low)/2;
+ int elmt= 0;
+
+ // Basic check
+ //
+ if (max < 1)
+ throw noSuchObjectException;
+
+ if (a[max-1] <= val)
+ throw noSuchObjectException;
+
+ while (low <= max) {
+ elmt= a[curr];
+ if (val == elmt) {
+ // We ned to get the next index ...
+ //
+ curr++;
+ return a[curr];
+ }
+ if (elmt < val) {
+ low= curr +1;
+ } else {
+ max= curr -1;
+ }
+ curr= low + (max-low)/2;
+ }
+ return a[curr];
+ }
+
+
+ //----------------------------------------------------------------------
+ // PRIVATE METHODS
+ //----------------------------------------------------------------------
+
+ final static private void swap(int a[], int i, int j) {
+ int T;
+ T = a[i];
+ a[i] = a[j];
+ a[j] = T;
+ }
+
+ //----------------------------------------------------------------------
+ // PROTECTED VARIABLES
+ //----------------------------------------------------------------------
+
+ /**
+ * Contains the list of variable identifiers.
+ */
+ protected int[] varList;
+
+ /**
+ * Contains a predefined exception that is often fired when an
+ * object is not found in the MIB.
+ */
+ static final protected SnmpStatusException noSuchInstanceException =
+ new SnmpStatusException(SnmpStatusException.noSuchInstance);
+ static final protected SnmpStatusException noSuchObjectException =
+ new SnmpStatusException(SnmpStatusException.noSuchObject);
+ static final protected SnmpStatusException noSuchNameException =
+ new SnmpStatusException(SnmpDefinitions.snmpRspNoSuchName);
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibOid.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibOid.java
new file mode 100644
index 0000000..d86389b
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibOid.java
@@ -0,0 +1,561 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package com.sun.jmx.snmp.agent;
+
+
+
+// java imports
+//
+import java.io.Serializable;
+import java.util.Vector;
+import java.util.Enumeration;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+/**
+ * Represents a node in an SNMP MIB which is neither a group nor a variable.
+ * This class defines a list of sub-nodes and the methods that allow to
+ * manipulate the sub-nodes.
+ * <P>
+ * This class is used internally and by the class generated by
+ * <CODE>mibgen</CODE>.
+ * You should not need to use this class directly.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public class SnmpMibOid extends SnmpMibNode implements Serializable {
+ private static final long serialVersionUID = 5012254771107446812L;
+
+ /**
+ * Default constructor.
+ */
+ public SnmpMibOid() {
+ }
+
+ // PUBLIC METHODS
+ //---------------
+
+ /**
+ * Generic handling of the <CODE>get</CODE> operation.
+ *
+ * <p> This method should be overridden in subclasses.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException The default implementation (if not
+ * overridden) is to generate a SnmpStatusException.
+ */
+ public void get(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException {
+ for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ SnmpStatusException x =
+ new SnmpStatusException(SnmpStatusException.noSuchObject);
+ req.registerGetException(var,x);
+ }
+ }
+
+ /**
+ * Generic handling of the <CODE>set</CODE> operation.
+ *
+ * <p> This method should be overridden in subclasses.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException The default implementation (if not
+ * overridden) is to generate a SnmpStatusException.
+ */
+ public void set(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException {
+ for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ SnmpStatusException x =
+ new SnmpStatusException(SnmpStatusException.noAccess);
+ req.registerSetException(var,x);
+ }
+ }
+
+ /**
+ * Generic handling of the <CODE>check</CODE> operation.
+ *
+ * <p> This method should be overridden in subclasses.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException The default implementation (if not
+ * overriden) is to generate a SnmpStatusException.
+ */
+ public void check(SnmpMibSubRequest req, int depth)
+ throws SnmpStatusException {
+ for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ SnmpStatusException x =
+ new SnmpStatusException(SnmpStatusException.noAccess);
+ req.registerCheckException(var,x);
+ }
+ }
+
+
+
+ // ---------------------------------------------------------------------
+ //
+ // Implements the method defined in SnmpMibNode.
+ //
+ // ---------------------------------------------------------------------
+ //
+ void findHandlingNode(SnmpVarBind varbind,
+ long[] oid, int depth,
+ SnmpRequestTree handlers)
+ throws SnmpStatusException {
+
+
+ final int length = oid.length;
+ SnmpMibNode node = null;
+
+ if (handlers == null)
+ throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
+
+ if (depth > length) {
+ // Nothing is left... the oid is not valid
+ throw noSuchObjectException;
+
+ } else if (depth == length) {
+ // The oid is not complete...
+ throw noSuchInstanceException;
+
+ } else {
+ // Some children variable or subobject is being querried
+ // getChild() will raise an exception if no child is found.
+ //
+ final SnmpMibNode child= getChild(oid[depth]);
+
+ // XXXX zzzz : what about null children?
+ // (variables for nested groups)
+ // if child==null, then we're dealing with a variable or
+ // a table: we register this node.
+ // This behaviour should be overriden in subclasses,
+ // in particular in group meta classes: the group
+ // meta classes that hold tables should take care
+ // of forwarding this call to all the tables involved.
+ //
+ if (child == null)
+ handlers.add(this,depth,varbind);
+ else
+ child.findHandlingNode(varbind,oid,depth+1,handlers);
+ }
+ }
+
+ // ---------------------------------------------------------------------
+ //
+ // Implements the method defined in SnmpMibNode.
+ //
+ // ---------------------------------------------------------------------
+ //
+ long[] findNextHandlingNode(SnmpVarBind varbind,
+ long[] oid, int pos, int depth,
+ SnmpRequestTree handlers,
+ AcmChecker checker)
+ throws SnmpStatusException {
+
+
+ final int length = oid.length;
+ SnmpMibNode node = null;
+ long[] result = null;
+ 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 noSuchObjectException;
+
+ final Object data = handlers.getUserData();
+ final int pduVersion = handlers.getRequestPduVersion();
+
+ if (pos >= length) {
+ long[] newOid= new long[1];
+ newOid[0]= getNextVarId(-1,data,pduVersion);
+ result = findNextHandlingNode(varbind,newOid,0,depth,handlers,
+ checker);
+ return result;
+ }
+
+ // search the element specified in the oid
+ //
+ long[] newOid= new long[1];
+ long index= oid[pos];
+
+ while (true) {
+
+ try {
+ final SnmpMibNode child = getChild(index);
+ // SnmpOid result = null;
+ if (child == null) {
+ // shouldn't happen
+ throw noSuchObjectException;
+ // validateVarId(index);
+ // handlers.add(this,varbind,depth);
+ // result = new SnmpOid(0);
+ } else {
+ checker.add(depth, index);
+ try {
+ result = child.findNextHandlingNode(varbind,oid,pos+1,
+ depth+1,handlers,
+ checker);
+ } finally {
+ checker.remove(depth);
+ }
+ }
+
+ // Build up the leaf OID
+ result[depth] = index;
+ return result;
+
+ } catch(SnmpStatusException e) {
+ // If there is no such element go one level up ...
+ //
+ index= getNextVarId(index,data,pduVersion);
+
+ // There is no need to carry the original oid ...
+ newOid[0]=index;
+ pos= 1;
+ oid=newOid;
+ }
+ }
+ }
+
+
+ /**
+ * Computes the root OID of the MIB.
+ */
+ public void getRootOid(Vector<Integer> result) {
+
+ // If a node has several children, let assume that we are one step to
+ // far in order to get the MIB root.
+ //
+ if (nbChildren != 1)
+ return;
+
+ result.addElement(varList[0]);
+
+ // Now query our child.
+ //
+ children.firstElement().getRootOid(result);
+
+ }
+
+ /**
+ * Registers a specific node in the tree.
+ */
+ public void registerNode(String oidString ,SnmpMibNode node)
+ throws IllegalAccessException {
+ SnmpOid oid= new SnmpOid(oidString);
+ registerNode(oid.longValue(), 0, node);
+ }
+
+ // PROTECTED METHODS
+ //------------------
+
+ /**
+ * Registers a specific node in the tree.
+ */
+ void registerNode(long[] oid, int cursor ,SnmpMibNode node)
+ throws IllegalAccessException {
+
+ if (cursor >= oid.length)
+ throw new IllegalAccessException();
+
+ // Check if the node is already defined
+ //
+ long var= oid[cursor];
+
+ //System.out.println("entering registration for val="
+ // + String.valueOf(var) + " position= " + cursor);
+
+ int pos = retrieveIndex(var);
+ if (pos == nbChildren) {
+ nbChildren++;
+ varList= new int[nbChildren];
+ varList[0]= (int) var;
+ pos =0;
+ if ( (cursor + 1) == oid.length) {
+ // That 's the end of the trip.
+ // Do not forward the registration
+
+ //System.out.println("End of trip for val="
+ // + String.valueOf(var) + " position= " + cursor);
+ children.insertElementAt(node,pos);
+ return;
+ }
+
+ //System.out.println("Create node for val="
+ // + String.valueOf(var) + " position= " + cursor);
+ SnmpMibOid child= new SnmpMibOid();
+ children.insertElementAt(child, pos);
+ child.registerNode(oid, cursor + 1, node);
+ return;
+ }
+ if (pos == -1) {
+ // The node is not yet registered
+ //
+ int[] tmp= new int[nbChildren + 1];
+ tmp[nbChildren]= (int) var;
+ System.arraycopy(varList, 0, tmp, 0, nbChildren);
+ varList= tmp;
+ nbChildren++;
+ SnmpMibNode.sort(varList);
+ int newPos = retrieveIndex(var);
+ varList[newPos]= (int) var;
+ if ( (cursor + 1) == oid.length) {
+ // That 's the end of the trip.
+ // Do not forward the registration
+
+ //System.out.println("End of trip for val="
+ // + String.valueOf(var) + " position= " + cursor);
+ children.insertElementAt(node, newPos);
+ return;
+ }
+ SnmpMibOid child= new SnmpMibOid();
+ // System.out.println("Create node for val=" +
+ // String.valueOf(var) + " position= " + cursor);
+ children.insertElementAt(child, newPos);
+ child.registerNode(oid, cursor + 1, node);
+ return;
+ }
+ else {
+ // The node is already registered
+ //
+ SnmpMibNode child= children.elementAt(pos);
+ if ( (cursor + 1) == oid.length ) {
+ //System.out.println("Node already registered val=" +
+ // String.valueOf(var) + " position= " + cursor);
+ if (child == node) return;
+ if (child != null && node != null) {
+ // Now we're going to patch the tree the following way:
+ // if a subgroup has been registered before its father,
+ // we're going to replace the father OID node with
+ // the actual group-node and export the children from
+ // the temporary OID node to the actual group node.
+ //
+
+ if (node instanceof SnmpMibGroup) {
+ // `node' is a group => replace `child' with `node'
+ // export the child's subtree to `node'.
+ //
+ ((SnmpMibOid)child).exportChildren((SnmpMibOid)node);
+ children.setElementAt(node,pos);
+ return;
+
+ } else if ((node instanceof SnmpMibOid) &&
+ (child instanceof SnmpMibGroup)) {
+ // `node' is a temporary node, and `child' is a
+ // group => keep child and export the node's
+ // subtree to `child'.
+ //
+ ((SnmpMibOid)node).exportChildren((SnmpMibOid)child);
+ return;
+ } else if (node instanceof SnmpMibOid) {
+ // `node' and `child' are both temporary OID nodes
+ // => replace `child' with `node' and export child's
+ // subtree to `node'.
+ //
+ ((SnmpMibOid)child).exportChildren((SnmpMibOid)node);
+ children.setElementAt(node,pos);
+ return;
+ }
+ }
+ children.setElementAt(node,pos);
+ return;
+ } else {
+ if (child == null)
+ throw new IllegalAccessException();
+ ((SnmpMibOid)child).registerNode(oid, cursor + 1, node);
+ }
+ }
+ }
+
+ /**
+ * Export this node's children to a brother node that will replace
+ * this node in the OID tree.
+ * This method is a patch that fixes the problem of registering
+ * a subnode before its father node.
+ *
+ **/
+ void exportChildren(SnmpMibOid brother)
+ throws IllegalAccessException {
+
+ if (brother == null) return;
+ final long[] oid = new long[1];
+ for (int i=0; i<nbChildren; i++) {
+ final SnmpMibNode child = children.elementAt(i);
+ if (child == null) continue;
+ oid[0] = varList[i];
+ brother.registerNode(oid,0,child);
+ }
+ }
+
+ // PRIVATE METHODS
+ //----------------
+
+ SnmpMibNode getChild(long id) throws SnmpStatusException {
+
+ // first we need to retrieve the identifier in the list of children
+ //
+ final int pos= getInsertAt(id);
+ if (pos >= nbChildren)
+ throw noSuchObjectException;
+
+ if (varList[pos] != (int) id)
+ throw noSuchObjectException;
+
+ // Access the node
+ //
+ SnmpMibNode child = null;
+ try {
+ child = children.elementAtNonSync(pos);
+ } catch(ArrayIndexOutOfBoundsException e) {
+ throw noSuchObjectException;
+ }
+ if (child == null)
+ throw noSuchInstanceException;
+ return child;
+ }
+
+ private int retrieveIndex(long val) {
+
+ int low= 0;
+ int cursor= (int) val;
+ if (varList == null || varList.length < 1)
+ return nbChildren;
+
+ int max= varList.length -1 ;
+ int curr= low + (max-low)/2;
+ int elmt= 0;
+ while (low <= max) {
+ elmt= varList[curr];
+ if (cursor == elmt) {
+ // We need to get the next index ...
+ //
+ return curr;
+ }
+ if (elmt < cursor) {
+ low= curr +1;
+ } else {
+ max= curr -1;
+ }
+ curr= low + (max-low)/2;
+ }
+ return -1;
+ }
+
+ private int getInsertAt(long val) {
+
+ int low= 0;
+ final int index= (int) val;
+ if (varList == null)
+ return -1;
+ int max= varList.length -1 ;
+ int elmt=0;
+ //final int[] v = varList;
+
+ //if (index > a[max])
+ //return max +1;
+
+
+ int curr= low + (max-low)/2;
+ while (low <= max) {
+
+ elmt= varList[curr];
+
+ // never know ...we might find something ...
+ //
+ if (index == elmt)
+ return curr;
+
+ if (elmt < index) {
+ low= curr +1;
+ } else {
+ max= curr -1;
+ }
+ curr= low + (max-low)/2;
+ }
+
+ return curr;
+ }
+
+ // PRIVATE VARIABLES
+ //------------------
+
+ /**
+ * Contains the list of sub nodes.
+ */
+ private NonSyncVector<SnmpMibNode> children = new NonSyncVector<SnmpMibNode>(1);
+
+ /**
+ * The number of sub nodes.
+ */
+ private int nbChildren= 0;
+
+
+ // All the methods of the Vector class are synchronized.
+ // Synchronization is a very expensive operation. In our case it is
+ // not always required...
+ //
+ @SuppressWarnings("serial") // We will never serialize this
+ class NonSyncVector<E> extends Vector<E> {
+
+ public NonSyncVector(int size) {
+ super(size);
+ }
+
+ final void addNonSyncElement(E obj) {
+ ensureCapacity(elementCount + 1);
+ elementData[elementCount++] = obj;
+ }
+
+ @SuppressWarnings("unchecked") // cast to E
+ final E elementAtNonSync(int index) {
+ return (E) elementData[index];
+ }
+
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibRequest.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibRequest.java
new file mode 100644
index 0000000..1b504ab
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibRequest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.jmx.snmp.agent;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpPdu;
+import com.sun.jmx.snmp.SnmpEngine;
+
+/**
+ * This interface models the part of a SNMP request that involves
+ * a specific MIB. One object implementing this interface will be created
+ * for every MIB involved in a SNMP request, and that object will be passed
+ * to the SnmpMibAgent in charge of handling that MIB.
+ *
+ * Objects implementing this interface will be allocated by the SNMP engine.
+ * You will never need to implement this interface. You will only use it.
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+public interface SnmpMibRequest {
+ /**
+ * Returns the list of varbind to be handled by the SNMP mib node.
+ *
+ * @return The element of the enumeration are instances of
+ * {@link com.sun.jmx.snmp.SnmpVarBind}
+ */
+ public Enumeration getElements();
+
+ /**
+ * Returns the vector of varbind to be handled by the SNMP mib node.
+ * The caller shall not modify this vector.
+ *
+ * @return The element of the vector are instances of
+ * {@link com.sun.jmx.snmp.SnmpVarBind}
+ */
+ public Vector<SnmpVarBind> getSubList();
+
+ /**
+ * Returns the SNMP protocol version of the original request. If SNMP V1 request are received, the version is upgraded to SNMP V2.
+ *
+ * @return The SNMP protocol version of the original request.
+ */
+ public int getVersion();
+
+ /**
+ * Returns the SNMP protocol version of the original request. No translation is done on the version. The actual received request SNMP version is returned.
+ *
+ * @return The SNMP protocol version of the original request.
+ *
+ * @since 1.5
+ */
+ public int getRequestPduVersion();
+
+ /**
+ * Returns the local engine. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise null is returned.
+ * @return the local engine.
+ *
+ * @since 1.5
+ */
+ public SnmpEngine getEngine();
+ /**
+ * Gets the incoming request principal. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise null is returned.
+ * @return The request principal.
+ *
+ * @since 1.5
+ **/
+ public String getPrincipal();
+ /**
+ * Gets the incoming request security level. This level is defined in {@link com.sun.jmx.snmp.SnmpEngine SnmpEngine}. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise -1 is returned.
+ * @return The security level.
+ *
+ * @since 1.5
+ */
+ public int getSecurityLevel();
+ /**
+ * Gets the incoming request security model. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise -1 is returned.
+ * @return The security model.
+ *
+ * @since 1.5
+ */
+ public int getSecurityModel();
+ /**
+ * Gets the incoming request context name. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise null is returned.
+ * @return The context name.
+ *
+ * @since 1.5
+ */
+ public byte[] getContextName();
+ /**
+ * Gets the incoming request context name used by Access Control Model in order to allow or deny the access to OIDs. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise null is returned.
+ * @return The checked context name.
+ *
+ * @since 1.5
+ */
+ public byte[] getAccessContextName();
+
+ /**
+ * Returns a handle on a user allocated contextual object.
+ * This contextual object is allocated through the SnmpUserDataFactory
+ * on a per SNMP request basis, and is handed back to the user via
+ * SnmpMibRequest (and derivative) objects. It is never accessed by
+ * the system, but might be handed back in multiple threads. It is thus
+ * the user responsibility to make sure he handles this object in a
+ * thread safe manner.
+ */
+ public Object getUserData();
+
+ /**
+ * Returns the varbind index that should be embedded in an
+ * SnmpStatusException for this particular varbind.
+ * This does not necessarily correspond to the "real"
+ * index value that will be returned in the result PDU.
+ *
+ * @param varbind The varbind for which the index value is
+ * querried. Note that this varbind <b>must</b> have
+ * been obtained from the enumeration returned by
+ * <CODE>getElements()</CODE>, or from the vector
+ * returned by <CODE>getSublist()</CODE>.
+ *
+ * @return The varbind index that should be embedded in an
+ * SnmpStatusException for this particular varbind.
+ */
+ public int getVarIndex(SnmpVarBind varbind);
+
+ /**
+ * Adds a varbind to this request sublist. This method is used for
+ * internal purposes and you should never need to call it directly.
+ *
+ * @param varbind The varbind to be added in the sublist.
+ *
+ */
+ public void addVarBind(SnmpVarBind varbind);
+
+
+ /**
+ * Returns the number of elements (varbinds) in this request sublist.
+ *
+ * @return The number of elements in the sublist.
+ *
+ **/
+ public int getSize();
+ /**
+ * Returns the SNMP PDU attached to the request.
+ * @return The SNMP PDU.
+ *
+ * @since 1.5
+ **/
+ public SnmpPdu getPdu();
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibRequestImpl.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibRequestImpl.java
new file mode 100644
index 0000000..c0d5e19
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibRequestImpl.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+
+import com.sun.jmx.snmp.SnmpPdu;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpEngine;
+
+/**
+ * This class implements the SnmpMibRequest interface.
+ * It represents the part of a SNMP request that involves a specific
+ * MIB. One instance of this class will be created for every MIB
+ * involved in a SNMP request, and will be passed to the SnmpMibAgent
+ * in charge of handling that MIB.
+ *
+ * Instances of this class are allocated by the SNMP engine. You will
+ * never need to use this class directly. You will only access
+ * instances of this class through their SnmpMibRequest interface.
+ *
+ */
+final class SnmpMibRequestImpl implements SnmpMibRequest {
+
+ /**
+ * @param engine The local engine.
+ * @param reqPdu The received pdu.
+ * @param vblist The vector of SnmpVarBind objects in which the
+ * MIB concerned by this request is involved.
+ * @param protocolVersion The protocol version of the SNMP request.
+ * @param userData User allocated contextual data. This object must
+ * be allocated on a per SNMP request basis through the
+ * SnmpUserDataFactory registered with the SnmpAdaptorServer,
+ * and is handed back to the user through SnmpMibRequest objects.
+ */
+ public SnmpMibRequestImpl(SnmpEngine engine,
+ SnmpPdu reqPdu,
+ Vector<SnmpVarBind> vblist,
+ int protocolVersion,
+ Object userData,
+ String principal,
+ int securityLevel,
+ int securityModel,
+ byte[] contextName,
+ byte[] accessContextName) {
+ varbinds = vblist;
+ version = protocolVersion;
+ data = userData;
+ this.reqPdu = reqPdu;
+ this.engine = engine;
+ this.principal = principal;
+ this.securityLevel = securityLevel;
+ this.securityModel = securityModel;
+ this.contextName = contextName;
+ this.accessContextName = accessContextName;
+ }
+ // -------------------------------------------------------------------
+ // PUBLIC METHODS from SnmpMibRequest
+ // -------------------------------------------------------------------
+
+ /**
+ * Returns the local engine. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise null is returned.
+ * @return the local engine.
+ */
+ public SnmpEngine getEngine() {
+ return engine;
+ }
+
+ /**
+ * Gets the incoming request principal. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise null is returned.
+ * @return The request principal.
+ **/
+ public String getPrincipal() {
+ return principal;
+ }
+
+ /**
+ * Gets the incoming request security level. This level is defined in {@link com.sun.jmx.snmp.SnmpEngine SnmpEngine}. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise -1 is returned.
+ * @return The security level.
+ */
+ public int getSecurityLevel() {
+ return securityLevel;
+ }
+ /**
+ * Gets the incoming request security model. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise -1 is returned.
+ * @return The security model.
+ */
+ public int getSecurityModel() {
+ return securityModel;
+ }
+ /**
+ * Gets the incoming request context name. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise null is returned.
+ * @return The context name.
+ */
+ public byte[] getContextName() {
+ return contextName;
+ }
+
+ /**
+ * Gets the incoming request context name used by Access Control Model in order to allow or deny the access to OIDs. This parameter is returned only if <CODE> SnmpV3AdaptorServer </CODE> is the adaptor receiving this request. Otherwise null is returned.
+ * @return The checked context.
+ */
+ public byte[] getAccessContextName() {
+ return accessContextName;
+ }
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public final SnmpPdu getPdu() {
+ return reqPdu;
+ }
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public final Enumeration getElements() {return varbinds.elements();}
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public final Vector<SnmpVarBind> getSubList() {return varbinds;}
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public final int getSize() {
+ if (varbinds == null) return 0;
+ return varbinds.size();
+ }
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public final int getVersion() {return version;}
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public final int getRequestPduVersion() {return reqPdu.version;}
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public final Object getUserData() {return data;}
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public final int getVarIndex(SnmpVarBind varbind) {
+ return varbinds.indexOf(varbind);
+ }
+
+ // -------------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------------
+ public void addVarBind(SnmpVarBind varbind) {
+ varbinds.addElement(varbind);
+ }
+
+ // -------------------------------------------------------------------
+ // PACKAGE METHODS
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // Allow to pass the request tree built during the check() phase
+ // to the set() method. Note: the if the tree is `null', then the
+ // set() method will rebuild a new tree identical to the tree built
+ // in the check() method.
+ //
+ // Passing this tree in the SnmpMibRequestImpl object allows to
+ // optimize the SET requests.
+ //
+ // -------------------------------------------------------------------
+ final void setRequestTree(SnmpRequestTree tree) {this.tree = tree;}
+
+ // -------------------------------------------------------------------
+ // Returns the SnmpRequestTree object built in the first operation
+ // phase for two-phase SNMP requests (like SET).
+ // -------------------------------------------------------------------
+ final SnmpRequestTree getRequestTree() {return tree;}
+
+ // -------------------------------------------------------------------
+ // Returns the underlying vector of SNMP varbinds (used for algorithm
+ // optimization).
+ // -------------------------------------------------------------------
+ final Vector getVarbinds() {return varbinds;}
+
+ // -------------------------------------------------------------------
+ // Private variables
+ // -------------------------------------------------------------------
+
+ // Ideally these variables should be declared final but it makes
+ // the jdk1.1.x compiler complain (seems to be a compiler bug, jdk1.2
+ // is OK).
+ private Vector<SnmpVarBind> varbinds;
+ private int version;
+ private Object data;
+ private SnmpPdu reqPdu = null;
+ // Non final variable.
+ private SnmpRequestTree tree = null;
+ private SnmpEngine engine = null;
+ private String principal = null;
+ private int securityLevel = -1;
+ private int securityModel = -1;
+ private byte[] contextName = null;
+ private byte[] accessContextName = null;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibSubRequest.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibSubRequest.java
new file mode 100644
index 0000000..6a6f3f5
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibSubRequest.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpStatusException;
+import com.sun.jmx.snmp.SnmpOid;
+// import com.sun.jmx.snmp.SnmpIndex;
+
+/**
+ * This interface models an SNMP sub request to be performed on a specific
+ * SNMP MIB node. The node involved can be either an SNMP group, an SNMP table,
+ * or an SNMP table entry (conceptual row). The conceptual row may or may not
+ * already exist. If the row did not exist at the time when the request
+ * was received, the <CODE>isNewEntry()</CODE> method will return <CODE>
+ * true</CODE>.
+ * <p>
+ * Objects implementing this interface will be allocated by the SNMP engine.
+ * You will never need to implement this interface. You will only use it.
+ * </p>
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+public interface SnmpMibSubRequest extends SnmpMibRequest {
+ /**
+ * Return the list of varbind to be handled by the SNMP MIB node.
+ * <p>
+ * <b>Note:</b> <ul>
+ * <i>In case of SET operation, if this node is a table row which
+ * contains a control variable (as identified by the table's
+ * isRowStatus() method) the control variable will not
+ * be included in this list: it will be obtained by calling
+ * getRowStatusVarBind(). This will allow you to handle the control
+ * variable specifically.</i><br>
+ * You will never need to worry about this unless you need to
+ * implement a non standard mechanism for handling row
+ * creation and deletion.
+ * </ul>
+ * <p>
+ * @return The elements of the enumeration are instances of
+ * {@link com.sun.jmx.snmp.SnmpVarBind}
+ */
+ public Enumeration getElements();
+
+ /**
+ * Return the list of varbind to be handled by the SNMP MIB node.
+ * <p>
+ * <b>Note:</b> <ul>
+ * <i>In case of SET operation, if this node is a table row which
+ * contains a control variable (as identified by the table's
+ * isRowStatus() method) the control variable will not
+ * be included in this list: it will be obtained by calling
+ * getRowStatusVarBind(). This will allow you to handle the control
+ * variable specifically.</i><br>
+ * You will never need to worry about this unless you need to
+ * implement a non standard mechanism for handling row
+ * creation and deletion.
+ * </ul>
+ * <p>
+ * @return The elements of the vector are instances of
+ * {@link com.sun.jmx.snmp.SnmpVarBind}
+ */
+ public Vector<SnmpVarBind> getSubList();
+
+ /**
+ * Return the part of the OID identifying the table entry involved.
+ * <p>
+ *
+ * @return {@link com.sun.jmx.snmp.SnmpOid} or <CODE>null</CODE>
+ * if the request is not directed to an entry.
+ */
+ public SnmpOid getEntryOid();
+
+ /**
+ * Indicate whether the entry involved is a new entry.
+ * This method will return <CODE>true</CODE> if the entry was not
+ * found when the request was processed. As a consequence, <CODE>
+ * true</CODE> means that either the entry does not exist yet,
+ * or it has been created while processing this request.
+ * The result of this method is only significant when an entry
+ * is involved.
+ *
+ * <p>
+ * @return <CODE>true</CODE> If the entry did not exist,
+ * or <CODE>false</CODE> if the entry involved was found.
+ */
+ public boolean isNewEntry();
+
+ /**
+ * Return the varbind that holds the RowStatus variable.
+ * It corresponds to the varbind that was identified by
+ * the <code>isRowStatus()</code> method generated by mibgen
+ * on {@link com.sun.jmx.snmp.agent.SnmpMibTable} derivatives.
+ * <ul><li>In SMIv2, it is the varbind which contains the columnar
+ * object implementing the RowStatus TEXTUAL-CONVENTION.</li>
+ * <li>In SMIv1 nothing special is generated</li>
+ * <ul>You may however subclass the generated table metadata
+ * class in order to provide your own implementation of
+ * isRowStatus(), getRowAction(), isRowReady() and
+ * setRowStatus()
+ * (see {@link com.sun.jmx.snmp.agent.SnmpMibTable}).</ul>
+ * </ul>
+ * <p>
+ * @return a varbind that serves to control the table modification.
+ * <code>null</code> means that no such varbind could be
+ * identified.<br>
+ * <b>Note:</b><i>The runtime will only try to identify
+ * the RowStatus varbind when processing an
+ * SNMP SET request. In this case, the identified
+ * varbind will not be included in the set of varbinds
+ * returned by getSubList() and getElements().
+ * </i>
+ *
+ **/
+ public SnmpVarBind getRowStatusVarBind();
+
+ /**
+ * This method should be called when a status exception needs to
+ * be raised for a given varbind of an SNMP GET request. This method
+ * performs all the necessary conversions (SNMPv1 <=> SNMPv2) and
+ * propagates the exception if needed:
+ * If the version is SNMP v1, the exception is propagated.
+ * If the version is SNMP v2, the exception is stored in the varbind.
+ * This method also takes care of setting the correct value of the
+ * index field.
+ * <p>
+ *
+ * @param varbind The varbind for which the exception is
+ * registered. Note that this varbind <b>must</b> have
+ * been obtained from the enumeration returned by
+ * <CODE>getElements()</CODE>, or from the vector
+ * returned by <CODE>getSubList()</CODE>
+ *
+ * @param exception The exception to be registered for the given varbind.
+ *
+ */
+ public void registerGetException(SnmpVarBind varbind,
+ SnmpStatusException exception)
+ throws SnmpStatusException;
+
+ /**
+ * This method should be called when a status exception needs to
+ * be raised for a given varbind of an SNMP SET request. This method
+ * performs all the necessary conversions (SNMPv1 <=> SNMPv2) and
+ * propagates the exception if needed.
+ * This method also takes care of setting the correct value of the
+ * index field.
+ * <p>
+ *
+ * @param varbind The varbind for which the exception is
+ * registered. Note that this varbind <b>must</b> have
+ * been obtained from the enumeration returned by
+ * <CODE>getElements()</CODE>, or from the vector
+ * returned by <CODE>getSubList()</CODE>
+ *
+ * @param exception The exception to be registered for the given varbind.
+ *
+ */
+ public void registerSetException(SnmpVarBind varbind,
+ SnmpStatusException exception)
+ throws SnmpStatusException;
+
+ /**
+ * This method should be called when a status exception needs to
+ * be raised when checking a given varbind for an SNMP SET request.
+ * This method performs all the necessary conversions (SNMPv1 <=>
+ * SNMPv2) and propagates the exception if needed.
+ * This method also takes care of setting the correct value of the
+ * index field.
+ * <p>
+ *
+ * @param varbind The varbind for which the exception is
+ * registered. Note that this varbind <b>must</b> have
+ * been obtained from the enumeration returned by
+ * <CODE>getElements()</CODE>, or from the vector
+ * returned by <CODE>getSubList()</CODE>
+ *
+ * @param exception The exception to be registered for the given varbind.
+ *
+ */
+ public void registerCheckException(SnmpVarBind varbind,
+ SnmpStatusException exception)
+ throws SnmpStatusException;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibTable.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibTable.java
new file mode 100644
index 0000000..1164087
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpMibTable.java
@@ -0,0 +1,2570 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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</i> that will implement the
+ * SnmpTableEntryFactory interface, and a corresponding
+ * <i>TableName</i>Meta class that will extend this class. <br>
+ * The Table<i>TableName</i> class corresponds to the MBean view of the
+ * table while the <i>TableName</i>Meta 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><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ * @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</CODE> 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)</code> and <code>
+ * setCreationEnabled(false)</code> on this object.
+ * <p><b><i>
+ * This method is called internally by the SNMP runtime and you
+ * should never need to call it directly. </b></i>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</code> 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</code> 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</CODE>]
+ **/
+ 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><li>
+ * <CODE>setCreationEnabled(true)</CODE> will enable remote entry
+ * creation via SET operations.</li>
+ * <li>
+ * <CODE>setCreationEnabled(false)</CODE> 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</code> 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</code>, and it is
+ * assumed that the table has no such control variable.<br>
+ * When <code>mibgen</code> is used over SMIv2 MIBs, it will generate
+ * an <code>hasRowStatus()</code> method returning <code>true</code>
+ * for each table containing an object with RowStatus syntax.
+ * <p>
+ * When this method returns <code>false</code> 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</code>.<br>
+ * You will then have to redefine the isRowStatus(), mapRowStatus(),
+ * isRowReady(), and setRowStatus() methods to suit your specific
+ * implementation.
+ * <p>
+ * @return <li><code>true</code> if this table contains a control
+ * variable (eg: a variable with RFC 2579 RowStatus syntax),
+ * </li>
+ * <li><code>false</code> 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</CODE> 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)</CODE> method. </li>
+ * </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)</CODE> on the generated
+ * derivative of <CODE>SnmpMibEntry</CODE>. 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)</CODE> on the generated
+ * derivative of <CODE>SnmpMibEntry</CODE>.
+ * <p>
+ *
+ */
+ 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 = null;
+ for (Enumeration e= r.getElements(); e.hasMoreElements();) {
+ var = (SnmpVarBind) e.nextElement();
+ r.registerGetException(var,noSuchInstanceException);
+ }
+ }
+
+ 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</CODE> 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)</CODE> method. </li>
+ * </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)</CODE> on the generated
+ * derivative of <CODE>SnmpMibEntry</CODE>. 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)</CODE> on the generated
+ * derivative of <CODE>SnmpMibEntry</CODE>.
+ * <p>
+ *
+ */
+ 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</CODE> operation.
+ * <p> The default implementation of this method is to
+ * call the generated
+ * <CODE>set(req,oid,depth+1)</CODE> 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)</CODE> on the generated
+ * derivative of <CODE>SnmpMibEntry</CODE>. 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)</CODE> on the generated
+ * derivative of <CODE>SnmpMibEntry</CODE>.
+ * <p>
+ *
+ */
+ 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</CODE>.
+ * 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 prefered.
+ * <br> This function is mainly provided for backward compatibility.
+ *
+ * <p>
+ * @param rowOid The <CODE>SnmpOid</CODE> 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</code>, 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</CODE>.
+ * 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</CODE> 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</code>, 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</CODE> 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</code> 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</CODE> identifying the table
+ * row to remove.
+ *
+ * @exception SnmpStatusException if the specified entry couldn't
+ * be removed (if the given <code>rowOid</code> 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</CODE> identifying the
+ * row to be retrieved.
+ *
+ * @return The entry.
+ *
+ * @exception SnmpStatusException There is no entry with the specified
+ * <code>rowOid</code> 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</CODE> 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</code> 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</CODE>.
+ * <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</code>. It all depends whether a non
+ * <code>null</code> entry was passed to addEntry().<br>
+ * 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</CODE>.
+ *
+ * <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.
+ */
+ 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<Object>() ;
+ filterList = new Vector<NotificationFilter>() ;
+ 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</CODE>.
+ *
+ * @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.
+ */
+ public synchronized void
+ removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {
+
+ // looking for listener in handbackTable
+ //
+ java.util.Vector handbackList =
+ (java.util.Vector) handbackTable.get(listener) ;
+ java.util.Vector filterList =
+ (java.util.Vector) filterTable.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</CODE> object containing the
+ * notification class and the notification type sent by the
+ * <CODE>SnmpMibTable</CODE>.
+ */
+ 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</code>
+ * 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</code>
+ * <p>
+ * If this table was defined using SMIv2, and if it contains a
+ * control variable with RowStatus syntax, <code>mibgen</code>
+ * 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</CODE> 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</i>
+ * value which is SNMP Runtime specific.
+ * <p>
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param rowOid The <CODE>SnmpOid</CODE> 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</i> is returned</li>
+ * <li>Otherwise, if the row exists and this table do not use any
+ * variable to control creation/deletion of rows,
+ * <i>unspecified</i> is returned.</li>
+ * <li>Otherwise, if the request does not contain the control variable,
+ * <i>unspecified</i> is returned.</li>
+ * <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</code> 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</i> 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</code>
+ * 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</CODE> 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</code>.
+ *
+ * @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</code>
+ * value.
+ *
+ * <p>
+ * This method maps the given <code>newStatus</code> to the appropriate
+ * value for the control variable, then sets the control variable in
+ * the entry identified by <code>rowOid</code>. 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</code>.
+ * <p>
+ * If this table was defined using SMIv2, and if it contains a
+ * control variable with RowStatus syntax, <code>mibgen</code>
+ * 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</CODE> 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</i> 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)</code>) or <code>null</code>
+ * if the table do not have any control variable.
+ *
+ * @exception SnmpStatusException If the given <code>newStatus</code>
+ * could not be set on the specified entry, or if the
+ * given <code>newStatus</code> 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</i> state.
+ * <p>
+ * This method is called only once, after all the varbind have been
+ * set on a new entry for which <i>createAndWait</i> 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</i> when it becomes ready.
+ * No further call to <code>isRowReady()</code> will be made.
+ * <p>
+ * By default, this method always return true. <br>
+ * <code>mibgen</code> will not generate any specific implementation
+ * for this method - meaning that by default, a row created using
+ * <i>createAndWait</i> will always be placed in <i>notInService</i>
+ * 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</code>
+ * 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</CODE> 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</code> if the row can be placed in
+ * <i>notInService</i> state.
+ *
+ * @exception SnmpStatusException An error occured 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</code>.
+ * <p>
+ * This method is called during the <i>check</i> phase of a SET
+ * request when the control variable specifies <i>active</i> or
+ * <i>notInService</i>.
+ * <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</CODE> 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</i> 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</i> phase of a SET
+ * request when the control variable specifies <i>destroy</i>
+ * <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</CODE> 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()</code>
+ * yields <i>destroy</i> - 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()</code>.
+ * If <code>checkRemoveTableRow()</code> 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</CODE> 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()</code>
+ * 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><li>check that the given <code>rowAction</code> returned by
+ * <code>getRowAction()</code> is valid.</li>
+ * <li>Then depending on the <code>rowAction</code> specified it will:
+ * <ul><li>either call <code>createNewEntry()</code> (<code>
+ * rowAction = <i>createAndGo</i> or <i>createAndWait</i>
+ * </code>),</li>
+ * <li>or call <code>checkRemoveTableRow()</code> (<code>
+ * rowAction = <i>destroy</i></code>),</li>
+ * <li>or call <code>checkRowStatusChange()</code> (<code>
+ * rowAction = <i>active</i> or <i>notInService</i></code>),</li>
+ * <li>or generate a SnmpStatusException if the passed <code>
+ * rowAction</code> is not correct.</li>
+ * </ul></li></ul>
+ * <p>
+ * In principle, you should not need to redefine this method.
+ * <p>
+ * <code>beginRowAction()</code> 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</CODE> 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</i> value which is SNMP Runtime specific.
+ *
+ * @exception SnmpStatusException if the specified <code>rowAction</code>
+ * 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()</code> 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><li>either call <code>setRowStatus(<i>active</i>)</code>
+ * (<code> rowAction = <i>createAndGo</i> or <i>active</i>
+ * </code>),</li>
+ * <li>or call <code>setRowStatus(<i>notInService</i> or <i>
+ * notReady</i>)</code> depending on the result of <code>
+ * isRowReady()</code> (<code>rowAction = <i>createAndWait</i>
+ * </code>),</li>
+ * <li>or call <code>setRowStatus(<i>notInService</i>)</code>
+ * (<code> rowAction = <i>notInService</i></code>),
+ * <li>or call <code>removeTableRow()</code> (<code>
+ * rowAction = <i>destroy</i></code>),</li>
+ * <li>or generate a SnmpStatusException if the passed <code>
+ * 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()</code> 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</code>).
+ *
+ * <p>
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param rowOid The <CODE>SnmpOid</CODE> 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</i> value which is SNMP Runtime specific.
+ *
+ * @exception SnmpStatusException if the specified <code>rowAction</code>
+ * 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><li>the variable is a leaf that is not instantiated,</li>
+ * <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</CODE> index of the row that follows
+ * the given <CODE>oid</CODE> in the table. The given <CODE>
+ * 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</CODE> index.
+ *
+ * @exception SnmpStatusException There is no index following the
+ * specified <CODE>oid</CODE> in the table.
+ */
+ protected SnmpOid getNextOid(SnmpOid oid, Object userData)
+ throws SnmpStatusException {
+
+ if (size == 0)
+ throw noSuchInstanceException;
+
+ 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 noSuchInstanceException;
+ }
+
+ // 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 noSuchInstanceException;
+ }
+ } else {
+ // We are dealing with the last element of the table ..
+ //
+ throw noSuchInstanceException;
+ }
+
+
+ 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</CODE> 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 noSuchInstanceException;
+ // XX return (SnmpOid) oids.firstElement();
+ return tableoids[0];
+ }
+
+ // -------------------------------------------------------------------
+ // Abstract Protected Methods
+ // -------------------------------------------------------------------
+
+ /**
+ * This method is used internally and is implemented by the
+ * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
+ *
+ * <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</CODE> subclasses generated by <CODE>mibgen</CODE>.
+ *
+ * <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</CODE> subclasses generated by <CODE>mibgen</CODE>.
+ *
+ * <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</CODE> subclasses generated by <CODE>mibgen</CODE>.
+ */
+ abstract protected void get(SnmpMibSubRequest req,
+ SnmpOid rowOid, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * This method is used internally and is implemented by the
+ * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
+ */
+ abstract protected void check(SnmpMibSubRequest req,
+ SnmpOid rowOid, int depth)
+ throws SnmpStatusException;
+
+ /**
+ * This method is used internally and is implemented by the
+ * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
+ */
+ abstract protected void set(SnmpMibSubRequest req,
+ SnmpOid rowOid, int depth)
+ throws SnmpStatusException;
+
+ // ----------------------------------------------------------------------
+ // PACKAGE METHODS
+ // ----------------------------------------------------------------------
+
+ /**
+ * Get the <CODE>SnmpOid</CODE> 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)</code>;
+ *
+ * <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</CODE>.
+ *
+ * @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
+ //
+ // ---------------------------------------------------------------------
+
+ final 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
+ //
+ // ---------------------------------------------------------------------
+
+ final 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.
+ //
+ // ---------------------------------------------------------------------
+ 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 noSuchInstanceException;
+ 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.
+ //
+ // ---------------------------------------------------------------------
+ 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 noSuchObjectException;
+
+ 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 noSuchObjectException;
+ } 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 = null ;
+
+ 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 noSuchObjectException;
+ } 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 noSuchObjectException;
+
+
+ // 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 noSuchObjectException;
+
+ // 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 noSuchObjectException;
+ }
+ }
+
+
+ /**
+ * 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 noSuchInstanceException;
+
+ // Check that the entry identifier is specified
+ //
+ if (oid[pos] != nodeId)
+ throw noSuchObjectException;
+
+ }
+
+ // ----------------------------------------------------------------------
+ // PRIVATE METHODS
+ // ----------------------------------------------------------------------
+
+ /**
+ * Enable this <CODE>SnmpMibTable</CODE> to send a notification.
+ *
+ * <p>
+ * @param notification The notification to send.
+ */
+ private synchronized void sendNotification(Notification notification) {
+
+ // loop on listener
+ //
+ for(java.util.Enumeration k = handbackTable.keys();
+ k.hasMoreElements(); ) {
+
+ NotificationListener listener =
+ (NotificationListener) k.nextElement();
+
+ // Get the associated handback list and the associated filter list
+ //
+ java.util.Vector handbackList =
+ (java.util.Vector) handbackTable.get(listener) ;
+ java.util.Vector filterList =
+ (java.util.Vector) filterTable.get(listener) ;
+
+ // loop on handback
+ //
+ java.util.Enumeration f = filterList.elements();
+ for(java.util.Enumeration h = handbackList.elements();
+ h.hasMoreElements(); ) {
+
+ Object handback = h.nextElement();
+ NotificationFilter filter =
+ (NotificationFilter)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</b>.
+ * <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</code> if the entry is found, <code>false</code>
+ * 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 final 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.
+ *
+ * @return The position at which the OID should be inserted in
+ * the table.
+ *
+ * @exception SnmpStatusException if the OID is already present in the
+ * table.
+ *
+ **/
+ private final int getInsertionPoint(SnmpOid oid)
+ throws SnmpStatusException {
+ return getInsertionPoint(oid, true);
+ }
+
+ /**
+ * 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</code> is <code>true</code>.
+ *
+ **/
+ private final 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 final 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 final 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 accomodate 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</CODE> if remote creation of entries via SET operations
+ * is enabled.
+ * [default value is <CODE>false</CODE>]
+ * @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<Object>();
+
+ /**
+ * The list of object names.
+ * @serial
+ */
+ private final Vector<ObjectName> entrynames= new Vector<ObjectName>();
+
+ /**
+ * Callback handlers
+ */
+ // final Vector callbacks = new Vector();
+
+ /**
+ * Listener hastable containing the hand-back objects.
+ */
+ private Hashtable<NotificationListener, Vector<Object>> handbackTable =
+ new Hashtable<NotificationListener, Vector<Object>>();
+
+ /**
+ * Listener hastable containing the filter objects.
+ */
+ private Hashtable<NotificationListener, Vector<NotificationFilter>>
+ filterTable =
+ new Hashtable<NotificationListener, Vector<NotificationFilter>>();
+
+ // PACKAGE VARIABLES
+ //------------------
+ /**
+ * SNMP table sequence number.
+ * The default value is set to 0.
+ */
+ transient long sequenceNumber = 0;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpRequestTree.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpRequestTree.java
new file mode 100644
index 0000000..4699024
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpRequestTree.java
@@ -0,0 +1,1071 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.jmx.snmp.agent;
+
+import java.util.Vector;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Arrays;
+import java.util.logging.Level;
+
+import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpStatusException;
+import com.sun.jmx.snmp.SnmpDefinitions;
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpPdu;
+import com.sun.jmx.snmp.SnmpEngine;
+
+// XXX: things to do: use SnmpOid rather than `instance' for future
+// evolutions.
+// XXX: Maybe use hashlists rather than vectors for entries?
+// => in that case, the key should be SnmpOid.toString()
+//
+/**
+ * This class is used to register varbinds from a SNMP varbind list with
+ * the SnmpMibNode responsible for handling the requests concerning that
+ * varbind.
+ * This class holds a hashtable of Handler nodes, whith the involved
+ * SnmpMibNode as a key.
+ * When the involved SnmpMibNode is a group, the sublist of varbind is
+ * directly stored in the Handler node.
+ * When the involved SnmpMibNode is a table, the sublist is stored in a
+ * sorted array indexed by the OID of the entry involved.
+ */
+final class SnmpRequestTree {
+
+ // Constructor:
+ // @param req The SnmpMibRequest that will be segmented in this
+ // tree. It holds the original varbind vector passed
+ // by the SnmpSubRequestHandler to this MIB. This
+ // varbind vector is used to retrieve the "real"
+ // position of a varbind in the vector. There is no other easy
+ // way to do this - since as a result of the segmentation the
+ // original positions will be lost.
+ // @param creationflag indicates whether the operation involved
+ // allows for entry creation (ie: it is a SET request).
+ // @param pdutype indicates the type of the request PDU as defined
+ // in SnmpDefinitions
+ //
+ SnmpRequestTree(SnmpMibRequest req, boolean creationflag, int pdutype) {
+ this.request = req;
+ this.version = req.getVersion();
+ this.creationflag = creationflag;
+ this.hashtable = new Hashtable<Object, Handler>();
+ setPduType(pdutype);
+ }
+
+ public static int mapSetException(int errorStatus, int version)
+ throws SnmpStatusException {
+
+ final int errorCode = errorStatus;
+
+ if (version == SnmpDefinitions.snmpVersionOne)
+ return errorCode;
+
+ int mappedErrorCode = errorCode;
+
+ // Now take care of V2 errorCodes that can be stored
+ // in the varbind itself:
+ if (errorCode == SnmpStatusException.noSuchObject)
+ // noSuchObject => notWritable
+ mappedErrorCode = SnmpStatusException.snmpRspNotWritable;
+
+ else if (errorCode == SnmpStatusException.noSuchInstance)
+ // noSuchInstance => notWritable
+ mappedErrorCode = SnmpStatusException.snmpRspNotWritable;
+
+ return mappedErrorCode;
+ }
+
+ public static int mapGetException(int errorStatus, int version)
+ throws SnmpStatusException {
+
+ final int errorCode = errorStatus;
+ if (version == SnmpDefinitions.snmpVersionOne)
+ return errorCode;
+
+ int mappedErrorCode = errorCode;
+
+ // Now take care of V2 errorCodes that can be stored
+ // in the varbind itself:
+ if (errorCode ==
+ SnmpStatusException.noSuchObject)
+ // noSuchObject => noSuchObject
+ mappedErrorCode = errorCode;
+
+ else if (errorCode ==
+ SnmpStatusException.noSuchInstance)
+ // noSuchInstance => noSuchInstance
+ mappedErrorCode = errorCode;
+
+ // Now we're going to try to transform every other
+ // global code in either noSuchInstance or noSuchObject,
+ // so that the get can return a partial result.
+ //
+ // Only noSuchInstance or noSuchObject can be stored
+ // in the varbind itself.
+ //
+
+ // According to RFC 1905: noAccess is emitted when the
+ // the access is denied because it is not in the MIB view...
+ //
+ else if (errorCode ==
+ SnmpStatusException.noAccess)
+ // noAccess => noSuchInstance
+ mappedErrorCode = SnmpStatusException.noSuchInstance;
+
+ // According to RFC 1905: (my interpretation because it is not
+ // really clear) The specified variable name exists - but the
+ // variable does not exists and cannot be created under the
+ // present circumstances (probably because the request specifies
+ // another variable/value which is incompatible, or because the
+ // value of some other variable in the MIB prevents the creation)
+ //
+ // Note that this error should never be raised in a GET context
+ // but who knows?
+ //
+ else if (errorCode == SnmpStatusException.snmpRspInconsistentName)
+ // inconsistentName => noSuchInstance
+ mappedErrorCode = SnmpStatusException.noSuchInstance;
+
+ // All the errors comprised between snmpRspWrongType and
+ // snmpRspInconsistentValue concern values: so we're going
+ // to assume the OID was correct, and reply with noSuchInstance.
+ //
+ // Note that this error should never be raised in a GET context
+ // but who knows?
+ //
+ else if ((errorCode >= SnmpStatusException.snmpRspWrongType) &&
+ (errorCode <= SnmpStatusException.snmpRspInconsistentValue))
+ mappedErrorCode = SnmpStatusException.noSuchInstance;
+
+ // We're going to assume the OID was correct, and reply
+ // with noSuchInstance.
+ //
+ else if (errorCode == SnmpStatusException.readOnly)
+ mappedErrorCode = SnmpStatusException.noSuchInstance;
+
+ // For all other errors but genErr, we're going to reply with
+ // noSuchObject
+ //
+ else if (errorCode != SnmpStatusException.snmpRspAuthorizationError &&
+ errorCode != SnmpStatusException.snmpRspGenErr)
+ mappedErrorCode = SnmpStatusException.noSuchObject;
+
+ // Only genErr will abort the GET and be returned as global
+ // error.
+ //
+ return mappedErrorCode;
+
+ }
+
+ //-------------------------------------------------------------------
+ // This class is a package implementation of the enumeration of
+ // SnmSubRequest associated with an Handler node.
+ //-------------------------------------------------------------------
+
+ static final class Enum implements Enumeration {
+ Enum(SnmpRequestTree hlist,Handler h) {
+ handler = h;
+ this.hlist = hlist;
+ size = h.getSubReqCount();
+ }
+ private final Handler handler;
+ private final SnmpRequestTree hlist;
+ private int entry = 0;
+ private int iter = 0;
+ private int size = 0;
+
+ public boolean hasMoreElements() {
+ return iter < size;
+ }
+
+ public Object nextElement() throws NoSuchElementException {
+ if (iter == 0) {
+ if (handler.sublist != null) {
+ iter++;
+ return hlist.getSubRequest(handler);
+ }
+ }
+ iter ++;
+ if (iter > size) throw new NoSuchElementException();
+ Object result = hlist.getSubRequest(handler,entry);
+ entry++;
+ return result;
+ }
+ }
+
+ //-------------------------------------------------------------------
+ // This class is a package implementation of the SnmpMibSubRequest
+ // interface. It can only be instantiated by SnmpRequestTree.
+ //-------------------------------------------------------------------
+
+ static final class SnmpMibSubRequestImpl implements SnmpMibSubRequest {
+ SnmpMibSubRequestImpl(SnmpMibRequest global, Vector<SnmpVarBind> sublist,
+ SnmpOid entryoid, boolean isnew,
+ boolean getnextflag, SnmpVarBind rs) {
+ this.global = global;
+ varbinds = sublist;
+ this.version = global.getVersion();
+ this.entryoid = entryoid;
+ this.isnew = isnew;
+ this.getnextflag = getnextflag;
+ this.statusvb = rs;
+ }
+
+ final private Vector<SnmpVarBind> varbinds;
+ final private SnmpMibRequest global;
+ final private int version;
+ final private boolean isnew;
+ final private SnmpOid entryoid;
+ final private boolean getnextflag;
+ final private SnmpVarBind statusvb;
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------
+ public Enumeration getElements() {
+ return varbinds.elements();
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------
+ public Vector<SnmpVarBind> getSubList() {
+ return varbinds;
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------
+ public final int getSize() {
+ if (varbinds == null) return 0;
+ return varbinds.size();
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------
+ public void addVarBind(SnmpVarBind varbind) {
+ // XXX not sure we must also add the varbind in the global
+ // request? or whether we should raise an exception:
+ // in principle, this method should not be called!
+ varbinds.addElement(varbind);
+ global.addVarBind(varbind);
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibSubRequest interface.
+ // See SnmpMibSubRequest for the java doc.
+ // -------------------------------------------------------------
+ public boolean isNewEntry() {
+ return isnew;
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibSubRequest interface.
+ // See SnmpMibSubRequest for the java doc.
+ // -------------------------------------------------------------
+ public SnmpOid getEntryOid() {
+ return entryoid;
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------
+ public int getVarIndex(SnmpVarBind varbind) {
+ if (varbind == null) return 0;
+ return global.getVarIndex(varbind);
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------
+ public Object getUserData() { return global.getUserData(); }
+
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibSubRequest interface.
+ // See SnmpMibSubRequest for the java doc.
+ // -------------------------------------------------------------
+
+ public void registerGetException(SnmpVarBind var,
+ SnmpStatusException exception)
+ throws SnmpStatusException {
+ // The index in the exception must correspond to
+ // the SNMP index ...
+ //
+ if (version == SnmpDefinitions.snmpVersionOne)
+ throw new SnmpStatusException(exception, getVarIndex(var)+1);
+
+ if (var == null)
+ throw exception;
+
+ // If we're doing a getnext ==> endOfMibView
+ if (getnextflag) {
+ var.value = SnmpVarBind.endOfMibView;
+ return;
+ }
+
+ final int errorCode = mapGetException(exception.getStatus(),
+ version);
+
+ // Now take care of V2 errorCodes that can be stored
+ // in the varbind itself:
+ if (errorCode ==
+ SnmpStatusException.noSuchObject)
+ // noSuchObject => noSuchObject
+ var.value= SnmpVarBind.noSuchObject;
+
+ else if (errorCode ==
+ SnmpStatusException.noSuchInstance)
+ // noSuchInstance => noSuchInstance
+ var.value= SnmpVarBind.noSuchInstance;
+
+ else
+ throw new SnmpStatusException(errorCode, getVarIndex(var)+1);
+
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibSubRequest interface.
+ // See SnmpMibSubRequest for the java doc.
+ // -------------------------------------------------------------
+ public void registerSetException(SnmpVarBind var,
+ SnmpStatusException exception)
+ throws SnmpStatusException {
+ // The index in the exception must correspond to
+ // the SNMP index ...
+ //
+ if (version == SnmpDefinitions.snmpVersionOne)
+ throw new SnmpStatusException(exception, getVarIndex(var)+1);
+
+ // Although the first pass of check() did not fail,
+ // the set() phase could not be carried out correctly.
+ // Since we don't know how to make an "undo", and some
+ // assignation may already have been performed, we're going
+ // to throw an snmpRspUndoFailed.
+ //
+ throw new SnmpStatusException(SnmpDefinitions.snmpRspUndoFailed,
+ getVarIndex(var)+1);
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibSubRequest interface.
+ // See SnmpMibSubRequest for the java doc.
+ // -------------------------------------------------------------
+ public void registerCheckException(SnmpVarBind var,
+ SnmpStatusException exception)
+ throws SnmpStatusException {
+ // The index in the exception must correspond to
+ // the SNMP index ...
+ //
+ // We throw the exception in order to abort the SET operation
+ // in an atomic way.
+ final int errorCode = exception.getStatus();
+ final int mappedErrorCode = mapSetException(errorCode,
+ version);
+
+ if (errorCode != mappedErrorCode)
+ throw new
+ SnmpStatusException(mappedErrorCode, getVarIndex(var)+1);
+ else
+ throw new SnmpStatusException(exception, getVarIndex(var)+1);
+ }
+
+ // -------------------------------------------------------------
+ // Implements the method defined in SnmpMibRequest interface.
+ // See SnmpMibRequest for the java doc.
+ // -------------------------------------------------------------
+ public int getVersion() {
+ return version;
+ }
+
+ public SnmpVarBind getRowStatusVarBind() {
+ return statusvb;
+ }
+
+ public SnmpPdu getPdu() {
+ return global.getPdu();
+ }
+
+ public int getRequestPduVersion() {
+ return global.getRequestPduVersion();
+ }
+
+ public SnmpEngine getEngine() {
+ return global.getEngine();
+ }
+
+ public String getPrincipal() {
+ return global.getPrincipal();
+ }
+
+ public int getSecurityLevel() {
+ return global.getSecurityLevel();
+ }
+
+ public int getSecurityModel() {
+ return global.getSecurityModel();
+ }
+
+ public byte[] getContextName() {
+ return global.getContextName();
+ }
+
+ public byte[] getAccessContextName() {
+ return global.getAccessContextName();
+ }
+ }
+
+ //-------------------------------------------------------------------
+ // This class implements a node in the SnmpRequestTree.
+ // It stores:
+ // o The SnmpMibNode involved (key)
+ // o The sublist of varbind directly handled by this node
+ // o A vector of sublists concerning the entries (existing or not)
+ // of the SnmpMIbNode (when it is a table).
+ //-------------------------------------------------------------------
+
+ static final class Handler {
+ SnmpMibNode meta; // The meta which handles the sublist.
+ int depth; // The depth of the meta node.
+ Vector<SnmpVarBind> sublist; // The sublist of varbinds to be handled.
+ // List entryoids; // Sorted array of entry oids
+ // List entrylists; // Sorted array of entry lists
+ // List isentrynew; // Sorted array of booleans
+ SnmpOid[] entryoids = null; // Sorted array of entry oids
+ Vector<SnmpVarBind>[] entrylists = null; // Sorted array of entry lists
+ boolean[] isentrynew = null; // Sorted array of booleans
+ SnmpVarBind[] rowstatus = null; // RowStatus varbind, if any
+ int entrycount = 0;
+ int entrysize = 0;
+
+ final int type; // request PDU type as defined in SnmpDefinitions
+ final private static int Delta = 10;
+
+ public Handler(int pduType) {
+ this.type = pduType;
+ }
+
+ /**
+ * Adds a varbind in this node sublist.
+ */
+ public void addVarbind(SnmpVarBind varbind) {
+ if (sublist == null) sublist = new Vector<SnmpVarBind>();
+ sublist.addElement(varbind);
+ }
+
+ /**
+ * register an entry for the given oid at the given position with
+ * the given sublist.
+ */
+ @SuppressWarnings("unchecked")
+ // We need this because of new Vector[n] instead of
+ // new Vector<SnmpVarBind>[n], which is illegal.
+ void add(int pos,SnmpOid oid, Vector<SnmpVarBind> v, boolean isnew,
+ SnmpVarBind statusvb) {
+
+ if (entryoids == null) {
+ // Vectors are null: Allocate new vectors
+
+ entryoids = new SnmpOid[Delta];
+ entrylists = new Vector[Delta];
+ isentrynew = new boolean[Delta];
+ rowstatus = new SnmpVarBind[Delta];
+ entrysize = Delta;
+ pos = 0;
+
+ } else if (pos >= entrysize || entrycount == entrysize) {
+ // Vectors must be enlarged
+
+ // Save old vectors
+ SnmpOid[] olde = entryoids;
+ Vector[] oldl = entrylists;
+ boolean[] oldn = isentrynew;
+ SnmpVarBind[] oldr = rowstatus;
+
+ // Allocate larger vectors
+ entrysize += Delta;
+ entryoids = new SnmpOid[entrysize];
+ entrylists = new Vector[entrysize];
+ isentrynew = new boolean[entrysize];
+ rowstatus = new SnmpVarBind[entrysize];
+
+ // Check pos validity
+ if (pos > entrycount) pos = entrycount;
+ if (pos < 0) pos = 0;
+
+ final int l1 = pos;
+ final int l2 = entrycount - pos;
+
+ // Copy original vectors up to `pos'
+ if (l1 > 0) {
+ java.lang.System.arraycopy(olde,0,entryoids,
+ 0,l1);
+ java.lang.System.arraycopy(oldl,0,entrylists,
+ 0,l1);
+ java.lang.System.arraycopy(oldn,0,isentrynew,
+ 0,l1);
+ java.lang.System.arraycopy(oldr,0,rowstatus,
+ 0,l1);
+ }
+
+ // Copy original vectors from `pos' to end, leaving
+ // an empty room at `pos' in the new vectors.
+ if (l2 > 0) {
+ final int l3 = l1+1;
+ java.lang.System.arraycopy(olde,l1,entryoids,
+ l3,l2);
+ java.lang.System.arraycopy(oldl,l1,entrylists,
+ l3,l2);
+ java.lang.System.arraycopy(oldn,l1,isentrynew,
+ l3,l2);
+ java.lang.System.arraycopy(oldr,l1,rowstatus,
+ l3,l2);
+ }
+
+
+ } else if (pos < entrycount) {
+ // Vectors are large enough to accomodate one additional
+ // entry.
+ //
+ // Shift vectors, making an empty room at `pos'
+ final int l1 = pos+1;
+ final int l2 = entrycount - pos;
+
+ java.lang.System.arraycopy(entryoids,pos,entryoids,
+ l1,l2);
+ java.lang.System.arraycopy(entrylists,pos,entrylists,
+ l1,l2);
+ java.lang.System.arraycopy(isentrynew,pos,isentrynew,
+ l1,l2);
+ java.lang.System.arraycopy(rowstatus,pos,rowstatus,
+ l1,l2);
+ }
+
+ // Fill the gap at `pos'
+ entryoids[pos] = oid;
+ entrylists[pos] = v;
+ isentrynew[pos] = isnew;
+ rowstatus[pos] = statusvb;
+ entrycount++;
+ }
+
+ public void addVarbind(SnmpVarBind varbind, SnmpOid entryoid,
+ boolean isnew, SnmpVarBind statusvb)
+ throws SnmpStatusException {
+ Vector<SnmpVarBind> v = null;
+ SnmpVarBind rs = statusvb;
+
+ if (entryoids == null) {
+// entryoids = new ArrayList();
+// entrylists = new ArrayList();
+// isentrynew = new ArrayList();
+ v = new Vector<SnmpVarBind>();
+// entryoids.add(entryoid);
+// entrylists.add(v);
+// isentrynew.add(new Boolean(isnew));
+ add(0,entryoid,v,isnew,rs);
+ } else {
+ // int pos = findOid(entryoids,entryoid);
+ // int pos = findOid(entryoids,entrycount,entryoid);
+ final int pos =
+ getInsertionPoint(entryoids,entrycount,entryoid);
+ if (pos > -1 && pos < entrycount &&
+ entryoid.compareTo(entryoids[pos]) == 0) {
+ v = entrylists[pos];
+ rs = rowstatus[pos];
+ } else {
+ // if (pos == -1 || pos >= entryoids.size() ) {
+ // if (pos == -1 || pos >= entrycount ) {
+ // pos = getInsertionPoint(entryoids,entryoid);
+ // pos = getInsertionPoint(entryoids,entrycount,entryoid);
+ v = new Vector<SnmpVarBind>();
+// entryoids.add(pos,entryoid);
+// entrylists.add(pos,v);
+// isentrynew.add(pos,new Boolean(isnew));
+ add(pos,entryoid,v,isnew,rs);
+ }
+// } else v = (Vector) entrylists.get(pos);
+ // } else v = entrylists[pos];
+ if (statusvb != null) {
+ if ((rs != null) && (rs != statusvb) &&
+ ((type == SnmpDefinitions.pduWalkRequest) ||
+ (type == SnmpDefinitions.pduSetRequestPdu))) {
+ throw new SnmpStatusException(
+ SnmpStatusException.snmpRspInconsistentValue);
+ }
+ rowstatus[pos] = statusvb;
+ }
+ }
+
+ // We do not include the status variable in the varbind,
+ // because we're going to set it separately...
+ //
+ if (statusvb != varbind)
+ v.addElement(varbind);
+ }
+
+ public int getSubReqCount() {
+ int count = 0;
+ if (sublist != null) count++;
+// if (entryoids != null) count += entryoids.size();
+ if (entryoids != null) count += entrycount;
+ return count;
+ }
+
+ public Vector<SnmpVarBind> getSubList() {
+ return sublist;
+ }
+
+ public int getEntryPos(SnmpOid entryoid) {
+ // return findOid(entryoids,entryoid);
+ return findOid(entryoids,entrycount,entryoid);
+ }
+
+ public SnmpOid getEntryOid(int pos) {
+ if (entryoids == null) return null;
+ // if (pos == -1 || pos >= entryoids.size() ) return null;
+ if (pos == -1 || pos >= entrycount ) return null;
+ // return (SnmpOid) entryoids.get(pos);
+ return entryoids[pos];
+ }
+
+ public boolean isNewEntry(int pos) {
+ if (entryoids == null) return false;
+ // if (pos == -1 || pos >= entryoids.size() ) return false;
+ if (pos == -1 || pos >= entrycount ) return false;
+ // return ((Boolean)isentrynew.get(pos)).booleanValue();
+ return isentrynew[pos];
+ }
+
+ public SnmpVarBind getRowStatusVarBind(int pos) {
+ if (entryoids == null) return null;
+ // if (pos == -1 || pos >= entryoids.size() ) return false;
+ if (pos == -1 || pos >= entrycount ) return null;
+ // return ((Boolean)isentrynew.get(pos)).booleanValue();
+ return rowstatus[pos];
+ }
+
+ public Vector<SnmpVarBind> getEntrySubList(int pos) {
+ if (entrylists == null) return null;
+ // if (pos == -1 || pos >= entrylists.size() ) return null;
+ if (pos == -1 || pos >= entrycount ) return null;
+ // return (Vector) entrylists.get(pos);
+ return entrylists[pos];
+ }
+
+ public Iterator<SnmpOid> getEntryOids() {
+ if (entryoids == null) return null;
+ // return entryoids.iterator();
+ return Arrays.asList(entryoids).iterator();
+ }
+
+ public int getEntryCount() {
+ if (entryoids == null) return 0;
+ // return entryoids.size();
+ return entrycount;
+ }
+
+ }
+
+
+ //-------------------------------------------------------------------
+ //-------------------------------------------------------------------
+ // Public interface
+ //-------------------------------------------------------------------
+ //-------------------------------------------------------------------
+
+ //-------------------------------------------------------------------
+ // Returns the contextual object containing user-data allocated
+ // through the SnmpUserDataFactory for this request.
+ //-------------------------------------------------------------------
+
+ public Object getUserData() { return request.getUserData(); }
+
+ //-------------------------------------------------------------------
+ // Tells whether creation of new entries is allowed with respect
+ // to the operation involved (GET=>false/SET=>true)
+ //-------------------------------------------------------------------
+
+ public boolean isCreationAllowed() {
+ return creationflag;
+ }
+
+ //-------------------------------------------------------------------
+ // Tells whether we are currently processing a SET request (check/set)
+ //-------------------------------------------------------------------
+
+ public boolean isSetRequest() {
+ return setreqflag;
+ }
+
+ //-------------------------------------------------------------------
+ // Returns the protocol version in which the original request is
+ // evaluated.
+ //-------------------------------------------------------------------
+
+ public int getVersion() {
+ return version;
+ }
+
+ //-------------------------------------------------------------------
+ // Returns the actual protocol version of the request PDU.
+ //-------------------------------------------------------------------
+
+ public int getRequestPduVersion() {
+ return request.getRequestPduVersion();
+ }
+
+ //-------------------------------------------------------------------
+ // Returns the SnmpMibNode associated with the given handler
+ //-------------------------------------------------------------------
+
+ public SnmpMibNode getMetaNode(Handler handler) {
+ return handler.meta;
+ }
+
+ //-------------------------------------------------------------------
+ // Indicates the depth of the arc in the OID that identifies the
+ // SnmpMibNode associated with the given handler
+ //-------------------------------------------------------------------
+
+ public int getOidDepth(Handler handler) {
+ return handler.depth;
+ }
+
+ //-------------------------------------------------------------------
+ // returns an enumeration of the SnmpMibSubRequest's to be invoked on
+ // the SnmpMibNode associated with a given Handler node.
+ // If this node is a group, there will be a single subrequest.
+ // If it is a table, there will be one subrequest per entry involved.
+ //-------------------------------------------------------------------
+
+ public Enumeration getSubRequests(Handler handler) {
+ return new Enum(this,handler);
+ }
+
+ //-------------------------------------------------------------------
+ // returns an enumeration of the Handlers stored in the Hashtable.
+ //-------------------------------------------------------------------
+
+ public Enumeration getHandlers() {
+ return hashtable.elements();
+ }
+
+ //-------------------------------------------------------------------
+ // adds a varbind to a handler node sublist
+ //-------------------------------------------------------------------
+
+ public void add(SnmpMibNode meta, int depth, SnmpVarBind varbind)
+ throws SnmpStatusException {
+ registerNode(meta,depth,null,varbind,false,null);
+ }
+
+ //-------------------------------------------------------------------
+ // adds an entry varbind to a handler node sublist
+ //-------------------------------------------------------------------
+
+ public void add(SnmpMibNode meta, int depth, SnmpOid entryoid,
+ SnmpVarBind varbind, boolean isnew)
+ throws SnmpStatusException {
+ registerNode(meta,depth,entryoid,varbind,isnew,null);
+ }
+
+ //-------------------------------------------------------------------
+ // adds an entry varbind to a handler node sublist - specifying the
+ // varbind which holds the row status
+ //-------------------------------------------------------------------
+
+ public void add(SnmpMibNode meta, int depth, SnmpOid entryoid,
+ SnmpVarBind varbind, boolean isnew,
+ SnmpVarBind statusvb)
+ throws SnmpStatusException {
+ registerNode(meta,depth,entryoid,varbind,isnew,statusvb);
+ }
+
+
+ //-------------------------------------------------------------------
+ //-------------------------------------------------------------------
+ // Protected interface
+ //-------------------------------------------------------------------
+ //-------------------------------------------------------------------
+
+ //-------------------------------------------------------------------
+ // Type of the request (see SnmpDefinitions)
+ //-------------------------------------------------------------------
+
+ void setPduType(int pduType) {
+ type = pduType;
+ setreqflag = ((pduType == SnmpDefinitions.pduWalkRequest) ||
+ (pduType == SnmpDefinitions.pduSetRequestPdu));
+ }
+
+ //-------------------------------------------------------------------
+ // We deal with a GET-NEXT request
+ //-------------------------------------------------------------------
+
+ void setGetNextFlag() {
+ getnextflag = true;
+ }
+
+ //-------------------------------------------------------------------
+ // Tell whether creation is allowed.
+ //-------------------------------------------------------------------
+ void switchCreationFlag(boolean flag) {
+ creationflag = flag;
+ }
+
+
+ //-------------------------------------------------------------------
+ // Returns the subrequest handled by the SnmpMibNode itself
+ // (in principle, only for Groups)
+ //-------------------------------------------------------------------
+
+ SnmpMibSubRequest getSubRequest(Handler handler) {
+ if (handler == null) return null;
+ return new SnmpMibSubRequestImpl(request,handler.getSubList(),
+ null,false,getnextflag,null);
+ }
+
+ //-------------------------------------------------------------------
+ // Returns the subrequest associated with the entry identified by
+ // the given entry (only for tables)
+ //-------------------------------------------------------------------
+
+ SnmpMibSubRequest getSubRequest(Handler handler, SnmpOid oid) {
+ if (handler == null) return null;
+ final int pos = handler.getEntryPos(oid);
+ if (pos == -1) return null;
+ return new SnmpMibSubRequestImpl(request,
+ handler.getEntrySubList(pos),
+ handler.getEntryOid(pos),
+ handler.isNewEntry(pos),
+ getnextflag,
+ handler.getRowStatusVarBind(pos));
+ }
+
+ //-------------------------------------------------------------------
+ // Returns the subrequest associated with the entry identified by
+ // the given entry (only for tables). The `entry' parameter is an
+ // index relative to the position of the entry in the handler sublist.
+ //-------------------------------------------------------------------
+
+ SnmpMibSubRequest getSubRequest(Handler handler, int entry) {
+ if (handler == null) return null;
+ return new
+ SnmpMibSubRequestImpl(request,handler.getEntrySubList(entry),
+ handler.getEntryOid(entry),
+ handler.isNewEntry(entry),getnextflag,
+ handler.getRowStatusVarBind(entry));
+ }
+
+ //-------------------------------------------------------------------
+ //-------------------------------------------------------------------
+ // Private section
+ //-------------------------------------------------------------------
+ //-------------------------------------------------------------------
+
+
+ //-------------------------------------------------------------------
+ // stores a handler node in the Hashtable
+ //-------------------------------------------------------------------
+
+ private void put(Object key, Handler handler) {
+ if (handler == null) return;
+ if (key == null) return;
+ if (hashtable == null) hashtable = new Hashtable<Object, Handler>();
+ hashtable.put(key,handler);
+ }
+
+ //-------------------------------------------------------------------
+ // finds a handler node in the Hashtable
+ //-------------------------------------------------------------------
+
+ private Handler get(Object key) {
+ if (key == null) return null;
+ if (hashtable == null) return null;
+ return hashtable.get(key);
+ }
+
+ //-------------------------------------------------------------------
+ // Search for the given oid in `oids'. If none is found, returns -1
+ // otherwise, returns the index at which the oid is located.
+ //-------------------------------------------------------------------
+
+ private static int findOid(SnmpOid[] oids, int count, SnmpOid oid) {
+ final int size = count;
+ int low= 0;
+ int max= size - 1;
+ int curr= low + (max-low)/2;
+ //System.out.println("Try to retrieve: " + oid.toString());
+ while (low <= max) {
+
+ final SnmpOid pos = oids[curr];
+
+ //System.out.println("Compare with" + pos.toString());
+ // never know ...we might find something ...
+ //
+ final int comp = oid.compareTo(pos);
+ if (comp == 0)
+ return curr;
+
+ if (oid.equals(pos)) {
+ return curr;
+ }
+ if (comp > 0) {
+ low = curr + 1;
+ } else {
+ max = curr - 1;
+ }
+ curr = low + (max-low)/2;
+ }
+ return -1;
+ }
+
+ //-------------------------------------------------------------------
+ // Return the index at which the given oid should be inserted in the
+ // `oids' array.
+ //-------------------------------------------------------------------
+
+ private static int getInsertionPoint(SnmpOid[] oids, int count,
+ SnmpOid oid) {
+ final SnmpOid[] localoids = oids;
+ final int size = count;
+ int low= 0;
+ int max= size - 1;
+ int curr= low + (max-low)/2;
+
+
+ while (low <= max) {
+
+ final SnmpOid pos = localoids[curr];
+
+ // never know ...we might find something ...
+ //
+ final int comp= oid.compareTo(pos);
+
+ // In the calling method we will have to check for this case...
+ // if (comp == 0)
+ // return -1;
+ // Returning curr instead of -1 avoids having to call
+ // findOid() first and getInsertionPoint() afterwards.
+ // We can simply call getInsertionPoint() and then checks whether
+ // there's an OID at the returned position which equals the
+ // given OID.
+ if (comp == 0)
+ return curr;
+
+ if (comp>0) {
+ low= curr +1;
+ } else {
+ max= curr -1;
+ }
+ curr= low + (max-low)/2;
+ }
+ return curr;
+ }
+
+ //-------------------------------------------------------------------
+ // adds a varbind in a handler node sublist
+ //-------------------------------------------------------------------
+
+ private void registerNode(SnmpMibNode meta, int depth, SnmpOid entryoid,
+ SnmpVarBind varbind, boolean isnew,
+ SnmpVarBind statusvb)
+ throws SnmpStatusException {
+ if (meta == null) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpRequestTree.class.getName(),
+ "registerNode", "meta-node is null!");
+ return;
+ }
+ if (varbind == null) {
+ SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
+ SnmpRequestTree.class.getName(),
+ "registerNode", "varbind is null!");
+ return ;
+ }
+
+ final Object key = meta;
+
+ // retrieve the handler node associated with the given meta,
+ // if any
+ Handler handler = get(key);
+
+ // If no handler node was found for that meta, create one.
+ if (handler == null) {
+ // if (isDebugOn())
+ // debug("registerNode", "adding node for " +
+ // varbind.oid.toString());
+ handler = new Handler(type);
+ handler.meta = meta;
+ handler.depth = depth;
+ put(key,handler);
+ }
+ // else {
+ // if (isDebugOn())
+ // debug("registerNode","found node for " +
+ // varbind.oid.toString());
+ // }
+
+ // Adds the varbind in the handler node's sublist.
+ if (entryoid == null)
+ handler.addVarbind(varbind);
+ else
+ handler.addVarbind(varbind,entryoid,isnew,statusvb);
+ return ;
+ }
+
+
+ //-------------------------------------------------------------------
+ // private variables
+ //-------------------------------------------------------------------
+
+ private Hashtable<Object, Handler> hashtable = null;
+ // Hashtable of Handler objects
+ private SnmpMibRequest request = null; // The original list of varbinds
+ private int version = 0; // The protocol version
+ private boolean creationflag = false; // Does the operation allow
+ // creation of entries
+ private boolean getnextflag = false; // Does the operation allow
+ // creation of entries
+ private int type = 0; // Request PDU type as defined
+ // in SnmpDefinitions
+ private boolean setreqflag = false; // True if we're processing a
+ // SET request (check/set).
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpStandardMetaServer.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpStandardMetaServer.java
new file mode 100644
index 0000000..da597f7
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpStandardMetaServer.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+/**
+ * <p>
+ * This interface defines the methods that must be implemented by an
+ * SNMP metadata object that needs to interact with an
+ * {@link com.sun.jmx.snmp.agent.SnmpStandardObjectServer} object.
+ * </p>
+ * <p>
+ * All these methods are usually generated by <code>mibgen</code> when
+ * run in standard-metadata mode (default).
+ * </p>
+ * <p><b><i>
+ * This interface is used internally between the generated Metadata and
+ * the SNMP runtime and you shouldn't need to worry about it, because
+ * you will never have to use it directly.
+ * </b></i></p>
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ **/
+public interface SnmpStandardMetaServer {
+ /**
+ * Returns the value of the scalar object identified by the given
+ * OID arc.
+ *
+ * @param arc OID arc of the querried scalar object.
+ *
+ * @return The <CODE>SnmpValue</CODE> of the scalar object identified
+ * by <CODE>arc</CODE>.
+ *
+ * @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 the arc is not valid, or if
+ * access is denied.
+ *
+ **/
+ public SnmpValue get(long arc, Object userData)
+ throws SnmpStatusException ;
+
+ /**
+ * Sets the value of the scalar object identified by the given
+ * OID arc.
+ *
+ * @param x New value for the scalar object identified by
+ * <CODE>arc</CODE>
+ *
+ * @param arc OID arc of the scalar object whose value is set.
+ *
+ * @return The new <CODE>SnmpValue</CODE> of the scalar object
+ * identified by <CODE>arc</CODE>.
+ *
+ * @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 the arc is not valid, or if
+ * access is denied.
+ *
+ **/
+ public SnmpValue set(SnmpValue x, long arc, Object userData)
+ throws SnmpStatusException ;
+
+ /**
+ * Checks that the new desired value of the scalar object identified
+ * by the given OID arc is valid.
+ *
+ * @param x New value for the scalar object identified by
+ * <CODE>arc</CODE>
+ *
+ * @param arc OID arc of the scalar object whose value is set.
+ *
+ * @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 the arc is not valid, or if
+ * access is denied, or if the new desired value is not valid.
+ *
+ **/
+ public void check(SnmpValue x, long arc, Object userData)
+ throws SnmpStatusException ;
+
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpStandardObjectServer.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpStandardObjectServer.java
new file mode 100644
index 0000000..3d1f92c
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpStandardObjectServer.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.jmx.snmp.agent;
+
+// java imports
+//
+import java.io.Serializable;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.Vector;
+
+// jmx imports
+//
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+// SNMP Runtime imports
+//
+
+/**
+ * <p>
+ * This class is a utility class that transform SNMP GET / SET requests
+ * into series of get<i>AttributeName</i>() set<i>AttributeName</i>()
+ * invoked on the MBean.
+ * </p>
+ *
+ * <p>
+ * The transformation relies on the metadata information provided by the
+ * {@link com.sun.jmx.snmp.agent.SnmpStandardMetaServer} object which is
+ * passed as first parameter to every method. This SnmpStandardMetaServer
+ * object is usually a Metadata object generated by <code>mibgen</code>.
+ * </p>
+ *
+ * <p>
+ * The MBean is not invoked directly by this class but through the
+ * metadata object which holds a reference on it.
+ * </p>
+ *
+ * <p><b><i>
+ * This class is used internally by mibgen generated metadata objects and
+ * you should never need to use it directly.
+ * </b></i></p>
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ **/
+
+public class SnmpStandardObjectServer implements Serializable {
+ private static final long serialVersionUID = -4641068116505308488L;
+
+ /**
+ * Generic handling of the <CODE>get</CODE> operation.
+ * <p> The default implementation of this method is to loop over the
+ * varbind list associated with the sub-request and to call
+ * <CODE>get(var.oid.getOidArc(depth), data);</CODE>
+ * <pre>
+ * public void get(SnmpStandardMetaServer meta, SnmpMibSubRequest req,
+ * int depth)
+ * throws SnmpStatusException {
+ *
+ * final Object data = req.getUserData();
+ *
+ * for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ *
+ * final SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ *
+ * try {
+ * // This method will generate a SnmpStatusException
+ * // if `depth' is out of bounds.
+ * //
+ * final long id = var.oid.getOidArc(depth);
+ * var.value = meta.get(id, data);
+ * } catch(SnmpStatusException x) {
+ * req.registerGetException(var,x);
+ * }
+ * }
+ * }
+ * </pre>
+ * <p> You can override this method if you need to implement some
+ * specific policies for minimizing the accesses made to some remote
+ * underlying resources.
+ * <p>
+ *
+ * @param meta A pointer to the generated meta-data object which
+ * implements the <code>SnmpStandardMetaServer</code>
+ * interface.
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ public void get(SnmpStandardMetaServer meta, SnmpMibSubRequest req,
+ int depth)
+ throws SnmpStatusException {
+
+ final Object data = req.getUserData();
+
+ for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ final SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ try {
+ final long id = var.oid.getOidArc(depth);
+ var.value = meta.get(id, data);
+ } catch(SnmpStatusException x) {
+ req.registerGetException(var,x);
+ }
+ }
+ }
+
+ /**
+ * Generic handling of the <CODE>set</CODE> operation.
+ * <p> The default implementation of this method is to loop over the
+ * varbind list associated with the sub-request and to call
+ * <CODE>set(var.value, var.oid.getOidArc(depth), data);</CODE>
+ * <pre>
+ * public void set(SnmpStandardMetaServer meta, SnmpMibSubRequest req,
+ * int depth)
+ * throws SnmpStatusException {
+ *
+ * final Object data = req.getUserData();
+ *
+ * for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ *
+ * final SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ *
+ * try {
+ * // This method will generate a SnmpStatusException
+ * // if `depth' is out of bounds.
+ * //
+ * final long id = var.oid.getOidArc(depth);
+ * var.value = meta.set(var.value, id, data);
+ * } catch(SnmpStatusException x) {
+ * req.registerSetException(var,x);
+ * }
+ * }
+ * }
+ * </pre>
+ * <p> You can override this method if you need to implement some
+ * specific policies for minimizing the accesses made to some remote
+ * underlying resources.
+ * <p>
+ *
+ * @param meta A pointer to the generated meta-data object which
+ * implements the <code>SnmpStandardMetaServer</code>
+ * interface.
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ public void set(SnmpStandardMetaServer meta, SnmpMibSubRequest req,
+ int depth)
+ throws SnmpStatusException {
+
+ final Object data = req.getUserData();
+
+ for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ SnmpVarBind var = null;
+ var = (SnmpVarBind) e.nextElement();
+ try {
+ // This method will generate a SnmpStatusException
+ // if `depth' is out of bounds.
+ //
+ final long id = var.oid.getOidArc(depth);
+ var.value = meta.set(var.value, id, data);
+ } catch(SnmpStatusException x) {
+ req.registerSetException(var,x);
+ }
+ }
+ }
+
+ /**
+ * Generic handling of the <CODE>check</CODE> operation.
+ * <p> The default implementation of this method is to loop over the
+ * varbind list associated with the sub-request and to call
+ * <CODE>check(var.value, var.oid.getOidArc(depth), data);</CODE>
+ * <pre>
+ * public void check(SnmpStandardMetaServer meta, SnmpMibSubRequest req,
+ * int depth)
+ * throws SnmpStatusException {
+ *
+ * final Object data = req.getUserData();
+ *
+ * for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ *
+ * final SnmpVarBind var= (SnmpVarBind) e.nextElement();
+ *
+ * try {
+ * // This method will generate a SnmpStatusException
+ * // if `depth' is out of bounds.
+ * //
+ * final long id = var.oid.getOidArc(depth);
+ * meta.check(var.value, id, data);
+ * } catch(SnmpStatusException x) {
+ * req.registerCheckException(var,x);
+ * }
+ * }
+ * }
+ * </pre>
+ * <p> You can override this method if you need to implement some
+ * 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.
+ * <p>
+ *
+ * @param meta A pointer to the generated meta-data object which
+ * implements the <code>SnmpStandardMetaServer</code>
+ * interface.
+ *
+ * @param req The sub-request that must be handled by this node.
+ *
+ * @param depth The depth reached in the OID tree.
+ *
+ * @exception SnmpStatusException An error occurred while accessing
+ * the MIB node.
+ */
+ public void check(SnmpStandardMetaServer meta, SnmpMibSubRequest req,
+ int depth)
+ throws SnmpStatusException {
+
+ final Object data = req.getUserData();
+
+ for (Enumeration e= req.getElements(); e.hasMoreElements();) {
+ final SnmpVarBind var = (SnmpVarBind) e.nextElement();
+ try {
+ // This method will generate a SnmpStatusException
+ // if `depth' is out of bounds.
+ //
+ final long id = var.oid.getOidArc(depth);
+ meta.check(var.value,id,data);
+ } catch(SnmpStatusException x) {
+ req.registerCheckException(var,x);
+ }
+ }
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableCallbackHandler.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableCallbackHandler.java
new file mode 100644
index 0000000..e08ec34
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableCallbackHandler.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.jmx.snmp.agent;
+
+import javax.management.ObjectName;
+import com.sun.jmx.snmp.SnmpStatusException;
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.agent.SnmpMibTable;
+
+/**
+ * This interface ensures the synchronization between Metadata table objects
+ * and bean-like table objects.
+ *
+ * It is used between mibgen generated table meta and table classes.
+ * <p><b><i>
+ * You should never need to use this interface directly.
+ * </p></b></i>
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ **/
+public interface SnmpTableCallbackHandler {
+ /**
+ * This method is called by the SNMP runtime after a new entry
+ * has been added to the table.
+ *
+ * If an SnmpStatusException is raised, the entry will be removed
+ * and the operation will be aborted. In this case, the removeEntryCb()
+ * callback will not be called.
+ *
+ * <p><b><i>
+ * You should never need to use this method directly.
+ * </p></b></i>
+ *
+ **/
+ public void addEntryCb(int pos, SnmpOid row, ObjectName name,
+ Object entry, SnmpMibTable meta)
+ throws SnmpStatusException;
+
+ /**
+ * This method is called by the SNMP runtime after a new entry
+ * has been removed from the table.
+ *
+ * If raised, SnmpStatusException will be ignored.
+ *
+ * <p><b><i>
+ * You should never need to use this method directly.
+ * </p></b></i>
+ *
+ **/
+ public void removeEntryCb(int pos, SnmpOid row, ObjectName name,
+ Object entry, SnmpMibTable meta)
+ throws SnmpStatusException;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableEntryFactory.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableEntryFactory.java
new file mode 100644
index 0000000..6ebdef4
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableEntryFactory.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+import com.sun.jmx.snmp.SnmpStatusException;
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.agent.SnmpMibTable;
+import com.sun.jmx.snmp.agent.SnmpMibSubRequest;
+
+/**
+ * This interface is implemented by mibgen generated table objects
+ * inheriting from {@link com.sun.jmx.snmp.agent.SnmpTableSupport}.
+ * <p>
+ * It is used internally by the metadata whenever a remote SNMP manager
+ * requests the creation of a new entry through an SNMP SET.
+ * </p>
+ * <p>
+ * At creation, the mibgen generated table object retrieves its
+ * corresponding metadata from the MIB and registers with
+ * this metadata as a SnmpTableEntryFactory.
+ * </p>
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ **/
+
+public interface SnmpTableEntryFactory extends SnmpTableCallbackHandler {
+
+ /**
+ * This method is called by the SNMP runtime whenever a new entry
+ * creation is requested by a remote manager.
+ *
+ * The factory is responsible for instantiating the appropriate MBean
+ * and for registering it with the appropriate metadata object.
+ *
+ * Usually this method will:
+ * <ul>
+ * <li>Check whether the creation can be accepted
+ * <li>Instantiate a new entry
+ * <li>Possibly register this entry with the MBeanServer, if needed.
+ * <li>Call <code>addEntry()</code> on the given <code>meta</code> object.
+ * </ul>
+ * This method is usually generated by <code>mibgen</code> on table
+ * objects (inheriting from
+ * {@link com.sun.jmx.snmp.agent.SnmpTableSupport}). <br>
+ *
+ * <p><b><i>
+ * This method is called internally by the SNMP runtime whenever a
+ * new entry creation is requested by a remote SNMP manager.
+ * You should never need to call this method directlty.
+ * </i></b></p>
+ *
+ * @param request The SNMP subrequest containing the sublist of varbinds
+ * for the new entry.
+ * @param rowOid The OID indexing the conceptual row (entry) for which
+ * the creation was requested.
+ * @param depth The depth reached in the OID tree (the position at
+ * which the columnar object ids start in the OIDs
+ * included in the varbind).
+ * @param meta The metadata object impacted by the subrequest
+ *
+ * @exception SnmpStatusException The new entry cannot be created.
+ *
+ **/
+ public void createNewEntry(SnmpMibSubRequest request, SnmpOid rowOid,
+ int depth, SnmpMibTable meta)
+ throws SnmpStatusException;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableEntryNotification.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableEntryNotification.java
new file mode 100644
index 0000000..a3b6454
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableEntryNotification.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 1998-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package com.sun.jmx.snmp.agent;
+
+
+
+// jmx imports
+//
+import javax.management.Notification;
+import javax.management.ObjectName;
+
+/**
+ * Represents a notification emitted when an
+ * entry is added or deleted from an SNMP table.
+ * <P>
+ * The <CODE>SnmpTableEntryNotification</CODE> object contains
+ * the reference to the entry added or removed from the table.
+ * <P>
+ * The list of notifications fired by the <CODE>SnmpMibTable</CODE> is
+ * the following:
+ * <UL>
+ * <LI>A new entry has been added to the SNMP table.
+ * <LI>An existing entry has been removed from the SNMP table.
+ </UL>
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ */
+
+public class SnmpTableEntryNotification extends Notification {
+
+ /**
+ * Creates and initializes a table entry notification object.
+ *
+ * @param type The notification type.
+ * @param source The notification producer.
+ * @param sequenceNumber The notification sequence number within the
+ * source object.
+ * @param timeStamp The notification emission date.
+ * @param entry The entry object (may be null if the entry is
+ * registered in the MBeanServer).
+ * @param entryName The ObjectName entry object (may be null if the
+ * entry is not registered in the MBeanServer).
+ * @since 1.5
+ */
+ SnmpTableEntryNotification(String type, Object source,
+ long sequenceNumber, long timeStamp,
+ Object entry, ObjectName entryName) {
+
+ super(type, source, sequenceNumber, timeStamp);
+ this.entry = entry;
+ this.name = entryName;
+ }
+
+ /**
+ * Gets the entry object.
+ * May be null if the entry is registered in the MBeanServer, and the
+ * MIB is using the generic MetaData (see mibgen).
+ *
+ * @return The entry.
+ */
+ public Object getEntry() {
+ return entry;
+ }
+
+ /**
+ * Gets the ObjectName of the entry.
+ * May be null if the entry is not registered in the MBeanServer.
+ *
+ * @return The ObjectName of the entry.
+ * @since 1.5
+ */
+ public ObjectName getEntryName() {
+ return name;
+ }
+
+ // PUBLIC VARIABLES
+ //-----------------
+
+ /**
+ * Notification type denoting that a new entry has been added to the
+ * SNMP table.
+ * <BR>The value of this notification type is
+ * <CODE>jmx.snmp.table.entry.added</CODE>.
+ */
+ public static final String SNMP_ENTRY_ADDED =
+ "jmx.snmp.table.entry.added";
+
+ /**
+ * Notification type denoting that an entry has been removed from the
+ * SNMP table.
+ * <BR>The value of this notification type is
+ * <CODE>jmx.snmp.table.entry.removed</CODE>.
+ */
+ public static final String SNMP_ENTRY_REMOVED =
+ "jmx.snmp.table.entry.removed";
+
+ // PRIVATE VARIABLES
+ //------------------
+
+ /**
+ * The entry object.
+ * @serial
+ */
+ private final Object entry;
+
+ /**
+ * The entry name.
+ * @serial
+ * @since 1.5
+ */
+ private final ObjectName name;
+
+ // Ensure compatibility
+ //
+ private static final long serialVersionUID = 5832592016227890252L;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableSupport.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableSupport.java
new file mode 100644
index 0000000..e61537e
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpTableSupport.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+
+
+// java imports
+//
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.ArrayList;
+
+// jmx imports
+//
+import javax.management.Notification;
+import javax.management.ObjectName;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.NotificationBroadcaster;
+import javax.management.MBeanNotificationInfo;
+import javax.management.ListenerNotFoundException;
+import com.sun.jmx.snmp.SnmpOid;
+import com.sun.jmx.snmp.SnmpValue;
+import com.sun.jmx.snmp.SnmpVarBind;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+/**
+ * This class is an abstraction for an SNMP table.
+ * It is the base class for implementing SNMP tables in the
+ * MBean world.
+ *
+ * <p>
+ * Its responsibility is to synchronize the MBean view of the table
+ * (Table of entries) with the MIB view (array of OID indexes). Each
+ * object of this class will be bound to the Metadata object which
+ * manages the same SNMP Table within the MIB.
+ * </p>
+ *
+ * <p>
+ * For each table defined in a MIB, mibgen will generate a specific
+ * class called Table<i>TableName</i> that will subclass this class, and
+ * a corresponding <i>TableName</i>Meta class extending SnmpMibTable
+ * and corresponding to the MIB view of the same table.
+ * </p>
+ *
+ * <p>
+ * Objects of this class are instantiated by MBeans representing
+ * the SNMP Group to which the table belong.
+ * </p>
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ * @see com.sun.jmx.snmp.agent.SnmpTableEntryFactory
+ * @see com.sun.jmx.snmp.agent.SnmpMibTable
+ *
+ */
+public abstract class SnmpTableSupport implements SnmpTableEntryFactory,
+// NPCTE fix for bugId 4499265, esc 0, MR 04 sept 2001
+// SnmpTableCallbackHandler {
+ SnmpTableCallbackHandler, Serializable {
+// end of NPCTE fix for bugId 4499265
+
+ //-----------------------------------------------------------------
+ //
+ // Protected Variables
+ //
+ //-----------------------------------------------------------------
+
+ /**
+ * The list of entries
+ **/
+ protected List<Object> entries;
+
+ /**
+ * The associated metadata object
+ **/
+ protected SnmpMibTable meta;
+
+ /**
+ * The MIB to which this table belongs
+ **/
+ protected SnmpMib theMib;
+
+ //-----------------------------------------------------------------
+ //
+ // Private Variables
+ //
+ //-----------------------------------------------------------------
+
+ /**
+ * This variable is initialized while binding this object to its
+ * corresponding meta object.
+ **/
+ private boolean registrationRequired = false;
+
+
+
+ //-----------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //-----------------------------------------------------------------
+
+ /**
+ * Initializes the table.
+ * The steps are these:
+ * <ul><li> allocate an array for storing entry object,</li>
+ * <li> retrieve the corresponding metadata object
+ * from the MIB,
+ * <li> bind this object to the corresponding metadata object
+ * from the MIB.</li>
+ * </ul>
+ *
+ * @param mib The MIB to which this table belong.
+ *
+ **/
+ protected SnmpTableSupport(SnmpMib mib) {
+ theMib = mib;
+ meta = getRegisteredTableMeta(mib);
+ bindWithTableMeta();
+ entries = allocateTable();
+ }
+
+
+ //-----------------------------------------------------------------
+ //
+ // Implementation of the SnmpTableEntryFactory interface
+ //
+ //-----------------------------------------------------------------
+
+ /**
+ * Creates a new entry in the table.
+ *
+ * This factory method is generated by mibgen and used internally.
+ * It is part of the
+ * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface.
+ * You may subclass this method to implement any specific behaviour
+ * your application requires.
+ *
+ * @exception SnmpStatusException if the entry cannot be created.
+ **/
+ public abstract void createNewEntry(SnmpMibSubRequest request,
+ SnmpOid rowOid, int depth,
+ SnmpMibTable meta)
+ throws SnmpStatusException;
+
+
+ //-----------------------------------------------------------------
+ //
+ // Public methods
+ //
+ //-----------------------------------------------------------------
+
+ /**
+ * Returns the entry located at the given position in the table.
+ *
+ * @return The entry located at the given position, <code>null</code>
+ * if no entry can be found at this position.
+ **/
+ // XXXX xxxx zzz ZZZZ => public? or protected?
+ public Object getEntry(int pos) {
+ if (entries == null) return null;
+ return entries.get(pos);
+ }
+
+ /**
+ * Returns the number of entries registered in the table.
+ *
+ * @return The number of entries registered in the table.
+ **/
+ public int getSize() {
+ return meta.getSize();
+ }
+
+ /**
+ * This method lets you dynamically switch the creation policy.
+ *
+ * <CODE>setCreationEnabled()</CODE> will switch the policy of
+ * remote entry creation via SET operations, by calling
+ * <code>setCreationEnabled()</code> on the metadata object
+ * associated with this table.
+ * <BR> By default remote entry creation via SET operation is disabled.
+ *
+ * @param remoteCreationFlag Tells whether remote entry creation must
+ * be enabled or disabled.
+ * <li>
+ * <CODE>setCreationEnabled(true)</CODE> will enable remote entry
+ * creation via SET operations.</li>
+ * <li>
+ * <CODE>setCreationEnabled(false)</CODE> will disable remote entry
+ * creation via SET operations.</li>
+ * <p> By default remote entry creation via SET operation is disabled.
+ * </p>
+ *
+ * @see com.sun.jmx.snmp.agent.SnmpMibTable
+ *
+ **/
+ public void setCreationEnabled(boolean remoteCreationFlag) {
+ meta.setCreationEnabled(remoteCreationFlag);
+ }
+
+ /**
+ * Tells whether a new entry should be created when a SET operation
+ * is received for an entry that does not exist yet.
+ * This method calls <code>isCreationEnabled()</code> on the metadata
+ * object associated with this table.
+ *
+ * @return true if a new entry must be created, false otherwise.<br>
+ * [default: returns <CODE>false</CODE>]
+ *
+ * @see com.sun.jmx.snmp.agent.SnmpMibTable
+ **/
+ public boolean isCreationEnabled() {
+ return meta.isCreationEnabled();
+ }
+
+ /**
+ * Tells whether the metadata object to which this table is linked
+ * requires entries to be registered. In this case passing an
+ * ObjectName when registering entries will be mandatory.
+ *
+ * @return <code>true</code> if the associated metadata requires entries
+ * to be registered (mibgen generated generic metadata).
+ **/
+ public boolean isRegistrationRequired() {
+ return registrationRequired;
+ }
+
+ /**
+ * Builds an entry SnmpIndex from its row OID.
+ *
+ * This method is generated by mibgen and used internally.
+ *
+ * @param rowOid The SnmpOid object identifying a table entry.
+ *
+ * @return The SnmpIndex of the entry identified by <code>rowOid</code>.
+ *
+ * @exception SnmpStatusException if the index cannot be built from the
+ * given OID.
+ **/
+ public SnmpIndex buildSnmpIndex(SnmpOid rowOid)
+ throws SnmpStatusException {
+ return buildSnmpIndex(rowOid.longValue(false), 0);
+ }
+
+ /**
+ * Builds an SnmpOid from an SnmpIndex object.
+ *
+ * This method is generated by mibgen and used internally.
+ *
+ * @param index An SnmpIndex object identifying a table entry.
+ *
+ * @return The SnmpOid form of the given entry index.
+ *
+ * @exception SnmpStatusException if the given index is not valid.
+ **/
+ public abstract SnmpOid buildOidFromIndex(SnmpIndex index)
+ throws SnmpStatusException;
+
+ /**
+ * Builds the default ObjectName of an entry from the SnmpIndex
+ * identifying this entry. No access is made on the entry itself.
+ *
+ * This method is generated by mibgen and used internally.
+ * You can subclass this method if you want to change the default
+ * ObjectName policy. This is only meaningfull when entries
+ * are registered MBeans.
+ *
+ * @param index The SnmpIndex identifying the entry from which we
+ * want to build the default ObjectName.
+ *
+ * @return The default ObjectName for the entry identified by
+ * the given index.
+ *
+ * @exception SnmpStatusException if the given index is not valid.
+ **/
+ public abstract ObjectName buildNameFromIndex(SnmpIndex index)
+ throws SnmpStatusException;
+
+
+ //-----------------------------------------------------------------
+ //
+ // Implementation of the SnmpTableEntryFactory interface
+ //
+ //-----------------------------------------------------------------
+
+ /**
+ * This callback is called by the associated metadata object
+ * when a new table entry has been registered in the
+ * table metadata.
+ *
+ * This method will update the <code>entries</code> list.
+ *
+ * @param pos The position at which the new entry was inserted
+ * in the table.
+ * @param row The row OID of the new entry
+ * @param name The ObjectName of the new entry (as specified by the
+ * factory)
+ * @param entry The new entry (as returned by the factory)
+ * @param meta The table metadata object.
+ *
+ **/
+ public void addEntryCb(int pos, SnmpOid row, ObjectName name,
+ Object entry, SnmpMibTable meta)
+ throws SnmpStatusException {
+ try {
+ if (entries != null) entries.add(pos,entry);
+ } catch (Exception e) {
+ throw new SnmpStatusException(SnmpStatusException.noSuchName);
+ }
+ }
+
+ /**
+ * This callback is called by the associated metadata object
+ * when a new table entry has been removed from the
+ * table metadata.
+ *
+ * This method will update the <code>entries</code> list.
+ *
+ * @param pos The position from which the entry was deleted
+ * @param row The row OID of the deleted entry
+ * @param name The ObjectName of the deleted entry (may be null if
+ * ObjectName's were not required)
+ * @param entry The deleted entry (may be null if only ObjectName's
+ * were required)
+ * @param meta The table metadata object.
+ *
+ **/
+ public void removeEntryCb(int pos, SnmpOid row, ObjectName name,
+ Object entry, SnmpMibTable meta)
+ throws SnmpStatusException {
+ try {
+ if (entries != null) entries.remove(pos);
+ } catch (Exception e) {
+ }
+ }
+
+
+
+ /**
+ * Enables to add an SNMP entry listener to this
+ * <CODE>SnmpMibTable</CODE>.
+ *
+ * @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.
+ */
+ public void
+ addNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback) {
+ meta.addNotificationListener(listener,filter,handback);
+ }
+
+ /**
+ * Enables to remove an SNMP entry listener from this
+ * <CODE>SnmpMibTable</CODE>.
+ *
+ * @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.
+ */
+ public synchronized void
+ removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {
+ meta.removeNotificationListener(listener);
+ }
+
+ /**
+ * Returns a <CODE>NotificationInfo</CODE> object containing the
+ * notification class and the notification type sent by the
+ * <CODE>SnmpMibTable</CODE>.
+ */
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ return meta.getNotificationInfo();
+ }
+
+ //-----------------------------------------------------------------
+ //
+ // Protected Abstract methods
+ //
+ //-----------------------------------------------------------------
+
+ /**
+ * Builds an SnmpIndex object from the index part of an OID.
+ *
+ * This method is generated by mibgen and used internally.
+ *
+ * @param oid The OID from which to build the index, represented
+ * as an array of long.
+ * @param start The position where to start from in the OID array.
+ *
+ * @return The SnmpOid form of the given entry index.
+ *
+ * @exception SnmpStatusException if the given index is not valid.
+ **/
+ protected abstract SnmpIndex buildSnmpIndex(long oid[], int start )
+ throws SnmpStatusException;
+
+ /**
+ * Returns the metadata object associated with this table.
+ *
+ * This method is generated by mibgen and used internally.
+ *
+ * @param mib The SnmpMib object holding the Metadata corresponding
+ * to this table.
+ *
+ * @return The metadata object associated with this table.
+ * Returns <code>null</code> if this implementation of the
+ * MIB doesn't support this table.
+ **/
+ protected abstract SnmpMibTable getRegisteredTableMeta(SnmpMib mib);
+
+
+ //-----------------------------------------------------------------
+ //
+ // Protected methods
+ //
+ //-----------------------------------------------------------------
+
+ /**
+ * Allocates an ArrayList for storing table entries.
+ *
+ * This method is called within the constructor at object creation.
+ * Any object implementing the {@link java.util.List} interface can
+ * be used.
+ *
+ * @return A new list in which to store entries. If <code>null</code>
+ * is returned then no entry will be stored in the list
+ * and getEntry() will always return null.
+ **/
+ protected List<Object> allocateTable() {
+ return new ArrayList<Object>();
+ }
+
+ /**
+ * Add an entry in this table.
+ *
+ * This method registers an entry in the table and perform
+ * synchronization with the associated table metadata object.
+ *
+ * This method assumes that the given entry will not be registered,
+ * or will be registered with its default ObjectName built from the
+ * associated SnmpIndex.
+ * <p>
+ * If the entry is going to be registered, then
+ * {@link com.sun.jmx.snmp.agent.SnmpTableSupport#addEntry(SnmpIndex, ObjectName, Object)} should be prefered.
+ * <br> This function is mainly provided for backward compatibility.
+ *
+ * @param index The SnmpIndex built from the given entry.
+ * @param entry The entry that should be added in the table.
+ *
+ * @exception SnmpStatusException if the entry cannot be registered with
+ * the given index.
+ **/
+ protected void addEntry(SnmpIndex index, Object entry)
+ throws SnmpStatusException {
+ SnmpOid oid = buildOidFromIndex(index);
+ ObjectName name = null;
+ if (isRegistrationRequired()) {
+ name = buildNameFromIndex(index);
+ }
+ meta.addEntry(oid,name,entry);
+ }
+
+ /**
+ * Add an entry in this table.
+ *
+ * This method registers an entry in the table and performs
+ * synchronization with the associated table metadata object.
+ *
+ * @param index The SnmpIndex built from the given entry.
+ * @param name The ObjectName with which this entry will be registered.
+ * @param entry The entry that should be added in the table.
+ *
+ * @exception SnmpStatusException if the entry cannot be registered with
+ * the given index.
+ **/
+ protected void addEntry(SnmpIndex index, ObjectName name, Object entry)
+ throws SnmpStatusException {
+ SnmpOid oid = buildOidFromIndex(index);
+ meta.addEntry(oid,name,entry);
+ }
+
+ /**
+ * Remove an entry from this table.
+ *
+ * This method unregisters an entry from the table and performs
+ * synchronization with the associated table metadata object.
+ *
+ * @param index The SnmpIndex identifying the entry.
+ * @param entry The entry that should be removed in the table. This
+ * parameter is optional and can be omitted if it doesn't
+ * need to be passed along to the
+ * <code>removeEntryCb()</code> callback defined in the
+ * {@link com.sun.jmx.snmp.agent.SnmpTableCallbackHandler}
+ * interface.
+ *
+ * @exception SnmpStatusException if the entry cannot be unregistered.
+ **/
+ protected void removeEntry(SnmpIndex index, Object entry)
+ throws SnmpStatusException {
+ SnmpOid oid = buildOidFromIndex(index);
+ meta.removeEntry(oid,entry);
+ }
+
+ // protected void removeEntry(ObjectName name, Object entry)
+ // throws SnmpStatusException {
+ // meta.removeEntry(name,entry);
+ // }
+
+ /**
+ * Returns the entries in the table.
+ *
+ * @return An Object[] array containing the entries registered in the
+ * table.
+ **/
+ protected Object[] getBasicEntries() {
+ if (entries == null) return null;
+ Object[] array= new Object[entries.size()];
+ entries.toArray(array);
+ return array;
+ }
+
+ /**
+ * Binds this table with its associated metadata, registering itself
+ * as an SnmpTableEntryFactory.
+ **/
+ protected void bindWithTableMeta() {
+ if (meta == null) return;
+ registrationRequired = meta.isRegistrationRequired();
+ meta.registerEntryFactory(this);
+ }
+
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpUserDataFactory.java b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpUserDataFactory.java
new file mode 100644
index 0000000..2c7c07f
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/SnmpUserDataFactory.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.snmp.agent;
+
+import com.sun.jmx.snmp.SnmpPduPacket;
+import com.sun.jmx.snmp.SnmpPdu;
+import com.sun.jmx.snmp.SnmpStatusException;
+
+/**
+ * This interface is provided to enable fine customization of the SNMP
+ * agent behaviour.
+ *
+ * <p>You will not need to implement this interface except if your agent
+ * needs extra customization requiring some contextual information.</p>
+ *
+ * <p>If an SnmpUserDataFactory is set on the SnmpAdaptorServer, then a new
+ * object containing user-data will be allocated through this factory
+ * for each incoming request. This object will be passed along to
+ * the SnmpMibAgent within SnmpMibRequest objects. By default, no
+ * SnmpUserDataFactory is set on the SnmpAdaptorServer, and the contextual
+ * object passed to SnmpMibAgent is null.</p>
+ *
+ * <p>You can use this feature to obtain on contextual information
+ * (such as community string etc...) or to implement a caching
+ * mechanism, or for whatever purpose might be required by your specific
+ * agent implementation.</p>
+ *
+ * <p>The sequence <code>allocateUserData() / releaseUserData()</code> can
+ * also be used to implement a caching mechanism:
+ * <ul>
+ * <li><code>allocateUserData()</code> could be used to allocate
+ * some cache space,</li>
+ * <li>and <code>releaseUserData()</code> could be used to flush it.</li>
+ * </ul></p>
+ *
+ * <p><b>This API is a Sun Microsystems internal API and is subject
+ * to change without notice.</b></p>
+ * @see com.sun.jmx.snmp.agent.SnmpMibRequest
+ * @see com.sun.jmx.snmp.agent.SnmpMibAgent
+ * @see com.sun.jmx.snmp.daemon.SnmpAdaptorServer
+ *
+ **/
+public interface SnmpUserDataFactory {
+ /**
+ * Called by the <CODE>SnmpAdaptorServer</CODE> adaptor.
+ * Allocate a contextual object containing some user data. This method
+ * is called once for each incoming SNMP request. The scope
+ * of this object will be the whole request. Since the request can be
+ * handled in several threads, the user should make sure that this
+ * object can be accessed in a thread-safe manner. The SNMP framework
+ * will never access this object directly - it will simply pass
+ * it to the <code>SnmpMibAgent</code> within
+ * <code>SnmpMibRequest</code> objects - from where it can be retrieved
+ * through the {@link com.sun.jmx.snmp.agent.SnmpMibRequest#getUserData() getUserData()} accessor.
+ * <code>null</code> is considered to be a valid return value.
+ *
+ * This method is called just after the SnmpPduPacket has been
+ * decoded.
+ *
+ * @param requestPdu The SnmpPduPacket received from the SNMP manager.
+ * <b>This parameter is owned by the SNMP framework and must be
+ * considered as transient.</b> If you wish to keep some of its
+ * content after this method returns (by storing it in the
+ * returned object for instance) you should clone that
+ * information.
+ *
+ * @return A newly allocated user-data contextual object, or
+ * <code>null</code>
+ * @exception SnmpStatusException If an SnmpStatusException is thrown,
+ * the request will be aborted.
+ *
+ * @since 1.5
+ **/
+ public Object allocateUserData(SnmpPdu requestPdu)
+ throws SnmpStatusException;
+
+ /**
+ * Called by the <CODE>SnmpAdaptorServer</CODE> adaptor.
+ * Release a previously allocated contextual object containing user-data.
+ * This method is called just before the responsePdu is sent back to the
+ * manager. It gives the user a chance to alter the responsePdu packet
+ * before it is encoded, and to free any resources that might have
+ * been allocated when creating the contextual object.
+ *
+ * @param userData The contextual object being released.
+ * @param responsePdu The SnmpPduPacket that will be sent back to the
+ * SNMP manager.
+ * <b>This parameter is owned by the SNMP framework and must be
+ * considered as transient.</b> If you wish to keep some of its
+ * content after this method returns you should clone that
+ * information.
+ *
+ * @exception SnmpStatusException If an SnmpStatusException is thrown,
+ * the responsePdu is dropped and nothing is returned to
+ * to the manager.
+ *
+ * @since 1.5
+ **/
+ public void releaseUserData(Object userData, SnmpPdu responsePdu)
+ throws SnmpStatusException;
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/agent/package.html b/jdk/src/share/classes/com/sun/jmx/snmp/agent/package.html
new file mode 100644
index 0000000..d091c65
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/agent/package.html
@@ -0,0 +1,34 @@
+<HTML>
+<HEAD>
+<!--
+
+Copyright 1999-2003 Sun Microsystems, Inc. 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. Sun designates this
+particular file as subject to the "Classpath" exception as provided
+by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+CA 95054 USA or visit www.sun.com if you need additional information or
+have any questions.
+-->
+</HEAD>
+<BODY>
+Provides the classes for creating an <B>SNMP agent</B>.
+<p><b>This API is a Sun Microsystems internal API and is subject
+ to change without notice.</b></p>
+</BODY>
+</HTML>