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