io.appform.ranger.client.AbstractRangerHubClient Maven / Gradle / Ivy
/*
* Copyright 2024 Authors, Flipkart Internet Pvt. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.appform.ranger.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Preconditions;
import io.appform.ranger.client.utils.CriteriaUtils;
import io.appform.ranger.core.finderhub.ServiceDataSource;
import io.appform.ranger.core.finderhub.ServiceFinderFactory;
import io.appform.ranger.core.finderhub.ServiceFinderHub;
import io.appform.ranger.core.model.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import io.appform.ranger.core.util.FinderUtils;
import lombok.Getter;
import lombok.experimental.SuperBuilder;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Getter
@SuperBuilder
public abstract class AbstractRangerHubClient, D extends Deserializer> implements RangerHubClient {
private final String namespace;
private final ObjectMapper mapper;
private final D deserializer;
private final Predicate initialCriteria;
private final boolean alwaysUseInitialCriteria;
private int nodeRefreshTimeMs;
private ServiceFinderHub hub;
private ServiceDataSource serviceDataSource;
/**
* Initial time to wait for service node data to be refreshed in service registry (in milliseconds)
*/
private long serviceRefreshTimeoutMs;
/**
* Time to wait for Hub Start completion (in milliseconds)
* Hub Start is considered to be completed if service registry for all eligible services has been refreshed
*/
private long hubStartTimeoutMs;
private Set excludedServices;
@Override
public void start() {
Preconditions.checkNotNull(mapper, "Mapper can't be null");
Preconditions.checkNotNull(namespace, "namespace can't be null");
Preconditions.checkNotNull(deserializer, "deserializer can't be null");
if (this.nodeRefreshTimeMs < HubConstants.MINIMUM_REFRESH_TIME_MS) {
log.warn("Node info update interval too low: {} ms. Has been upgraded to {} ms ",
this.nodeRefreshTimeMs,
HubConstants.MINIMUM_REFRESH_TIME_MS);
}
this.nodeRefreshTimeMs = Math.max(HubConstants.MINIMUM_REFRESH_TIME_MS, this.nodeRefreshTimeMs);
if (this.serviceRefreshTimeoutMs <= 0) {
log.warn("Service Refresh interval too low: {} ms. Has been upgraded to {} ms ",
this.serviceRefreshTimeoutMs,
HubConstants.SERVICE_REFRESH_TIMEOUT_MS);
this.serviceRefreshTimeoutMs = HubConstants.SERVICE_REFRESH_TIMEOUT_MS;
}
if (this.hubStartTimeoutMs <= 0) {
log.warn("Hub Refresh interval too low: {} ms. Has been upgraded to {} ms ",
this.hubStartTimeoutMs,
HubConstants.HUB_START_TIMEOUT_MS);
this.hubStartTimeoutMs = HubConstants.HUB_START_TIMEOUT_MS;
}
this.excludedServices = Objects.requireNonNullElseGet(this.excludedServices, Set::of);
if(null == this.serviceDataSource){
this.serviceDataSource = getDefaultDataSource();
}
this.hub = buildHub();
this.hub.start();
}
@Override
public void stop() {
if (null != hub) {
hub.stop();
}
}
@Override
public Optional> getNode(final Service service) {
return getNode(service, initialCriteria);
}
@Override
public List> getAllNodes(final Service service) {
return getAllNodes(service, initialCriteria);
}
@Override
public Optional> getNode(final Service service, final Predicate criteria) {
return this.getNode(service, criteria, null);
}
@Override
public Optional> getNode(
final Service service,
final Predicate criteria,
final ShardSelector shardSelector) {
return getNode(service, criteria, shardSelector, null);
}
@Override
public Optional> getNode(
final Service service,
final Predicate criteria,
final ShardSelector shardSelector,
final ServiceNodeSelector nodeSelector) {
return this.getHub()
.finder(service)
.flatMap(trServiceFinder
-> trServiceFinder.get(CriteriaUtils.getCriteria(alwaysUseInitialCriteria,
initialCriteria,
criteria),
shardSelector,
nodeSelector));
}
@Override
public List> getAllNodes(
final Service service,
final Predicate criteria
) {
return getAllNodes(service, criteria, null);
}
@Override
public List> getAllNodes(
final Service service,
final Predicate criteria,
final ShardSelector shardSelector) {
return this.getHub()
.finder(service)
.map(trServiceFinder -> trServiceFinder.getAll(
CriteriaUtils.getCriteria(alwaysUseInitialCriteria, initialCriteria, criteria),
shardSelector))
.orElse(Collections.emptyList());
}
@Override
public Collection getRegisteredServices() {
try {
return FinderUtils.getEligibleServices(this.getHub().getServiceDataSource().services(), excludedServices);
}
catch (Exception e) {
log.error("Call to the hub failed with exception, {}", e.getMessage());
return Collections.emptySet();
}
}
/**
* Tries to dynamically add service for discovery.
* Method will return asynchronously after adding service to ServiceDataSource.
* To block till rangerHub is ready to discover service wait for future completion
*
* @throws UnsupportedOperationException for any datasource which doesnt support
* dynamic addition of services
* @throws IllegalStateException if called before hub is started
*
* @return CompletableFuture which waits for hub to be ready for discovering the new service
*/
@Override
public CompletableFuture> addService(Service service) {
if(hub == null) {
throw new IllegalStateException("Hub not started yet. Call .start()");
}
return hub.buildFinder(service);
}
protected abstract ServiceDataSource getDefaultDataSource();
protected abstract ServiceFinderFactory getFinderFactory();
protected abstract ServiceFinderHub buildHub();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy