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

com.gs.api.accelrx.web.client.servicediscovery.AccelRxWebServiceDiscovery Maven / Gradle / Ivy

package com.gs.api.accelrx.web.client.servicediscovery;

import com.gs.api.accelrx.AccelRxWebClientServiceDiscovery;
import com.gs.api.accelrx.WebClientEndpoint;
import com.gs.api.accelrx.web.client.servicediscovery.endpoint.ServiceDiscoveryEndpoint;
import com.gs.api.accelrx.web.client.servicediscovery.endpoint.ServiceDiscoveryEndpointPolicy;
import com.gs.api.accelrx.web.client.servicediscovery.endpoint.WeightedRoundRobinEndpointPolicy;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.Single;
import io.vertx.core.http.HttpMethod;
import io.vertx.rxjava3.core.MultiMap;
import io.vertx.rxjava3.core.Vertx;
import io.vertx.rxjava3.servicediscovery.ServiceDiscovery;
import io.vertx.servicediscovery.Record;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class AccelRxWebServiceDiscovery implements AccelRxWebClientServiceDiscovery {
    private static final Logger log = LoggerFactory.getLogger(AccelRxWebServiceDiscovery.class);

    private final String serviceName;
    private final ServiceDiscovery serviceDiscovery;
    private final ServiceDiscoveryEndpointPolicy policy;

    private AccelRxServiceImporter serviceImporter;

    private Set currentRecordIds;
    protected List records;

    private AccelRxWebServiceDiscovery(Vertx vertx, String serviceName) {
        this.serviceDiscovery = ServiceDiscovery.create(vertx);
        this.serviceName = serviceName;
        this.policy = new WeightedRoundRobinEndpointPolicy();
    }

    public static AccelRxWebServiceDiscovery create(Vertx vertx, String serviceName) {
        return new AccelRxWebServiceDiscovery(vertx, serviceName);
    }

    public Completable registerServiceImporter(AccelRxServiceImporter serviceImporter) {
        log.info("Initialising Service Discovery Registry");
        if (serviceImporter != null) {
            this.serviceImporter = serviceImporter;
            return serviceImporter.register(serviceDiscovery);
        } else {
            return Completable.complete();
        }
    }

    @Override
    public Completable refresh() {
        return serviceImporter.refresh()
                .andThen(Completable.fromAction(policy::reset));
    }

    @Override
    public Maybe endpoint(HttpMethod method, String path, MultiMap headers, MultiMap queryParams) {
        return records()
                .filter(records -> !records.isEmpty())
                .map(records -> selectEndpoint(records, method, path, headers, queryParams))
                .map(selectedEndpoint -> ServiceDiscoveryEndpoint.create(selectedEndpoint.service(), selectedEndpoint.instance(), selectedEndpoint.isSsl(), selectedEndpoint.host(), selectedEndpoint.port(), selectedEndpoint.pathPrefix(), path))
                .doOnSuccess(endpoint -> log.info("Selected endpoint {}", endpoint));
    }

    private ServiceDiscoveryEndpoint selectEndpoint(List records, HttpMethod method, String path, MultiMap headers, MultiMap queryParams) {
        Map> matchingRecordsByOrder = records.stream()
                .filter(record -> record.matches(method, path, headers, queryParams))
                .collect(Collectors.groupingBy(ServiceDiscoveryRecord::order));

        int minOrder = matchingRecordsByOrder.keySet().stream()
                .mapToInt(order -> order)
                .min()
                .orElseThrow();

        List matchingRecords = matchingRecordsByOrder.get(minOrder);
        if (matchingRecords.size() == 0) {
            throw new RuntimeException("Service discovery found no matching endpoints");
        } else if (matchingRecords.size() == 1) {
            return matchingRecords.get(0).endpoint();
        } else {
            return policy.select(matchingRecords).endpoint();
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AccelRxWebServiceDiscovery that = (AccelRxWebServiceDiscovery) o;
        return records.equals(that.records);
    }

    @Override
    public int hashCode() {
        return Objects.hash(records);
    }

    private Single> records() {
        return serviceDiscovery.rxGetRecords(record -> record.getName().equals(serviceName))
                .filter(this::needsRefresh)
                .map(records -> records.stream()
                        .map(ServiceDiscoveryRecord::fromRecord)
                        .collect(Collectors.toList()))
                .map(newRecords -> {
                    this.records = newRecords;
                    return newRecords;
                })
                .switchIfEmpty(Single.fromCallable(() -> this.records));
    }

    boolean needsRefresh(List records) {
        Set newRecordIds = records.stream()
                .map(Record::getRegistration)
                .collect(Collectors.toSet());

        if (currentRecordIds == null || !currentRecordIds.equals(newRecordIds)) {
            currentRecordIds = newRecordIds;
            return true;
        } else {
            return false;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy