| /* |
| * Copyright (c) 2000, 2012, 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.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<SnmpVarBind> e=req.getElements(); e.hasMoreElements();) { |
| final SnmpVarBind var= 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<SnmpVarBind> e=req.getElements(); e.hasMoreElements();) { |
| final SnmpVarBind var= 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; |
| 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<SnmpVarBind> e=req.getElements(); e.hasMoreElements();) { |
| final SnmpVarBind var= 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); |
| } |
| } |
| |
| } |