Java Dynamic Management Kit 5.1 Tutorial

18.2.3 Point of Entry into the SNMP Table Instrumentation Example

In this example, the table instrumentation operations shown in the preceding sections are all demonstrated by a single class, the Agent. The fact that this Agent class creates MBeans, and registers them in an MBean server so that they can be mirrored by the SNMP MIB, is irrelevant to this example. The real purpose of the Agent is to demonstrate how to add instrumentation to the SNMP tables using Java DMK technology, not to demonstrate what the example actually does.


Example 18–11 Making an MBean Server Accessible by an SNMP Manager

public class Agent {
    public interface SimpleMBean {
	       public String getName();
	       public int    getCount();
	       public void   reset();
    }

    public static class Simple implements SimpleMBean {
	       public Simple() {
	           this(null);
	       }
    // Define MBean operations    
    [...]
    }

    public static MBeanServer getPlatformMBeanServer() {
	        final MBeanServer test = MBeanServerFactory.createMBeanServer();
	        final MBeanServer first = (MBeanServer)
	           MBeanServerFactory.findMBeanServer(null).get(0);
	        if (test != first) MBeanServerFactory.releaseMBeanServer(test);
	        return first;
    }

    public int populate(MBeanServer server, int mbeanCount) {
	      int count = 0;
	      for (int i=0; i<mbeanCount; i++) {
	          try {
		            final SimpleMBean simple = new Simple();
		            final ObjectName name = 
		               new ObjectName("Example:type=Simple,name="+
				                         simple.getName());
		            server.registerMBean(simple,name);
		            count ++;
		            System.out.println("Registered MBean: " + name);
	          } catch (Exception x) {
		            System.err.println("Failed to register MBean: " + x);
		            debug(x);
	          }
	      }
	      return count;
    }

    public int depopulate(MBeanServer server, int mbeanCount) {
	      int count = 0;
	      while (true) {
	          try { 
		           final ObjectName pattern = 
		              new ObjectName("Example:type=Simple,*");
		           Set mbeans = server.queryNames(pattern,null);
		           if (mbeans.isEmpty()) break;
		           for (Iterator it=mbeans.iterator(); it.hasNext() ; ) {
		                if (count == mbeanCount) return count;
		                final ObjectName next = (ObjectName) it.next();
		                try {
			                  server.unregisterMBean(next);
			                  count++;
                        System.out.println("Deregistered MBean: " 
                                            + next);
		                } catch (InstanceNotFoundException x) {
			               continue;
		                }
		           }
		           if (count >= mbeanCount) break;
	          } catch (Exception x) {
		           System.err.println("Unexpected exception: " + x);
		           debug(x);
		           break;
	          }
	      }
	      return count;
   }
[...]

The Agent class shown in Example 18–11 defines a basic MBean called SimpleMBean, that performs very basic MBean operations. The getPlatformMBeanServer method is used to obtain the first MBean server that has been created in this session by the MBeanServerFactory.


Example 18–12 Creating an SNMPv3 Adaptor Server and JMX-MBEAN-SERVER-MIB

[...]

