package com.dbg.cloud.acheron.pluginconfig.service; import com.datastax.driver.core.utils.UUIDs; import com.dbg.cloud.acheron.exception.TechnicalException; import com.dbg.cloud.acheron.exception.ValidationException; import com.dbg.cloud.acheron.pluginconfig.PluginConfig; import com.dbg.cloud.acheron.pluginconfig.store.PluginConfigStore; import com.dbg.cloud.acheron.routing.service.RouteService; import lombok.NonNull; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import java.util.*; public interface PluginConfigService { List<PluginConfig> getAllPluginConfigs() throws TechnicalException; List<PluginConfig> getPluginConfigsOfConsumer(@NonNull UUID consumerId) throws TechnicalException; List<PluginConfig> getPluginConfigsOfRoute(@NonNull String routeId) throws TechnicalException; Optional<PluginConfig> getPluginConfig(@NonNull UUID pluginConfigId) throws TechnicalException; PluginConfig addNewPluginConfig(@NonNull PluginConfig pluginConfig) throws ValidationException, TechnicalException; PluginConfig replacePluginConfig(@NonNull PluginConfig pluginConfig) throws ValidationException, TechnicalException; PluginConfig mergePluginConfig(@NonNull PluginConfig pluginConfig) throws ValidationException, TechnicalException; void deletePluginConfig(@NonNull UUID pluginConfigId) throws TechnicalException; @Service class PluginConfigServiceImpl implements PluginConfigService { private static final Collection<String> SUPPORTED_PLUGINS = Arrays.asList("oauth2", "api_key", "correlation_id", "rate_limiting"); private final PluginConfigStore pluginConfigStore; private final RouteService routeService; public PluginConfigServiceImpl(final PluginConfigStore pluginConfigStore, final @Lazy RouteService routeService) { this.pluginConfigStore = pluginConfigStore; this.routeService = routeService; } @Override public List<PluginConfig> getAllPluginConfigs() throws TechnicalException { try { return pluginConfigStore.findAll(); } catch (final RuntimeException e) { throw new TechnicalException(e); } } @Override public List<PluginConfig> getPluginConfigsOfConsumer(final @NonNull UUID consumerId) throws TechnicalException { try { return pluginConfigStore.findByConsumer(consumerId); } catch (final RuntimeException e) { throw new TechnicalException(e); } } @Override public List<PluginConfig> getPluginConfigsOfRoute(final @NonNull String routeId) throws TechnicalException { try { return pluginConfigStore.findByRoute(routeId); } catch (final RuntimeException e) { throw new TechnicalException(e); } } @Override public Optional<PluginConfig> getPluginConfig(final @NonNull UUID pluginConfigId) throws TechnicalException { try { return pluginConfigStore.findById(pluginConfigId); } catch (final RuntimeException e) { throw new TechnicalException(e); } } @Override public PluginConfig addNewPluginConfig(final @NonNull PluginConfig pluginConfig) throws ValidationException, TechnicalException { validatePluginConfigForCreate(pluginConfig); try { // Generate ID and creation date final UUID pluginConfigId = UUIDs.random(); final Date createdAt = new Date(); return pluginConfigStore.add( new PluginConfig.Default( pluginConfigId, pluginConfig.getName(), pluginConfig.getRouteId(), pluginConfig.getHttpMethods(), pluginConfig.getConsumerId(), pluginConfig.getConfig(), pluginConfig.isEnabled(), createdAt)); } catch (final RuntimeException e) { throw new TechnicalException(e); } } @Override public PluginConfig replacePluginConfig(final @NonNull PluginConfig pluginConfig) throws ValidationException, TechnicalException { validatePluginConfigForReplace(pluginConfig); try { this.getPluginConfig(pluginConfig.getId()).orElseThrow(() -> new ValidationException("not found")); return pluginConfigStore.update(new PluginConfig.WithoutCreatedDate(pluginConfig)); } catch (final RuntimeException e) { throw new TechnicalException(e); } } @Override public PluginConfig mergePluginConfig(final @NonNull PluginConfig pluginConfig) throws ValidationException, TechnicalException { validatePluginConfigForMerge(pluginConfig); try { final UUID uuid = pluginConfig.getId(); final PluginConfig existingPluginConfig = this.getPluginConfig(uuid).orElseThrow(() -> new ValidationException("not found")); final PluginConfig mergedPluginConfig = new PluginConfig.WithoutCreatedDate( new PluginConfig.Merge( existingPluginConfig, pluginConfig)); return pluginConfigStore.update(mergedPluginConfig); } catch (final RuntimeException e) { throw new TechnicalException(e); } } @Override public void deletePluginConfig(final @NonNull UUID pluginConfigId) throws TechnicalException { try { pluginConfigStore.deleteById(pluginConfigId); } catch (final RuntimeException e) { throw new TechnicalException(e); } } private void validatePluginConfigForCreate(final PluginConfig pluginConfig) throws ValidationException, TechnicalException { if (!SUPPORTED_PLUGINS.contains(pluginConfig.getName())) { throw new ValidationException("plugin is not supported"); } if (pluginConfig.getRouteId() == null || pluginConfig.getRouteId().isEmpty()) { throw new ValidationException("route id cannot be empty"); } try { routeService.getRoute(pluginConfig.getRouteId()).orElseThrow( () -> new ValidationException("route not found")); } catch (final RuntimeException e) { throw new TechnicalException(e); } } private void validatePluginConfigForReplace(final PluginConfig pluginConfig) throws ValidationException { if (pluginConfig.getId() == null) { throw new ValidationException("plugin id cannot be null"); } validatePluginConfigForCreate(pluginConfig); } private void validatePluginConfigForMerge(final PluginConfig pluginConfig) throws ValidationException, TechnicalException { if (pluginConfig.getId() == null) { throw new ValidationException("plugin id cannot be null"); } // if present, plugin name is supported if (pluginConfig.getName() != null && !SUPPORTED_PLUGINS.contains(pluginConfig.getName())) { throw new ValidationException("plugin is not supported"); } // if present, route id must not be empty and must exist if (pluginConfig.getRouteId() != null) { if (pluginConfig.getRouteId().isEmpty()) { throw new ValidationException("route id cannot be set to an empty value"); } try { routeService.getRoute(pluginConfig.getRouteId()).orElseThrow( () -> new ValidationException("route not found")); } catch (final RuntimeException e) { throw new TechnicalException(e); } } } } }