I'm working on a project that uses Tapestry and ActiveMQ together; it works great on my Mac, but on my client's Windows workstation, ActiveMQ doesn't shut down cleanly and corrupts its local files pretty consistently.
Unfortunately, there isn't a way (using RunJettyRun, the Eclipse plugin for Jetty) to gracefully shutdown Jetty. You just pull the plug on it, mid execution.
Looking for a solution, I realized that Jetty can expose most of its internals via JMX; this would allow us to start it up and shut it down cleanly in development.
So, I created a Groovy LaunchApp class to launch Jetty with JMX enabled:
package com.example.main import java.lang.management.ManagementFactory import org.eclipse.jetty.jmx.MBeanContainer import org.eclipse.jetty.server.Server import org.eclipse.jetty.webapp.WebAppContext import org.slf4j.LoggerFactory /** * Alternative the RunJettyRun Eclipse plugin that allows greater control over how Jetty starts up. */ class LaunchApp { static PORT = 8080 public static void main(String[] args) { def LOG = LoggerFactory.getLogger(LaunchApp.class) LOG.info "Starting up Jetty ${Server.getVersion()} instance on port $PORT ..." def server = new Server(PORT) server.stopAtShutdown = true server.gracefulShutdown = 1000 // 1 second def context = new WebAppContext() context.setContextPath "/" context.setWar "src/main/webapp" server.setHandler context def mBeanServer = ManagementFactory.getPlatformMBeanServer(); def mBeanContainer = new MBeanContainer(mBeanServer); server.container.addEventListener(mBeanContainer); mBeanContainer.start(); server.start() LOG.info "Join the fun at http://localhost:$PORT/landing" server.join() LOG.info("Jetty instance has shut down") } }... and a Groovy StopApp class:
package com.example.main import javax.management.ObjectName import javax.management.remote.JMXConnectorFactory import javax.management.remote.JMXServiceURL /** * The flip-side of {@link LaunchApp}, this tool locates the running Jetty instance and uses JMX * to request a graceful shutdown. */ class StopApp { static JMX_PORT = 8085 static JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:$JMX_PORT/jmxrmi" public static void main(String[] args) { println "Shutting down Jetty instance" def connector = JMXConnectorFactory.connect(new JMXServiceURL(JMX_URL), null) connector.connect null def connection = connector.getMBeanServerConnection() def on = new ObjectName("org.eclipse.jetty.server:type=server,id=0") connection.invoke on, "stop", null, null println "Shutdown command sent" } }
The only trick is to ensure that LaunchApp's JMX MBean server is exposed for access, so you need the following system properties set:
-Dcom.sun.management.jmxremote.port=8085 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false