    public void startmib(MBeanServer server,int port) throws IOException {
	      final SnmpV3AdaptorServer adaptor = 
	          new SnmpV3AdaptorServer((InetAddressAcl)null,port);
	      adaptor.enableSnmpV1V2SetRequest();
	      adaptor.start();
	      do {
	          adaptor.waitState(CommunicatorServer.ONLINE,1000);
	      } while (adaptor.getState() == CommunicatorServer.STARTING);

	      final int state = adaptor.getState();
	      if (state != CommunicatorServer.ONLINE) {
	          try { adaptor.stop(); } catch (Exception x) { /* OK */ }
	          throw new IOException("Can't start adaptor: " + 
				                        adaptor.getStateString());
	      }

       JMX_MBEAN_SERVER_MIB_Impl mib = 
              new JMX_MBEAN_SERVER_MIB_Impl(server);

	      try {
	           mib.init();
	           mib.setSnmpAdaptor(adaptor);
	           server.registerMBean(adaptor,null);
	           mib.start();
	      } catch (Exception x) {
	           System.err.println("Failed to register SnmpAdaptor: " + x);
	           try { adaptor.stop(); } catch (Exception e) { /* OK */ }
	           final IOException io = 
		            new IOException("Failed to register SnmpAdaptor");
	           io.initCause(x);
	           throw io;
	      }
       System.out.println("SnmpAdaptor ready at port: " 
                          + adaptor.getPort());
    }
[...]

The Agent class then defines a method, startmib, to instantiate an SNMPv3 adaptor server named adaptor, and creates an instance of the JMX_MBEAN_SERVER_MIB_Impl MIB, named mib. The mib is constructed around an MBean server named server, the content of which is mirrored in this MIB. The MIB is then initialized by a call to the init() method defined by JMX_MBEAN_SERVER_MIB_Impl. The reference to the SNMP protocol adaptor through which the MIB is accessible, in this case adaptor, is set by calling the SnmpMibAgent method setSnmpAdaptor, and this adaptor is then registered as an MBean in the MBean server server. The start() method defined by JMX_MBEAN_SERVER_MIB_Impl is then called. The start() method starts the mbeanServerGroup, which itself is an instance of JmxMBeanServerImpl, and which activates the mirroring of the MBean server in the MIB. See the JMX_MBEAN_SERVER_MIB_Impl.java file in the generated directory for the full implementation of the start() method.


Example 18–13 Starting the Agent

[...]
      public void start(int port, String[] args) throws IOException {
	       final MBeanServer server =  getPlatformMBeanServer();
	       final JMXServiceURL[] urls = new JMXServiceURL[args.length];
	       for (int i=0;i<args.length;i++) {
	            try {
		              urls[i] = new JMXServiceURL(args[i]);
	            } catch (MalformedURLException x) {
		       			throw x;
	            }
	       }
	       for (int i=0;i<urls.length;i++) {
	           try {
		            final JMXConnectorServer s = 
		                    JMXConnectorServerFactory. 
                       newJMXConnectorServer(urls[i],
								  null,null);
		            final ObjectName name = 
                  new ObjectName("Connector:type=
                                 "+s.getClass().getName()+
				                        ",instance="+i);
		            server.registerMBean(s,name);
		            s.start();
		    	   } catch (Exception x) {
		            final String msg = "Failed to start connector: 
                                  " + args[i];
		            System.err.println(msg);
		            final IOException io = new IOException(msg);
		            io.initCause(x);
		            throw io;
	    	      }
	       }

	       populate(server,5);

	       startmib(server,port);
	
	       final Timer timer = new Timer();
	       final long  period= 2000;
	       final long  now=0;
	       final int   max=4;
	       for (int i=0;i<max;i++) {
	           final TimerTask taskAdd = new TimerTask() {
		                public void run() {
                       final MBeanServer server = 
                                getPlatformMBeanServer();
			                 populate(server,1);
		                }
		             };
	           final TimerTask taskRem = new TimerTask() {
		                public void run() {
                       final MBeanServer server = 
                                getPlatformMBeanServer();
			                 depopulate(server,1);
		                }
		             };
	           timer.schedule(taskAdd,now+period*i,2*period*max);
	           timer.schedule(taskRem,now+period*max+period*i,2*period*max);
	       }
    }

    public static void initOidTable() {	
	       final SnmpOidTable orig = SnmpOid.getSnmpOidTable();
	       SnmpOidDatabaseSupport mibs = new SnmpOidDatabaseSupport();
	       mibs.add(new JMX_MBEAN_SERVER_MIBOidTable());
	       if (orig != null) mibs.add(orig);
	       SnmpOid.setSnmpOidTable(mibs);
    }
[...]

Agent now defines a start() method of its own. The start method firstly obtains an MBean server instance, server, by calling the getPlatformMBeanServer method defined earlier in the class. It also retrieves any JMX service URLs that might be passed to Agent as arguments when it is launched. If any JMX service URLs are provided at start-time, the Agent.start() method uses them to create JMXConnectorServer instances that it registers in the MBean server server as MBeans.

The MBean server instance server is populated with dummy MBeans by calling the populate() method. These MBeans are mirrored in the MIB, when the mirroring is activated.

The SNMP adaptor and the MIB are started by calling startmib, that was defined in Example 18–12.

Once the startmib method has been called, timer tasks are defined that periodically add and remove MBeans from the MBean server. These periodic tasks serve merely to test and demonstrate that the jmxMBeanTable and jmxMBeanAttrTable are updated accordingly in the MIB.

JMX_MBEAN_SERVER_MIBOidTable metadata definitions for the MIBs are loaded into the global SNMP OID table, to enable the use of symbolic OID names.


Example 18–14 Agent main() Method

[...]
    public static void main(String[] args) {

	       Agent agent = new Agent();
	       try {
	            initOidTable();
             final String portStr = System.getProperty("snmp.port",
                                                       "16161");
	            final int port;
	            try {
		              port = Integer.parseInt(portStr);
	            } catch (Exception x) {
                 System.err.println("Invalid value specified for 
                                    snmp.port: "
				                          + portStr);
		             System.err.println("Error is: " + x);
		             throw x;
	            }
	            System.out.println("Using SNMP port " + port);

	            agent.start(port,args);

	            // Wait forever...
	            Thread.sleep(Long.MAX_VALUE);
	       } catch (Exception x) {
	            System.err.println("Failed to start agent: " + x);
	            debug(x);
	            System.exit(1);
	       }

    }

}

Finally, an instance of Agent, agent, is started on the appropriate SNMP port by calling the start method defined in Example 18–13.