I am attempting to enable my core java application for remote accessibility via JMX. However, two restrictions are making it harder than it should be.
a) I am not at the liberty to change the script which starts the app on the linux box. Therefore, I cannot pass any of the "jmxremote" parameters to the jvm.
b) It is very possible that the remote port ( com.sun.management.jmxremote.port = xxxx
) I specify is not open and I cannot modify the script to try another open port. I must do it automatically.
I tried to get around these restrictions by writing a class with would set all the required jmxremote params as well as find a "free" port.
public class JmxRemoteConnectionHelper{
@Override
public void init( ) throws Exception{
InetAddress address = InetAddress.getLocalHost();
String ipAddress = address.getHostAddress();
String hostname = address.getHostName();
String port = String.valueOf( getFreePort( ) );
System.setProperty("java.rmi.server.hostname", ipAddress );
System.setProperty("com.sun.management.jmxremote", "true" );
System.setProperty("com.sun.management.jmxremote.authenticate", "false" );
System.setProperty("com.sun.management.jmxremote.ssl", "false" );
System.setProperty("com.sun.management.jmxremote.port", port );
}
private final int getFreePort( ){
**//seedPort is passed in the constructor**
int freePort = seedPort;
ServerSocket sSocket = null;
for( int i=ZERO; i<PORT_SCAN_COUNTER; i++ ){
try{
freePort = freePort + i;
sSocket = new ServerSocket( freePort );
//FOUND a free port.
break;
}catch( Exception e ){
//Log
}finally{
if( sSocket != null ){
try{
sSocket.close();
sSocket = null;
}catch(Exception e ){
//Log
}
}
}
}
return freePort;
}
}
As shown below, I, then initialize it via spring.
<bean id="JmxRemoteConnection" class="JmxRemoteConnectionHelper" init-method="init" />
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean" depends-on="JmxRemoteConnection" />
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false" >
<property name="assembler" ref="assembler"/>
<property name="namingStrategy" ref="namingStrategy"/>
<property name="autodetect" value="true"/>
<property name="server" ref="mbeanServer"/>
</bean>
<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
<bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy" lazy-init="true">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
To test, I start the app on my windows machine. It starts up correctly. However, when I bring up JConsole on the same box and try to connect via "remote process" (ip:port), I get a "connection refused" message at the bottom.
My suspicion is that the JMX agent is not seeing any of the remote system properties that I am setting.
I am using JDK 1.6.
Since you are already using Spring I think you should see if using a ConnectorServerFactoryBean
can do what you are looking to do. I've never had to start a remote JMX server but it looks like that's what that object can do for you.
See the answers to this for enabling jmx within the process:
Is it possible to enable remote jmx monitoring programmatically?
To find a free port simply wrap LocateRegistry.createRegistry() in a loop which retries with a new port number until it succeeds. Of course you'll have to communicate the final port number to whatever needs to connect. Alternatively running jstatd on the host should make it discoverable
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With