I am currently using the following solution. It works, but the client application that shuts down the main app via JMX throws stack traces. The client app calls close() on the main app's appContext and while the appContext shuts down the JMX connection is broken. I am not sure how to get around this.
The main application:
Code:
public class AppStart {
public static void main(String args[]) {
new ClassPathXmlApplicationContext(args).registerShutdownHook();
}
}
The main application's jmx settings:
Code:
<beans>
<bean id="appShutdownSupport"
class="my.own.class.ApplicationShutdownSupport" />
<bean id="serverConnector"
class="org.springframework.jmx.support.ConnectorServerFactoryBean"
depends-on="mbeanServer">
<property name="daemon" value="true" />
</bean>
<bean id="mbeanServer"
class="org.springframework.jmx.support.MBeanServerFactoryBean" />
<!-- this bean must not be lazily initialized if the exporting is to happen -->
<bean id="exporter"
class="org.springframework.jmx.export.MBeanExporter"
lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=appShutdownSupport"
value-ref="appShutdownSupport" />
</map>
</property>
</bean>
</beans>
The ApplicationShutdownSupport bean implementation:
Code:
public class ApplicationShutdownSupport extends ApplicationObjectSupport implements DisposableBean {
public boolean isContextRequired() {
return true;
}
public void initApplicationContext() {
if (!(getApplicationContext() instanceof ConfigurableApplicationContext)) {
throw new RuntimeException("Unsupported context type: "+
getApplicationContext().getClass());
}
}
public void destroy() throws Exception {
if (((ConfigurableApplicationContext)getApplicationContext()).isActive()) {
((ConfigurableApplicationContext)getApplicationContext()).close();
}
}
}
The client app to stop the main app:
Code:
public class AppStop {
public static void main(String args[]) throws Exception {
AbstractApplicationContext ctx =
new ClassPathXmlApplicationContext(args);
ctx.registerShutdownHook();
((DisposableBean)ctx.getBean("appShutdownSupportProxy")).destroy();
}
}
The client jmx configuration:
Code:
<beans>
<bean id="clientConnector"
class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean">
<property name="serviceUrl"
value="service:jmx:jmxmp://localhost:9875" />
</bean>
<bean id="appShutdownSupportProxy"
class="org.springframework.jmx.access.MBeanProxyFactoryBean">
<property name="objectName"
value="bean:name=appShutdownSupport" />
<property name="proxyInterface"
value="org.springframework.beans.factory.DisposableBean" />
<property name="server" ref="clientConnector" />
</bean>
</beans>
The stacktraces thrown are:
Code:
May 29, 2008 9:56:24 AM ClientCommunicatorAdmin restart
WARNING: Failed to restart: java.net.ConnectException: Connection refused: connect
javax.management.remote.generic.ConnectionClosedException: The connection has been closed by the server.
at com.sun.jmx.remote.generic.ClientSynchroMessageConnectionImpl.close(ClientSynchroMessageConnectionImpl.java:343)
at javax.management.remote.generic.GenericConnector.close(GenericConnector.java:276)
at javax.management.remote.generic.GenericConnector.close(GenericConnector.java:231)
at javax.management.remote.generic.ClientIntermediary$GenericClientCommunicatorAdmin.doStop(ClientIntermediary.java:839)
at com.sun.jmx.remote.opt.internal.ClientCommunicatorAdmin.restart(ClientCommunicatorAdmin.java:133)
at com.sun.jmx.remote.opt.internal.ClientCommunicatorAdmin.gotIOException(ClientCommunicatorAdmin.java:34)
at javax.management.remote.generic.GenericConnector$RequestHandler.execute(GenericConnector.java:622)
at com.sun.jmx.remote.generic.ClientSynchroMessageConnectionImpl$RemoteJob.run(ClientSynchroMessageConnectionImpl.java:528)
at com.sun.jmx.remote.opt.util.ThreadService$ThreadServiceJob.run(ThreadService.java:208)
at com.sun.jmx.remote.opt.util.JobExecutor.run(JobExecutor.java:59)
May 29, 2008 9:56:25 AM ClientIntermediary close
INFO: java.io.IOException: The connection is not currently established.
java.io.IOException: The connection is not currently established.
at com.sun.jmx.remote.generic.ClientSynchroMessageConnectionImpl.checkState(ClientSynchroMessageConnectionImpl.java:577)
at com.sun.jmx.remote.generic.ClientSynchroMessageConnectionImpl.sendOneWay(ClientSynchroMessageConnectionImpl.java:162)
at javax.management.remote.generic.GenericConnector.close(GenericConnector.java:260)
at javax.management.remote.generic.GenericConnector.close(GenericConnector.java:231)
at javax.management.remote.generic.ClientIntermediary$GenericClientCommunicatorAdmin.doStop(ClientIntermediary.java:839)
at com.sun.jmx.remote.opt.internal.ClientCommunicatorAdmin.restart(ClientCommunicatorAdmin.java:133)
at com.sun.jmx.remote.opt.internal.ClientCommunicatorAdmin.gotIOException(ClientCommunicatorAdmin.java:34)
at javax.management.remote.generic.GenericConnector$RequestHandler.execute(GenericConnector.java:622)
at com.sun.jmx.remote.generic.ClientSynchroMessageConnectionImpl$RemoteJob.run(ClientSynchroMessageConnectionImpl.java:528)
at com.sun.jmx.remote.opt.util.ThreadService$ThreadServiceJob.run(ThreadService.java:208)
at com.sun.jmx.remote.opt.util.JobExecutor.run(JobExecutor.java:59)
I dont really see a way around the stack traces and they dont really bother me since the main app does get shut down properly.
Basically I was hoping to get rid of my own AppStart, AppStop, and ApplicationShutdownSupport code and use something from the spring distribution if it exists.