The customized classes extend the functionality of the classes of the generated MIB. As was the case in the previous example, the JMX_MBEAN_SERVER_MIB_Impl extends the JMX-MBEAN-SERVER-MIB generated by mibgen, to instantiate the instrumented JmxMBeanServerImpl class. However, the extended behavior that the customized classes bring to the MIB in this example differs from that provided by the SNMP table instrumentation example. Most significantly, whereas the JmxMBeanServerImpl class was the principal author of the customized behavior of the MIB in the previous example, in this example the bulk of the work is done by JmxMBeanTableMetaImpl.
The following sections examine each of the customized classes, describing their purpose, and where necessary, highlighting their differences with the corresponding classes in the SNMP table instrumentation example.
JmxMBeanServerImpl instruments the jmxMBeanServer group defined in the MIB. It implements the JmxMBeanServerMBean interface that is generated by mibgen, but unlike the previous example, it does not extend the generated JmxMBeanServer skeleton. As a result of not extending the JmxMBeanServer object, and also because the MIB was generated with the -X:no-table-access option, the generated TableJmxMBeanTable and TableJmxMBeanAttrTable objects are not instantiated. Although they are still generated by mibgen, these classes are not used in this example.
The jmxMBeanTable and jmxMBeanAttrTable tables are implemented as virtual tables. They are computed on the fly when an SNMP request needs to access them. Furthermore, the jmxMBeanTable and jmxMBeanAttrTable tables are managed by their respective customized JmxMBeanTableMetaImpl and JmxMBeanAttrTableMetaImpl meta objects. In the table instrumentation example, the tables were managed by the JmxMBeanServerImpl object.
JmxMBeanServerMetaImpl extends the generated JmxMBeanServerMeta class, that is used to represent SNMP metadata for the JmxMBeanServer group.
JmxMBeanServerMetaImpl overrides the table-meta factory methods in order to instantiate customized implementations of the JmxMBeanTableMeta and JmxMBeanAttrTableMeta meta classes. These meta classes are customized in the JmxMBeanTableMetaImpl and JmxMBeanAttrTableMetaImpl meta classes, that are shown in 18.3.2.3 JmxMBeanTableMetaImpl and 18.3.2.4 JmxMBeanAttrTableMetaImpl respectively.
JmxMBeanTableMetaImpl extends the generated JmxMBeanTableMeta class, and overrides the following JmxMBeanTableMeta methods.
getEntry(SnmpOid rowOid), so that it returns a JmxMBeanEntryImpl object for the indicated row instead of a JmxMBeanEntry table entry.
contains(SnmpOid oid, Object userData), so that it tells whether the indicated row is present in the table.
getNextOid(Object userData), so that it returns the row index, the rowOid, of the first row in the table.
getNextOid(SnmpOid rowOid,Object userData), so that it returns the index of the row that immediately follows the indicated row in the table.
createNewEntry(SnmpMibSubRequest req, SnmpOid rowOid, int depth), so that it makes it possible to create new rows from SNMP SET requests. Overriding this method is not necessary when the table is read-only.
removeTableRow(SnmpMibSubRequest req, SnmpOid rowOid, int depth), so that it makes it possible to delete rows from SNMP SET requests. Overriding this method is not necessary when the table is read-only.
In addition to overriding the above methods, it is the JmxMBeanTableMetaImpl class that implements the caching mechanism. An SnmpUserData factory is used to create a transient request-contextual cache, that will remain active for the duration of the incoming request. After the request has completed, the contextual-cache is garbage-collected.
JmxMBeanTableMetaImpl defines the following subclasses, that implement the caching mechanism.
The JmxMBeanTableData is a snapshot of the table index. It is computed on demand, and cached in a JmxMBeanTableCache object which holds it through a WeakReference. The JmxMBeanTableData includes a time-stamp which is used to determine whether the cached data is still valid, or if it needs to be recomputed.
The JmxMBeanTableCache is a weak cache used to avoid constant recomputation of the JmxMBeanTableData. It holds the last computed JmxMBeanTableData in a weak reference, so that the garbage collector might reclaim it at any time, provided that no request is currently working on that most-recently computed copy. When an SNMP request that needs to access the jmxMBeanTable comes in, the JmxMBeanTableData is looked up from the JmxMBeanTableCache, and recomputed if needed. The JmxMBeanTableData object is then put in the request-contextual cache where it remains until the request is completed. The request will always consult that particular copy, thus ensuring the consistency of the returned data. If in the meantime a concurrent request comes in, it might obtain the same JmxMBeanTableData copy as the previous request, or a newly computed object, if the previous one was found to be obsolete. Consequently, the two requests might work on the same, or on different snapshots of the table. The snapshot obtained by a given request never changes.
The JmxMBeanTableDataItem is a simple class that wraps an ObjectName and a JmxMBeanEntry. The JmxMBeanEntry is lazy-evaluated. The JmxMBeanTableData contains an array of JmxMBeanTableDataItem objects.
JmxMBeanAttrTableMetaImpl extends the generated JmxMBeanAttrTableMeta class, and overrides the following methods.
getEntry(SnmpOid rowOid), so that it returns an JmxMBeanAttrEntryImpl object for the indicated row.
contains(SnmpOid oid, Object userData), so that it tells whether the indicated row is present int the table.
getNextOid(Object userData), so that it returns the row index, the rowOid, of the first row in the table.
getNextOid(SnmpOid rowOid,Object userData), so that it returns the index of the row that immediately follows the indicated row in the table.
The methods createNewEntry(SnmpMibSubRequest req, SnmpOid rowOid, int depth), and removeTableRow(SnmpMibSubRequest req, SnmpOid rowOid, int depth) are not overriden. The table is read-only, so these methods will never be called.
This class does not use any specific caching mechanism. Since the jmxMBeanAttrTable is an extension of the jmxMBeanTable it simply relies on the cache established for the jmxMBeanTable. The list of attributes pertaining to a specific MBean is cached, if necessary, in the corresponding JmxMBeanEntryImpl object, which can be reclaimed at the end of the request. Note that attribute values are not cached, but rather they are obtained when they are needed.
JmxMBeanContextFactory implements the com.sun.management.snmp.agent.SnmpUserDataFactory interface. The userData allocated by this factory is a java.util.Map that serves as a request-contextual cache. When the MIB instrumentation needs to access a piece of data, it proceeds as follows.
Firstly, it looks for it in the request-contextual cache, namely, in the userData.
If the required data is not found,the MIB instrumentation computes its value, puts it in the request-contextual cache, and then returns it.
This mechanism ensures the coherency of the data returned in the response. Once a piece of data has been loaded into the request-contextual cache, it is consistently reused for the whole duration of the request. This makes sure that the same snapshot is always used during the request, even if the underlying managed object constantly changes its value.
JmxMBeanEntryImpl extends theJmxMBeanEntry skeleton that is generated by mibgen, and adds instrumentation to the entries of the jmxMBeanTable table defined in the MIB. Each JmxMBeanEntry represents an MBean registered in the exposed MBean server. The JmxMBeanEntry objects are created on the fly when needed. They are temporary objects which are created when an SNMP request needs access to the instrumented MBean. Once created, JmxMBeanEntry objects are put in the request-contextual cache, where they remain until the request completes.
JmxMBeanAttrEntryImpl extends theJmxMBeanAttrEntry skeleton that is generated by mibgen, and adds instrumentation to the entries of the jmxMBeanAttrTable table defined in the MIB. Like JmxMBeanEntry objects, JmxMBeanAttrEntry objects are created on the fly when an SNMP request needs access to the instrumented MBean attributed.
JmxMBeanAttrEntry objects are stored in their corresponding JmxMBeanEntryImpl objects, which are themselves cached in the request-contextual cache and in the JmxMBeanTableCache.