While studying about JMX, I have seen one of the important feature of it is that it can manage a JVM itself, which i didn't understand about in what sense it can manage JVM. So can anybody elaborate this with some examples.
You can see this for yourself very easily.
Step 1: Download JConsole
Step 2: Start a Java Process (Java 5 or later)
Step 3: Connect to your Java process with JConsole
Step 4: View the MBeans for triggering a heap dump event, a garbage collection request, thread information, loaded classes, etc
Whats particularly interesting is that you can write code to access the MBeans of a running Java program:
There are three different ways to
access the management interfaces. Call
the methods in the MXBean directly
within the same Java virtual machine.
RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
// Get the standard attribute "VmVendor" String vendor = mxbean.getVmVendor();
Go through a MBeanServerConnection
connecting to the platform MBeanServer
of a running virtual machine.
MBeanServerConnection mbs;
// Connect to a running JVM (or itself) and get MBeanServerConnection // that has the JVM MXBeans registered in it ...
try {
// Assuming the RuntimeMXBean has been registered in mbs
ObjectName oname = new ObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME);
// Get standard attribute "VmVendor"
String vendor = (String) mbs.getAttribute(oname, "VmVendor"); } catch (....) {
// Catch the exceptions thrown by ObjectName constructor
// and MBeanServer.getAttribute method
... }
Use MXBean proxy.
MBeanServerConnection mbs;
// Connect to a running JVM (or itself) and get MBeanServerConnection // that has the JVM MBeans registered in it ...
// Get a MBean proxy for RuntimeMXBean interface RuntimeMXBean proxy =
ManagementFactory.newPlatformMXBeanProxy(mbs,
ManagementFactory.RUNTIME_MXBEAN_NAME,
RuntimeMXBean.class); // Get standard attribute "VmVendor" String vendor = proxy.getVmVendor();
See also The Java Language Management API
Related
I have an RMI server which publishes an object like so:
int port = ....;
String name = "...";
Remote server = UnicastRemoteObject.exportObject(someobject, port+1);
Registry registry = LocateRegistry.createRegistry(port);
registry.rebind(name, server);
log.info("created service name "+name+", on port "+(port+1)
+" in registry on port "+port);
When I stop the program and just rerun it, it logs that it has created everything, but then immediately exits, likely due to the rmi server thread exiting (the last non-daemon). I registered a defaultUncaughtExceptionHandler, but get nothing logged from it. Only after a minute or so I am able to restart the program without it immediately exiting.
If I would always use the same port, this would only half surprise me, because I know that ports may be blocked a little while after their last use. But the behavior is the same even if I use a different port (+100 or so) each time.
Any ideas why this happens and how to possible prevent it?
You need to store the result of createRegistry() into a static variable. Otherwise it is liable to be garbage-collected.
When I run jconsole it shows me a list of Java processes:
I could then connect to one of these and see its MBeans. How does it discover the JMX processes? How can I do this in a program?
This article shows how to do it using Attach API from JDK tools.jar
Replying since I had this question too and got an answer.
There is a JPS program in JDK which shows java processes.
I am not 100% sure (don't want to dive deep into jconsole code) but 99% sure jconsole uses the same mechanism as jps:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/tools/jps/Jps.java?av=f
HostIdentifier hostId = arguments.hostId();
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(hostId);
// get the set active JVMs on the specified host.
Set<Integer> jvms = monitoredHost.activeVms();
These class are part of tools.jar, you need to include it in the project's classpath.
If we go deeper (I do not expose all the intermediate steps) - finally we'll know that active VMs list is populated from hsperfdata files in temporary directories:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java
Here is a link to know more:
java hsperfdata directory
At last, here is a code snippet allowing you to get the java processes ids:
sun.jvmstat.monitor.MonitoredHost host = sun.jvmstat.monitor.MonitoredHost.getMonitoredHost(new sun.jvmstat.monitor.HostIdentifier((String) null));
System.out.println(host.activeVms());
P.S.
Then you can use Attach API (as kostya mentioned) to discover the rest of needed things.
After you register the MBean in your application, like this:
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
//register the MBean
ObjectMbean mBean = new ObjectMbean();
ObjectName name = new ObjectName("com.gd.eventfiltering.jmx:type=SystemConfig");
mbs.registerMBean(mBean, name);
Then you can call your MBean like this:
JMXServiceURL url = new JMXServiceURL(JMX_PATH);
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName(JMX_OBJECT);
IObjectMbean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName,IObjectMbean.class, false);
//call the method
List<EventType> filters = mbeanProxy.methodFromYourMBean();
jmxc.close();
i'm looking for a way to manage tomcat (on localhost) programmatically via java.
I want to start/stop tomcat and deploy WARs.
Any help is appreciated.
You can run Tomcat embedded in your app.
The way to start/stop tomcat through java is to call execute on the bootstrap.jar (Use the class Runtime) with the sample parameters: -Dcatalina.home=c:/tomcat/
Sample code to see how ant executes tomcat start stop:
http://ptrthomas.wordpress.com/2006/03/25/how-to-start-and-stop-tomcat-from-ant
Sample code to see how external programs are executed from java:
http://www.linglom.com/2007/06/06/how-to-run-command-line-or-execute-external-application-from-java/
You can use java Runtime class to call a bat file. make sure User running java process has rights to start and stop tomcat.
try{
Runtime.getRuntime().exec("c:/program files/tomcat/bin/startup.bat");
} catch(IOException e) {System.out.println("exception");}
To manage tomcat programmatically, you may want to take a look at JMX and the bulit-in MBeans' capabilities of Tomcat.
In essence, you can write your own java based JMX client to talk to the MBeans via RMI or you can take advantage of the JMX Http Proxy in the Manager App and use plain old http requests to script and manage the tomcat instance.
For a good reference of JMX and Tomcat 6:
http://www.datadisk.co.uk/html_docs/java_app/tomcat6/tomcat6_jmx.htm
A good reference of Manager App and JMX Http Proxy:
http://tomcat.apache.org/tomcat-6.0-doc/manager-howto.html#JMX_Set_command
You should be able to deploy and undeploy WARs fairly easily.
I don't think there is an existing MBean that allow you to shutdown tomcat, but it's fairly easy to implement one yourself and call System.exit();
You can use tomcat manager, or see its sources to learn how manager process the deploy operations.
You can restart individual Tomcat connector i.e. port restart like 8843 where your application is running. One scenario when this is required is when you are getting signed certificate through API or you are modifying your truststore.
Here is the complete code/method that I am using to restart tomcat connectors after I add/delete certificates.
public void refreshTrustStore() throws Exception
{
try
{
//following line need to be replaced based on where you get your port. It may be passed in as argument
String httpsPort = configurationManager.getHttpsPort();
String objectString = "*:type=Connector,port=" + httpsPort + ",*";
final ObjectName objectNameQuery = new ObjectName(objectString);
for (final MBeanServer server : MBeanServerFactory.findMBeanServer(null))
{
if (server.queryNames(objectNameQuery, null).size() > 0)
{
MBeanServer mbeanServer = server;
ObjectName objectName = (ObjectName) server.queryNames(objectNameQuery, null).toArray()[0];
mbeanServer.invoke(objectName, "stop", null, null);
// Polling sleep to reduce delay to safe minimum.
// Use currentTimeMillis() over nanoTime() to avoid issues
// with migrating threads across sleep() calls.
long start = System.currentTimeMillis();
// Maximum of 6 seconds, 3x time required on an idle system.
long max_duration = 6000L;
long duration = 0L;
do
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
duration = (System.currentTimeMillis() - start);
} while (duration < max_duration &&
server.queryNames(objectNameQuery, null).size() > 0);
// Use below to get more accurate metrics.
String message = "TrustStoreManager TrustStore Stop: took " + duration + "milliseconds";
logger.information(message);
mbeanServer.invoke(objectName, "start", null, null);
break;
}
}
}
catch (Exception exception)
{
//Log and throw exception
throw exception
}
}
I'm missing something about the difference between
starting rmiregistry at the command prompt (separately from whatever Java process is running a server that implements an RMI interface)
having the server call LocateRegistry.getRegistry()
having the server call LocateRegistry.createRegistry(Registry.REGISTRY_PORT)
I just want my server to register its exported objects with the registry, creating one if there isn't one running already. What's the best way to do this?
Old thread but...
man rmiregistry
says:
The methods of the java.rmi.registry.LocateRegistry class are used to
get a registry operating on the local host or local host and port.
otherwise you have:
The URL-based methods of the java.rmi.Naming class operate on a registry and can be used to look up a remote object on any host and on the local host
So I guess that's the important difference. Other thing is SecurityManager and policies.
This is how I used to do it, not sure if it is the right way though :/. I also had to mess around with policy files, so if this gives you trouble as well (the security manager part) you must create a policy file and use it.
try
{
try
{
java.rmi.registry.LocateRegistry.createRegistry(1099);
}
catch (java.rmi.server.ExportException e) { /* */ }
System.setSecurityManager(new java.rmi.RMISecurityManager());
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);
registry.rebind(...);
}
catch (Exception e) { /* */ }
}
Using RMI to pass String object from WebAppA to WebAppB.WebAppB is the RMIServer whereas WebAppA is RMIClient.I have added ContextListener in WebAppB, so that the rmi service starts right away when the context is initialized in tomcat.And in the contextDestroyed method of tomcat I am trying to close/shut down rmi using the following statements:
unexportObject(remoteObj,true);
LocateRegistry.getRegistry(3232).unbind("MessagePath"); //MessagePath - name of the remote reference
But even after the execution of the aforeseen statements, rmi is listening for incoming requests at port 3232.I saw that by using "netsat -ano" in command prompt.Please do help me to close RMI Service.
getRegistry returns a stub only, so use the instance returned by createRegistry in unexportObject. However in my case this does not help either - the registry is not active anymore, but the sockets are still open and listening :-(
createRegistry won't work when you're trying to shutdown the registry.
Registry registry = LocateRegistry.createRegistry(3232);
This will throw a BindException when the registry is already running. So you cannot the create object to use it in
UnicastRemoteObject.unexportObject(registry, true);
However, even if you use
Registry registry = LocateRegistry.getRegistry(3232);
You just get the stub, which cannot be used as a parameter to unexport the object.
The reason its a cause of concern for me is because I only wish to start the registry if I could check it has not started yet. And I haven't found a way to do that!
I have found a way of shutting down the registry from any process (and for that matter shutting down any bound processes which are bound in the registry)
Any of the Interfaces which extends remote and which you eventually want to kill off should also extend the following Interface:
public interface PIDSupplierInterface extends Remote {
String getPID() throws RemoteException;
}
every server class you create with this as part of its interface must then implement getPID(). The thing you then have to do is return the process ID. Google "getpids" for Windows, or go here: www.jroller.com/santhosh/entry/get_current_java_process_id. For Linux as I understand it getting the PID is more straightforward. Then (in Windows) you want to go
String PID = myServer.getPID();
String[] a_command = { "taskkill", "/pid", PID };
Runtime.getRuntime().exec(a_command, envp, dir);
to kill off the PID of the registry itself, first, when starting the registry (programatically), simply go
PIDSupplierInterface stub = PIDSupplierInterface)UnicastRemoteObject.exportObject(
new PIDSupplierServer(), 0);
reg.bind( "regKiller", stub );
where PIDSupplierServer is a class which implements only PIDSupplierInterface.
Then, when you want to kill off the RMI registry from any Process just go
PIDSupplierInterface regProcess = (PIDSupplierInterface)reg.lookup( "regKiller" );
String regPID = regProcess.getPID();
String[] a_command = { "taskkill", "/pid", regPID };
Runtime.getRuntime().exec(a_command, envp, dir);
the reg has disappeared from your system. Or is your question more complicated for some reason? Any comments welcome.