1. /*
  2. * @(#)file SnmpGenericObjectServer.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 1.12
  5. * @(#)date 04/09/15
  6. *
  7. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  8. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  9. */
  10. package com.sun.jmx.snmp.agent;
  11. // java imports
  12. //
  13. import java.util.Vector;
  14. import java.util.Enumeration;
  15. import java.util.Iterator;
  16. // jmx imports
  17. //
  18. import javax.management.AttributeList;
  19. import javax.management.Attribute;
  20. import javax.management.MBeanException;
  21. import javax.management.MBeanServer;
  22. import javax.management.ObjectName;
  23. import javax.management.ReflectionException;
  24. import javax.management.InstanceNotFoundException;
  25. import javax.management.InvalidAttributeValueException;
  26. import javax.management.InstanceAlreadyExistsException;
  27. import javax.management.MBeanRegistrationException;
  28. import javax.management.NotCompliantMBeanException;
  29. import javax.management.RuntimeOperationsException;
  30. import com.sun.jmx.snmp.SnmpOid;
  31. import com.sun.jmx.snmp.SnmpValue;
  32. import com.sun.jmx.snmp.SnmpVarBind;
  33. import com.sun.jmx.snmp.SnmpStatusException;
  34. /**
  35. * <p>
  36. * This class is a utility class that transforms SNMP GET / SET requests
  37. * into standard JMX getAttributes() setAttributes() requests.
  38. * </p>
  39. *
  40. * <p>
  41. * The transformation relies on the metadata information provided by the
  42. * {@link com.sun.jmx.snmp.agent.SnmpGenericMetaServer} object which is
  43. * passed as the first parameter to every method. This SnmpGenericMetaServer
  44. * object is usually a Metadata object generated by <code>mibgen</code>.
  45. * </p>
  46. *
  47. * <p><b><i>
  48. * This class is used internally by mibgen generated metadata objects and
  49. * you should never need to use it directly.
  50. * </b></i></p>
  51. * <p><b>This API is a Sun Microsystems internal API and is subject
  52. * to change without notice.</b></p>
  53. **/
  54. public class SnmpGenericObjectServer {
  55. // ----------------------------------------------------------------------
  56. //
  57. // Protected variables
  58. //
  59. // ----------------------------------------------------------------------
  60. /**
  61. * The MBean server through which the MBeans will be accessed.
  62. **/
  63. protected final MBeanServer server;
  64. // ----------------------------------------------------------------------
  65. //
  66. // Constructors
  67. //
  68. // ----------------------------------------------------------------------
  69. /**
  70. * Builds a new SnmpGenericObjectServer. Usually there will be a single
  71. * object of this type per MIB.
  72. *
  73. * @param server The MBeanServer in which the MBean accessed by this
  74. * MIB are registered.
  75. **/
  76. public SnmpGenericObjectServer(MBeanServer server) {
  77. this.server = server;
  78. }
  79. /**
  80. * Execute an SNMP GET request.
  81. *
  82. * <p>
  83. * This method first builds the list of attributes that need to be
  84. * retrieved from the MBean and then calls getAttributes() on the
  85. * MBean server. Then it updates the SnmpMibSubRequest with the values
  86. * retrieved from the MBean.
  87. * </p>
  88. *
  89. * <p>
  90. * The SNMP metadata information is obtained through the given
  91. * <code>meta</code> object, which usually is an instance of a
  92. * <code>mibgen</code> generated class.
  93. * </p>
  94. *
  95. * <p><b><i>
  96. * This method is called internally by <code>mibgen</code> generated
  97. * objects and you should never need to call it directly.
  98. * </i></b></p>
  99. *
  100. * @param meta The metadata object impacted by the subrequest
  101. * @param name The ObjectName of the MBean impacted by this subrequest
  102. * @param req The SNMP subrequest to execute on the MBean
  103. * @param depth The depth of the SNMP object in the OID tree.
  104. *
  105. * @exception SnmpStatusException whenever an SNMP exception must be
  106. * raised. Raising an exception will abort the request.<br>
  107. * Exceptions should never be raised directly, but only by means of
  108. * <code>
  109. * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
  110. * </code>
  111. **/
  112. public void get(SnmpGenericMetaServer meta, ObjectName name,
  113. SnmpMibSubRequest req, int depth)
  114. throws SnmpStatusException {
  115. // java.lang.System.out.println(">>>>>>>>> GET " + name);
  116. final int size = req.getSize();
  117. final Object data = req.getUserData();
  118. final String[] nameList = new String[size];
  119. final SnmpVarBind[] varList = new SnmpVarBind[size];
  120. final long[] idList = new long[size];
  121. int i = 0;
  122. for (Enumeration e=req.getElements(); e.hasMoreElements();) {
  123. final SnmpVarBind var= (SnmpVarBind) e.nextElement();
  124. try {
  125. final long id = var.oid.getOidArc(depth);
  126. nameList[i] = meta.getAttributeName(id);
  127. varList[i] = var;
  128. idList[i] = id;
  129. // Check the access rights according to the MIB.
  130. // The MBean might be less restrictive (have a getter
  131. // while the MIB defines the variable as AFN)
  132. //
  133. meta.checkGetAccess(id,data);
  134. //java.lang.System.out.println(nameList[i] + " added.");
  135. i++;
  136. } catch(SnmpStatusException x) {
  137. //java.lang.System.out.println("exception for " + nameList[i]);
  138. //x.printStackTrace();
  139. req.registerGetException(var,x);
  140. }
  141. }
  142. AttributeList result = null;
  143. int errorCode = SnmpStatusException.noSuchInstance;
  144. try {
  145. result = server.getAttributes(name,nameList);
  146. } catch (InstanceNotFoundException f) {
  147. //java.lang.System.out.println(name + ": instance not found.");
  148. //f.printStackTrace();
  149. result = new AttributeList();
  150. } catch (ReflectionException r) {
  151. //java.lang.System.out.println(name + ": reflexion error.");
  152. //r.printStackTrace();
  153. result = new AttributeList();
  154. } catch (Exception x) {
  155. result = new AttributeList();
  156. }
  157. final Iterator it = result.iterator();
  158. for (int j=0; j < i; j++) {
  159. if (!it.hasNext()) {
  160. //java.lang.System.out.println(name + "variable[" + j +
  161. // "] absent");
  162. final SnmpStatusException x =
  163. new SnmpStatusException(errorCode);
  164. req.registerGetException(varList[j],x);
  165. continue;
  166. }
  167. final Attribute att = (Attribute) it.next();
  168. while ((j < i) && (! nameList[j].equals(att.getName()))) {
  169. //java.lang.System.out.println(name + "variable[" +j +
  170. // "] not found");
  171. final SnmpStatusException x =
  172. new SnmpStatusException(errorCode);
  173. req.registerGetException(varList[j],x);
  174. j++;
  175. }
  176. if ( j == i) break;
  177. try {
  178. varList[j].value =
  179. meta.buildSnmpValue(idList[j],att.getValue());
  180. } catch (SnmpStatusException x) {
  181. req.registerGetException(varList[j],x);
  182. }
  183. //java.lang.System.out.println(att.getName() + " retrieved.");
  184. }
  185. //java.lang.System.out.println(">>>>>>>>> END GET");
  186. }
  187. /**
  188. * Get the value of an SNMP variable.
  189. *
  190. * <p><b><i>
  191. * You should never need to use this method directly.
  192. * </i></b></p>
  193. *
  194. * @param meta The impacted metadata object
  195. * @param name The ObjectName of the impacted MBean
  196. * @param id The OID arc identifying the variable we're trying to set.
  197. * @param data User contextual data allocated through the
  198. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
  199. *
  200. * @return The value of the variable.
  201. *
  202. * @exception SnmpStatusException whenever an SNMP exception must be
  203. * raised. Raising an exception will abort the request. <br>
  204. * Exceptions should never be raised directly, but only by means of
  205. * <code>
  206. * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
  207. * </code>
  208. **/
  209. public SnmpValue get(SnmpGenericMetaServer meta, ObjectName name,
  210. long id, Object data)
  211. throws SnmpStatusException {
  212. final String attname = meta.getAttributeName(id);
  213. Object result = null;
  214. try {
  215. result = server.getAttribute(name,attname);
  216. } catch (MBeanException m) {
  217. Exception t = m.getTargetException();
  218. if (t instanceof SnmpStatusException)
  219. throw (SnmpStatusException) t;
  220. throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
  221. } catch (Exception e) {
  222. throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
  223. }
  224. return meta.buildSnmpValue(id,result);
  225. }
  226. /**
  227. * Execute an SNMP SET request.
  228. *
  229. * <p>
  230. * This method first builds the list of attributes that need to be
  231. * set on the MBean and then calls setAttributes() on the
  232. * MBean server. Then it updates the SnmpMibSubRequest with the new
  233. * values retrieved from the MBean.
  234. * </p>
  235. *
  236. * <p>
  237. * The SNMP metadata information is obtained through the given
  238. * <code>meta</code> object, which usually is an instance of a
  239. * <code>mibgen</code> generated class.
  240. * </p>
  241. *
  242. * <p><b><i>
  243. * This method is called internally by <code>mibgen</code> generated
  244. * objects and you should never need to call it directly.
  245. * </i></b></p>
  246. *
  247. * @param meta The metadata object impacted by the subrequest
  248. * @param name The ObjectName of the MBean impacted by this subrequest
  249. * @param req The SNMP subrequest to execute on the MBean
  250. * @param depth The depth of the SNMP object in the OID tree.
  251. *
  252. * @exception SnmpStatusException whenever an SNMP exception must be
  253. * raised. Raising an exception will abort the request. <br>
  254. * Exceptions should never be raised directly, but only by means of
  255. * <code>
  256. * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
  257. * </code>
  258. **/
  259. public void set(SnmpGenericMetaServer meta, ObjectName name,
  260. SnmpMibSubRequest req, int depth)
  261. throws SnmpStatusException {
  262. final int size = req.getSize();
  263. final AttributeList attList = new AttributeList(size);
  264. final String[] nameList = new String[size];
  265. final SnmpVarBind[] varList = new SnmpVarBind[size];
  266. final long[] idList = new long[size];
  267. int i = 0;
  268. for (Enumeration e=req.getElements(); e.hasMoreElements();) {
  269. final SnmpVarBind var= (SnmpVarBind) e.nextElement();
  270. try {
  271. final long id = var.oid.getOidArc(depth);
  272. final String attname = meta.getAttributeName(id);
  273. final Object attvalue=
  274. meta.buildAttributeValue(id,var.value);
  275. final Attribute att = new Attribute(attname,attvalue);
  276. attList.add(att);
  277. nameList[i] = attname;
  278. varList[i] = var;
  279. idList[i] = id;
  280. i++;
  281. } catch(SnmpStatusException x) {
  282. req.registerSetException(var,x);
  283. }
  284. }
  285. AttributeList result = null;
  286. int errorCode = SnmpStatusException.noAccess;
  287. try {
  288. result = server.setAttributes(name,attList);
  289. } catch (InstanceNotFoundException f) {
  290. result = new AttributeList();
  291. errorCode = SnmpStatusException.snmpRspInconsistentName;
  292. } catch (ReflectionException r) {
  293. errorCode = SnmpStatusException.snmpRspInconsistentName;
  294. result = new AttributeList();
  295. } catch (Exception x) {
  296. result = new AttributeList();
  297. }
  298. final Iterator it = result.iterator();
  299. for (int j=0; j < i; j++) {
  300. if (!it.hasNext()) {
  301. final SnmpStatusException x =
  302. new SnmpStatusException(errorCode);
  303. req.registerSetException(varList[j],x);
  304. continue;
  305. }
  306. final Attribute att = (Attribute) it.next();
  307. while ((j < i) && (! nameList[j].equals(att.getName()))) {
  308. final SnmpStatusException x =
  309. new SnmpStatusException(SnmpStatusException.noAccess);
  310. req.registerSetException(varList[j],x);
  311. j++;
  312. }
  313. if ( j == i) break;
  314. try {
  315. varList[j].value =
  316. meta.buildSnmpValue(idList[j],att.getValue());
  317. } catch (SnmpStatusException x) {
  318. req.registerSetException(varList[j],x);
  319. }
  320. }
  321. }
  322. /**
  323. * Set the value of an SNMP variable.
  324. *
  325. * <p><b><i>
  326. * You should never need to use this method directly.
  327. * </i></b></p>
  328. *
  329. * @param meta The impacted metadata object
  330. * @param name The ObjectName of the impacted MBean
  331. * @param x The new requested SnmpValue
  332. * @param id The OID arc identifying the variable we're trying to set.
  333. * @param data User contextual data allocated through the
  334. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
  335. *
  336. * @return The new value of the variable after the operation.
  337. *
  338. * @exception SnmpStatusException whenever an SNMP exception must be
  339. * raised. Raising an exception will abort the request. <br>
  340. * Exceptions should never be raised directly, but only by means of
  341. * <code>
  342. * req.registerSetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
  343. * </code>
  344. **/
  345. public SnmpValue set(SnmpGenericMetaServer meta, ObjectName name,
  346. SnmpValue x, long id, Object data)
  347. throws SnmpStatusException {
  348. final String attname = meta.getAttributeName(id);
  349. final Object attvalue=
  350. meta.buildAttributeValue(id,x);
  351. final Attribute att = new Attribute(attname,attvalue);
  352. Object result = null;
  353. try {
  354. server.setAttribute(name,att);
  355. result = server.getAttribute(name,attname);
  356. } catch(InvalidAttributeValueException iv) {
  357. throw new
  358. SnmpStatusException(SnmpStatusException.snmpRspWrongValue);
  359. } catch (InstanceNotFoundException f) {
  360. throw new
  361. SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
  362. } catch (ReflectionException r) {
  363. throw new
  364. SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
  365. } catch (MBeanException m) {
  366. Exception t = m.getTargetException();
  367. if (t instanceof SnmpStatusException)
  368. throw (SnmpStatusException) t;
  369. throw new
  370. SnmpStatusException(SnmpStatusException.noAccess);
  371. } catch (Exception e) {
  372. throw new
  373. SnmpStatusException(SnmpStatusException.noAccess);
  374. }
  375. return meta.buildSnmpValue(id,result);
  376. }
  377. /**
  378. * Checks whether an SNMP SET request can be successfully performed.
  379. *
  380. * <p>
  381. * For each variable in the subrequest, this method calls
  382. * checkSetAccess() on the meta object, and then tries to invoke the
  383. * check<i>AttributeName</i>() method on the MBean. If this method
  384. * is not defined then it is assumed that the SET won't fail.
  385. * </p>
  386. *
  387. * <p><b><i>
  388. * This method is called internally by <code>mibgen</code> generated
  389. * objects and you should never need to call it directly.
  390. * </i></b></p>
  391. *
  392. * @param meta The metadata object impacted by the subrequest
  393. * @param name The ObjectName of the MBean impacted by this subrequest
  394. * @param req The SNMP subrequest to execute on the MBean
  395. * @param depth The depth of the SNMP object in the OID tree.
  396. *
  397. * @exception SnmpStatusException if the requested SET operation must
  398. * be rejected. Raising an exception will abort the request. <br>
  399. * Exceptions should never be raised directly, but only by means of
  400. * <code>
  401. * req.registerCheckException(<i>VariableId</i>,<i>SnmpStatusException</i>)
  402. * </code>
  403. *
  404. **/
  405. public void check(SnmpGenericMetaServer meta, ObjectName name,
  406. SnmpMibSubRequest req, int depth)
  407. throws SnmpStatusException {
  408. final Object data = req.getUserData();
  409. for (Enumeration e=req.getElements(); e.hasMoreElements();) {
  410. final SnmpVarBind var= (SnmpVarBind) e.nextElement();
  411. try {
  412. final long id = var.oid.getOidArc(depth);
  413. // call meta.check() here, and meta.check will call check()
  414. check(meta,name,var.value,id,data);
  415. } catch(SnmpStatusException x) {
  416. req.registerCheckException(var,x);
  417. }
  418. }
  419. }
  420. /**
  421. * Checks whether a SET operation can be performed on a given SNMP
  422. * variable.
  423. *
  424. * @param meta The impacted metadata object
  425. * @param name The ObjectName of the impacted MBean
  426. * @param x The new requested SnmpValue
  427. * @param id The OID arc identifying the variable we're trying to set.
  428. * @param data User contextual data allocated through the
  429. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
  430. *
  431. * <p>
  432. * This method calls checkSetAccess() on the meta object, and then
  433. * tries to invoke the check<i>AttributeName</i>() method on the MBean.
  434. * If this method is not defined then it is assumed that the SET
  435. * won't fail.
  436. * </p>
  437. *
  438. * <p><b><i>
  439. * This method is called internally by <code>mibgen</code> generated
  440. * objects and you should never need to call it directly.
  441. * </i></b></p>
  442. *
  443. * @exception SnmpStatusException if the requested SET operation must
  444. * be rejected. Raising an exception will abort the request. <br>
  445. * Exceptions should never be raised directly, but only by means of
  446. * <code>
  447. * req.registerCheckException(<i>VariableId</i>,<i>SnmpStatusException</i>)
  448. * </code>
  449. *
  450. **/
  451. // XXX xxx ZZZ zzz Maybe we should go through the MBeanInfo here?
  452. public void check(SnmpGenericMetaServer meta, ObjectName name,
  453. SnmpValue x, long id, Object data)
  454. throws SnmpStatusException {
  455. meta.checkSetAccess(x,id,data);
  456. try {
  457. final String attname = meta.getAttributeName(id);
  458. final Object attvalue= meta.buildAttributeValue(id,x);
  459. final Object[] params = new Object[1];
  460. final String[] signature = new String[1];
  461. params[0] = attvalue;
  462. signature[0] = attvalue.getClass().getName();
  463. server.invoke(name,"check"+attname,params,signature);
  464. } catch( SnmpStatusException e) {
  465. throw e;
  466. }
  467. catch (InstanceNotFoundException i) {
  468. throw new
  469. SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
  470. } catch (ReflectionException r) {
  471. // checkXXXX() not defined => do nothing
  472. } catch (MBeanException m) {
  473. Exception t = m.getTargetException();
  474. if (t instanceof SnmpStatusException)
  475. throw (SnmpStatusException) t;
  476. throw new SnmpStatusException(SnmpStatusException.noAccess);
  477. } catch (Exception e) {
  478. throw new
  479. SnmpStatusException(SnmpStatusException.noAccess);
  480. }
  481. }
  482. public void registerTableEntry(SnmpMibTable meta, SnmpOid rowOid,
  483. ObjectName objname, Object entry)
  484. throws SnmpStatusException {
  485. if (objname == null)
  486. throw new
  487. SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
  488. try {
  489. if (entry != null && !server.isRegistered(objname))
  490. server.registerMBean(entry, objname);
  491. } catch (InstanceAlreadyExistsException e) {
  492. throw new
  493. SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
  494. } catch (MBeanRegistrationException e) {
  495. throw new SnmpStatusException(SnmpStatusException.snmpRspNoAccess);
  496. } catch (NotCompliantMBeanException e) {
  497. throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
  498. } catch (RuntimeOperationsException e) {
  499. throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
  500. } catch(Exception e) {
  501. throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
  502. }
  503. }
  504. }