grails-profiles/base/commands/stop-app.groovy (85 lines of code) (raw):
import javax.management.remote.JMXServiceURL
import javax.management.remote.JMXConnectorFactory
import javax.management.ObjectName
import org.grails.io.support.*
import groovy.jmx.GroovyMBean
description("Stops the running Grails application") {
usage "grails stop-app"
synonyms 'stop'
flag name:'port', description:"Specifies the port which the Grails application is running on (defaults to 8080 or 8443 for HTTPS)"
flag name:'host', description:"Specifies the host the Grails application is bound to"
}
System.setProperty("run-app.running", "false")
def getJMXLocalConnectorAddresses = {->
final applicationMainClassName = MainClassFinder.findMainClass()
if(applicationMainClassName) {
try {
final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress"
def VirtualMachine = getClass().classLoader.loadClass('com.sun.tools.attach.VirtualMachine')
return VirtualMachine.list()
.findAll {
it.displayName() == applicationMainClassName
}
.collect { desc ->
def vm = VirtualMachine.attach(desc.id())
try {
def connectorAddress = vm.agentProperties.getProperty(CONNECTOR_ADDRESS)
if (connectorAddress == null) {
// Trying to load agent
def agent = [vm.systemProperties.getProperty("java.home"), "lib", "management-agent.jar"].join(File.separator)
vm.loadAgent(agent)
connectorAddress = vm.agentProperties.getProperty(CONNECTOR_ADDRESS)
}
if (connectorAddress) {
return connectorAddress
}
} finally {
vm.detach()
}
}.findAll { it }
}
catch(Throwable e) {
// fallback to REST request if JMX not available
}
}
}
def addresses = getJMXLocalConnectorAddresses()
if(addresses) {
JMXServiceURL url = new JMXServiceURL(addresses[0])
def connector = JMXConnectorFactory.connect(url)
try {
def server = connector.MBeanServerConnection
def objectName = server.queryNames(null,null).find { it.canonicalName.contains('name=shutdownEndpoint,type=Endpoint') }
def mbean = new GroovyMBean(server, objectName)
console.addStatus "Shutting down application..."
mbean.shutdown()
console.addStatus "Application shutdown."
return true
}
catch(e) {
console.addStatus "Application not found via JMX, attempting remote shutdown."
}
finally {
connector.close()
}
}
Integer port = flag('port')?.toInteger() ?: config.getProperty('server.port', Integer) ?: 8080
String host = flag('host') ?: config.getProperty('server.address', String) ?: "localhost"
String contextPath = config.getProperty('server.context-path') ?: config.getProperty('server.contextPath') ?: ""
String managementPath = config.getProperty('management.endpoints.web.base-path') ?: config.getProperty('management.endpoints.web.basePath') ?: "/actuator"
console.updateStatus "Shutting down application..."
def url = new URL("http://$host:${port}${contextPath}${managementPath}/shutdown")
try {
def connection = url.openConnection()
connection.setRequestMethod("POST")
connection.doOutput = true
connection.connect()
console.updateStatus connection.content.text
while(isServerAvailable(host, port)) {
sleep 100
}
console.updateStatus "Application shutdown."
return true
}
catch (e) {
console.error "Application not running.", e
return false
}