All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.pivotal.services.plugin.CfRouteUtil Maven / Gradle / Ivy

There is a newer version: 2.3.0-rc.6
Show newest version
package io.pivotal.services.plugin;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.cloudfoundry.operations.CloudFoundryOperations;
import org.cloudfoundry.operations.DefaultCloudFoundryOperations;
import org.cloudfoundry.operations.applications.DecomposedRoute;
import org.cloudfoundry.operations.applications.DomainSummary;
import reactor.core.publisher.Mono;

/**
 * @author Gabriel Couto
 */
public class CfRouteUtil {
    private static Map> domainCache = new HashMap<>();

    /**
     * Returns a list of decomposed routes
     *
     * @param cfOperations the operations to check the domain names against
     * @param routes       all aplication's routes
     * @param routePath    the application path to be included in the routes
     * @return the decomposed routes
     */
    public static List decomposedRoutes(CloudFoundryOperations cfOperations, List routes, String routePath) {
        final List finalDomainSummaries = getCachedDomainSummaries(cfOperations);
        return routes.stream().map(route ->
            decomposeRoute(finalDomainSummaries, route, routePath)
        ).collect(Collectors.toList());
    }

    /**
     * Get the first route and generate a temp route from it, adding the suffix
     * after the hostname.
     *
     * @param cfOperations the operations to check the domain names against
     * @param cfProperties the properties of the app
     * @param suffix       the suffix to add in the host
     * @return the calculated route
     */
    public static String getTempRoute(CloudFoundryOperations cfOperations, CfProperties cfProperties, String suffix) {
        if (cfProperties.routes() == null || cfProperties.routes().isEmpty())
            return getTempRoute(cfProperties.host(), cfProperties.domain(), null, cfProperties.path(), suffix);
        DecomposedRoute route = decomposeRoute(getCachedDomainSummaries(cfOperations), cfProperties.routes().get(0), cfProperties.path());
        return getTempRoute(route.getHost(), route.getDomain(), route.getPort(), route.getPath(), suffix);
    }

    private static String getTempRoute(String host, String domain, Integer port, String path, String suffix) {
        return (host != null ? host + suffix + "." : suffix + ".")
            + domain
            + (port != null ? ":" + port : "")
            + (path != null ? "/" + path : "");
    }

    public static List getCachedDomainSummaries(CloudFoundryOperations cfOperations) {
        if(cfOperations instanceof  DefaultCloudFoundryOperations) {
            return domainCache.get(cfOperations);
        }
        throw new IllegalArgumentException(cfOperations.getClass().getName() + " does not support caching yet.");
    }

    public static void cacheDomainSummaries(DefaultCloudFoundryOperations cfOperations) {
        if (!domainCache.containsKey(cfOperations)) {
            domainCache.put(cfOperations, fetchDomainSummaries(cfOperations).block());
        }
    }

    public static Mono> fetchDomainSummaries(CloudFoundryOperations cfOperations) {
        return cfOperations.domains().list()
            .map(domain -> DomainSummary.builder()
                .id(domain.getId())
                .name(domain.getName())
                .type(domain.getType())
                .build())
            .collectList();
    }

    /**
     * Copy of org.cloudfoundry.operations.applications.RouteUtil.decomposeRoute
     */
    private static DecomposedRoute decomposeRoute(List availableDomains, String route, String routePath) {
        String domain = null;
        String host = null;
        String path = null;
        Integer port = null;
        String routeWithoutSuffix = route;

        if (availableDomains.size() == 0) {
            throw new IllegalArgumentException(String.format("The route %s did not match any existing domains", route));
        }

        List sortedDomains = availableDomains.stream()
            .sorted(Comparator.comparingInt(domainSummary -> domainSummary.getName().length()).reversed())
            .collect(Collectors.toList());

        if (route.contains("/")) {
            int index = route.indexOf("/");
            path = routePath != null ? routePath : route.substring(index);
            routeWithoutSuffix = route.substring(0, index);
        } else if (hasPort(route)) {
            port = getPort(route);
            routeWithoutSuffix = route.substring(0, route.indexOf(":"));
        }

        for (DomainSummary item : sortedDomains) {
            if (isDomainMatch(routeWithoutSuffix, item.getName())) {
                domain = item.getName();
                if (domain.length() < routeWithoutSuffix.length()) {
                    host = routeWithoutSuffix.substring(0, routeWithoutSuffix.lastIndexOf(domain) - 1);
                }
                break;
            }
        }

        if (domain == null) {
            throw new IllegalArgumentException(String.format("The route %s did not match any existing domains", route));
        }

        if ((host != null || path != null) && port != null) {
            throw new IllegalArgumentException(String.format("The route %s is invalid: Host/path cannot be set with port", route));
        }

        return DecomposedRoute.builder()
            .domain(domain)
            .host(host)
            .path(path)
            .port(port)
            .build();
    }

    private static Integer getPort(String route) {
        Pattern pattern = Pattern.compile(":\\d+$");
        Matcher matcher = pattern.matcher(route);

        matcher.find();
        return Integer.valueOf(route.substring(matcher.start() + 1, matcher.end()));
    }

    private static Boolean hasPort(String route) {
        Pattern pattern = Pattern.compile("^.+?:\\d+$");
        Matcher matcher = pattern.matcher(route);

        return matcher.matches();
    }

    private static boolean isDomainMatch(String route, String domain) {
        return route.equals(domain) || route.endsWith(domain) && route.charAt(route.length() - domain.length() - 1) == '.';
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy