package com.dbg.cloud.acheron.routing.service;
import com.dbg.cloud.acheron.cluster.ClusterEventBus;
import com.dbg.cloud.acheron.exception.TechnicalException;
import com.dbg.cloud.acheron.exception.ValidationException;
import com.dbg.cloud.acheron.pluginconfig.service.PluginConfigService;
import com.dbg.cloud.acheron.routing.Route;
import com.dbg.cloud.acheron.routing.store.RouteStore;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public interface RouteService {
List<Route> getAllRoutes() throws TechnicalException;
Optional<Route> getRoute(@NonNull String routeId) throws TechnicalException;
Route addNewRoute(@NonNull Route route) throws ValidationException, TechnicalException;
void deleteRoute(@NonNull String routeId) throws TechnicalException;
Set<String> getHttpMethodsOfRoute(@NonNull String routeId);
@Service
@AllArgsConstructor
class RouteServiceImpl implements RouteService {
private final RouteStore routeStore;
private final PluginConfigService pluginConfigService;
private final ClusterEventBus bus;
@Override
public List<Route> getAllRoutes() throws TechnicalException {
try {
return routeStore.findAll();
} catch (final RuntimeException e) {
throw new TechnicalException(e);
}
}
@Override
public Optional<Route> getRoute(final @NonNull String routeId) throws TechnicalException {
try {
return routeStore.findById(routeId);
} catch (final RuntimeException e) {
throw new TechnicalException(e);
}
}
@Override
public Route addNewRoute(final @NonNull Route route) throws ValidationException, TechnicalException {
validateRoute(route);
try {
final Date createdAt = new Date();
return routeStore.add(new Route.Smart(
route.getId(),
route.getHttpMethods(),
route.getPath(),
route.getServiceId(),
route.getUrl(),
route.isKeepPrefix(),
route.isRetryable(),
route.isOverrideSensitiveHeaders(),
route.getSensitiveHeaders(),
createdAt));
} catch (final RuntimeException e) {
throw new TechnicalException(e);
}
}
@Override
public void deleteRoute(final @NonNull String routeId) throws TechnicalException {
try {
routeStore.deleteById(routeId);
refreshRoutes();
// FIXME: This is not sustainable. Come up with an event-based model (event bus, publish/subscribe,
// whatever)
pluginConfigService.getPluginConfigsOfRoute(routeId).stream().forEach(
pluginConfig -> pluginConfigService.deletePluginConfig(pluginConfig.getId()));
} catch (final RuntimeException e) {
throw new TechnicalException(e);
}
}
@Override
public Set<String> getHttpMethodsOfRoute(@NonNull String routeId) {
try {
return routeStore.findHttpMethodsByRouteId(routeId);
} catch (final RuntimeException e) {
throw new TechnicalException(e);
}
}
private void validateRoute(final Route route) throws ValidationException {
if (route.getId() == null || route.getId().isEmpty()) {
throw new ValidationException("route id must not be null");
}
if ((route.getServiceId() == null || route.getServiceId().isEmpty()) &&
(route.getUrl() == null || route.getUrl().isEmpty())) {
throw new ValidationException("either service id or url must be given");
}
if (route.getPath() == null || route.getPath().isEmpty()) {
throw new ValidationException("path must be given");
}
}
private void refreshRoutes() {
bus.refreshRoutes();
}
}
}