12 Lookup Services

The lookup services allow JMX technology clients to find and connect to connector servers that have registered with the lookup services.

The JMX Specification defines three bindings to lookup services, using existing lookup technologies, as described in the following sections:

Initial Configuration

As shown in Accessing Standard and Dynamic MBeans By Using the RMI Connector, if you are using remote method invocation (RMI) connectors, you can use an external directory to register the connector server stubs you want to look up. The following cases are presented in the lookup service examples relating to RMI connectors:

  • RMI connectors that use one of the following external directories:

    • An RMI registry, for RMI connectors that implement the default Java Remote Method Protocol (JRMP) transport

    • Lightweight Directory Access Protocol (LDAP), for JRMP transports

  • RMI connectors that do not use an external directory

If you register the RMI connector stubs in an external directory, some initial configuration is required. You must set up your RMI registry or LDAP server. If you do not use an external directory, the RMI connector stub is encoded into the JMX service URL.

The following sections describe the external directories that you can use in conjunction with the lookup service examples that use RMI connectors. These external directories are referred to when running the three examples of lookup services that are given in the subsequent sections in this chapter.

External RMI Registry

To register the RMI connector server stubs in an external RMI registry, for use by connectors implementing the JRMP transport, perform the following actions:

  1. Start the RMI registry on port 9999 of the local host.

    As in JMX Connectors, the RMI registry is used to store the RMI connector stubs for RMI connectors implementing the JRMP transport.

    $ rmiregistry 9999 &
  2. For your convenience when typing commands, create an environment variable for the address of the RMI registry.

    To shorten the commands that you will type when you run the examples, set the service URL for the RMI registry as an environment variable, jndirmi. In these examples, the service URL is given in JNDI form. See the API documentation for the javax.management.remote.rmi package for an explanation of JNDI form. If you want to run the external directories on a machine other than the local machine, you must specify that machine’s host name instead of localhost.

    $ jndirmi="rmi://localhost:9999"

External LDAP Registry

To register the RMI connector server stubs in an external LDAP registry, for use by connectors implementing the JRMP transport:

  1. Start an LDAP Server.

    The LDAP server you use is your choice, although the schema for representing Java objects in an LDAP directory must be known to the server. See the relevant Request For Comments (RFC) document for details:

    http://www.ietf.org/rfc/rfc2713.txt

  2. Create a domain component suffix.

    These examples require that you create the following domain component suffix:

    dc=Test

    See the documentation accompanying your LDAP server for details of how to configure the server and create this suffix.

  3. For your convenience, set the following LDAP parameters as environment variables.

    These variables are used to shorten the commands you type when starting the Server and Client classes in the lookup service examples that register RMI connector stubs in the external LDAP server.

    • The name of the machine running your LDAP server (ldap_host)

      $ ldaphost=ldap_host
    • The port the LDAP server is running on (ldap_port)

      $ ldapport=ldap_port
    • The LDAP common name attribute, which in these examples is “Directory Manager”

      $ principal=”cn=Directory Manager”
    • The password required by your LDAP server . Supply the password for your LDAP server.

      $ credentials=your_ldap_password
    • The address of the LDAP server. In this example, the service URL for the LDAP server is given in JNDI form and is identified by the variable jndildap.

      $ jndildap="ldap://$ldaphost:$ldapport"

You are now ready to run the different lookup service examples.

Service Location Protocol (SLP) Lookup Service

The JMX technology specifies how to register RMI connectors with the SLP lookup service.

This example demonstrates how a JMX Remote API connector client can find and connect to a connector server that has registered with the SLP lookup service. This example performs the following operations:

  • The agent:

    • Creates an MBean server

    • Gets a pointer to the SLP lookup service

    • Creates a connector server

    • Registers the connector address with the SLP lookup service

  • The client:

    • Gets a pointer to the SLP lookup service

    • Looks for any connector servers registered in the SLP lookup service

    • Creates a JMX Remote API connector

    • Retrieves information about the MBeans in the MBean server

