001/* 002 * Copyright 2012-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.maven; 018 019import java.io.IOException; 020import java.lang.management.ManagementFactory; 021 022import javax.management.InstanceNotFoundException; 023import javax.management.MBeanServerConnection; 024import javax.management.remote.JMXConnector; 025 026import org.apache.maven.plugin.AbstractMojo; 027import org.apache.maven.plugin.MojoExecutionException; 028import org.apache.maven.plugin.MojoFailureException; 029import org.apache.maven.plugins.annotations.LifecyclePhase; 030import org.apache.maven.plugins.annotations.Mojo; 031import org.apache.maven.plugins.annotations.Parameter; 032import org.apache.maven.project.MavenProject; 033 034/** 035 * Stop a spring application that has been started by the "start" goal. Typically invoked 036 * once a test suite has completed. 037 * 038 * @author Stephane Nicoll 039 * @since 1.3.0 040 */ 041@Mojo(name = "stop", requiresProject = true, defaultPhase = LifecyclePhase.POST_INTEGRATION_TEST) 042public class StopMojo extends AbstractMojo { 043 044 /** 045 * The Maven project. 046 * @since 1.4.1 047 */ 048 @Parameter(defaultValue = "${project}", readonly = true, required = true) 049 private MavenProject project; 050 051 /** 052 * Flag to indicate if process to stop was forked. By default, the value is inherited 053 * from the {@link MavenProject}. If it is set, it must match the value used to 054 * {@link StartMojo start} the process. 055 * @since 1.3 056 */ 057 @Parameter(property = "fork") 058 private Boolean fork; 059 060 /** 061 * The JMX name of the automatically deployed MBean managing the lifecycle of the 062 * application. 063 */ 064 @Parameter 065 private String jmxName = SpringApplicationAdminClient.DEFAULT_OBJECT_NAME; 066 067 /** 068 * The port to use to lookup the platform MBeanServer if the application has been 069 * forked. 070 */ 071 @Parameter 072 private int jmxPort = 9001; 073 074 /** 075 * Skip the execution. 076 * @since 1.3.2 077 */ 078 @Parameter(property = "skip", defaultValue = "false") 079 private boolean skip; 080 081 @Override 082 public void execute() throws MojoExecutionException, MojoFailureException { 083 if (this.skip) { 084 getLog().debug("skipping stop as per configuration."); 085 return; 086 } 087 getLog().info("Stopping application..."); 088 try { 089 if (isForked()) { 090 stopForkedProcess(); 091 } 092 else { 093 stop(); 094 } 095 } 096 catch (IOException ex) { 097 // The response won't be received as the server has died - ignoring 098 getLog().debug("Service is not reachable anymore (" + ex.getMessage() + ")"); 099 } 100 } 101 102 private boolean isForked() { 103 if (this.fork != null) { 104 return this.fork; 105 } 106 String property = this.project.getProperties() 107 .getProperty("_spring.boot.fork.enabled"); 108 return Boolean.valueOf(property); 109 } 110 111 private void stopForkedProcess() 112 throws IOException, MojoFailureException, MojoExecutionException { 113 JMXConnector connector = SpringApplicationAdminClient.connect(this.jmxPort); 114 try { 115 MBeanServerConnection connection = connector.getMBeanServerConnection(); 116 doStop(connection); 117 } 118 finally { 119 connector.close(); 120 } 121 } 122 123 private void stop() throws IOException, MojoFailureException, MojoExecutionException { 124 doStop(ManagementFactory.getPlatformMBeanServer()); 125 } 126 127 private void doStop(MBeanServerConnection connection) 128 throws IOException, MojoExecutionException { 129 try { 130 new SpringApplicationAdminClient(connection, this.jmxName).stop(); 131 } 132 catch (InstanceNotFoundException ex) { 133 throw new MojoExecutionException( 134 "Spring application lifecycle JMX bean not found (fork is " + "" 135 + this.fork + "). Could not stop application gracefully", 136 ex); 137 } 138 } 139 140}