-
Notifications
You must be signed in to change notification settings - Fork 40.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for making endpoints accessible via HTTP
This commit adds support for exposing endpoint operations over HTTP. Jersey, Spring MVC, and WebFlux are all supported but the programming model remains web framework agnostic. When using WebFlux, blocking operations are automatically performed on a separate thread using Reactor's scheduler support. Support for web-specific extensions is provided via a new `@WebEndpointExtension` annotation. Closes gh-7970 Closes gh-9946 Closes gh-9947
- Loading branch information
1 parent
4592e07
commit 9687a50
Showing
25 changed files
with
3,130 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
spring-boot/src/main/java/org/springframework/boot/endpoint/web/EndpointLinksResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* 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.endpoint.web; | ||
|
||
import java.util.Collection; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
|
||
import org.springframework.boot.endpoint.EndpointInfo; | ||
|
||
/** | ||
* A resolver for {@link Link links} to web endpoints. | ||
* | ||
* @author Andy Wilkinson | ||
* @since 2.0.0 | ||
*/ | ||
public class EndpointLinksResolver { | ||
|
||
/** | ||
* Resolves links to the operations of the given {code webEndpoints} based on a | ||
* request with the given {@code requestUrl}. | ||
* | ||
* @param webEndpoints the web endpoints | ||
* @param requestUrl the url of the request for the endpoint links | ||
* @return the links | ||
*/ | ||
public Map<String, Link> resolveLinks( | ||
Collection<EndpointInfo<WebEndpointOperation>> webEndpoints, | ||
String requestUrl) { | ||
String normalizedUrl = normalizeRequestUrl(requestUrl); | ||
Map<String, Link> links = new LinkedHashMap<String, Link>(); | ||
links.put("self", new Link(normalizedUrl)); | ||
for (EndpointInfo<WebEndpointOperation> endpoint : webEndpoints) { | ||
for (WebEndpointOperation operation : endpoint.getOperations()) { | ||
webEndpoints.stream().map(EndpointInfo::getId).forEach((id) -> links | ||
.put(operation.getId(), createLink(normalizedUrl, operation))); | ||
} | ||
} | ||
return links; | ||
} | ||
|
||
private String normalizeRequestUrl(String requestUrl) { | ||
if (requestUrl.endsWith("/")) { | ||
return requestUrl.substring(0, requestUrl.length() - 1); | ||
} | ||
return requestUrl; | ||
} | ||
|
||
private Link createLink(String requestUrl, WebEndpointOperation operation) { | ||
String path = operation.getRequestPredicate().getPath(); | ||
return new Link(requestUrl + (path.startsWith("/") ? path : "/" + path)); | ||
} | ||
|
||
} |
66 changes: 66 additions & 0 deletions
66
spring-boot/src/main/java/org/springframework/boot/endpoint/web/Link.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* 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.endpoint.web; | ||
|
||
import org.springframework.core.style.ToStringCreator; | ||
|
||
/** | ||
* Details for a link in a | ||
* <a href="https://tools.ietf.org/html/draft-kelly-json-hal-08">HAL</a>-formatted | ||
* response. | ||
* | ||
* @author Andy Wilkinson | ||
* @since 2.0.0 | ||
*/ | ||
public class Link { | ||
|
||
private final String href; | ||
|
||
private final boolean templated; | ||
|
||
/** | ||
* Creates a new {@link Link} with the given {@code href}. | ||
* @param href the href | ||
*/ | ||
public Link(String href) { | ||
this.href = href; | ||
this.templated = href.contains("{"); | ||
|
||
} | ||
|
||
/** | ||
* Returns the href of the link. | ||
* @return the href | ||
*/ | ||
public String getHref() { | ||
return this.href; | ||
} | ||
|
||
/** | ||
* Returns whether or not the {@link #getHref() href} is templated. | ||
* @return {@code true} if the href is templated, otherwise {@code false} | ||
*/ | ||
public boolean isTemplated() { | ||
return this.templated; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return new ToStringCreator(this).append("href", this.href).toString(); | ||
} | ||
|
||
} |
136 changes: 136 additions & 0 deletions
136
...g-boot/src/main/java/org/springframework/boot/endpoint/web/OperationRequestPredicate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/* | ||
* 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.endpoint.web; | ||
|
||
import java.util.Collection; | ||
import java.util.Collections; | ||
|
||
import org.springframework.core.style.ToStringCreator; | ||
|
||
/** | ||
* A predicate for a request to an operation on a web endpoint. | ||
* | ||
* @author Andy Wilkinson | ||
* @since 2.0.0 | ||
*/ | ||
public class OperationRequestPredicate { | ||
|
||
private final String path; | ||
|
||
private final String canonicalPath; | ||
|
||
private final WebEndpointHttpMethod httpMethod; | ||
|
||
private final Collection<String> consumes; | ||
|
||
private final Collection<String> produces; | ||
|
||
/** | ||
* Creates a new {@code WebEndpointRequestPredict}. | ||
* | ||
* @param path the path for the operation | ||
* @param httpMethod the HTTP method that the operation supports | ||
* @param produces the media types that the operation produces | ||
* @param consumes the media types that the operation consumes | ||
*/ | ||
public OperationRequestPredicate(String path, WebEndpointHttpMethod httpMethod, | ||
Collection<String> consumes, Collection<String> produces) { | ||
this.path = path; | ||
this.canonicalPath = path.replaceAll("\\{.*?}", "{*}"); | ||
this.httpMethod = httpMethod; | ||
this.consumes = consumes; | ||
this.produces = produces; | ||
} | ||
|
||
/** | ||
* Returns the path for the operation. | ||
* @return the path | ||
*/ | ||
public String getPath() { | ||
return this.path; | ||
} | ||
|
||
/** | ||
* Returns the HTTP method for the operation. | ||
* @return the HTTP method | ||
*/ | ||
public WebEndpointHttpMethod getHttpMethod() { | ||
return this.httpMethod; | ||
} | ||
|
||
/** | ||
* Returns the media types that the operation consumes. | ||
* @return the consumed media types | ||
*/ | ||
public Collection<String> getConsumes() { | ||
return Collections.unmodifiableCollection(this.consumes); | ||
} | ||
|
||
/** | ||
* Returns the media types that the operation produces. | ||
* @return the produced media types | ||
*/ | ||
public Collection<String> getProduces() { | ||
return Collections.unmodifiableCollection(this.produces); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return new ToStringCreator(this).append("httpMethod", this.httpMethod) | ||
.append("path", this.path).append("consumes", this.consumes) | ||
.append("produces", this.produces).toString(); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
final int prime = 31; | ||
int result = 1; | ||
result = prime * result + this.consumes.hashCode(); | ||
result = prime * result + this.httpMethod.hashCode(); | ||
result = prime * result + this.canonicalPath.hashCode(); | ||
result = prime * result + this.produces.hashCode(); | ||
return result; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) { | ||
return true; | ||
} | ||
if (obj == null) { | ||
return false; | ||
} | ||
if (getClass() != obj.getClass()) { | ||
return false; | ||
} | ||
OperationRequestPredicate other = (OperationRequestPredicate) obj; | ||
if (!this.consumes.equals(other.consumes)) { | ||
return false; | ||
} | ||
if (this.httpMethod != other.httpMethod) { | ||
return false; | ||
} | ||
if (!this.canonicalPath.equals(other.canonicalPath)) { | ||
return false; | ||
} | ||
if (!this.produces.equals(other.produces)) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
} |
Oops, something went wrong.