This example assumes that you are already familiar with SLP technology. The code provided for this example conforms to Oracle’s implementation of SLP, as defined by RFC 2614 (see http://www.ietf.org/rfc/rfc2614.txt). You must obtain a version of SLP that is compliant with RFC 2614, section 5. You can download the OpenSLP Java implementation from http://www.openslp.org/.

Analyzing the SLP Lookup Example Classes

  1. Copy the source code contained in the Service Location Protocol (SLP) Lookup Service section and create corresponding files in the work_dir/jmx_examples/Lookup/slp directory. The files inside this directory should then include the following:

    • README
    • Server.java
    • Client.java
  2. Open the *.java files, in your IDE or text editor.

The following sections analyze each of these classes and explain how they perform the operations described in the example.

Server.java in the SLP Lookup Example

Due to its size, the SLP lookup service Server.java class is analyzed in the following series of code excerpts:

For explanations of the SLP code used in this example, see RFC 2614 and the API documentation for SLP.

CODE EXAMPLE 12-1 SLP Lookup Service Example Class Server.java (Excerpt 1)


 
public class Server { 
   public final static int JMX_DEFAULT_LEASE = 300; 
   public final static String JMX_SCOPE = "DEFAULT"; 
 
   private final MBeanServer mbs; 
   public Server() { 
       mbs = MBeanServerFactory.createMBeanServer(); 
   } 
    
[...] 
 

CODE EXAMPLE 12-1 sets the default SLP lease JMX_DEFAULT_LEASE to a default lease of 300 seconds, corresponding to the length of time the URL is registered, and shows the initial creation of the MBean server mbs.

In code that is not shown in the example, you then define an SLP advertiser slpAdvertiser, and an SLP service URL url. The slpAdvertiser is used to register the service URL in the SLP lookup service. The SCOPE and the agentName are registered in SLP as lookup attributes.

CODE EXAMPLE 12-2 SLP Lookup Service Example Class Server.java (Excerpt 2)


 
[...] 
 
   public static void register(JMXServiceURL jmxUrl, String name) 
     throws ServiceLocationException { 
     ServiceURL serviceURL = 
          new ServiceURL(jmxUrl.toString(), 
                         JMX_DEFAULT_LEASE); 
     debug("ServiceType is: " + serviceURL.getServiceType()); 
     Vector attributes = new Vector(); 
     Vector attrValues = new Vector(); 
     attrValues.add(JMX_SCOPE); 
     ServiceLocationAttribute attr1 = 
          new ServiceLocationAttribute("SCOPE", attrValues); 
     attributes.add(attr1); 
     attrValues.removeAllElements(); 
     attrValues.add(name); 
     ServiceLocationAttribute attr2 = 
          new ServiceLocationAttribute("AgentName", attrValues); 
     attributes.add(attr2); 
     final Advertiser slpAdvertiser = 
          ServiceLocationManager.getAdvertiser(Locale.US); 
     slpAdvertiser.register(serviceURL, attributes); 
      
   }  
 
[...] 
 

CODE EXAMPLE 12-2 shows the registration of the JMX connector server’s URL with the SLP lookup service.

The JMX service URL jmxUrl is the address of the connector server, and is obtained by a call to the getAddress() method of JMXConnectorServer when the connector server is started.

The SLP lookup attributes, namely the scope and the agent name under which the connector server address is to be registered (name), are then specified by the SLP class ServiceLocationAttribute. The AgentName attribute is mandatory, but other optional attributes, such as ProtocolType, AgentHost, and Property can also be registered in the SLP lookup service.

Finally, the JMX connector server address is registered in the SLP service with a call to the register() method of the Advertiser interface, with the serviceURL and the attributes passed in as parameters.

CODE EXAMPLE 12-3 SLP Lookup Service Example Class Server.java (Excerpt 3)


 
[...] 
 
   public JMXConnectorServer rmi(String url) throws 
     IOException, 
     JMException, 
     NamingException, 
     ClassNotFoundException, 
     ServiceLocationException { 
     JMXServiceURL jurl = new JMXServiceURL(url); 
     final HashMap env = new HashMap(); 
     // Environment map attributes 
     [...] 
 
  
     JMXConnectorServer rmis = 
        JMXConnectorServerFactory.newJMXConnectorServer(jurl, env, mbs); 
     final String agentName = System.getProperty("agent.name", 
                                                 "DefaultAgent"); 
     start(rmis, agentName); 
 
     return rmis; 
  } 
[...] 
 

CODE EXAMPLE 12-3 shows the creation of an RMI connector server. The JMX service URL jurl is constructed from the string url that is included in the command used to launch the Server at the command line. An RMI connector server named rmis is then created with the system properties defined by the environment map and the address jurl.

The connector server is then started, and the RMI connector server address is registered in the SLP lookup service under the name agentName.

CODE EXAMPLE 12-4 SLP Lookup Service Example Class Server.java (Excerpt 4)


 
[...] 
 
   public void start(JMXConnectorServer server, String agentName) 
      throws IOException, ServiceLocationException { 
      server.start(); 
      final JMXServiceURL address = server.getAddress(); 
      register(address,agentName); 
   } 
    
[...] 
 

CODE EXAMPLE 12-4 shows the launching of the connector server server and the registration of server in the SLP lookup service with the given address address.

Client.java in the SLP Lookup Example

Due to its size, the SLP lookup service Client.java class is analyzed in the following series of code excerpts:

CODE EXAMPLE 12-5 SLP Lookup Service Example Class Client.java (Excerpt 1)


 
public class Client { 
 
    public final static String JMX_SCOPE = "DEFAULT"; 
 
    public static Locator getLocator() throws ServiceLocationException { 
      final Locator slpLocator = 
          ServiceLocationManager.getLocator(Locale.US); 
      return slpLocator; 
    } 
     
      public static List lookup(Locator slpLocator, String name) 
          throws IOException, ServiceLocationException { 
 
   
          final ArrayList list = new ArrayList(); 
          Vector scopes = new Vector(); 
 
          scopes.add(JMX_SCOPE); 
          String query =  
              "(&(AgentName=" + ((name!=null)?name:"*") + "))"; 
 
          ServiceLocationEnumeration result = 
              slpLocator.findServices(new ServiceType("service:jmx"), 
                                      scopes, query); 
 
          while(result.hasMoreElements()) { 
                final ServiceURL surl = (ServiceURL) result.next(); 
                 
 
             JMXServiceURL jmxUrl = new JMXServiceURL(surl.toString()); 
             try { 
                  JMXConnector client = 
                     JMXConnectorFactory.newJMXConnector(jmxUrl,null); 
                  if (client != null) list.add(client); 
             } catch (IOException x ) {  
             [...] 
             } 
          } 
      } 
      return list; 
    } 
 

CODE EXAMPLE 12-5 obtains the SLP service ,Locator by calling the getLocator method of the SLP class ServiceLocationManager. The Client then retrieves all the connector servers registered in the SLP service under a given agent name, or under agent names that match a certain pattern. If no agent name is specified when Client is started, all agent names will be considered.

A JMX technology service URL, jmxUrl, is generated for each of the agents retrieved by SLP, with each agent’s SLP service URL, surl, passed as a parameter into the JMXServiceURL instance. The URL ,jmxUrl, is then passed to the newJMXConnector() method of JMXConnectorFactory, to create a new connector client named client for each agent that is registered in the SLP service.

The connector clients that are retrieved are stored in an array list called list.

CODE EXAMPLE 12-6 SLP Lookup Service Example Class Client.java (Excerpt 2)


 
public static void listMBeans(MBeanServerConnection server) 
     throws IOException { 
 
     final Set names = server.queryNames(null,null); 
     for (final Iterator i=names.iterator(); i.hasNext(); ) { 
          ObjectName name = (ObjectName)i.next(); 
          System.out.println("Got MBean: "+name); 
          try { 
               MBeanInfo info = 
                  server.getMBeanInfo((ObjectName)name); 
               MBeanAttributeInfo[] attrs = info.getAttributes(); 
               if (attrs == null) continue; 
               for (int j=0; j<attrs.length; j++) { 
                    try { 
                         Object o = 
                         server.getAttribute(name,attrs[j].getName()); 
                         System.out.println("\t\t" + attrs[j].getName() + 
                         " = "+o); 
                    } catch (Exception x) { 
                         System.err.println("JmxClient failed to get " + 
                                             attrs[j].getName() + x); 
                         x.printStackTrace(System.err); 
                    } 
     } 
} 
 

In CODE EXAMPLE 12-6, a reference to the MBeanServerConnection is retrieved for every connector client that is created from the connector server address stored in the SLP service. A list of all the MBeans and their attributes is retrieved.

CODE EXAMPLE 12-7 SLP Lookup Service Example Class Client.java (Excerpt 3)


 
public static void main(String[] args) { 
      try { 
           final String agentName = System.getProperty("agent.name"); 
           final Locator slpLocator = getLocator(); 
           List l = lookup(slpLocator,agentName); 
           int j = 1; 
           for (Iterator i=l.iterator();i.hasNext();j++) { 
                JMXConnector c1 = (JMXConnector) i.next(); 
                if (c1 != null) { 
                    try { 
                         c1.connect(env); 
                    } catch (IOException x) { 
                         System.err.println ("Connection failed: " + x); 
                         x.printStackTrace(System.err); 
                         continue; 
                    } 
 
                    MBeanServerConnection conn = 
                         c1.getMBeanServerConnection(); 
 
                    try { 
                         listMBeans(conn); 
                    } catch (IOException x) { 
                         x.printStackTrace(System.err); 
                    } 
                    try { 
                         c1.close(); 
                    } catch (IOException x) { 
                         x.printStackTrace(System.err); 
                    } 
                } 
           } 
      } catch (Exception x) { 
           x.printStackTrace(System.err); 
      } 
} 
 

In CODE EXAMPLE 12-7, the agent.name property is retrieved by calling the getProperty() method of the System class, and the SLP lookup service is found by calling the getLocator() method of Locator.

All the agents named agentName are then looked up, and connections are made to the agents that are discovered. If no agent is specified, then all agents are looked up. Connections are made to the MBean server created by Server, and all the MBeans in it are listed, before the connection is closed down.

Running the SLP Lookup Service Example

This example demonstrates the use of the SLP lookup service to look up RMI connector servers that use RMI’s default transport, JRMP. As described in Initial Configuration, different external directories are used to register the RMI connector stubs.

The following combinations of transports and external directories are demonstrated:

  • RMI connector over the JRMP transport, with:

    • No external directory

    • An RMI registry

    • An LDAP registry

In addition to the actions you performed in Initial Configuration, you must perform additional actions specific to this example before you can run the examples that use the SLP. You can then start looking up connectors using SLP in conjunction with the two connectors supported by the JMX technology.

Note:

When you run the examples, to help you keep track of which agent has been created with which transport, the agent names include a letter suffix that is the same as the lettering of the corresponding section. For example, the agent from Starting the Server, substep a, RMI connector over JRMP, without an external directory, is called example-server-a.

To run the example, perform the sequence of steps described in:

Setting up the SLP Lookup Service Example

The following steps are required by all the different transports you can run in this example.

  1. For convenience when compiling and running the classes, define an additional environment variable. In addition to the common environment variables that were set in Initial Configuration, you need to add the path to the SLP service.

    Set SLPLIB appropriately for the platform that you are using.
  2. Define and export the classp environment variable. This example requires a classpath that includes the Java archive (JAR) files for SLP:

    $ classp=$SLPLIB/slp.jar
  3. Compile the example Client and Server classes by typing the following command:

    $ javac -d . -classpath $classp Server.java Client.java
  4. Start the SLP daemon according to the implementation of SLP that you are using.

Starting the Server

The command you use to start the Server varies according to which external directory you are using. Before starting the Client, start one or more of the following instances of the Server . You can start instances of the Server with different transports and external registries.

  • RMI connector over JRMP, that does not use an external directory: Start the Server by typing the following command.

    $ java -classpath .:$classp -Ddebug=true \ 
      -Dagent.name=example-server-a \ 
      -Durl ="service:jmx:rmi://" \ 
      slp.Server & 
    

    In this command:

    • The value for debug is set to true to provide more complete screen output when the Server runs.
    • The name of the agent is example-server-a.
    • The service URL specifies that the selected connector is an RMI connector, running over the RMI default transport JRMP.

    When the Server is launched, you will see confirmation of the creation of the RMI connector, and the registration of its URL in the SLP service.

  • RMI connector over JRMP, using an RMI registry as an external directory: Start the Server by typing the following command.

     $ java -classpath .:$classp -Ddebug=true \ 
      -Dagent.name=example-server-b \ 
      -Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \ 
      slp.Server & 
    

    In this command:

    • The name of the agent that is created is example-server-b.
    • The service URL specifies the selected connector as RMI over JRMP, and the external directory in which the RMI connector stub, server, is stored is the RMI registry you identified as jndirmi in Initial Configuration.

    When the Server is launched, you will see confirmation of the creation of the RMI connector, and the registration of its URL in the SLP service.

  • RMI connector over JRMP, using LDAP as the external directory: Start the Server by typing the following command.

     $ java -classpath .:$classp -Ddebug=true \ 
      -Dagent.name=example-server-c \ 
      -Durl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test" \ 
      -Djava.naming.security.principal="$principal" \ 
      -Djava.naming.security.credentials="$credentials" \ 
      slp.Server & 
    

    In this command:

    • The name of the agent created is example-server-c.
    • The service URL specifies the selected connector as RMI over JRMP, and the external directory in which the RMI connector stub is stored is the LDAP server you identified as jndildap in Initial Configuration.
    • The stub is registered in the Test domain component in the LDAP server.
    • The common name attribute, principal, and password credentials, are given to gain access to the LDAP server.

    When the Server is launched, you will see confirmation of the creation of the RMI connector, and the registration of its URL in the SLP service under the agent name example-server-c.

Starting the Client

After you start the Server by using the transport and external directory of your choice, start the Client.

$ java -classpath .:$classp -Ddebug=true \ 
     -Djava.naming.security.principal="$principal" \ 
     -Djava.naming.security.credentials="$credentials" \ 
     slp.Client 

You will see output confirming the detection of the agents created by the Server and registered in the lookup service. You will also see the identification and confirmation of the connection made to the agents.

To look up a specific agent, type the following command:

$ java -classpath .:$classp -Ddebug=true \  
     -Djava.naming.security.principal="$principal" \ 
     -Djava.naming.security.credentials="$credentials" \ 
     -Dagent.name="agentName" \ 
    slp.Client 

In this command shown above, agentName is the name of the agent you want to look up. You can specify a partial agent name by using *; for example, x* for all agent names beginning with the letter x.

Java Naming and Directory Interface (JNDI) / LDAP Lookup Service

JMX technology allows you to register RMI connectors with a JNDI lookup service using an LDAP registry as a back end. This example performs the following operations:

  • The agent:

    • Creates an MBean server

    • Creates a connector server

    • Registers the connector address with the LDAP server

  • The client:

    • Gets a pointer to the JNDI/LDAP lookup Service

    • Looks for any connector servers registered in the JNDI/LDAP lookup service

    • Creates a JMX Remote API connector

    • Retrieves information about the MBeans in the MBean server

Analyzing the Example Classes

  1. Copy the source code contained in the Java Naming and Directory Interface (JNDI)/LDAP Lookup Service section and create corresponding files in the work_dir/jmx_examples/Lookup/ldap directory. The files inside this directory should then include the following:

    • README
    • Server.java
    • Client.java
    • jmx-schema.txt
    • 60jmx-schema.ldif
  2. Open the *.java files, in your IDE or text editor.

The following sections analyze each of the classes used in the JNDI/LDAP lookup service example, and explain how they perform the operations described above.

Server.java in the JNDI/LDAP Lookup Service Example

Due to its size, the JNDI/LDAP lookup service Server.java class is analyzed in the following series of code excerpts:

CODE EXAMPLE 12-12 JNDI/LDAP Lookup Service Example Server.java (Excerpt 1)

[...]

public class Server {
   public final static int JMX_DEFAULT_LEASE = 60;
   private static boolean debug = false;
   private final MBeanServer mbs;
   public Server() {
      mbs = MBeanServerFactory.createMBeanServer();
   }

  public static DirContext getRootContext() throws NamingException {
      final Hashtable env = new Hashtable();

      final String factory =
        System.getProperty(Context.INITIAL_CONTEXT_FACTORY,
                           "com.sun.jndi.ldap.LdapCtxFactory");
      final String ldapServerUrl =
        System.getProperty(Context.PROVIDER_URL);
      final String ldapUser =
        System.getProperty(Context.SECURITY_PRINCIPAL,
                           "cn=Directory Manager");
      final String ldapPasswd =
        System.getProperty(Context.SECURITY_CREDENTIALS);
      debug(Context.PROVIDER_URL + "=" + ldapServerUrl);
      debug(Context.SECURITY_PRINCIPAL + "=" + ldapUser);
      if (debug) {
                  System.out.print(Context.SECURITY_CREDENTIALS + "=");
                  final int len = (ldapPasswd==null)?0:ldapPasswd.length();
                  for (int i=0;i<len;i++) System.out.print("*");
                  System.out.println();
      }
      env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
      env.put(Context.SECURITY_PRINCIPAL, ldapUser);
      if (ldapServerUrl != null)
           env.put(Context.PROVIDER_URL, ldapServerUrl);
      if (ldapPasswd != null)
           env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);
      InitialContext root = new InitialLdapContext(env,null);
      return (DirContext)(root.lookup(""));
  }
[...]

CODE EXAMPLE 12-12 shows the initial creation of an MBean server, mbs , and obtains a pointer to the root context of the LDAP directory tree in which the connector server address is registered. All the relevant LDAP access variables, such as the provider URL, the LDAP user name, and the security credentials, are given here and passed into the environment map, env. The environment map, env, is then passed as a parameter into a call to the InitialLdapContext, from which the initial LDAP context is obtained.

CODE EXAMPLE 12-13 JNDI/LDAP Lookup Service Example Class Server.java (Excerpt 2)

[...]

public static void register(DirContext root,
                           JMXServiceURL jmxUrl,
                           String name)
   throws NamingException, IOException {

   final String mydn = System.getProperty("dn","cn="+name);

   debug("dn: " + mydn );

   Object o = null;
   try {
       o = root.lookup(mydn);
   } catch (NameNotFoundException n) {
       Attributes attrs = new BasicAttributes();
       Attribute objclass = new BasicAttribute("objectClass");
       objclass.add("top");
       objclass.add("javaContainer");
       objclass.add("jmxConnector");
       attrs.put(objclass);
       attrs.put("jmxAgentName", name);
       o = root.createSubcontext(mydn,attrs);
   }
   if (o == null) throw new NameNotFoundException();
   final Attributes attrs = root.getAttributes(mydn);
   final Attribute oc = attrs.get("objectClass");
   if (!oc.contains("jmxConnector")) {
       final String msg = "The supplied node [" + mydn + 
         "] does not contain the jmxConnector objectclass";
       throw new NamingException(msg);
   }
   final Attributes newattrs = new BasicAttributes();
   newattrs.put("jmxAgentName",name);
   newattrs.put("jmxServiceURL",jmxUrl.toString());
   newattrs.put("jmxAgentHost",InetAddress.getLocalHost().getHostName());
   newattrs.put("jmxProtocolType",jmxUrl.getProtocol());
   newattrs.put("jmxExpirationDate",
                getExpirationDate(JMX_DEFAULT_LEASE));
   root.modifyAttributes(mydn,DirContext.REPLACE_ATTRIBUTE,newattrs);
}

[...]

CODE EXAMPLE 12-13 shows the registration of the JMX connector server service URL in the LDAP directory. You can specify the DN where the URL will be registered can be passed on the command line through the dn System property, that is, -Ddn=mydn . See the commands used start the server for a description. If the dn System property is not specified, then you can use theDN: cn=name where name is the agentName. However, this is not mandatory. The location where the URL is registered does not matter, because the client code never uses that DN directly, but instead performs an LDAP search to find the nodes which have an auxiliary jmxConnector ObjectClass . What is important is that each URL is registered in its own LDAP node. How to name these nodes is left to the LDAP administrator, who in this case is you. In this example, it is assumed that you have configured your LDAP server by creating a root context under which the node cn=name can be created, and that this root context has been passed to the LDAP initial context through the Context.PROVIDER_URL property. See CODE EXAMPLE 12-12 JNDI/LDAP Lookup Service Example Server.java (Excerpt 1)).

The code in CODE EXAMPLE 12-13 checks whether the node in which you will register the server URL already exists. If it does not, you try to create it. This will fail if the parent node does not exist. The jmxConnector ObjectClass is a simple auxiliary class, you will use the javaContainer ObjectClass as structural class if you need to create a new context. This is completely optional. Any structural class to which the jmxConnector auxiliary class can be added is acceptable. It then checks whether the node in which you will register the server already has the jmxConnector auxiliary class. If not, an exception is thrown.

At this point, you are sure that the node in which you will register the URL exists and has the appropriate jmxConnector auxiliary class. You only need to replace the values of the attributes defined by JMX Remote API for LDAP lookup. See jmx-schema.txt.

  • jmxServiceUrl: Contains the String form of the server URL, as obtained from server.getAddress() after the server was started

  • jmxAgentName: Contains the JMX agent name

  • jmxProtocolType: Contains the JMX protocol type, as returned by jmxUrl.getProtocolType()

  • jmxAgentHost: Contains the name of the agent host

  • jmxExpirationDate: Contains the date at which the URL will be considered obsolete

 EXAMPLE 12-14 JNDI/LDAP Lookup Service Example Class Server.java (Excerpt 3)

 [...]

   public JMXConnectorServer rmi(String url)
     throws IOException, JMException,
        NamingException, ClassNotFoundException {

     JMXServiceURL jurl = new JMXServiceURL(url);
     final HashMap env = new HashMap();
     // Prepare the environment Map
[...]

     JMXConnectorServer rmis =
JMXConnectorServerFactory.newJMXConnectorServer(jurl, env, mbs)

     final String agentName = System.getProperty("agent.name",
                                                 "DefaultAgent");
     start(rmis,env,agentName);
     return rmis;
   }
[...]

CODE EXAMPLE 12-14 creates a new RMI connector server named rmis with the JMX service URL jurl and the appropriate LDAP properties passed to its environment map env. The connector server rmis is launched by calling JMXConnectorServer.start() and is registered in the LDAP server..

 EXAMPLE 12-15 JNDI/LDAP Lookup Service Example Class Server.java (Excerpt 4)

[...]

    public void start(JMXConnectorServer server, Map env, String agentName)
       throws IOException, NamingException {server.start()
       final DirContext root=getRootContext();
       final JMXServiceURL address = server.getAddress();register(root,address,agentName)
    }
[...]

CODE EXAMPLE 12-15 creates a JMX connector server server, obtains a pointer to the LDAP server root directory root, and creates a URL for the server named address. The root directory, the URL, and an agent name are passed as parameters to register() and are registered in the LDAP server.

Client.java in the JNDI/LDAP Lookup Service Example

The JNDI/LDAP lookup service example class, Client.java, is shown in the following code example.

CODE EXAMPLE 12-16 JNDI/LDAP Lookup Service Example Class Client.java

[...]

public class Client {

   private static boolean debug = false;

   public static void listAttributes(DirContext root, String dn)
     throws NamingException {
     final Attributes attrs = root.getAttributes(dn);
     System.out.println("dn: " + dn);
     System.out.println("attributes: " + attrs);
   }
   public static DirContext getRootContext() throws NamingException {
      final Hashtable env = new Hashtable();
      // Prepare environment map
      [...]
      InitialContext root = new InitialLdapContext(env,null);
      return (DirContext)(root.lookup(""));
   }
   // Confirm URL has not expired 
  [...] 

   public static List lookup(DirContext root, String protocolType,
                             String name)
      throws IOException, NamingException {
      final ArrayList list = new ArrayList();
      String queryProtocol =
         (protocolType==null)?"":"(jmxProtocolType="+protocolType+")";
      String query =
          "(&" + "(objectClass=jmxConnector) " +
          "(jmxServiceURL=*) " +
          queryProtocol +
          "(jmxAgentName=" + ((name!=null)?name:"*") + "))";

      SearchControls ctrls = new SearchControls();
      ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
      final NamingEnumeration results = root.search("", query, ctrls);
      while (results.hasMore()) { 
           final SearchResult r = (SearchResult) results.nextElement();
           debug("Found node: " + r.getName());
           final Attributes attrs = r.getAttributes();
           final Attribute attr = attrs.get("jmxServiceURL");
           if (attr == null) continue;
           final Attribute exp = attrs.get("jmxExpirationDate");
           if ((exp != null) && hasExpired((String)exp.get())) {
               System.out.print(r.getName() + ": ");
               System.out.println("URL expired since: " + exp.get());
               continue;}
           final String urlStr = (String)attr.get();
           if (urlStr.length() == 0) continue;

           debug("Found URL: "+ urlStr);

           final JMXServiceURL url = new JMXServiceURL(urlStr);
           final JMXConnector conn =
               JMXConnectorFactory.newJMXConnector(url,null);
           list.add(conn);
           if (debug) listAttributes(root,r.getName());
      }

      return list;
}
}

In this code example, the Client first returns a pointer, root, to the LDAP directory DirContext, and then it searches through the directory for object classes of the type jmxConnector. The service URL and expiry date attributes, attr and exp respectively, for the jmxConnector object classes are obtained, exp is checked to make sure that the URL has not expired and a call is made to JMXConnectorFactory to create a new connector conn. The connector conn is added to the list of connectors and is used to access the MBeans in the MBean server created by the Server.

jmx-schema.txt

The jmx-schema.txt file is the LDAP schema file for the JMX Remote API.

60jmx-schema.ldif

The 60jmx-schema.ldif file is an ldif file that corresponds to the LDAP schema file, jmx-schema.txt, for JMX technology.

Running the JNDI/LDAP Lookup Service Example

This example demonstrates the use of the JNDI/LDAP lookup service to look up RMI connector servers that implement the default JRMP transport as well as the IIOP transport. In addition, as described in Initial Configuration, different external directories are used to register the RMI connector stubs.

The combinations of transports and external directories are demonstrated here are:

  • RMI connector over the JRMP transport, with:

    • No external directory

    • An RMI registry

    • An LDAP registry

Before you can run the examples that use the JNDI/LDAP lookup service, you must complete the actions in the Initial Configuration, section and the actions that are specific to this example. You can then start looking up connectors using the JNDI/LDAP network technology, in conjunction with the two connectors supported by the JMX technology

Note:

When you run the examples, to help you keep track of which agent is created with which transport, the agent names include a letter suffix that is the same as the lettering of the corresponding section. For example, the agent in Starting the Server, RMI connector over JRMP, without an external directory, is named example-server-a.

To run the example, perform the sequence of steps described in:

Setting up the JNDI/LDAP Lookup Service Example

The following steps are required by all the different connector/transport combinations you can run in this example.

Note:

Complete the following steps according to the type of LDAP server that you are using.

  1. Stop the LDAP server you started in the Initial Configuration.

  2. Copy the JMX technology schema into your LDAP server’s schema directory.

  3. Restart the LDAP server

  4. Define the root under which the Server will register its service URL. You must provide the Server with the path to the domain component suffix dc=Test that you created in Initial Configuration.
    $ provider="ldap://$ldaphost:$ldapport/dc=Test"
  5. Compile the example Client and Server classes by typing the following command:

    $ javac -d . -classpath $classp Server.java Client.java

Starting the Server

The command you use to start the Server varies according to which external directory you are using. You can start one or more of the following instances of Server with different transports and external registries before starting the Client.

The combinations of transports and external directories are demonstrated here:

  • RMI connector over JRMP, without an external directory: Start the Server by typing the following command.

    $ java -classpath . -Ddebug=true \
      -Dagent.name=example-server-a \
      -Durl="service:jmx:rmi://" \
      -Djava.naming.provider.url="$provider" \
      -Djava.naming.security.principal="$principal" \
      -Djava.naming.security.credentials="$credentials" \
      jndi.Server &

    In this command:

    • The

      debug, is set to true to provide more complete screen output when the Server runs.

    • The name of the agent to be created is example-server-a.

    • The URL, provider, that points to the domain component suffix in which the agent will be registered, is given.

    • The common name attribute, principal, and password, credentials, are given to gain access to the LDAP server.

    • The service URL specifies that the chosen connector is an RMI connector, running over the RMI default JRMP transport.

    When the Server is launched, you will see confirmation of the creation of the RMI connector, and the registration of its URL in the JNDI/LDAP lookup service.

  • RMI connector over JRMP, that uses an RMI registry as an external directory: Start the Server by typing the following command.

    $ java -classpath . -Ddebug=true \ 
      -Dagent.name=example-server-b \ 
      -Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \ 
      -Djava.naming.provider.url="$provider" \ 
      -Djava.naming.security.principal="$principal" \ 
      -Djava.naming.security.credentials="$credentials" \ 
      jndi.Server &

    In this command:

    • The name of the agent that is created is example-server-b.

    • The URL, provider, that points to the domain component suffix in which the agent will be registered, is given.

    • The common name attribute, principal, and password, credentials, are given to gain access to the LDAP server.

    • The service URL specifies the selected connector as RMI over JRMP, and the external directory in which the RMI connector stub, server, is stored is the RMI registry you identified as jndirmi in Initial Configuration.

    When the Server is launched, you will see the confirmation of the creation of the RMI connector and the registration of its URL in the JNDI/LDAP lookup service.

  • RMI connector over JRMP, that uses LDAP as the external directory: Start the Server by typing the following command.

    $ java -classpath . -Ddebug=true \ 
      -Dagent.name=example-server-c \ 
      -Durl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test" \ 
      -Djava.naming.provider.url="$provider" \ 
      -Djava.naming.security.principal="$principal" \ 
      -Djava.naming.security.credentials="$credentials" \ 
      jndi.Server &

    In this command:

    • The name of the agent, created is example-server-c.

    • The URL, provider, that points to the domain component suffix in which the agent will be registered, is given.

    • The common name attribute, principal, and password, credentials, are given to gain access to the LDAP server.

    • The service URL specifies the chosen connector as RMI over JRMP, and the external directory in which the RMI connector stub, server, is stored is the RMI registry that you identified as jndildap in the Initial Configuration.

    When the Server is launched, you will see the confirmation of the creation of the RMI connector and the registration of its URL in the JNDI/LDAP lookup service under the agent name example-server-c.

Starting the Client

After you start the Server that is using the transport and external directory of your choice, start the Client by typing the following command:

$ java -classpath . -Ddebug=true \ 
  -Djava.naming.provider.url="$provider" \ 
  -Djava.naming.security.principal="$principal" \ 
  -Djava.naming.security.credentials="$credentials" \ 
  jndi.Client

You will see the output that confirms the detection of the agents that are created by the Server and registered in the lookup service. You will also see the identification and confirmation of the connection made to the agents.

To look up a specific agent, type the following command:

$ java -classpath . -Ddebug=true \ 
  -Djava.naming.provider.url="$provider" \ 
  -Djava.naming.security.principal="$principal" \ 
  -Djava.naming.security.credentials="$credentials" \ 
  -Dagent.name=agentName \ 
  jndi.Client 

In the command shown above, agentName is the name of the agent you want to look up. You can also specify a partial agent name by using *; for example, x* for all agent names beginning with the letter x.