package com.xfestudio.xfeservermanager.core.policy;
import com.xfestudio.xfeservermanager.api.policy.PolicyRule;
import com.xfestudio.xfeservermanager.api.policy.PolicySnapshot;
import java.time.Clock;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
/** Lock-free holder for an active snapshot, one draft, and immutable version history. */
public final class AtomicPolicyRepository implements PolicySnapshotProvider {
private final Clock clock;
private final PolicyValidator validator;
private final AtomicReference<State> state;
public AtomicPolicyRepository(PolicySnapshot initialSnapshot) {
this(initialSnapshot, Clock.systemUTC(), new PolicyValidator());
}
public AtomicPolicyRepository(PolicySnapshot initialSnapshot, Clock clock, PolicyValidator validator) {
this.clock = java.util.Objects.requireNonNull(clock, "clock");
this.validator = java.util.Objects.requireNonNull(validator, "validator");
validator.validate(initialSnapshot.rules()).throwIfInvalid();
if (!PolicySnapshotFactory.hasValidChecksum(initialSnapshot)) {
throw new InvalidPolicyException(List.of(new PolicyValidationIssue(
"", "snapshot_checksum", "Initial policy snapshot checksum is invalid")));
}
this.state = new AtomicReference<>(new State(
initialSnapshot, null, Map.of(initialSnapshot.version(), initialSnapshot)));
}
public static AtomicPolicyRepository empty(Clock clock) {
PolicySnapshot initial = PolicySnapshotFactory.create(
0L, clock.instant(), "system", "Initial pass-through policy", List.of());
return new AtomicPolicyRepository(initial, clock, new PolicyValidator());
}
@Override
public PolicySnapshot activeSnapshot() {
return state.get().active();
}
public Optional<PolicySnapshot> draftSnapshot() {
return Optional.ofNullable(state.get().draft());
}
public List<PolicySnapshot> history() {
return List.copyOf(state.get().history().values());
}
public PolicySnapshot stageDraft(List<PolicyRule> rules, String createdBy, String description) {
validator.validate(rules).throwIfInvalid();
while (true) {
State current = state.get();
PolicySnapshot draft = PolicySnapshotFactory.create(
current.active().version() + 1, clock.instant(), createdBy, description, rules);
State updated = new State(current.active(), draft, current.history());
if (state.compareAndSet(current, updated)) {
return draft;
}
}
}
public PolicySnapshot publishDraft(long expectedActiveVersion) {
State observed = state.get();
requireVersion(observed, expectedActiveVersion);
if (observed.draft() == null) {
throw new NoPolicyDraftException();
}
return publishDraft(expectedActiveVersion, observed.draft().checksum());
}
/** Publishes only if both the active base and reviewed draft still match. */
public PolicySnapshot publishDraft(long expectedActiveVersion, String expectedDraftChecksum) {
java.util.Objects.requireNonNull(expectedDraftChecksum, "expectedDraftChecksum");
while (true) {
State current = state.get();
requireVersion(current, expectedActiveVersion);
if (current.draft() == null) {
throw new NoPolicyDraftException();
}
if (!current.draft().checksum().equals(expectedDraftChecksum)) {
throw new PolicyDraftConflictException(expectedDraftChecksum, current.draft().checksum());
}
Map<Long, PolicySnapshot> history = new LinkedHashMap<>(current.history());
history.put(current.draft().version(), current.draft());
State updated = new State(current.draft(), null, history);
if (state.compareAndSet(current, updated)) {
return updated.active();
}
}
}
/** Publishes a copy of an old version as a new immutable version. */
public PolicySnapshot rollback(long targetVersion, long expectedActiveVersion, String createdBy, String description) {
while (true) {
State current = state.get();
requireVersion(current, expectedActiveVersion);
if (current.draft() != null) {
throw new PolicyDraftPresentException();
}
PolicySnapshot target = current.history().get(targetVersion);
if (target == null) {
throw new IllegalArgumentException("Unknown policy version " + targetVersion);
}
PolicySnapshot restored = PolicySnapshotFactory.create(
current.active().version() + 1, clock.instant(), createdBy, description, target.rules());
Map<Long, PolicySnapshot> history = new LinkedHashMap<>(current.history());
history.put(restored.version(), restored);
State updated = new State(restored, null, history);
if (state.compareAndSet(current, updated)) {
return restored;
}
}
}
public void discardDraft(long expectedActiveVersion, String expectedDraftChecksum) {
java.util.Objects.requireNonNull(expectedDraftChecksum, "expectedDraftChecksum");
while (true) {
State current = state.get();
requireVersion(current, expectedActiveVersion);
if (current.draft() == null) {
throw new NoPolicyDraftException();
}
if (!current.draft().checksum().equals(expectedDraftChecksum)) {
throw new PolicyDraftConflictException(expectedDraftChecksum, current.draft().checksum());
}
if (state.compareAndSet(current, new State(current.active(), null, current.history()))) {
return;
}
}
}
public PolicyDiff diff(long fromVersion, long toVersion) {
State current = state.get();
PolicySnapshot from = requireHistory(current, fromVersion);
PolicySnapshot to = current.draft() != null && current.draft().version() == toVersion
? current.draft() : requireHistory(current, toVersion);
return PolicyDiff.between(from, to);
}
private static void requireVersion(State state, long expected) {
if (state.active().version() != expected) {
throw new PolicyVersionConflictException(expected, state.active().version());
}
}
private static PolicySnapshot requireHistory(State state, long version) {
PolicySnapshot snapshot = state.history().get(version);
if (snapshot == null) {
throw new IllegalArgumentException("Unknown policy version " + version);
}
return snapshot;
}
private record State(PolicySnapshot active, PolicySnapshot draft, Map<Long, PolicySnapshot> history) {
private State {
java.util.Objects.requireNonNull(active, "active");
history = java.util.Collections.unmodifiableMap(new LinkedHashMap<>(history));
}
}
}
package com.xfestudio.xfeservermanager.core.policy;
import com.xfestudio.xfeservermanager.api.policy.PolicyRule;
import com.xfestudio.xfeservermanager.api.policy.PolicySnapshot;
import java.time.Clock;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
/** Lock-free holder for an active snapshot, one draft, and immutable version history. */
public final class AtomicPolicyRepository implements PolicySnapshotProvider {
private final Clock clock;
private final PolicyValidator validator;
private final AtomicReference<State> state;
public AtomicPolicyRepository(PolicySnapshot initialSnapshot) {
this(initialSnapshot, Clock.systemUTC(), new PolicyValidator());
}
public AtomicPolicyRepository(PolicySnapshot initialSnapshot, Clock clock, PolicyValidator validator) {
this.clock = java.util.Objects.requireNonNull(clock, "clock");
this.validator = java.util.Objects.requireNonNull(validator, "validator");
validator.validate(initialSnapshot.rules()).throwIfInvalid();
if (!PolicySnapshotFactory.hasValidChecksum(initialSnapshot)) {
throw new InvalidPolicyException(List.of(new PolicyValidationIssue(
"", "snapshot_checksum", "Initial policy snapshot checksum is invalid")));
}
this.state = new AtomicReference<>(new State(
initialSnapshot, null, Map.of(initialSnapshot.version(), initialSnapshot)));
}
public static AtomicPolicyRepository empty(Clock clock) {
PolicySnapshot initial = PolicySnapshotFactory.create(
0L, clock.instant(), "system", "Initial pass-through policy", List.of());
return new AtomicPolicyRepository(initial, clock, new PolicyValidator());
}
@Override
public PolicySnapshot activeSnapshot() {
return state.get().active();
}
public Optional<PolicySnapshot> draftSnapshot() {
return Optional.ofNullable(state.get().draft());
}
public List<PolicySnapshot> history() {
return List.copyOf(state.get().history().values());
}
public PolicySnapshot stageDraft(List<PolicyRule> rules, String createdBy, String description) {
validator.validate(rules).throwIfInvalid();
while (true) {
State current = state.get();
PolicySnapshot draft = PolicySnapshotFactory.create(
current.active().version() + 1, clock.instant(), createdBy, description, rules);
State updated = new State(current.active(), draft, current.history());
if (state.compareAndSet(current, updated)) {
return draft;
}
}
}
public PolicySnapshot publishDraft(long expectedActiveVersion) {
State observed = state.get();
requireVersion(observed, expectedActiveVersion);
if (observed.draft() == null) {
throw new NoPolicyDraftException();
}
return publishDraft(expectedActiveVersion, observed.draft().checksum());
}
/** Publishes only if both the active base and reviewed draft still match. */
public PolicySnapshot publishDraft(long expectedActiveVersion, String expectedDraftChecksum) {
java.util.Objects.requireNonNull(expectedDraftChecksum, "expectedDraftChecksum");
while (true) {
State current = state.get();
requireVersion(current, expectedActiveVersion);
if (current.draft() == null) {
throw new NoPolicyDraftException();
}
if (!current.draft().checksum().equals(expectedDraftChecksum)) {
throw new PolicyDraftConflictException(expectedDraftChecksum, current.draft().checksum());
}
Map<Long, PolicySnapshot> history = new LinkedHashMap<>(current.history());
history.put(current.draft().version(), current.draft());
State updated = new State(current.draft(), null, history);
if (state.compareAndSet(current, updated)) {
return updated.active();
}
}
}
/** Publishes a copy of an old version as a new immutable version. */
public PolicySnapshot rollback(long targetVersion, long expectedActiveVersion, String createdBy, String description) {
while (true) {
State current = state.get();
requireVersion(current, expectedActiveVersion);
if (current.draft() != null) {
throw new PolicyDraftPresentException();
}
PolicySnapshot target = current.history().get(targetVersion);
if (target == null) {
throw new IllegalArgumentException("Unknown policy version " + targetVersion);
}
PolicySnapshot restored = PolicySnapshotFactory.create(
current.active().version() + 1, clock.instant(), createdBy, description, target.rules());
Map<Long, PolicySnapshot> history = new LinkedHashMap<>(current.history());
history.put(restored.version(), restored);
State updated = new State(restored, null, history);
if (state.compareAndSet(current, updated)) {
return restored;
}
}
}
public void discardDraft(long expectedActiveVersion, String expectedDraftChecksum) {
java.util.Objects.requireNonNull(expectedDraftChecksum, "expectedDraftChecksum");
while (true) {
State current = state.get();
requireVersion(current, expectedActiveVersion);
if (current.draft() == null) {
throw new NoPolicyDraftException();
}
if (!current.draft().checksum().equals(expectedDraftChecksum)) {
throw new PolicyDraftConflictException(expectedDraftChecksum, current.draft().checksum());
}
if (state.compareAndSet(current, new State(current.active(), null, current.history()))) {
return;
}
}
}
public PolicyDiff diff(long fromVersion, long toVersion) {
State current = state.get();
PolicySnapshot from = requireHistory(current, fromVersion);
PolicySnapshot to = current.draft() != null && current.draft().version() == toVersion
? current.draft() : requireHistory(current, toVersion);
return PolicyDiff.between(from, to);
}
private static void requireVersion(State state, long expected) {
if (state.active().version() != expected) {
throw new PolicyVersionConflictException(expected, state.active().version());
}
}
private static PolicySnapshot requireHistory(State state, long version) {
PolicySnapshot snapshot = state.history().get(version);
if (snapshot == null) {
throw new IllegalArgumentException("Unknown policy version " + version);
}
return snapshot;
}
private record State(PolicySnapshot active, PolicySnapshot draft, Map<Long, PolicySnapshot> history) {
private State {
java.util.Objects.requireNonNull(active, "active");
history = java.util.Collections.unmodifiableMap(new LinkedHashMap<>(history));
}
}
}