Replace priority field with dependsOn dependency resolver for Providers
- Removed the `priority` method from `Provider` interface and its implementations. - Introduced a `dependsOn` method for defining dependencies between Providers. - Implemented a topological sorting mechanism in `ProviderManager` to handle Provider initialization order based on dependencies. - Included validation for self-dependencies and unknown dependencies.
This commit is contained in:
@@ -6,11 +6,6 @@ import dev.coph.simplesql.query.Query;
|
|||||||
public class CompetitionProvider implements Provider {
|
public class CompetitionProvider implements Provider {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int priority() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String key() {
|
public String key() {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -2,8 +2,12 @@ package dev.coph.flightscore.backend.provider;
|
|||||||
|
|
||||||
import dev.coph.simplesql.query.Query;
|
import dev.coph.simplesql.query.Query;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public interface Provider {
|
public interface Provider {
|
||||||
int priority();
|
default Set<String> dependsOn() {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
|
||||||
String key();
|
String key();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,13 @@ package dev.coph.flightscore.backend.provider;
|
|||||||
import dev.coph.flightscore.backend.Backend;
|
import dev.coph.flightscore.backend.Backend;
|
||||||
import dev.coph.simplesql.query.Query;
|
import dev.coph.simplesql.query.Query;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Deque;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class ProviderManager {
|
public class ProviderManager {
|
||||||
private final Backend backend;
|
private final Backend backend;
|
||||||
@@ -15,13 +21,13 @@ public class ProviderManager {
|
|||||||
|
|
||||||
public void createAllDatabaseTables() {
|
public void createAllDatabaseTables() {
|
||||||
Query query = new Query(backend.databaseAdapter());
|
Query query = new Query(backend.databaseAdapter());
|
||||||
providers.values().stream().sorted((a, b) -> Integer.compare(b.priority(), a.priority())).forEach(provider -> provider.createDatabaseTables(query));
|
resolveOrder().forEach(provider -> provider.createDatabaseTables(query));
|
||||||
query.execute();
|
query.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableAllProviders() {
|
public void enableAllProviders() {
|
||||||
Query query = new Query(backend.databaseAdapter());
|
Query query = new Query(backend.databaseAdapter());
|
||||||
providers.values().stream().sorted((a, b) -> Integer.compare(b.priority(), a.priority())).forEach(provider -> provider.onEnable(query));
|
resolveOrder().forEach(provider -> provider.onEnable(query));
|
||||||
query.execute();
|
query.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,4 +39,49 @@ public class ProviderManager {
|
|||||||
return (T) providers.get(key);
|
return (T) providers.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Provider> resolveOrder() {
|
||||||
|
HashMap<String, Integer> inDegree = new HashMap<>();
|
||||||
|
HashMap<String, Set<String>> dependents = new HashMap<>();
|
||||||
|
for (Provider provider : providers.values()) {
|
||||||
|
inDegree.putIfAbsent(provider.key(), 0);
|
||||||
|
dependents.putIfAbsent(provider.key(), new HashSet<>());
|
||||||
|
}
|
||||||
|
for (Provider provider : providers.values()) {
|
||||||
|
for (String dependency : provider.dependsOn()) {
|
||||||
|
if (dependency.equals(provider.key())) {
|
||||||
|
throw new IllegalStateException("Provider '" + provider.key() + "' depends on itself.");
|
||||||
|
}
|
||||||
|
if (!providers.containsKey(dependency)) {
|
||||||
|
throw new IllegalStateException("Provider '" + provider.key() + "' depends on unknown provider '" + dependency + "'.");
|
||||||
|
}
|
||||||
|
if (dependents.get(dependency).add(provider.key())) {
|
||||||
|
inDegree.merge(provider.key(), 1, Integer::sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Deque<String> ready = new ArrayDeque<>();
|
||||||
|
inDegree.forEach((key, degree) -> {
|
||||||
|
if (degree == 0) ready.add(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
List<Provider> ordered = new ArrayList<>(providers.size());
|
||||||
|
while (!ready.isEmpty()) {
|
||||||
|
String key = ready.poll();
|
||||||
|
ordered.add(providers.get(key));
|
||||||
|
for (String dependent : dependents.get(key)) {
|
||||||
|
if (inDegree.merge(dependent, -1, Integer::sum) == 0) {
|
||||||
|
ready.add(dependent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ordered.size() != providers.size()) {
|
||||||
|
Set<String> remaining = new HashSet<>(providers.keySet());
|
||||||
|
ordered.forEach(provider -> remaining.remove(provider.key()));
|
||||||
|
throw new IllegalStateException("Circular dependency detected among providers: " + remaining);
|
||||||
|
}
|
||||||
|
return ordered;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.time.Duration;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@@ -45,8 +46,8 @@ public class UserProvider implements Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int priority() {
|
public Set<String> dependsOn() {
|
||||||
return 50;
|
return Set.of("role-provider");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ public class PermissionProvider implements Provider {
|
|||||||
this.backend = backend;
|
this.backend = backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int priority() {
|
|
||||||
return 150;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String key() {
|
public String key() {
|
||||||
return "permission-provider";
|
return "permission-provider";
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import lombok.experimental.Accessors;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Accessors(fluent = true)
|
@Accessors(fluent = true)
|
||||||
public class RoleProvider implements Provider {
|
public class RoleProvider implements Provider {
|
||||||
@@ -29,8 +30,8 @@ public class RoleProvider implements Provider {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int priority() {
|
public Set<String> dependsOn() {
|
||||||
return 100;
|
return Set.of("permission-provider");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user