In last tutorial we learned about JMX Basics and how can we use JConsole to manage MBeans. Today we will look into java jmx client example and role based authentication through config files.
Java JMX Client
Although JConsole provides a graphical view but it requires human effort to work with MBean and not suitable where you want to invoke some features of MBean periodically. For example, you have a MBean that provides the current state of application and you want to invoke it to check the state every 10 minutes. In this case, having a java program that can work as JMX Client to connect to JMX MBean server and invoke MBean operations are very useful.
JMX Client Example
Here we will write a java program that can connect to MBean server and create a proxy application to invoke MBean operations. I will use the MBean application created in JMX Tutorial and use our client program to connect to MBean. Later on we will check how to make our MBean server secure using JMX Configuration files for role based access and how we can use credentials in the JMX Client to connect to MBean server with correct role.
Before writing JMX Client application, we need to know the port where MBean server is running. Also for starter, we will disable all the authentication. We can do all these by passing correct java options.
So I will start my MBean with following command. Notice the java options specified for MBean server port and disabling SSL and authentication.
pankaj@JD:~/CODE/JavaProject/bin$ java -cp . -Dcom.sun.management.jmxremote.port=1234 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false com.journaldev.jmx.SystemConfigManagement
Thread Count=10:::Schema Name=default
Thread Count=10:::Schema Name=default
Thread Count=10:::Schema Name=default
...
JMX URL
For client application to get the MBean proxy, first we need to create JMXServiceURL
by passing the RMI host and port.
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + HOST + ":" + PORT + "/jmxrmi");
After that we have to get the JMXConnector
instance using it’s factory class.
JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
After that we get MBeanServerConnection
from the JMXConnector instance.
MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
After that we get MBean proxy instance using MBeanServerInvocationHandler
.
//ObjectName should be same as your MBean name
ObjectName mbeanName = new ObjectName("com.journaldev.jmx:type=SystemConfig");
//Get MBean proxy instance that will be used to make calls to registered MBean
SystemConfigMBean mbeanProxy =
(SystemConfigMBean) MBeanServerInvocationHandler.newProxyInstance(
mbeanServerConnection, mbeanName, SystemConfigMBean.class, true);
Once we get the proxy instance, we can invoke any operation exposed by the MBean.
Java JMX Client Example Program
Here is the complete JMX Client program that connects to the MBean server and get the SystemConfig MBean proxy instance and invoke exposed methods.
package com.journaldev.jmx;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class SystemConfigClient {
public static final String HOST = "localhost";
public static final String PORT = "1234";
public static void main(String[] args) throws IOException, MalformedObjectNameException {
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + HOST + ":" + PORT + "/jmxrmi");
JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
//ObjectName should be same as your MBean name
ObjectName mbeanName = new ObjectName("com.journaldev.jmx:type=SystemConfig");
//Get MBean proxy instance that will be used to make calls to registered MBean
SystemConfigMBean mbeanProxy =
(SystemConfigMBean) MBeanServerInvocationHandler.newProxyInstance(
mbeanServerConnection, mbeanName, SystemConfigMBean.class, true);
//let's make some calls to mbean through proxy and see the results.
System.out.println("Current SystemConfig::" + mbeanProxy.doConfig());
mbeanProxy.setSchemaName("NewSchema");
mbeanProxy.setThreadCount(5);
System.out.println("New SystemConfig::" + mbeanProxy.doConfig());
//let's terminate the mbean by making thread count as 0
mbeanProxy.setThreadCount(0);
//close the connection
jmxConnector.close();
}
}
Before running the client application, make sure our MBean application is started with command given at start of the post.
When we will execute client application, it will print following to console.
Current SystemConfig::No of Threads=10 and DB Schema Name=default
New SystemConfig::No of Threads=5 and DB Schema Name=NewSchema
If you will check terminal where our MBean application is running, you will find following output before program terminates.
Thread Count=10:::Schema Name=default
Thread Count=10:::Schema Name=default
Thread Count=0:::Schema Name=NewSchema
So now we know how to write JMX Client program that can connect to remote MBean server and create MBean proxy to use attributes and operations exposed by MBean.
JMX Role Based Authentication
Let’s start configuring our MBean for role based authentication. For this we need to create three files.
- JMX Access File: This file contains the roles and access associated with the roles. The access types are
readonly
orreadwrite
. For our purpose, createjmxremote.access
file with following content.jmxremote.access
myrole readwrite
So the role is “myrole” and it has readwrite access to the MBeans.
- JMX Password File: This file contains the password of the different roles we have, the password are cleartext, so Java adds a restriction that only application owner should have read-write access on the file.
Create a file
jmxremote.password
with following content.jmxremote.password
myrole MYP@SSWORD
After file is created change permission using command
chmod 600 jmxremote.password
. - JMX Management Config File: This file contains the JMX properties like port, authentication rules, SSL etc. Create a file
management.properties
with following content.management.properties
#enable remote management of MBean com.sun.management.jmxremote=true com.sun.management.jmxremote.port=1234 com.sun.management.jmxremote.local.only=false #enable authentication com.sun.management.jmxremote.authenticate=true com.sun.management.jmxremote.password.file=/Users/pankaj/CODE/JavaProject/bin/jmxremote.password com.sun.management.jmxremote.access.file=/Users/pankaj/CODE/JavaProject/bin/jmxremote.access #disable SSL authentication com.sun.management.jmxremote.ssl=false
Notice the file path given for access file and password file.
Once all the required files are we will start our JMX MBean application with following command.
java -cp . -Dcom.sun.management.config.file=management.properties com.journaldev.jmx.SystemConfigManagement
Now if you will try to run our JMX Client application, it will throw following exception.
Exception in thread "main" java.lang.SecurityException: Authentication failed! Credentials required
at com.sun.jmx.remote.security.JMXPluggableAuthenticator.authenticationFailure(JMXPluggableAuthenticator.java:211)
at com.sun.jmx.remote.security.JMXPluggableAuthenticator.authenticate(JMXPluggableAuthenticator.java:163)
at sun.management.jmxremote.ConnectorBootstrap$AccessFileCheckerAuthenticator.authenticate(ConnectorBootstrap.java:219)
at javax.management.remote.rmi.RMIServerImpl.doNewClient(RMIServerImpl.java:232)
The exception message clearly shows that we need to provide credentials to access the JMX MBean. To provide credentials we need to add following code to our client program.
//for passing credentials for password
Map<String, String[]> env = new HashMap<>();
String[] credentials = {"myrole", "MYP@SSWORD"};
env.put(JMXConnector.CREDENTIALS, credentials);
JMXConnector jmxConnector = JMXConnectorFactory.connect(url, env);
Notice the constructor is changed to provide credentials while connecting to JMX MBean server. Now the program will run fine and produce same output as earlier.
That’s all for Java JMX Client example and JMX authentication for role based access.
I am very much new to jmx. I tried the same and able to connect to the osgi container with the simple java application. But getting connection error in web application deployed in jboss application server. Could you please guide me on this? I want to show all the bundles information deployed in the osgi container from a separate web application running on the same jvm and in different container.
Simple and straightforward as always. I always try to find your tutorial for any new point I want to learn. And this time also it fulfilled my expectations. Keep it up. Thanks again 馃檪
Hi,
With this JMX client I can see system related mbeans but not those which I created. And I can see my mbeans in JConsole.
Using below code to get the registered mbeans but not able to find my mbeans
Set queryNames = mbeanServerConnection.queryNames(null, null);
It would be very helpful if anybody can help me.
Thanks
Srinivas T
Thanks Pankaj, this article is surely going to help a lot of beginners like me. Keep up the good work. Would appreciate to have few more advance examples on JMX.
Dear Pankaj
Thanks a lot for these two very well written tutorials on JMX.
I am professor at University Savoie Mont Blanc (France) on Computer Science and I will use them for my students (master 1 and 2).
I espially aprreciated the progressive presentation of the technical points.
I only rewrote the various classes (and changed their names) to discrad the threaCount variable which could introduuce some confusion since in fact, the example application doesn’t use threads.
Best regards,
Patrice.
Hi Patrice,
Thanks for liking the articles and sharing with your students, is it a digital publication or you are using it in the class?
i dont want to see all the mbeans while i connect using jconsole
Hello Pankaj,
i am new to Java and I am given a task for JMX. Your article was quite nice and I have created an mbean server. I can access it by jconsole.
Now I am strugling to make it secure with username and passwrod invocation from remote access.
I dont need to create any client program. Just i need to ensure that my mbeans methods are not accesible without authentication.
my locla servre runs on localhos:8080.
My question is what is the url ? is it localhost:8080 ?
I have prepared att the password, acess, properties files. I just need to check by using jconsole whether i can access my mbean with proper credential.
Please suggest me.
System.setProperty(“com.sun.management.jmxremote”, “true”);
System.setProperty(“java.rmi.server.randomIDs”, “true”);
System.setProperty(“com.sun.management.jmxremote.port”, “6789”);
System.setProperty(“com.sun.management.jmxremote.ssl”, “false”);
System.setProperty(“com.sun.management.jmxremote.ssl.need.client.auth”, “true”);
System.setProperty(“com.sun.management.jmxremote.authenticate”, “true”);
System.setProperty(“com.sun.management.jmxremote.password.file”,”C:/Program Files/Java/jdk1.7.0_25/jre/lib/management/jmxremote.password”);
System.setProperty(“com.sun.management.jmxremote.access.file”,”C:/Program Files/Java/jdk1.7.0_25/jre/lib/management/jmxremote.access”);
Thank you so much Pankaj. I really like your way of explanation and simple example.
I was having trouble making a JMXConnector with authentication enabled work. Thank you for the lovely working snippets !
You are welcome Binita.