diff --git a/spring-platform-config-client/src/main/java/org/springframework/platform/autoconfigure/RefreshAutoConfiguration.java b/spring-platform-config-client/src/main/java/org/springframework/platform/autoconfigure/RefreshAutoConfiguration.java index c1885868..55636aae 100644 --- a/spring-platform-config-client/src/main/java/org/springframework/platform/autoconfigure/RefreshAutoConfiguration.java +++ b/spring-platform-config-client/src/main/java/org/springframework/platform/autoconfigure/RefreshAutoConfiguration.java @@ -20,6 +20,7 @@ package org.springframework.platform.autoconfigure; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -28,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; @@ -83,10 +85,22 @@ public class RefreshAutoConfiguration { @Bean @ConditionalOnMissingBean - public RestartEndpoint restartContextListener() { + public RestartEndpoint restartEndpoint() { return new RestartEndpoint(); } + @Bean + @ConfigurationProperties("endpoints.pause") + public Endpoint pauseEndpoint(RestartEndpoint restartEndpoint) { + return restartEndpoint.getPauseEndpoint(); + } + + @Bean + @ConfigurationProperties("endpoints.resume") + public Endpoint resumeEndpoint(RestartEndpoint restartEndpoint) { + return restartEndpoint.getResumeEndpoint(); + } + @Configuration @ConditionalOnExpression("${endpoints.refresh.enabled:true}") @ConditionalOnBean(ConfigServiceBootstrapConfiguration.class) @@ -124,6 +138,16 @@ public class RefreshAutoConfiguration { return new RestartMvcEndpoint(restartEndpoint); } + @Bean + public MvcEndpoint pauseMvcEndpoint(RestartMvcEndpoint restartEndpoint) { + return restartEndpoint.getPauseEndpoint(); + } + + @Bean + public MvcEndpoint resumeMvcEndpoint(RestartMvcEndpoint restartEndpoint) { + return restartEndpoint.getResumeEndpoint(); + } + } } diff --git a/spring-platform-config-client/src/main/java/org/springframework/platform/config/client/RefreshEndpoint.java b/spring-platform-config-client/src/main/java/org/springframework/platform/config/client/RefreshEndpoint.java index 32e7e341..18b5b247 100644 --- a/spring-platform-config-client/src/main/java/org/springframework/platform/config/client/RefreshEndpoint.java +++ b/spring-platform-config-client/src/main/java/org/springframework/platform/config/client/RefreshEndpoint.java @@ -17,6 +17,7 @@ package org.springframework.platform.config.client; import java.lang.reflect.Field; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -29,6 +30,8 @@ import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.platform.bootstrap.config.ConfigServiceBootstrapConfiguration; import org.springframework.platform.context.environment.EnvironmentChangeEvent; import org.springframework.util.ReflectionUtils; @@ -38,6 +41,7 @@ import org.springframework.util.ReflectionUtils; * */ @ConfigurationProperties(prefix = "endpoints.refresh", ignoreUnknownFields = false) +@ManagedResource public class RefreshEndpoint extends AbstractEndpoint> { private ConfigurableApplicationContext context; @@ -49,18 +53,23 @@ public class RefreshEndpoint extends AbstractEndpoint> { this.context = context; this.bootstrap = bootstrap; } - - @Override - public Collection invoke() { + + @ManagedOperation + public synchronized String[] refresh() { Map before = extract(context.getEnvironment().getPropertySources()); bootstrap.initialize(context); Set keys = changes(before, extract(context.getEnvironment().getPropertySources())).keySet(); if (keys.isEmpty()) { - return keys; + return new String[0]; } context.publishEvent(new EnvironmentChangeEvent(keys)); - return keys; + return keys.toArray(new String[keys.size()]); + } + + @Override + public Collection invoke() { + return Arrays.asList(refresh()); } private Map changes(Map before, diff --git a/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartEndpoint.java b/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartEndpoint.java index e916efe4..be30f19c 100644 --- a/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartEndpoint.java +++ b/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartEndpoint.java @@ -20,11 +20,15 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.actuate.endpoint.AbstractEndpoint; +import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.jmx.export.annotation.ManagedAttribute; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.util.ClassUtils; /** @@ -37,6 +41,7 @@ import org.springframework.util.ClassUtils; * */ @ConfigurationProperties("endpoints.restart") +@ManagedResource public class RestartEndpoint extends AbstractEndpoint implements ApplicationListener { @@ -79,7 +84,48 @@ public class RestartEndpoint extends AbstractEndpoint implements return false; } } + + public Endpoint getPauseEndpoint() { + return new PauseEndpoint(); + } + + public Endpoint getResumeEndpoint() { + return new ResumeEndpoint(); + } + + private class PauseEndpoint extends AbstractEndpoint { + + public PauseEndpoint() { + super("pause", true, true); + } + @Override + public Boolean invoke() { + if (isRunning()) { + pause(); + return true; + } + return false; + } + } + + private class ResumeEndpoint extends AbstractEndpoint { + + public ResumeEndpoint() { + super("resume", true, true); + } + + @Override + public Boolean invoke() { + if (!isRunning()) { + resume(); + return true; + } + return false; + } + } + + @ManagedOperation public synchronized ConfigurableApplicationContext restart() { if (context != null) { context.close(); @@ -90,6 +136,28 @@ public class RestartEndpoint extends AbstractEndpoint implements } return context; } + + @ManagedAttribute + public boolean isRunning() { + if (context != null) { + return context.isRunning(); + } + return false; + } + + @ManagedOperation + public synchronized void pause() { + if (context != null) { + context.stop(); + } + } + + @ManagedOperation + public synchronized void resume() { + if (context != null) { + context.start(); + } + } private void overrideClassLoaderForRestart() { ClassUtils.overrideThreadContextClassLoader(application.getClass().getClassLoader()); diff --git a/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartMvcEndpoint.java b/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartMvcEndpoint.java index 9b9743b7..c3e06ef3 100644 --- a/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartMvcEndpoint.java +++ b/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartMvcEndpoint.java @@ -18,7 +18,9 @@ package org.springframework.platform.context.restart; import java.util.Collections; import java.util.Map; +import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -55,5 +57,34 @@ public class RestartMvcEndpoint extends EndpointMvcAdapter { return Collections.singletonMap( "message", "Restarting"); } + + public MvcEndpoint getPauseEndpoint() { + return new GenericPostableMvcEndpoint(((RestartEndpoint)getDelegate()).getPauseEndpoint()); + } + + public MvcEndpoint getResumeEndpoint() { + return new GenericPostableMvcEndpoint(((RestartEndpoint)getDelegate()).getResumeEndpoint()); + } + + + private static class GenericPostableMvcEndpoint extends EndpointMvcAdapter { + + public GenericPostableMvcEndpoint(Endpoint delegate) { + super(delegate); + } + + @RequestMapping(method = RequestMethod.POST) + @ResponseBody + @Override + public Object invoke() { + if (!getDelegate().isEnabled()) { + return new ResponseEntity>(Collections.singletonMap( + "message", "This endpoint is disabled"), HttpStatus.NOT_FOUND); + } + return super.invoke(); + } + + } + }