Skip to content

Commit c000863

Browse files
committed
Add session endpoints
1 parent 1da9e4d commit c000863

File tree

4 files changed

+221
-0
lines changed

4 files changed

+221
-0
lines changed

spring-boot-actuator/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@
213213
<artifactId>spring-security-config</artifactId>
214214
<optional>true</optional>
215215
</dependency>
216+
<dependency>
217+
<groupId>org.springframework.session</groupId>
218+
<artifactId>spring-session</artifactId>
219+
<optional>true</optional>
220+
</dependency>
216221
<dependency>
217222
<groupId>org.apache.tomcat.embed</groupId>
218223
<artifactId>tomcat-embed-core</artifactId>

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfiguration.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,21 @@
3535
import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint;
3636
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
3737
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
38+
import org.springframework.boot.actuate.endpoint.mvc.SessionMvcEndpoint;
3839
import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint;
3940
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
4041
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
42+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
4143
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
4244
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
4345
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4446
import org.springframework.context.annotation.Bean;
4547
import org.springframework.context.annotation.ConditionContext;
4648
import org.springframework.context.annotation.Conditional;
49+
import org.springframework.context.annotation.Configuration;
4750
import org.springframework.core.env.Environment;
4851
import org.springframework.core.type.AnnotatedTypeMetadata;
52+
import org.springframework.session.FindByIndexNameSessionRepository;
4953
import org.springframework.util.CollectionUtils;
5054
import org.springframework.util.StringUtils;
5155
import org.springframework.web.cors.CorsConfiguration;
@@ -54,6 +58,7 @@
5458
* Configuration to expose {@link Endpoint} instances over Spring MVC.
5559
*
5660
* @author Dave Syer
61+
* @author Eddú Meléndez
5762
* @since 1.3.0
5863
*/
5964
@ManagementContextConfiguration
@@ -166,6 +171,19 @@ public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) {
166171
return new ShutdownMvcEndpoint(delegate);
167172
}
168173

174+
@Configuration
175+
@ConditionalOnClass(FindByIndexNameSessionRepository.class)
176+
@ConditionalOnBean(FindByIndexNameSessionRepository.class)
177+
static class SessionMvcEndpointConfiguration {
178+
179+
@Bean
180+
@ConditionalOnEnabledEndpoint("session")
181+
public SessionMvcEndpoint sessionMvcEndpoint() {
182+
return new SessionMvcEndpoint();
183+
}
184+
185+
}
186+
169187
private static class LogFileCondition extends SpringBootCondition {
170188

171189
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.endpoint.mvc;
18+
19+
import java.util.Collection;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.boot.actuate.endpoint.Endpoint;
23+
import org.springframework.boot.context.properties.ConfigurationProperties;
24+
import org.springframework.session.ExpiringSession;
25+
import org.springframework.session.FindByIndexNameSessionRepository;
26+
import org.springframework.web.bind.annotation.PathVariable;
27+
import org.springframework.web.bind.annotation.RequestMapping;
28+
import org.springframework.web.bind.annotation.RequestMethod;
29+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
30+
31+
/**
32+
* {@link MvcEndpoint} to expose actuator session.
33+
*
34+
* @author Eddú Meléndez
35+
* @since 1.4.0
36+
*/
37+
@ConfigurationProperties("endpoints.session")
38+
public class SessionMvcEndpoint extends WebMvcConfigurerAdapter
39+
implements MvcEndpoint {
40+
41+
/**
42+
* Endpoint URL path.
43+
*/
44+
private String path = "/session";
45+
46+
/**
47+
* Enable the endpoint.
48+
*/
49+
private boolean enabled = true;
50+
51+
@Autowired
52+
private FindByIndexNameSessionRepository<? extends ExpiringSession> sessionRepository;
53+
54+
@RequestMapping(path = "/{username}", method = RequestMethod.GET)
55+
public Collection<? extends ExpiringSession> result(@PathVariable String username) {
56+
return this.sessionRepository.findByIndexNameAndIndexValue(
57+
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username)
58+
.values();
59+
}
60+
61+
@RequestMapping(path = "/{sessionId}", method = RequestMethod.DELETE)
62+
public void delete(@PathVariable String sessionId) {
63+
ExpiringSession session = this.sessionRepository.getSession(sessionId);
64+
if (session != null) {
65+
this.sessionRepository.delete(sessionId);
66+
}
67+
}
68+
69+
public void setPath(String path) {
70+
this.path = path;
71+
}
72+
73+
@Override
74+
public String getPath() {
75+
return this.path;
76+
}
77+
78+
public void setEnabled(boolean enabled) {
79+
this.enabled = enabled;
80+
}
81+
82+
public boolean isEnabled() {
83+
return this.enabled;
84+
}
85+
86+
@Override
87+
public boolean isSensitive() {
88+
return true;
89+
}
90+
91+
@Override
92+
public Class<? extends Endpoint> getEndpointType() {
93+
return Endpoint.class;
94+
}
95+
96+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.endpoint.mvc;
18+
19+
import java.util.Set;
20+
21+
import org.junit.Before;
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
27+
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
28+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
29+
import org.springframework.boot.test.context.SpringBootTest;
30+
import org.springframework.context.annotation.Bean;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.context.annotation.Import;
33+
import org.springframework.session.FindByIndexNameSessionRepository;
34+
import org.springframework.test.annotation.DirtiesContext;
35+
import org.springframework.test.context.junit4.SpringRunner;
36+
import org.springframework.test.web.servlet.MockMvc;
37+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
38+
import org.springframework.web.context.WebApplicationContext;
39+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
40+
41+
import static org.assertj.core.api.Assertions.assertThat;
42+
import static org.mockito.Mockito.mock;
43+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
44+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
45+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
46+
47+
/**
48+
* Tests for {@link SessionMvcEndpoint}
49+
*
50+
* @author Eddú Meléndez
51+
*/
52+
@RunWith(SpringRunner.class)
53+
@DirtiesContext
54+
@SpringBootTest
55+
public class SessionMvcEndpointTests {
56+
57+
@Autowired
58+
private MvcEndpoints endpoints;
59+
60+
@Autowired
61+
private WebApplicationContext context;
62+
63+
private MockMvc mvc;
64+
65+
@Before
66+
public void setUp() {
67+
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
68+
}
69+
70+
@Test
71+
public void endpointRegistered() {
72+
Set<? extends MvcEndpoint> values = this.endpoints.getEndpoints();
73+
assertThat(values).hasAtLeastOneElementOfType(SessionMvcEndpoint.class);
74+
}
75+
76+
@Test
77+
public void searchEndpointAvailable() throws Exception {
78+
this.mvc.perform(get("/session/springuser"))
79+
.andExpect(status().isOk());
80+
}
81+
82+
@Test
83+
public void deleteEndpointAvailable() throws Exception {
84+
this.mvc.perform(delete("/session/123"))
85+
.andExpect(status().isOk());
86+
}
87+
88+
@Configuration
89+
@EnableConfigurationProperties
90+
@EnableWebMvc
91+
@Import({ EndpointWebMvcAutoConfiguration.class,
92+
ManagementServerPropertiesAutoConfiguration.class })
93+
public static class Config {
94+
95+
@Bean
96+
public FindByIndexNameSessionRepository findByIndexNameSessionRepository() {
97+
return mock(FindByIndexNameSessionRepository.class);
98+
}
99+
100+
}
101+
102+
}

0 commit comments

Comments
 (0)