Skip to content

Commit

Permalink
Support multiple health groups with an additional path with Jersey
Browse files Browse the repository at this point in the history
This commit knowingly makes breaking API changes to
JerseyHealthEndpointAdditionalPathResourceFactory. We considered
other options but they all had the potential to be backwards
incompatible in one way or another. Faced with that situation we
concluded that the likelihood of anyone using the modified API
directly is small enough to warrant making the breaking changes.
If it becomes apparent that we have misjudged things we can revisit
the changes in the future.

Closes gh-36250
  • Loading branch information
wilkinsona committed Jul 7, 2023
1 parent 76cd102 commit 52f7329
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private void register(ResourceConfig config) {
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
WebServerNamespace.MANAGEMENT, this.groups);
Collection<Resource> endpointResources = resourceFactory
.createEndpointResources(mapping, Collections.singletonList(this.endpoint), null, null, false)
.createEndpointResources(mapping, Collections.singletonList(this.endpoint))
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ private void register(ResourceConfig config) {
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
WebServerNamespace.SERVER, this.groups);
Collection<Resource> endpointResources = resourceFactory
.createEndpointResources(mapping, Collections.singletonList(this.endpoint), null, null, false)
.createEndpointResources(mapping, Collections.singletonList(this.endpoint))
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;

import static org.assertj.core.api.Assertions.assertThatNoException;

/**
* Abstract base class for health groups with an additional path.
*
Expand All @@ -52,6 +54,18 @@ void groupIsAvailableAtAdditionalPath() {
.run(withWebTestClient(this::testResponse, "local.server.port"));
}

@Test
void multipleGroupsAreAvailableAtAdditionalPaths() {
this.runner
.withPropertyValues("management.endpoint.health.group.one.include=diskSpace",
"management.endpoint.health.group.two.include=diskSpace",
"management.endpoint.health.group.one.additional-path=server:/alpha",
"management.endpoint.health.group.two.additional-path=server:/bravo",
"management.endpoint.health.group.one.show-components=always",
"management.endpoint.health.group.two.show-components=always")
.run(withWebTestClient((client) -> testResponses(client, "/alpha", "/bravo"), "local.server.port"));
}

@Test
void groupIsAvailableAtAdditionalPathWithoutSlash() {
this.runner
Expand Down Expand Up @@ -125,17 +139,24 @@ void groupsAreNotConfiguredWhenHealthEndpointIsNotExposedWithDifferentManagement
}

private void testResponse(WebTestClient client) {
client.get()
.uri("/healthz")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.jsonPath("status")
.isEqualTo("UP")
.jsonPath("components.diskSpace")
.exists();
testResponses(client, "/healthz");
}

private void testResponses(WebTestClient client, String... paths) {
for (String path : paths) {
assertThatNoException().as(path)
.isThrownBy(() -> client.get()
.uri(path)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.jsonPath("status")
.isEqualTo("UP")
.jsonPath("components.diskSpace")
.exists());
}
}

private ContextConsumer<A> withWebTestClient(Consumer<WebTestClient> consumer, String property) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2023 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.
Expand All @@ -16,11 +16,17 @@

package org.springframework.boot.actuate.endpoint.web.jersey;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.glassfish.jersey.server.model.Resource;

import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
Expand All @@ -35,7 +41,9 @@
* @author Madhura Bhave
* @since 2.6.0
*/
public class JerseyHealthEndpointAdditionalPathResourceFactory extends JerseyEndpointResourceFactory {
public final class JerseyHealthEndpointAdditionalPathResourceFactory {

private final JerseyEndpointResourceFactory delegate = new JerseyEndpointResourceFactory();

private final Set<HealthEndpointGroup> groups;

Expand All @@ -47,20 +55,30 @@ public JerseyHealthEndpointAdditionalPathResourceFactory(WebServerNamespace serv
this.groups = groups.getAllWithAdditionalPath(serverNamespace);
}

@Override
protected Resource createResource(EndpointMapping endpointMapping, WebOperation operation) {
public Collection<Resource> createEndpointResources(EndpointMapping endpointMapping,
Collection<ExposableWebEndpoint> endpoints) {
return endpoints.stream()
.flatMap((endpoint) -> endpoint.getOperations().stream())
.flatMap((operation) -> createResources(endpointMapping, operation))
.collect(Collectors.toList());
}

private Stream<Resource> createResources(EndpointMapping endpointMapping, WebOperation operation) {
WebOperationRequestPredicate requestPredicate = operation.getRequestPredicate();
String matchAllRemainingPathSegmentsVariable = requestPredicate.getMatchAllRemainingPathSegmentsVariable();
if (matchAllRemainingPathSegmentsVariable != null) {
List<Resource> resources = new ArrayList<>();
for (HealthEndpointGroup group : this.groups) {
AdditionalHealthEndpointPath additionalPath = group.getAdditionalPath();
if (additionalPath != null) {
return getResource(endpointMapping, operation, requestPredicate, additionalPath.getValue(),
this.serverNamespace, (data, pathSegmentsVariable) -> data.getUriInfo().getPath());
resources.add(this.delegate.getResource(endpointMapping, operation, requestPredicate,
additionalPath.getValue(), this.serverNamespace,
(data, pathSegmentsVariable) -> data.getUriInfo().getPath()));
}
}
return resources.stream();
}
return null;
return Stream.empty();
}

}

0 comments on commit 52f7329

Please sign in to comment.