JMX-RMI problem

This question is a bit long, but I hope you'll hang in there with me, because I've Googled around a bit and I'm not sure where to go next. It looks like we're having a problem with the RMI server in conjunction with JMX. Here's what happened:

One of our QA folks was using my Spring and JMX-enabled application, hosted on a VMWare virtual machine. Things were fine. Then he took his laptop home, connected the computer through his wireless router, and worked from home. When he came back to the office, he had to release his router's IP address and renew his IP with our network. At that point, my application wouldn't start correctly. When we examined the logs, we found the following:

[exception:BeanCreationException][reason:Error creating bean with name'connectorServer' defined inclass path resource

[proxyServerContext-jmx.xml]: Initialization of bean failed; nested exception is java.io.IOException: Cannot bind to URL

[rmi://10.22.2.61:5000/jmxrmi]: javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException:

Connection refused to host: 10.22.2.61; nested exception is:

java.net.ConnectException: Connection timed out: connect]][stack trace:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:370)

org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:226)

org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:147)

org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:269)

org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:320)

org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:87)

org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:72)

...

Here's what my JMX/Spring configuration looks like:

<!DOCTYPE beans PUBLIC"-//SPRING//DTD BEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean class="org.springframework.jmx.support.MBeanServerFactoryBean"/>

<!-- Configure the RMI Registry -->

<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">

<property name="port" value="5000"/>

</bean>

<!-- Configure the Connector -->

<bean id="connectorServer" class="org.springframework.jmx.support.ConnectorServerFactoryBean">

<property name="serviceUrl" value="service:jmx:rmi://localhost/jndi/rmi://localhost:5000/jmxrmi"/>

</bean>

<bean id="exporter"

class="org.springframework.jmx.export.MBeanExporter">

<property name="beans">

<map>

<entry key="VL3 Proxy Server:type=monitoring,name=Statistics" value-ref="theStatistician"/>

<entry key="VL3 Proxy Server:type=configuration,name=StartUpConfig" value-ref="startUpConfig"/>

<entry key="VL3 Proxy Server:type=control,name=Control" value-ref="control"/>

</map>

</property>

</bean>

...

</beans>

I'd be grateful for your assistance...

Thanks,

Steve

[4080 byte] By [Steve__Ta] at [2007-11-26 16:59:22]
# 1

Steve,

It looks as if you are running into the issue I described at length in <http://weblogs.java.net/blog/emcmanus/archive/2006/12/multihomed_comp.html>. There might be a further twist in that the wireless IP address of the laptop might have changed, so you might see a problem even if there isn't any multihoming in the picture. In that case you might be able to get the ThreadLocalClientSocketFactory that I describe to work.

emcmanusa at 2007-7-8 23:27:09 > top of Java-index,Core,Monitoring & Management...
# 2
Thank you, Eamonn. I appreciate your insight and recommendation. If we confined JMX/JConsole usage to the local machine (i.e. no remote access), would we still see this problem? Just wondering on how to get around it in the short term.Thanks and regards,Steve
Steve__Ta at 2007-7-8 23:27:09 > top of Java-index,Core,Monitoring & Management...
# 3

I guess if you are only accessing from the local machine, you could set java.rmi.server.hostname to "localhost", e.g. with -Djava.rmi.server.hostname=localhost on the command line. That would mean that all RMI communication to that process would be limited to the local machine. But it should work regardless of what is going on with network connections.

emcmanusa at 2007-7-8 23:27:09 > top of Java-index,Core,Monitoring & Management...
# 4

Thanks again. Allow me to clarify. We found this problem while running with remote access enabled through RMI, as I posted.

Since then our requirements have changed, and we are only supporting local JMX/JConsole access for this release (hopefully in the next, we'll be moving to Java 6 with all its JMX benefits!) -- i.e. administration on the same machine. With this in mind, if I remove from my Spring configuration the nodes associated with MBeanServerFactoryBean, RmiRegistryFactoryBean, and ConnectorServerFactoryBean, leaving only the entries for the exported MBeans, and adding

-Dcom.sun.management.jmxremote

to the JVM command line, I can only connect locally. Do you think I will still have the RMI addressing issues with this modified/local configuration? I would think not, but I don't know all the internals of JMX.

Thanks for your patience, and your willingness to help.

Regards,

Steve

Steve__Ta at 2007-7-8 23:27:09 > top of Java-index,Core,Monitoring & Management...
# 5

I'm afraid this will probably not work if you are using a machine whose network address can change. For example, a laptop whose address is obtained with DHCP. Even though the access is local, it still goes through RMI. As I described in the blog entry referenced above, the default behaviour of RMI for a server on machine X is to export objects with the address returned by InetAddress.getLocalHost(). That address is usually the address of your local network interface (Ethernet or WiFi). It might be something like 129.157.203.59.

If you try to connect from machine Y and this address is not reachable from Y, then it will fail. Even if you try to connect locally from machine X it will fail if the old address is no longer valid. This is why I'm suggesting you override this default behaviour of RMI by explicitly setting java.rmi.server.hostname to localhost. Then objects will be exported with the loopback address (127.0.0.1), which is always valid, but of course only useful if you are connecting from the same machine.

I realize this is all very confusing but alas that's the way RMI works.

emcmanusa at 2007-7-8 23:27:09 > top of Java-index,Core,Monitoring & Management...
# 6
Thank you, Eamonn. Your advice was much needed and is very much appreciated. I will pursue what you have recommended.Regards,Steve
Steve__Ta at 2007-7-8 23:27:09 > top of Java-index,Core,Monitoring & Management...