XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEServerManager

【Java】我的世界XFE服务器管理器

公开
关注 0 Fork 0 Star 0
UTF-8
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));
        }
    }
}