Java Dynamic Management Kit 5.1 Tutorial

15.1 Active Discovery

In active discovery, the discovery client initiates searches for agents on the network. It involves a discovery client that sends the discovery request and a discovery responder in each agent that responds. Each instance of the responder supplies the return information about the agent in which it is registered. The return information is represented in the discovery client by a vector of discovery response objects.

The application containing the discovery client can initiate a search at any time. For example, it might do a search when it is first started and periodically search again for information about the communicators that might have changed. For each search, the discovery client broadcasts a request and waits for the return information from any responders.

In the following sections, we describe each of these objects in further detail.

15.1.1 Discovery Client

The DiscoveryClient class provides methods to discover agents. The active discovery operation sends a discovery request to a multicast group and waits for responses. These messages are proprietary and are not exposed to the user. Discovery clients can only discover agents listening on the same multicast group and port, so your design must coordinate this information between the discovery client and responders.

You can instantiate and perform searches from multiple discovery clients in a single application. Each discovery client can be configured to use different multicast groups or ports, enabling you to discover different groups of agents.

The discovery services enable users to specify a local interface from which to send out multicast messages. This is useful when working on a system that has multihome interfaces connecting to disconnected multinetworks. In addition, the DiscoveryResponder constructor enables you to specify the host address to be used to build the discovery response. The address can be specified either as an IPV4 or IPv6 address, or as a host name.


Example 15–1 Instantiating and Initializing a Discovery Client

