ConcurrencyImpl.java

package io.github.jonloucks.concurrency.impl;

import io.github.jonloucks.concurrency.api.*;
import io.github.jonloucks.contracts.api.AutoClose;
import io.github.jonloucks.contracts.api.AutoOpen;
import io.github.jonloucks.contracts.api.Repository;

import java.util.function.Consumer;

import static io.github.jonloucks.contracts.api.Checks.configCheck;
import static io.github.jonloucks.contracts.api.Checks.nullCheck;

final class ConcurrencyImpl implements Concurrency {
    
    @Override
    public AutoClose open() {
        return stateMachine.transition(b -> b
            .event("open")
            .successState(Idempotent.OPENED)
            .successValue(this::realOpen)
       .failedValue(AutoOpen.NONE::open));
    }
    
    @Override
    public <T> Waitable<T> createWaitable(T initialValue) {
        return waitableFactory.create(initialValue);
    }
    
    @Override
    public <T> StateMachine<T> createStateMachine(T initialState) {
        return stateMachineFactory.create(b -> b.initial(initialState));
    }
    
    @Override
    public <T extends Enum<T>> StateMachine<T> createStateMachine(Class<T> enumClass, T initialState) {
        return stateMachineFactory.create(enumClass, initialState);
    }
    
    @Override
    public <T> StateMachine<T> createStateMachine(Consumer<StateMachine.Config.Builder<T>> builderConsumer) {
        return stateMachineFactory.create(builderConsumer);
    }
    
    ConcurrencyImpl(Config config, Repository repository, boolean autoOpen) {
        final Config validConfig = configCheck(config);
        final Repository validRepository = nullCheck(repository, "Repository must be present.");
        this.closeRepository = autoOpen ? validRepository.open() : AutoClose.NONE;
        this.waitableFactory = validConfig.contracts().claim(WaitableFactory.CONTRACT);
        this.stateMachineFactory = validConfig.contracts().claim(StateMachineFactory.CONTRACT);
        this.stateMachine = createStateMachine(Idempotent.class, Idempotent.OPENABLE);
    }
    
    private AutoClose realOpen() {
        return this::close;
    }

    private void close() {
        stateMachine.transition(b -> b
            .event("close")
            .successState(Idempotent.CLOSED)
            .successValue(this::realClose));
    }
    
    private void realClose() {
        closeRepository.close();
    }
    
    private final AutoClose closeRepository;
    private final WaitableFactory waitableFactory;
    private final StateMachineFactory stateMachineFactory;
    private final StateMachine<Idempotent> stateMachine;
}