content: /*
   * Copyright The OpenTelemetry Authors
   * SPDX-License-Identifier: Apache-2.0
   */
  
  package io.opentelemetry.instrumentation.api.incubator.semconv.net;
  
  import static java.util.Comparator.comparing;
  import static java.util.Comparator.naturalOrder;
  import static java.util.Comparator.nullsFirst;
  
  import com.google.auto.value.AutoValue;
  import io.opentelemetry.instrumentation.api.incubator.semconv.net.internal.UrlParser;
  import java.util.Comparator;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.function.Supplier;
  import javax.annotation.Nullable;
  
  class PeerServiceResolverImpl implements PeerServiceResolver {
  
    private static final Comparator<ServiceMatcher> matcherComparator =
        nullsFirst(
            comparing(ServiceMatcher::getPort, nullsFirst(naturalOrder()))
                .thenComparing(comparing(ServiceMatcher::getPath, nullsFirst(naturalOrder()))));
  
    private final Map<String, Map<ServiceMatcher, String>> mapping = new HashMap<>();
  
    PeerServiceResolverImpl(Map<String, String> peerServiceMapping) {
      peerServiceMapping.forEach(
          (key, serviceName) -> {
            String url = "https://" + key;
            String host = UrlParser.getHost(url);
            Integer port = UrlParser.getPort(url);
            String path = UrlParser.getPath(url);
            Map<ServiceMatcher, String> matchers =
                mapping.computeIfAbsent(host, x -> new HashMap<>());
            matchers.putIfAbsent(ServiceMatcher.create(port, path), serviceName);
          });
    }
  
    @Override
    public boolean isEmpty() {
      return mapping.isEmpty();
    }
  
    @Override
    @Nullable
    public String resolveService(
        String host, @Nullable Integer port, @Nullable Supplier<String> pathSupplier) {
      Map<ServiceMatcher, String> matchers = mapping.get(host);
      if (matchers == null) {
        return null;
      }
      return matchers.entrySet().stream()
          .filter(entry -> entry.getKey().matches(port, pathSupplier))
          .max((o1, o2) -> matcherComparator.compare(o1.getKey(), o2.getKey()))
          .map(Map.Entry::getValue)
          .orElse(null);
    }
  
    @AutoValue
    abstract static class ServiceMatcher {
  
      static ServiceMatcher create(Integer port, String path) {
        return new AutoValue_PeerServiceResolverImpl_ServiceMatcher(port, path);
      }
  
      @Nullable
      abstract Integer getPort();
  
      @Nullable
      abstract String getPath();
  
      public boolean matches(Integer port, Supplier<String> pathSupplier) {
        if (this.getPort() != null) {
          if (!this.getPort().equals(port)) {
            return false;
          }
        }
        if (this.getPath() != null && this.getPath().length() > 0) {
          if (pathSupplier == null) {
            return false;
          }
          String path = pathSupplier.get();
          if (path == null) {
            return false;
          }
          if (!path.startsWith(this.getPath())) {
            return false;
          }
          if (port != null) {
            return port.equals(this.getPort());
          }
        }
        return true;
      }
    }
  }
  