public class Client {
    public static void main(String[] args) throws Exception {
	       BufferedReader br
	           = new BufferedReader(new InputStreamReader(System.in));
 
	       discoveryClient = new DiscoveryClient();
	       discoveryClient.start();

	       while(true) {
	          echo("\n>>> Press return to discover connector servers;");
	          echo(">>> Type a host name then return to discover connector 
                servers running on that machine;");
	          echo(">>> Type bye then return to stop the client.");

    	    String s = br.readLine();

	          if (s.equalsIgnoreCase("bye")) {
		           System.exit(0);
	          } else {
		           try {
		                discover(s);
		           } catch (Exception e) {
		                echo("Got exception "+e);
		                e.printStackTrace();
		           }
	          }
	       }
    }

Once you have created the discovery client, before initiating searches, you must call the discovery client's start method, as shown in Example 15–1. This will create its multicast socket and join the multicast group used for broadcasting its discovery request. The default multicast group is 224.224.224.224 and the default port is 9000. These can be set to other values through the multicastGroup and multicastPort attributes, but only when the state of the discovery client is OFFLINE.

The scope of the discovery request depends on the time-to-live used by the multicast socket. Time-to-live is defined by the Java class java.net.MulticastSocket to be a number between 1 and 255. By default, the time-to-live is 1, which corresponds to the host's local area network. You can modify this value at any time by setting the discovery client's TimeToLive attribute.

By default, a discovery client waits for responses for one second after it has sent a discovery request. This period can be customized by setting a value in milliseconds for its TimeOut attribute. When setting this attribute, you should take into account estimated time for a round-trip of a network packet using the given time-to-live.

Once started, the discovery client in the example above awaits user inputs before starting searches.

15.1.2 Performing a Discovery Operation

An application triggers a search operation by invoking the findMBeanServers or findCommunicators methods on an active DiscoveryClient object. Using the current settings, it will send the multicast request and block for the timeout period. At the end of the timeout period, these methods return the responses that were received.

Both methods return a vector of DiscoveryResponse objects. This class exposes methods for retrieving information about the MBean server and the registered communicator MBeans in the agent. The MBean server information is the same as that exposed by that agent's MBean server delegate. The communicators are identified by ConnectorAddress objects and indexed by object name in a hash table.

Both search methods return the information about the agent's MBean server. The hash table of communicator MBeans is always empty for discovery responses returned by the findMBeanServers method. Otherwise, you can extract object names and protocol information from the hash table. One way of distinguishing the communicator MBeans is to rely on the default names provided by the ServiceName class.


Note –

All discovery messages sent between components of the discovery service are compatible between applications running different versions of the Java platform or between versions 5.0 and 5.1 of the Java DMK. However, these different configurations are not compatible for subsequent management operations through connectors. You can use the getImplementationVersion method of the DiscoveryResponse object to determine both the Java platform and product version numbers.


In our example, we request all information about the agents and print out all information in the discovery responses.


Example 15–2 Performing a Discovery Operation

private static void discover(String host) throws Exception {
	   Vector v = null;
	   if (host ==  null || host.equals("")) {
	      v = discoveryClient.findCommunicators();
	   } else {
	      v= discoveryClient.findCommunicators(host);
	   }

	   if (v.size() == 0) {
	      echo("No connector server has been found.");

	      return;
	   }

	   for (int i=0; i<v.size(); i++) {
	        DiscoveryResponse dr = (DiscoveryResponse)v.get(i);
	        JMXServiceURL url = null;

	        // legacy servers
	        Collection c = dr.getObjectList().values();
	        for (Iterator iter=c.iterator(); iter.hasNext();) {
		         Object o = iter.next();

		         if (!(o instanceof ConnectorAddress)) {
		             continue;
		         }

		         ConnectorAddress ca = (ConnectorAddress)o;
		         if (ca.getConnectorType().equals("SUN RMI")) {
		             url = new JMXServiceURL("jdmk-rmi",
					                           ((RmiConnectorAddress)ca).getHost(),
					                           ((RmiConnectorAddress)ca).getPort());
		        // Repeat for jdmk-http and jdmk-https connectors 
           [...]
 	        } else {
		            echo("Got an unknown protocol: "+ca.getConnectorType());

		            continue;
		        }

		        echo("\nFound a legacy server which is registered 
                  as a legacy MBean: "
		              +url.getProtocol()+" 
                 "+url.getHost()+" 
                 "+url.getPort());
		        echo("Connecting to that server.");
		        JMXConnector jc = JMXConnectorFactory.connect(url);
		        echo("Its default domain is 
                 "+jc.getMBeanServerConnection().getDefaultDomain());
		        echo("Closing the connection to that server.");
		        jc.close();
	       }

	       // JMX-remote servers
	       JMXServiceURL[] urls = dr.getServerAddresses();

	       echo("");
		    for (int ii=0; ii<urls.length; ii++) {
		      echo("\nFound a server which is registered 
                as a JMXConnectorServerMBean: "
		            +urls[ii]);
		      echo("Connecting to that server.");
		      JMXConnector jc = JMXConnectorFactory.connect(urls[ii]);
		      echo("Its default domain is 
              "+jc.getMBeanServerConnection().getDefaultDomain());
		      echo("Closing the connection to that server.");
		      jc.close();
	       }
	    }
}

On the agent side, the discovery responder automatically replies to discovery requests. Any active, registered responder in the same multicast group that is reached within the given time-to-live of the request will respond. It will automatically gather the requested information about its MBean server and send the response. The settings of the responder do not affect its automatic reply to discovery requests. In 15.2.1 Discovery Responder we will cover how its settings control passive discovery.

The discovery client can search for agents via all the connector protocols supported by Java DMK, both current and legacy. Java DMK 5.1 introduces a new DiscoveryResponse method, getServerAddresses, which is used to get the addresses of any servers registered in an MBean server as a JMXConnectorServerMBean. The getServerAddresses method can discover servers that are either instances of the JMX Remote API JMXConnectorServer, or legacy servers wrapped to appear as such. This new method ensures compatibility between the following pairs of discovery clients and servers created using versions 5.0 and 5.1 of Java DMK.

All the above relations between versions are also true for the passive discovery monitor.

In active discovery, the discovery client controls all parameters of a search it initiates, including the response mode of the discovery responder. The discovery client determines whether responses are sent back on a different socket (unicast) or sent to the same multicast group. The default is unicast: if you want to use the multicast response mode, set the PointToPointResponse attribute to false before initiating the discovery.

15.1.2.1 Unicast Response Mode

When the PointToPointResponse boolean attribute is true, the discovery client specifies unicast mode in its discovery requests. The responder will create a datagram socket for sending the response only to the discovery client. As shown in the following diagram, each responder will send its response directly back to the discovery client. The datagram socket used by each responder is bound to its local host address; this cannot be customized.

Figure 15–1 Unicast Response Mode

Unicast response mode

15.1.2.2 Multicast Response Mode

When the PointToPointResponse boolean attribute is false, the discovery client specifies multicast mode in its requests. The discovery responder will use the existing multicast socket to send response, broadcasting it to the same multicast group as the request. As shown in the following diagram, every member of the multicast group will receive the message, but only the discovery client can make use of its contents. Multicast mode avoids having to open another socket for the response, but all of the responses will create traffic in each application's socket.

Figure 15–2 Multicast Response Mode

Multicast response mode