Contents | Previous | Next | Java Management Extensions (JMX) Technology Tutorial |
The Java Management Extensions (JMX) specification defines three bindings to lookup services, using existing lookup technologies, as described in the following sections:
The lookup services allow JMX technology clients to find and connect to connector servers that have registered with the lookup services.
As shown simply in Section "Accessing Standard and Dynamic MBeans via the RMI Connector", if you are using remote method invocation (RMI) connectors, you can choose to 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:
If you choose to register the RMI connector stubs in an external directory, some initial configuration is required, to set up your RMI registry, CORBA naming service 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.
To register the RMI connector server stubs in an external RMI registry, for use by connectors implementing the JRMP transport, perform the following actions:
As was the case in Chapter 3, "JMX Connectors", the RMI registry is used to store the RMI connector stubs for RMI connectors implementing the JRMP transport.
$
rmiregistry 9999 &
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"
To register the RMI connector server stubs in an external CORBA naming service, for use by connectors implementing the IIOP transport, perform the following actions:
RMI connectors that implement the IIOP transport can use CORBA naming to identify the RMI connector stub.
$
orbd -ORBInitialPort 7777 &
To shorten the commands that you type when you run the examples, set the service URL for the CORBA naming service as an environment variable, jndiiiop. In these examples, the service URL is given in 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.
$
jndiiiop="iiop://localhost:7777"
To register the RMI connector server stubs in an external LDAP registry, for use by connectors implementing either of the JRMP or IIOP transports, perform the following actions:
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
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.
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.
$
ldaphost=ldap_host
$
ldapport=ldap_port
$
principal=”cn=Directory Manager”
Supply the password for your LDAP server.
$
credentials=your_ldap_password
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"
The JMX technology specifies how to register RMI connectors with the SLP lookup service.
The purpose of this example is to demonstrate 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:
This example assumes that you are already familiar
with SLP
technology. The code provided for this example conforms to Sun
Microsystems’ implementation of SLP, as defined by RFC 2614
(see http://www.ietf.org/rfc/rfc2614.txt).
Sun Microsystems’ implementation of SLP is available in the
Solaris operating environment in the directory/usr/share/lib/slp
. If you are not running the
Solaris operating environment, 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/.
The SLP lookup example is contained in the
directory work_dir/jmx_examples/Lookup/slp
.
/jmx_examples/Lookup/slp
.
Inside this directory, you will find the following files:
*.java
files in a text
editor.
These classes will be analyzed in the following sections.
The following sections analyze each of the classes used in the SLP lookup example, and explain how they perform the operations described above.
Server.java
and Client.java
to import your version of the SLP Java
classes instead of the com.sun.slp
package. See RFC 2614, section 5.
Due to its size, the SLP lookup service
Server.java
class is shown as a series
of code excerpts. For explanations of the SLP code used in this
example, see RFC 2614 and the API documentation for SLP.
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 4-1 sets the
default SLP lease JMX_DEFAULT_LEASE
to a
default lease of 300 seconds, corresponding to the length of time
the URL will be registered, and shows the initial creation of the
MBean server mbs
.
In code that is not shown here, 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.
[...] 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 4-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.
[...] 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 4-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
.
[...] public void start(JMXConnectorServer server, String agentName) throws IOException, ServiceLocationException { server.start(); final JMXServiceURL address = server.getAddress(); register(address,agentName); } [...]
CODE EXAMPLE 4-4 shows the
launching of the connector server server
and the registration of server
in the
SLP lookup service with the given address address
.
The SLP lookup service Client.java
class is shown in CODE EXAMPLE 4-1, CODE EXAMPLE 4-2, and
CODE EXAMPLE 4-3:
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 4-1 first of all
obtains the SLP service Locator
by
calling the getLocator
method of the SLP
class ServiceLocationManager
.
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 the 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 retrieved are stored in an
array list called list
.
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 4-2, 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.
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 4-3, 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 discovered. If no agent is specified, then all
agents are lookup 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.
In addition to the actions you performed in Section "Initial Configuration", before you can run the lookup service examples that use the SLP, you must perform some further initial actions that are specific to this example. You can then start looking up connectors using SLP in conjunction with the two connectors supported by the JMX technology.
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 Section a. "RMI connector over JRMP,
without an external directory" is called
example-server-a
.
The following steps are required by all of the different transports you can run in this example.
In addition to the common environment variables that were set in Section "Initial Configuration", you need to add the path to the SLP service. If you are using the Solaris operating environment, add the following variable:
$
SLPLIB=/usr/share/lib/slp
If you are using another platform, set
SLPLIB
appropriately for the platform
you are using.
classp
environment variable.
This example requires a classpath that includes the Java archive (JAR) files for SLP.
$
classp=$SLPLIB/slp.jar
Client
and
Server
classes.
Type the following command:
$
javac -d . -classpath $classp Server.java
Client.java
If you are using the Solaris operating environment, type the following command, which requires you to know your super user password:
$
su root -c "java -cp $SLPLIB/slpd.jar
com.sun.slp.slpd &"
Password:
[type superuser
password]
If you are not running a Solaris system, start the SLP daemon according to the implementation of SLP you are using.
This example demonstrates the use of the SLP lookup service to look up RMI connector servers that use RMI’s default transport, JRMP, as well as the IIOP transport. In addition, as described in Section "Initial Configuration", different external directories are used to register the RMI connector stubs.
The combinations of transports and external directories demonstrated here are:
Perform the following steps to run the example:
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
.
Start 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:
debug
is set to true to provide more
complete screen output when the Server
runsexample-server-a
When Server is launched, you will see confirmation of the creation of the RMI connector, and the registration of its URL in the SLP service.
Start 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:
example-server-b
When Server
is
launched, you will see confirmation of the creation of the RMI
connector, and the registration of its URL in the SLP service.
Start 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:
example-server-c
jndildap
in Section
"Initial Configuration".Test
domain component in the LDAP server.principal
and password credentials
are given to
gain access to the LDAP server.When 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
.
Start Server
by typing
the following command:
$ java -classpath .:$classp -Ddebug=true \ -Dagent.name=example-server-d \ -Durl="service:jmx:iiop://" \ slp.Server &
In this command:
example-server-d
When the Server
is
launched, you will see confirmation of the creation of the RMI
connector, and the registration of its automatically generated URL
in the SLP service.
Start Server
by typing
the following command:
$ java -classpath .:$classp -Ddebug=true \ -Dagent.name=example-server-e \ -Durl="service:jmx:iiop:///jndi/${jndiiiop}/server" \ slp.Server &
In this command:
example-server-e
server
is stored is the CORBA naming
service you identified as jndiiiop
in
Section "Initial
Configuration"When 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 name example-server-e
.
Start Server
by typing
the following command:
$ java -classpath .:$classp -Ddebug=true \ -Dagent.name=example-server-f \ -Durl="service:jmx:iiop:///jndi/${jndildap}/cn=x,dc=Test" \ -Djava.naming.security.principal="$principal" \ -Djava.naming.security.credentials="$credentials" \ slp.Server &
In this command:
example-server-f
jndildap
in Section
"Initial Configuration".Test
domain component in the LDAP server.principal
and password credentials
are given to
gain access to the LDAP server.When 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-f
.
Client
.After starting the Server
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 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.
The purpose of this example is to demonstrate how a JMX technology connector client can find and connect to a connector server that has registered with the Jini lookup service. This example performs the following operations:
The Jini lookup service example is contained in
the directory work_dir/jmx_examples/Lookup/jini
.
/jmx_examples
/Lookup/jini
directory.
Inside this directory, you will find the following files:
These classes will be analyzed in the following sections.
The following sections analyze each of the classes used in the Jini lookup service example, and explain how they perform the operations described above.
Due to its size, the Jini lookup service
Server.java
class is shown as a series
of code excerpts.
public class Server { private final MBeanServer mbs; private static boolean debug = false; public Server() { mbs = MBeanServerFactory.createMBeanServer(); } [...]
CODE EXAMPLE 4-1 shows the
creation of an MBean server mbs
. As was
the case for the SLP examples, the JMX service URL and the agent
name are passed to Server
when it is
launched at the command line.
[...] public JMXConnectorServer rmi(String url) throws IOException, JMException, ClassNotFoundException { 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,env,agentName); return rmis; } [...]
CODE EXAMPLE 4-2 shows the
creation of an RMI connector server named rmis
, using the system properties defined by the
environment map env
and the address
jurl
.
The RMI connector server rmis
is started. The RMI connector server address is
registered in the Jini lookup service under the name agentName
.
[...] public void start(JMXConnectorServer server, Map env, String agentName) throws IOException, ClassNotFoundException { server.start(); final ServiceRegistrar registrar=getRegistrar(); final JMXConnector proxy = server.toJMXConnector(env); register(registrar,proxy,agentName); } public static ServiceRegistrar getRegistrar() throws IOException, ClassNotFoundException, MalformedURLException { final String jurl = System.getProperty("jini.lookup.url","jini://localhost"); final LookupLocator lookup = new LookupLocator(jurl); final ServiceRegistrar registrar = lookup.getRegistrar(); if (registrar instanceof Administrable) debug("Registry is administrable."); return registrar; } public static ServiceRegistration register(ServiceRegistrar registrar, JMXConnector proxy, String name) throws IOException { Entry[] serviceAttrs = new Entry[] { new net.jini.lookup.entry.Name(name) }; System.out.println("Registering proxy: AgentName=" + name ); debug("" + proxy); ServiceItem srvcItem = new ServiceItem(null, proxy, serviceAttrs); ServiceRegistration srvcRegistration = registrar.register(srvcItem, Lease.ANY); debug("Registered ServiceID: " + srvcRegistration.getServiceID().toString()); return srvcRegistration; } [...]
CODE EXAMPLE 4-3 shows the
creation of a connector server named server
with the environment map env
and the service URL jurl
. The connector server instance server then gets
a pointer to the Jini lookup service by calling the Jini lookup
service method LookupLocator.getRegistrar()
.
The connector server is registered in the Jini
lookup service in the form of a proxy, using the Jini lookup
service locator registrar
and the agent
name under which the connector server will be registered. The proxy
is in fact a client stub for the connector server, obtained by a
call to the toJMXConnector()
method of
JMXConnectorServer
.
The registration itself is performed by a call to
the register()
method of the Jini lookup
service class ServiceRegistrar
, with an
array of service items.
The Jini lookup service example class Client.java
is shown in CODE EXAMPLE 4-1.
public class Client { private static boolean debug = false; public static ServiceRegistrar getRegistrar() throws IOException, ClassNotFoundException, MalformedURLException { final String jurl = System.getProperty("jini.lookup.url","jini://localhost"); final LookupLocator lookup = new LookupLocator(jurl); final ServiceRegistrar registrar = lookup.getRegistrar(); if (registrar instanceof Administrable) debug("Registry is administrable."); return registrar; } public static List lookup(ServiceRegistrar registrar, String name) throws IOException { final ArrayList list = new ArrayList(); final Class[] classes = new Class[] {JMXConnector.class}; final Entry[] serviceAttrs = new Entry[] { new net.jini.lookup.entry.Name(name) }; ServiceTemplate template = new ServiceTemplate(null,classes,serviceAttrs); ServiceMatches matches = registrar.lookup(template, Integer.MAX_VALUE); for(int i = 0; i < matches.totalMatches; i++) { debug("Found Service: " + matches.items[i].serviceID); if (debug) { if (matches.items[i].attributeSets != null) { final Entry[] attrs = matches.items[i].attributeSets; for (int j = 0; j < attrs.length ; j++) { debug("Attribute["+j+"]=" + attrs[j]); } } } if(matches.items[i].service != null) { JMXConnector c = (JMXConnector)(matches.items[i].service); debug("Found a JMXConnector: " + c); list.add(c); } } return list; } [...]
CODE EXAMPLE 4-1 shows how
the connector client obtains a pointer to the Jini lookup service
with a call to lookup.getRegistrar()
.
The client then obtains the list of the connectors registered as
entries in the Jini lookup service with the agent name name
. Unlike in the SLP example, the agent name you
pass to Client
when it is launched must
be either an exact match of an existing agent name, or null, in
which case the Jini lookup service will look up all the agents.
Once the list of connectors has been obtained, in
code that is not shown here, the client connects to the MBean
server started by Server
, and retrieves
the list of all the MBeans registered in it.
The java.policy
file is
a Java technology security policy file, configured for this
example.
A template Jini networking technology properties
file, to be configured for this example. Change
@INSTALL_HOME_FOR_JINI@ and rename the file to jini.properties
.
In addition to the actions you performed in Section "Initial Configuration", before you can run the lookup service examples that use the Jini lookup service, you must perform some further initial actions that are specific to this example. You can then start looking up connectors using the Jini network technology, in conjunction with the connector supported by the JMX technology.
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 Section a. "RMI connector over JRMP,
without an external directory." is called
example-server-a
.
The following steps are required by all of the different transports you can run in this example.
In addition to the common environment variables that you set in Section "Initial Configuration" you can add the path to the Jini lookup service. The directory where you have installed the Jini networking technology is referred to as jini_dir.
$
JINI_HOME=jini_dir
$
JINILIB=$JINI_HOME/lib
classp
environment
variable.
This example requires the JAR files for the Jini lookup services core and extensions.
$
classp=$JINILIB/jini-core.jar:$JINILIB/jini-ext.jar
jini.properties
file.
A properties file for Solaris, Linux, or Mac OS X platforms is provided in the same directory as the classes for this example. If you are not running a Solaris, Linux, or Mac OS X platform, you can obtain a properties file for your platform in the following directory:
$JINI_HOME/example/launcher/jini12_<platform>.properties
jini.properties
file.
You must complete the file to include all the necessary paths, host names and port numbers for your system. Even if you are not running a Solaris, Linux, or Mac OS X platform, you can use the template provided as a guide.
StartService
.
$
java -cp $JINILIB/jini-examples.jar
com.sun.jini.example.launcher.StartService &
This will open the StartService
graphical user interface.
jini.properties
file into
StartService
.
Click on ‘File’, ‘Open Property
File’ and then select your properties file from within
work_dir/jmx_examples
/Lookup/jini.
Start the required Jini lookup services by clicking on the ‘Run’ tab and then pressing the ‘START’ button for each of the following:
You will see confirmation that the services are running.
Client
and Server
classes.
Type the following command:
$
javac -d . -classpath $classp Server.java
Client.java
This example demonstrates the use of the Jini lookup service to look up RMI connector servers that use RMI’s default transport, JRMP, as well as the IIOP transport. In addition, as described in Section "Initial Configuration", different external directories are used to register the RMI connector stubs.
The combinations of transports and external directories demonstrated here are:
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
.
Start Server by typing the following command:
$ java -classpath .:$classp -Ddebug=true \ -Dagent.name=example-server-a \ -Durl="service:jmx:rmi://" \ -Djava.security.policy=java.policy \ jini.Server &
In this command:
debug
is set to true
to provide more complete screen output when the
Server
runs.example-server-a
.When Server
is
launched, you will see confirmation of the creation of the RMI
connector, and the registration of its URL in the Jini lookup
service.
Start Server by typing the following command:
$ java -classpath .:$classp -Ddebug=true \ -Dagent.name=example-server-b \ -Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \ -Djava.security.policy=java.policy \ jini.Server &
In this command:
example-server-b
.server
, is stored is the RMI registry
you identified as jndirmi
in Section
"Initial Configuration".When Server
is
launched, you will see confirmation of the creation of the RMI
connector, and the registration of its URL in the Jini lookup
service.
Start 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.security.policy=java.policy \ -Djava.naming.security.principal="$principal" \ -Djava.naming.security.credentials="$credentials" \ jini.Server &
In this command:
example-server-c
.The service URL specifies the
chosen 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 Section
"Initial Configuration".Test
domain component in the LDAP server.principal
and password credentials
are given to
gain access to the LDAP server.When Server
is
launched, you will see confirmation of the creation of the RMI
connector, and the registration of its URL in the Jini lookup
service under the agent name example-server-c
.
Start Server
by typing
the following command:
$ java -classpath .:$classp -Ddebug=true \ -Dagent.name=example-server-d \ -Durl="service:jmx:iiop://" \ -Djava.security.policy=java.policy \ jini.Server &
In this command:
example-server-d
When the Server
is
launched, you will see confirmation of the creation of the RMI
connector, and the registration of its automatically generated URL
in the Jini lookup service.
Start Server
by typing
the following command:
$ java -classpath .:$classp -Ddebug=true \ -Dagent.name=example-server-e \ -Durl="service:jmx:iiop:///jndi/${jndiiiop}/server" \ -Djava.security.policy=java.policy \ jini.Server &
In this command:
example-server-e
.server
, is stored is the CORBA naming
service you identified as jndiiiop
in
Section "Initial
Configuration".When Server
is
launched, you will see confirmation of the creation of the RMI
connector, and the registration of its URL in the Jini lookup
service under the name example-server-e
.
Start Server by typing the following command:
$ java -classpath .:$classp -Ddebug=true \ -Dagent.name=example-server-f \ -Durl="service:jmx:iiop:///jndi/${jndildap}/cn=x,dc=Test" \ -Djava.security.policy=java.policy \ -Djava.naming.security.principal="$principal" \ -Djava.naming.security.credentials="$credentials" \ jini.Server &
In this command:
example-server-f
.jndildap
in Section
"Initial Configuration".Test
domain component in the LDAP server.principal
and password credentials
are given to
gain access to the LDAP server.When Server
is launched, you will see confirmation of the creation of the RMI
connector, and the registration of its URL in the Jini lookup
service under the agent name example-server-f
.
Client
.After starting the Server
using the transport and external directory of
your choice, start the 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, you can do so by typing the following command:
$ java -classpath .:$classp -Ddebug=true \ -Djava.security.policy=java.policy \ -Dagent.name=agentName \ jini.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
.
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 JNDI/LDAP lookup example is contained in the
directory work_dir/jmx_examples/Lookup/ldap
.
/jmx_examples/Lookup/ldap
directory.
Inside this directory, you will find the following files:
These classes will be analyzed in the following sections.
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.
Due to its size, the JNDI/LDAP lookup service
Server.java
class is shown as a series
of code excerpts.
[...] 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 4-1 shows the
initial creation of an MBean server mbs
,
and the obtention of a pointer to the root context of the LDAP
directory tree in which the connector server address is to be
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
InitialLdapContext
, from which the
initial LDAP context is obtained.
Code that is omitted from CODE EXAMPLE 4-1 retrieves the agent name under which the connector will be registered in the LDAP server.
[...] 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 4-2 shows the
registration of JMX connector server service URL in the LDAP
directory. 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 later the commands used start the
server). If the dn
System property is
not specified, then you can use the DN: cn=
name where name is the agentName
.
Naturally, this is not mandatory. The location where the URL is
registered does not really 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 here 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 4-1).
The code shown in CODE EXAMPLE 4-2 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). Since 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. Once again, this is completely
optional. Any structural class to which the jmxConnector
auxiliary class could be added would be
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. So you
need only 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 startedjmxAgentName
: contains the JMX agent
namejmxProtocolType
: contains the JMX
protocol type, as returned by jmxUrl.getProtocolType()
jmxAgentHost
: contains the name of
the agent hostjmxExpirationDate
: contains the date
at which the URL will be considered obsolete.[...] 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; } [...]
In CODE EXAMPLE 4-3, a new RMI
connector server named rmis
is created
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.
[...] 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 4-4 shows the
creation of a JMX connector server server
, the obtention of a pointer to the LDAP
server root directory root
and the
creation of a URL for 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.
The JNDI/LDAP lookup service Client.java
class is shown in CODE EXAMPLE 4-1.
[...] 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 CODE EXAMPLE 4-1, the
Client
firstly returns a pointer
root
to the LDAP directory DirContext
, 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 Server
.
The jmx-schema.txt
file
is the LDAP schema file for the JMX Remote API.
The 60jmx-schema.ldif
file is an ldif
file corresponding to
the LDAP schema file, jmx-schema.txt
,
for JMX technology. If you are using Sun ONE Directory Server, this
file can be copied directly to the config/schema
directory of the Sun ONE Directory
Server (see Section "Setting up the JNDI/LDAP
Lookup Service Example").
In addition to the actions you performed in Section "Initial Configuration", before you can run the lookup service examples that use the JNDI/LDAP lookup service, you must perform some further initial 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.
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 Section a. "RMI connector over JRMP,
without an external directory." is called
example-server-a
.
The following steps are required by all of the different connector/transport combinations you can run in this example.
Do this according to the type of LDAP server you are using.
schema
directory.
For example, if you are using Sun ONE Directory Server 5.0, you would type:
$
cp 60jmx-schema.ldif
/var/ds5/slapd-<hostname>/config/schema
Otherwise, do this according to the type of LDAP server you are using.
Do this according to the type of LDAP server you are using.
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 Section
"Initial Configuration".
$
provider="ldap://$ldaphost:$ldapport/dc=Test"
Client
and Server
classes.
$
javac -d . Server.java
Client.java
This example demonstrates the use of the JNDI/LDAP lookup service to look up RMI connector servers that use RMI’s default transport, JRMP, as well as the IIOP transport. In addition, as described in Section "Initial Configuration", different external directories are used to register the RMI connector stubs.
The combinations of transports and external directories demonstrated here are:
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
.
Start 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:
debug
is set to true to provide more
complete screen output when the Server
runs.example-server-a
.provider
, that points to
the domain component suffix in which the agent will be registered,
is given.principal
and password credentials
are given to
gain access to the LDAP server.When 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.
Start 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:
example-server-b
.provider
, that points to
the domain component suffix in which the agent will be registered,
is given.principal
and password credentials
are given to
gain access to the LDAP server.server
, is stored is the RMI registry
you identified as jndirmi
in Section
"Initial Configuration".When 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.
Start 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:
example-server-c
.provider
, that points to
the domain component suffix in which the agent will be registered,
is given.principal
and password credentials
are given to
gain access to the LDAP server.jndildap
in Section
"Initial Configuration".When 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 under the agent name example-server-c
.
Start Server
by typing
the following command:
$ java -classpath . -Ddebug=true \ -Dagent.name=example-server-d \ -Durl="service:jmx:iiop://" \ -Djava.naming.provider.url="$provider" \ -Djava.naming.security.principal="$principal" \ -Djava.naming.security.credentials="$credentials" \ jndi.Server &
In this command:
example-server-d
.provider
, that points to
the domain component suffix in which the agent will be registered,
is given.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 automatically generated URL
in the JNDI/LDAP lookup service.
Start Server
by typing
the following command:
$ java -classpath . -Ddebug=true \ -Dagent.name=example-server-e \ -Durl="service:jmx:iiop:///jndi/${jndiiiop}/server" \ -Djava.naming.provider.url="$provider" \ -Djava.naming.security.principal="$principal" \ -Djava.naming.security.credentials="$credentials" \ jndi.Server &
In this command:
example-server-e
.provider
, that points to
the domain component suffix in which the agent will be registered,
is given.principal
and password credentials
are given to
gain access to the LDAP server.jndiiiop
in Section
"Initial Configuration".When 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 under the name example-server-e
.
Start Server
by typing
the following command:
$ java -classpath . -Ddebug=true \ -Dagent.name=example-server-f \ -Durl="service:jmx:iiop:///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:
example-server-f
.provider
, that points to
the domain component suffix in which the agent will be registered,
is given.principal
and password credentials
are given to
gain access to the LDAP server.jndildap
in Section
"Initial Configuration".When 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 under the agent name example-server-f
.
Client
.After starting the Server
using the transport and external directory of
your choice, start the Client
:
$ java -classpath . -Ddebug=true \ -Djava.naming.provider.url="$provider" \ -Djava.naming.security.principal="$principal" \ -Djava.naming.security.credentials="$credentials" \ jndi.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 . -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.