/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.admin;
import java.lang.management.ManagementFactory;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link SpringApplicationAdminMXBeanRegistrar}.
*
* @author Stephane Nicoll
* @author Andy Wilkinson
*/
public class SpringApplicationAdminMXBeanRegistrarTests {
private static final String OBJECT_NAME = "org.springframework.boot:type=Test,name=SpringApplication";
@Rule
public final ExpectedException thrown = ExpectedException.none();
private MBeanServer mBeanServer;
private ConfigurableApplicationContext context;
@Before
public void setup() throws MalformedObjectNameException {
this.mBeanServer = ManagementFactory.getPlatformMBeanServer();
}
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void validateReadyFlag() {
final ObjectName objectName = createObjectName(OBJECT_NAME);
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.addListeners(new ApplicationListener<ContextRefreshedEvent>() {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
assertThat(isApplicationReady(objectName)).isFalse();
}
catch (Exception ex) {
throw new IllegalStateException(
"Could not contact spring application admin bean", ex);
}
}
});
this.context = application.run();
assertThat(isApplicationReady(objectName)).isTrue();
}
@Test
public void eventsFromOtherContextsAreIgnored() throws MalformedObjectNameException {
SpringApplicationAdminMXBeanRegistrar registrar = new SpringApplicationAdminMXBeanRegistrar(
OBJECT_NAME);
ConfigurableApplicationContext context = mock(
ConfigurableApplicationContext.class);
registrar.setApplicationContext(context);
registrar.onApplicationReadyEvent(new ApplicationReadyEvent(new SpringApplication(),
null, mock(ConfigurableApplicationContext.class)));
assertThat(isApplicationReady(registrar)).isFalse();
registrar.onApplicationReadyEvent(
new ApplicationReadyEvent(new SpringApplication(), null, context));
assertThat(isApplicationReady(registrar)).isTrue();
}
private boolean isApplicationReady(SpringApplicationAdminMXBeanRegistrar registrar) {
return (Boolean) ReflectionTestUtils.getField(registrar, "ready");
}
@Test
public void environmentIsExposed() {
final ObjectName objectName = createObjectName(OBJECT_NAME);
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run("--foo.bar=blam");
assertThat(isApplicationReady(objectName)).isTrue();
assertThat(isApplicationEmbeddedWebApplication(objectName)).isFalse();
assertThat(getProperty(objectName, "foo.bar")).isEqualTo("blam");
assertThat(getProperty(objectName, "does.not.exist.test")).isNull();
}
@Test
public void shutdownApp() throws InstanceNotFoundException {
final ObjectName objectName = createObjectName(OBJECT_NAME);
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run();
assertThat(this.context.isRunning()).isTrue();
invokeShutdown(objectName);
assertThat(this.context.isRunning()).isFalse();
this.thrown.expect(InstanceNotFoundException.class); // JMX cleanup
this.mBeanServer.getObjectInstance(objectName);
}
private Boolean isApplicationReady(ObjectName objectName) {
return getAttribute(objectName, Boolean.class, "Ready");
}
private Boolean isApplicationEmbeddedWebApplication(ObjectName objectName) {
return getAttribute(objectName, Boolean.class, "EmbeddedWebApplication");
}
private String getProperty(ObjectName objectName, String key) {
try {
return (String) this.mBeanServer.invoke(objectName, "getProperty",
new Object[] { key }, new String[] { String.class.getName() });
}
catch (Exception ex) {
throw new IllegalStateException(ex.getMessage(), ex);
}
}
private <T> T getAttribute(ObjectName objectName, Class<T> type, String attribute) {
try {
Object value = this.mBeanServer.getAttribute(objectName, attribute);
assertThat(value == null || type.isInstance(value)).isTrue();
return type.cast(value);
}
catch (Exception ex) {
throw new IllegalStateException(ex.getMessage(), ex);
}
}
private void invokeShutdown(ObjectName objectName) {
try {
this.mBeanServer.invoke(objectName, "shutdown", null, null);
}
catch (Exception ex) {
throw new IllegalStateException(ex.getMessage(), ex);
}
}
private ObjectName createObjectName(String jmxName) {
try {
return new ObjectName(jmxName);
}
catch (MalformedObjectNameException e) {
throw new IllegalStateException("Invalid jmx name " + jmxName, e);
}
}
@Configuration
static class Config {
@Bean
public SpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar()
throws MalformedObjectNameException {
return new SpringApplicationAdminMXBeanRegistrar(OBJECT_NAME);
}
}
}