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.Collections;
021import java.util.Iterator;
022import java.util.LinkedHashMap;
023import java.util.List;
024import java.util.Map;
025import java.util.stream.Collectors;
026import java.util.stream.Stream;
027
028import org.springframework.boot.actuate.endpoint.EndpointId;
029import org.springframework.boot.actuate.endpoint.EndpointsSupplier;
030import org.springframework.util.Assert;
031
032/**
033 * A collection of {@link PathMappedEndpoint path mapped endpoints}.
034 *
035 * @author Phillip Webb
036 */
037public class PathMappedEndpoints implements Iterable<PathMappedEndpoint> {
038
039        private final String basePath;
040
041        private final Map<EndpointId, PathMappedEndpoint> endpoints;
042
043        /**
044         * Create a new {@link PathMappedEndpoints} instance for the given supplier.
045         * @param basePath the base path of the endpoints
046         * @param supplier the endpoint supplier
047         */
048        public PathMappedEndpoints(String basePath, EndpointsSupplier<?> supplier) {
049                Assert.notNull(supplier, "Supplier must not be null");
050                this.basePath = (basePath != null) ? basePath : "";
051                this.endpoints = getEndpoints(Collections.singleton(supplier));
052        }
053
054        /**
055         * Create a new {@link PathMappedEndpoints} instance for the given suppliers.
056         * @param basePath the base path of the endpoints
057         * @param suppliers the endpoint suppliers
058         */
059        public PathMappedEndpoints(String basePath,
060                        Collection<EndpointsSupplier<?>> suppliers) {
061                Assert.notNull(suppliers, "Suppliers must not be null");
062                this.basePath = (basePath != null) ? basePath : "";
063                this.endpoints = getEndpoints(suppliers);
064        }
065
066        private Map<EndpointId, PathMappedEndpoint> getEndpoints(
067                        Collection<EndpointsSupplier<?>> suppliers) {
068                Map<EndpointId, PathMappedEndpoint> endpoints = new LinkedHashMap<>();
069                suppliers.forEach((supplier) -> {
070                        supplier.getEndpoints().forEach((endpoint) -> {
071                                if (endpoint instanceof PathMappedEndpoint) {
072                                        endpoints.put(endpoint.getEndpointId(),
073                                                        (PathMappedEndpoint) endpoint);
074                                }
075                        });
076                });
077                return Collections.unmodifiableMap(endpoints);
078        }
079
080        /**
081         * Return the base path for the endpoints.
082         * @return the base path
083         */
084        public String getBasePath() {
085                return this.basePath;
086        }
087
088        /**
089         * Return the root path for the endpoint with the given ID or {@code null} if the
090         * endpoint cannot be found.
091         * @param endpointId the endpoint ID
092         * @return the root path or {@code null}
093         */
094        public String getRootPath(EndpointId endpointId) {
095                PathMappedEndpoint endpoint = getEndpoint(endpointId);
096                return (endpoint != null) ? endpoint.getRootPath() : null;
097        }
098
099        /**
100         * Return the full path for the endpoint with the given ID or {@code null} if the
101         * endpoint cannot be found.
102         * @param endpointId the endpoint ID
103         * @return the full path or {@code null}
104         */
105        public String getPath(EndpointId endpointId) {
106                return getPath(getEndpoint(endpointId));
107        }
108
109        /**
110         * Return the root paths for each mapped endpoint.
111         * @return all root paths
112         */
113        public Collection<String> getAllRootPaths() {
114                return asList(stream().map(PathMappedEndpoint::getRootPath));
115        }
116
117        /**
118         * Return the full paths for each mapped endpoint.
119         * @return all root paths
120         */
121        public Collection<String> getAllPaths() {
122                return asList(stream().map(this::getPath));
123        }
124
125        /**
126         * Return the {@link PathMappedEndpoint} with the given ID or {@code null} if the
127         * endpoint cannot be found.
128         * @param endpointId the endpoint ID
129         * @return the path mapped endpoint or {@code null}
130         */
131        public PathMappedEndpoint getEndpoint(EndpointId endpointId) {
132                return this.endpoints.get(endpointId);
133        }
134
135        /**
136         * Stream all {@link PathMappedEndpoint path mapped endpoints}.
137         * @return a stream of endpoints
138         */
139        public Stream<PathMappedEndpoint> stream() {
140                return this.endpoints.values().stream();
141        }
142
143        @Override
144        public Iterator<PathMappedEndpoint> iterator() {
145                return this.endpoints.values().iterator();
146        }
147
148        private String getPath(PathMappedEndpoint endpoint) {
149                return (endpoint != null) ? this.basePath + "/" + endpoint.getRootPath() : null;
150        }
151
152        private <T> List<T> asList(Stream<T> stream) {
153                return stream.collect(Collectors.collectingAndThen(Collectors.toList(),
154                                Collections::unmodifiableList));
155        }
156
157}