001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.actuate.endpoint.web; 018 019import java.util.Collection; 020import java.util.LinkedHashMap; 021import java.util.Map; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025 026import org.springframework.boot.actuate.endpoint.ExposableEndpoint; 027 028/** 029 * A resolver for {@link Link links} to web endpoints. 030 * 031 * @author Andy Wilkinson 032 * @since 2.0.0 033 */ 034public class EndpointLinksResolver { 035 036 private static final Log logger = LogFactory.getLog(EndpointLinksResolver.class); 037 038 private final Collection<? extends ExposableEndpoint<?>> endpoints; 039 040 /** 041 * Creates a new {@code EndpointLinksResolver} that will resolve links to the given 042 * {@code endpoints}. 043 * @param endpoints the endpoints 044 */ 045 public EndpointLinksResolver(Collection<? extends ExposableEndpoint<?>> endpoints) { 046 this.endpoints = endpoints; 047 } 048 049 /** 050 * Creates a new {@code EndpointLinksResolver} that will resolve links to the given 051 * {@code endpoints} that are exposed beneath the given {@code basePath}. 052 * @param endpoints the endpoints 053 * @param basePath the basePath 054 */ 055 public EndpointLinksResolver(Collection<? extends ExposableEndpoint<?>> endpoints, 056 String basePath) { 057 this.endpoints = endpoints; 058 if (logger.isInfoEnabled()) { 059 logger.info("Exposing " + endpoints.size() 060 + " endpoint(s) beneath base path '" + basePath + "'"); 061 } 062 } 063 064 /** 065 * Resolves links to the known endpoints based on a request with the given 066 * {@code requestUrl}. 067 * @param requestUrl the url of the request for the endpoint links 068 * @return the links 069 */ 070 public Map<String, Link> resolveLinks(String requestUrl) { 071 String normalizedUrl = normalizeRequestUrl(requestUrl); 072 Map<String, Link> links = new LinkedHashMap<>(); 073 links.put("self", new Link(normalizedUrl)); 074 for (ExposableEndpoint<?> endpoint : this.endpoints) { 075 if (endpoint instanceof ExposableWebEndpoint) { 076 collectLinks(links, (ExposableWebEndpoint) endpoint, normalizedUrl); 077 } 078 else if (endpoint instanceof PathMappedEndpoint) { 079 String rootPath = ((PathMappedEndpoint) endpoint).getRootPath(); 080 Link link = createLink(normalizedUrl, rootPath); 081 links.put(endpoint.getEndpointId().toLowerCaseString(), link); 082 } 083 } 084 return links; 085 } 086 087 private String normalizeRequestUrl(String requestUrl) { 088 if (requestUrl.endsWith("/")) { 089 return requestUrl.substring(0, requestUrl.length() - 1); 090 } 091 return requestUrl; 092 } 093 094 private void collectLinks(Map<String, Link> links, ExposableWebEndpoint endpoint, 095 String normalizedUrl) { 096 for (WebOperation operation : endpoint.getOperations()) { 097 links.put(operation.getId(), createLink(normalizedUrl, operation)); 098 } 099 } 100 101 private Link createLink(String requestUrl, WebOperation operation) { 102 return createLink(requestUrl, operation.getRequestPredicate().getPath()); 103 } 104 105 private Link createLink(String requestUrl, String path) { 106 return new Link(requestUrl + (path.startsWith("/") ? path : "/" + path)); 107 } 108 109}