Browse Source
User adds @OnManagementContext to a bean or @Configuration and it should be included in the management context (if there is one) whether it is the main context or a child. Makes it easy to secure the management endpoints and keep the rest open (see actuator-ui-sample). [#50721675]pull/2/merge
21 changed files with 756 additions and 133 deletions
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
/* |
||||
* Copyright 2012-2013 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.bootstrap.actuate.autoconfigure; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.springframework.context.annotation.Conditional; |
||||
|
||||
/** |
||||
* A bean with this annotation will only be instantiated in the management context, |
||||
* whether that is the current context or a child context. Using this feature makes it |
||||
* easy to have a single set of configuration beans for both contexts and be able to |
||||
* switch the management features to a child context externally. Very useful if (for |
||||
* instance) you want management endpoints but open, or differently secured public facing |
||||
* endpoints. |
||||
* |
||||
* @author Dave Syer |
||||
* |
||||
*/ |
||||
@Conditional(OnManagementContextCondition.class) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Target({ ElementType.TYPE, ElementType.METHOD }) |
||||
public @interface ConditionalOnManagementContext { |
||||
|
||||
} |
||||
@ -0,0 +1,163 @@
@@ -0,0 +1,163 @@
|
||||
/* |
||||
* Copyright 2012-2013 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.bootstrap.actuate.autoconfigure; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
|
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.beans.factory.BeanCreationException; |
||||
import org.springframework.beans.factory.BeanFactory; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.bootstrap.actuate.autoconfigure.ManagementAutoConfiguration.RememberManagementConfiguration; |
||||
import org.springframework.bootstrap.actuate.properties.ManagementServerProperties; |
||||
import org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerCustomizerConfiguration; |
||||
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; |
||||
import org.springframework.bootstrap.properties.ServerProperties; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.ApplicationContextAware; |
||||
import org.springframework.context.ApplicationListener; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Condition; |
||||
import org.springframework.context.annotation.ConditionContext; |
||||
import org.springframework.context.annotation.Conditional; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.context.event.ContextClosedEvent; |
||||
import org.springframework.context.event.ContextRefreshedEvent; |
||||
import org.springframework.core.env.ConfigurableEnvironment; |
||||
import org.springframework.core.env.Environment; |
||||
import org.springframework.core.type.AnnotatedTypeMetadata; |
||||
import org.springframework.util.ClassUtils; |
||||
|
||||
/** |
||||
* @author Dave Syer |
||||
* |
||||
*/ |
||||
@Configuration |
||||
@Conditional(RememberManagementConfiguration.class) |
||||
@Import(ManagementEndpointsRegistration.class) |
||||
public class ManagementAutoConfiguration implements ApplicationContextAware { |
||||
|
||||
public static final String MEMO_BEAN_NAME = ManagementAutoConfiguration.class |
||||
.getName() + ".MEMO"; |
||||
|
||||
private ApplicationContext parent; |
||||
private ConfigurableApplicationContext context; |
||||
|
||||
@Autowired |
||||
private ServerProperties configuration = new ServerProperties(); |
||||
|
||||
@Autowired |
||||
private ManagementServerProperties management = new ManagementServerProperties(); |
||||
|
||||
@Override |
||||
public void setApplicationContext(ApplicationContext applicationContext) |
||||
throws BeansException { |
||||
this.parent = applicationContext; |
||||
} |
||||
|
||||
@Bean |
||||
public ApplicationListener<ContextClosedEvent> managementContextClosedListener() { |
||||
return new ApplicationListener<ContextClosedEvent>() { |
||||
@Override |
||||
public void onApplicationEvent(ContextClosedEvent event) { |
||||
if (event.getSource() != ManagementAutoConfiguration.this.parent) { |
||||
return; |
||||
} |
||||
if (ManagementAutoConfiguration.this.context != null) { |
||||
ManagementAutoConfiguration.this.context.close(); |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
@Bean |
||||
public ApplicationListener<ContextRefreshedEvent> managementContextRefeshedListener() { |
||||
|
||||
return new ApplicationListener<ContextRefreshedEvent>() { |
||||
|
||||
@Override |
||||
public void onApplicationEvent(ContextRefreshedEvent event) { |
||||
|
||||
if (event.getSource() != ManagementAutoConfiguration.this.parent) { |
||||
return; |
||||
} |
||||
|
||||
if (ManagementAutoConfiguration.this.configuration.getPort() != ManagementAutoConfiguration.this.management |
||||
.getPort()) { |
||||
AnnotationConfigEmbeddedWebApplicationContext context = new AnnotationConfigEmbeddedWebApplicationContext(); |
||||
context.setParent(ManagementAutoConfiguration.this.parent); |
||||
context.setEnvironment((ConfigurableEnvironment) ManagementAutoConfiguration.this.parent |
||||
.getEnvironment()); |
||||
context.register(assembleConfigClasses(ManagementAutoConfiguration.this.parent)); |
||||
context.refresh(); |
||||
ManagementAutoConfiguration.this.context = context; |
||||
|
||||
} |
||||
} |
||||
|
||||
}; |
||||
|
||||
} |
||||
|
||||
protected static class RememberManagementConfiguration implements Condition { |
||||
|
||||
@Override |
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { |
||||
Environment environment = context.getEnvironment(); |
||||
int serverPort = environment.getProperty("server.port", Integer.class, 8080); |
||||
int managementPort = environment.getProperty("management.port", |
||||
Integer.class, serverPort); |
||||
if (!context.getBeanFactory().containsSingleton(MEMO_BEAN_NAME)) { |
||||
context.getBeanFactory().registerSingleton(MEMO_BEAN_NAME, |
||||
managementPort > 0); |
||||
} |
||||
return managementPort > 0; |
||||
} |
||||
|
||||
} |
||||
|
||||
protected Class<?>[] assembleConfigClasses(BeanFactory parent) { |
||||
|
||||
// Some basic context configuration that all child context need
|
||||
ArrayList<Class<?>> configs = new ArrayList<Class<?>>(Arrays.<Class<?>> asList( |
||||
EmbeddedContainerCustomizerConfiguration.class, |
||||
ManagementServerConfiguration.class, ErrorConfiguration.class)); |
||||
|
||||
String managementContextBeanName = OnManagementContextCondition.class.getName(); |
||||
|
||||
// Management context only beans pulled in from the deferred list in the parent
|
||||
// context
|
||||
if (parent.containsBean(managementContextBeanName)) { |
||||
String[] names = parent.getBean(managementContextBeanName, String[].class); |
||||
for (String name : names) { |
||||
try { |
||||
configs.add(ClassUtils.forName(name, |
||||
ManagementAutoConfiguration.this.parent.getClassLoader())); |
||||
} catch (ClassNotFoundException e) { |
||||
throw new BeanCreationException(managementContextBeanName, |
||||
"Class not found: " + name); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return configs.toArray(new Class<?>[configs.size()]); |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,103 +0,0 @@
@@ -1,103 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2013 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.bootstrap.actuate.autoconfigure; |
||||
|
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.bootstrap.actuate.properties.ManagementServerProperties; |
||||
import org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerCustomizerConfiguration; |
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnExpression; |
||||
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; |
||||
import org.springframework.bootstrap.properties.ServerProperties; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.ApplicationContextAware; |
||||
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.annotation.Import; |
||||
import org.springframework.context.event.ContextClosedEvent; |
||||
import org.springframework.context.event.ContextRefreshedEvent; |
||||
|
||||
/** |
||||
* @author Dave Syer |
||||
* |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnExpression("${management.port:${server.port:8080}}>0") |
||||
public class ManagementConfiguration implements ApplicationContextAware { |
||||
|
||||
private ApplicationContext parent; |
||||
private ConfigurableApplicationContext context; |
||||
|
||||
@Autowired |
||||
private ServerProperties configuration = new ServerProperties(); |
||||
|
||||
@Autowired |
||||
private ManagementServerProperties management = new ManagementServerProperties(); |
||||
|
||||
@ConditionalOnExpression("${server.port:8080} == ${management.port:${server.port:8080}}") |
||||
@Configuration |
||||
@Import({ MetricsConfiguration.class, HealthConfiguration.class, |
||||
ShutdownConfiguration.class, TraceConfiguration.class }) |
||||
public static class ManagementEndpointsConfiguration { |
||||
} |
||||
|
||||
@Override |
||||
public void setApplicationContext(ApplicationContext applicationContext) |
||||
throws BeansException { |
||||
this.parent = applicationContext; |
||||
} |
||||
|
||||
@Bean |
||||
public ApplicationListener<ContextClosedEvent> managementContextClosedListener() { |
||||
return new ApplicationListener<ContextClosedEvent>() { |
||||
@Override |
||||
public void onApplicationEvent(ContextClosedEvent event) { |
||||
if (event.getSource() != ManagementConfiguration.this.parent) { |
||||
return; |
||||
} |
||||
if (ManagementConfiguration.this.context != null) { |
||||
ManagementConfiguration.this.context.close(); |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
@Bean |
||||
public ApplicationListener<ContextRefreshedEvent> managementContextRefeshedListener() { |
||||
return new ApplicationListener<ContextRefreshedEvent>() { |
||||
@Override |
||||
public void onApplicationEvent(ContextRefreshedEvent event) { |
||||
if (event.getSource() != ManagementConfiguration.this.parent) { |
||||
return; |
||||
} |
||||
if (ManagementConfiguration.this.configuration.getPort() != ManagementConfiguration.this.management |
||||
.getPort()) { |
||||
AnnotationConfigEmbeddedWebApplicationContext context = new AnnotationConfigEmbeddedWebApplicationContext(); |
||||
context.setParent(ManagementConfiguration.this.parent); |
||||
context.register(EmbeddedContainerCustomizerConfiguration.class, |
||||
ManagementServerConfiguration.class, |
||||
MetricsConfiguration.class, HealthConfiguration.class, |
||||
ShutdownConfiguration.class, TraceConfiguration.class); |
||||
context.refresh(); |
||||
ManagementConfiguration.this.context = context; |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright 2012-2013 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.bootstrap.actuate.autoconfigure; |
||||
|
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
|
||||
/** |
||||
* Convenient collector for all the management endpoints (stuff that goes in the |
||||
* management context whether it is a child context or not). |
||||
* |
||||
* @author Dave Syer |
||||
* |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnManagementContext |
||||
@Import({ MetricsConfiguration.class, HealthConfiguration.class, |
||||
ShutdownConfiguration.class, TraceConfiguration.class }) |
||||
public class ManagementEndpointsRegistration { |
||||
|
||||
} |
||||
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
/* |
||||
* Copyright 2012-2013 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.bootstrap.actuate.autoconfigure; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.HashSet; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; |
||||
import org.springframework.bootstrap.context.annotation.ConditionLogUtils; |
||||
import org.springframework.context.annotation.Condition; |
||||
import org.springframework.context.annotation.ConditionContext; |
||||
import org.springframework.core.env.Environment; |
||||
import org.springframework.core.type.AnnotatedTypeMetadata; |
||||
import org.springframework.core.type.AnnotationMetadata; |
||||
|
||||
/** |
||||
* A condition that can determine if the bean it applies to is in the management context |
||||
* (the application context with the management endpoints). |
||||
* |
||||
* @author Dave Syer |
||||
* |
||||
* @see ConditionalOnManagementContext |
||||
* |
||||
*/ |
||||
public class OnManagementContextCondition implements Condition { |
||||
|
||||
private static Log logger = LogFactory.getLog(OnManagementContextCondition.class); |
||||
|
||||
@Override |
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { |
||||
|
||||
String checking = ConditionLogUtils.getPrefix(logger, metadata); |
||||
|
||||
Environment environment = context.getEnvironment(); |
||||
int serverPort = environment.getProperty("server.port", Integer.class, 8080); |
||||
int managementPort = environment.getProperty("management.port", Integer.class, |
||||
serverPort); |
||||
|
||||
// If there is no management context, the decision is easy (match=false)
|
||||
boolean managementEnabled = managementPort > 0; |
||||
|
||||
// The management context is the same as the parent context
|
||||
boolean managementContextInParent = serverPort == managementPort; |
||||
|
||||
// The current context is a child context with a management server
|
||||
boolean managementChildContext = context.getBeanFactory().getBeanNamesForType( |
||||
ManagementServerConfiguration.class).length > 0; |
||||
|
||||
// The management auto configuration either hasn't been added yet or has been
|
||||
// added to the context and it is enabled
|
||||
boolean containsManagementBeans = !context.getBeanFactory().containsSingleton( |
||||
ManagementAutoConfiguration.MEMO_BEAN_NAME) |
||||
|| (Boolean) context.getBeanFactory().getSingleton( |
||||
ManagementAutoConfiguration.MEMO_BEAN_NAME); |
||||
|
||||
boolean result = managementEnabled |
||||
&& ((managementContextInParent && containsManagementBeans) || managementChildContext); |
||||
|
||||
if (logger.isDebugEnabled()) { |
||||
if (!managementEnabled) { |
||||
logger.debug(checking + "Management context is disabled"); |
||||
} else { |
||||
logger.debug(checking + "Management context is in parent: " |
||||
+ managementContextInParent + " (management.port=" |
||||
+ managementPort + ", server.port=" + serverPort + ")"); |
||||
logger.debug(checking + "In management child context: " |
||||
+ managementChildContext); |
||||
logger.debug(checking + "In management parent context: " |
||||
+ containsManagementBeans); |
||||
logger.debug(checking + "Finished matching and result is matches=" |
||||
+ result); |
||||
} |
||||
} |
||||
|
||||
if (!result && metadata instanceof AnnotationMetadata) { |
||||
Collection<String> beanClasses = getManagementContextClasses(context |
||||
.getBeanFactory()); |
||||
beanClasses.add(((AnnotationMetadata) metadata).getClassName()); |
||||
} |
||||
return result; |
||||
|
||||
} |
||||
|
||||
private Collection<String> getManagementContextClasses( |
||||
ConfigurableListableBeanFactory beanFactory) { |
||||
String name = OnManagementContextCondition.class.getName(); |
||||
if (!beanFactory.containsSingleton(name)) { |
||||
beanFactory.registerSingleton(name, new HashSet<String>()); |
||||
} |
||||
@SuppressWarnings("unchecked") |
||||
Collection<String> result = (Collection<String>) beanFactory.getSingleton(name); |
||||
return result; |
||||
} |
||||
|
||||
} |
||||
@ -1,2 +1,4 @@
@@ -1,2 +1,4 @@
|
||||
org.springframework.bootstrap.context.annotation.EnableAutoConfiguration=\ |
||||
org.springframework.bootstrap.actuate.autoconfigure.ActuatorAutoConfiguration |
||||
org.springframework.bootstrap.actuate.autoconfigure.ActuatorAutoConfiguration,\ |
||||
org.springframework.bootstrap.actuate.autoconfigure.SecurityAutoConfiguration,\ |
||||
org.springframework.bootstrap.actuate.autoconfigure.ManagementAutoConfiguration |
||||
|
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
||||
<groupId>org.springframework.bootstrap</groupId> |
||||
<artifactId>spring-bootstrap-samples</artifactId> |
||||
<version>0.5.0.BUILD-SNAPSHOT</version> |
||||
</parent> |
||||
<artifactId>spring-bootstrap-actuator-ui-sample</artifactId> |
||||
<properties> |
||||
<m2eclipse.wtp.contextRoot>/</m2eclipse.wtp.contextRoot> |
||||
<start-class>org.springframework.bootstrap.sample.ui.UiBootstrapApplication</start-class> |
||||
</properties> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>${project.groupId}</groupId> |
||||
<artifactId>spring-bootstrap</artifactId> |
||||
<version>${project.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>${project.groupId}</groupId> |
||||
<artifactId>spring-bootstrap-actuator</artifactId> |
||||
<version>${project.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.thymeleaf</groupId> |
||||
<artifactId>thymeleaf-spring3</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.tomcat.embed</groupId> |
||||
<artifactId>tomcat-embed-core</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.tomcat.embed</groupId> |
||||
<artifactId>tomcat-embed-logging-juli</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.hibernate</groupId> |
||||
<artifactId>hibernate-validator</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-jdk14</artifactId> |
||||
<scope>runtime</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.security</groupId> |
||||
<artifactId>spring-security-javaconfig</artifactId> |
||||
</dependency> |
||||
</dependencies> |
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<artifactId>maven-dependency-plugin</artifactId> |
||||
</plugin> |
||||
<plugin> |
||||
<artifactId>maven-shade-plugin</artifactId> |
||||
</plugin> |
||||
<plugin> |
||||
<artifactId>maven-exec-plugin</artifactId> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
</project> |
||||
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
package org.springframework.bootstrap.sample.ui; |
||||
|
||||
import java.util.Date; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.bootstrap.SpringApplication; |
||||
import org.springframework.bootstrap.actuate.autoconfigure.ConditionalOnManagementContext; |
||||
import org.springframework.bootstrap.actuate.autoconfigure.ManagementAutoConfiguration; |
||||
import org.springframework.bootstrap.actuate.autoconfigure.SecurityAutoConfiguration; |
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnExpression; |
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; |
||||
import org.springframework.context.annotation.ComponentScan; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.stereotype.Controller; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
||||
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, |
||||
ManagementAutoConfiguration.class }) |
||||
@ComponentScan |
||||
@Controller |
||||
public class ActuatorUiBootstrapApplication { |
||||
|
||||
@RequestMapping("/") |
||||
public String home(Map<String, Object> model) { |
||||
model.put("message", "Hello World"); |
||||
model.put("title", "Hello Home"); |
||||
model.put("date", new Date()); |
||||
return "home"; |
||||
} |
||||
|
||||
public static void main(String[] args) throws Exception { |
||||
SpringApplication.run(ActuatorUiBootstrapApplication.class, args); |
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnExpression("${server.port:8080} != ${management.port:${server.port:8080}}") |
||||
@Import(ManagementAutoConfiguration.class) |
||||
protected static class ManagementConfiguration { |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnExpression("${server.port:8080} != ${management.port:${server.port:8080}}") |
||||
@ConditionalOnManagementContext |
||||
@Import(SecurityAutoConfiguration.class) |
||||
protected static class ManagementSecurityConfiguration { |
||||
|
||||
} |
||||
|
||||
} |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html> |
||||
<html xmlns:th="http://www.thymeleaf.org"> |
||||
<head> |
||||
<title th:text="${title}">Title</title> |
||||
<link rel="stylesheet" th:href="@{/resources/css/bootstrap.min.css}" |
||||
href="../../resources/css/bootstrap.min.css" /> |
||||
</head> |
||||
<body> |
||||
<div class="container"> |
||||
<div class="navbar"> |
||||
<div class="navbar-inner"> |
||||
<a class="brand" href="http://www.thymeleaf.org"> Thymeleaf - |
||||
Plain </a> |
||||
<ul class="nav"> |
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li> |
||||
</ul> |
||||
</div> |
||||
</div> |
||||
<h1 th:text="${title}">Title</h1> |
||||
<div th:text="${message}">Fake content</div> |
||||
<div id="created" th:text="${#dates.format(date)}">July 11, |
||||
2012 2:17:16 PM CDT</div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
package org.springframework.bootstrap.sample.ui; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.concurrent.Callable; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.Future; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import org.junit.AfterClass; |
||||
import org.junit.BeforeClass; |
||||
import org.junit.Test; |
||||
import org.springframework.bootstrap.SpringApplication; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.http.client.ClientHttpResponse; |
||||
import org.springframework.web.client.DefaultResponseErrorHandler; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
/** |
||||
* Basic integration tests for demo application. |
||||
* |
||||
* @author Dave Syer |
||||
* |
||||
*/ |
||||
public class ActuatorUiBootstrapApplicationTests { |
||||
|
||||
private static ConfigurableApplicationContext context; |
||||
|
||||
@BeforeClass |
||||
public static void start() throws Exception { |
||||
Future<ConfigurableApplicationContext> future = Executors |
||||
.newSingleThreadExecutor().submit( |
||||
new Callable<ConfigurableApplicationContext>() { |
||||
@Override |
||||
public ConfigurableApplicationContext call() throws Exception { |
||||
return (ConfigurableApplicationContext) SpringApplication |
||||
.run(ActuatorUiBootstrapApplication.class); |
||||
} |
||||
}); |
||||
context = future.get(30, TimeUnit.SECONDS); |
||||
} |
||||
|
||||
@AfterClass |
||||
public static void stop() { |
||||
if (context != null) { |
||||
context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void testHome() throws Exception { |
||||
ResponseEntity<String> entity = getRestTemplate().getForEntity( |
||||
"http://localhost:8080", String.class); |
||||
assertEquals(HttpStatus.OK, entity.getStatusCode()); |
||||
assertTrue("Wrong body (title doesn't match):\n" + entity.getBody(), entity |
||||
.getBody().contains("<title>Hello")); |
||||
} |
||||
|
||||
@Test |
||||
public void testCss() throws Exception { |
||||
ResponseEntity<String> entity = getRestTemplate().getForEntity( |
||||
"http://localhost:8080/css/bootstrap.min.css", String.class); |
||||
assertEquals(HttpStatus.OK, entity.getStatusCode()); |
||||
assertTrue("Wrong body:\n" + entity.getBody(), entity.getBody().contains("body")); |
||||
} |
||||
|
||||
private RestTemplate getRestTemplate() { |
||||
RestTemplate restTemplate = new RestTemplate(); |
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { |
||||
@Override |
||||
public void handleError(ClientHttpResponse response) throws IOException { |
||||
} |
||||
}); |
||||
return restTemplate; |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,94 @@
@@ -0,0 +1,94 @@
|
||||
package org.springframework.bootstrap.sample.ui; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
import java.util.concurrent.Callable; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.Future; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import org.junit.AfterClass; |
||||
import org.junit.BeforeClass; |
||||
import org.junit.Test; |
||||
import org.springframework.bootstrap.SpringApplication; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.http.client.ClientHttpResponse; |
||||
import org.springframework.web.client.DefaultResponseErrorHandler; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
/** |
||||
* Integration tests for separate management and main service ports. |
||||
* |
||||
* @author Dave Syer |
||||
* |
||||
*/ |
||||
public class ManagementServiceBootstrapApplicationTests { |
||||
|
||||
private static ConfigurableApplicationContext context; |
||||
|
||||
private static int port = 9000; |
||||
private static int managementPort = 9001; |
||||
|
||||
@BeforeClass |
||||
public static void start() throws Exception { |
||||
final String[] args = new String[] { "--server.port=" + port, |
||||
"--management.port=" + managementPort, "--management.address=127.0.0.1" }; |
||||
Future<ConfigurableApplicationContext> future = Executors |
||||
.newSingleThreadExecutor().submit( |
||||
new Callable<ConfigurableApplicationContext>() { |
||||
@Override |
||||
public ConfigurableApplicationContext call() throws Exception { |
||||
return (ConfigurableApplicationContext) SpringApplication |
||||
.run(ActuatorUiBootstrapApplication.class, args); |
||||
} |
||||
}); |
||||
context = future.get(10, TimeUnit.SECONDS); |
||||
} |
||||
|
||||
@AfterClass |
||||
public static void stop() { |
||||
if (context != null) { |
||||
context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void testHome() throws Exception { |
||||
ResponseEntity<String> entity = getRestTemplate().getForEntity( |
||||
"http://localhost:" + port, String.class); |
||||
assertEquals(HttpStatus.OK, entity.getStatusCode()); |
||||
} |
||||
|
||||
@Test |
||||
public void testMetrics() throws Exception { |
||||
@SuppressWarnings("rawtypes") |
||||
ResponseEntity<Map> entity = getRestTemplate().getForEntity( |
||||
"http://localhost:" + managementPort + "/metrics", Map.class); |
||||
assertEquals(HttpStatus.UNAUTHORIZED, entity.getStatusCode()); |
||||
} |
||||
|
||||
@Test |
||||
public void testHealth() throws Exception { |
||||
ResponseEntity<String> entity = getRestTemplate().getForEntity( |
||||
"http://localhost:" + managementPort + "/health", String.class); |
||||
assertEquals(HttpStatus.OK, entity.getStatusCode()); |
||||
assertEquals("ok", entity.getBody()); |
||||
} |
||||
|
||||
private RestTemplate getRestTemplate() { |
||||
|
||||
RestTemplate restTemplate = new RestTemplate(); |
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { |
||||
@Override |
||||
public void handleError(ClientHttpResponse response) throws IOException { |
||||
} |
||||
}); |
||||
return restTemplate; |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
handlers = java.util.logging.ConsoleHandler |
||||
.level = INFO |
||||
|
||||
java.util.logging.ConsoleHandler.level = FINE |
||||
sun.net.www.protocol.http.HttpURLConnection.level = ALL |
||||
org.springframework.bootstrap.context.annotation.level = ALL |
||||
org.springframework.bootstrap.actuate.autoconfigure.level = ALL |
||||
Loading…
Reference in new issue