All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.pellse.concurrent.ReentrantExecutor Maven / Gradle / Ivy

Go to download

Small library allowing to efficiently assemble entities from querying/merging external datasources or aggregating microservices

The newest version!
/*
 * Copyright 2024 Sebastien Pelletier
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.pellse.concurrent;

import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.function.Function;
import java.util.function.Supplier;

import static io.github.pellse.util.reactive.ReactiveUtils.nullToEmpty;
import static java.time.Duration.ofSeconds;
import static reactor.core.publisher.Mono.*;

public interface ReentrantExecutor {

    @FunctionalInterface
    interface WriteLockExecutor {
        default Mono withLock(Supplier> monoSupplier) {
            return withLock(defer(monoSupplier));
        }

        Mono withLock(Mono mono);
    }

    Duration DEFAULT_TIMEOUT = ofSeconds(10);

    default  Mono withReadLock(Mono mono) {
        return withReadLock(mono, null);
    }

    default  Mono withReadLock(Mono mono, Supplier defaultValueProvider) {
        return withReadLock(mono, DEFAULT_TIMEOUT, defaultValueProvider);
    }

    default  Mono withReadLock(Mono mono, Duration timeout, Supplier defaultValueProvider) {
        return withReadLock(__ -> mono, timeout, defaultValueProvider);
    }

    default  Mono withReadLock(Function, Mono> writeLockMonoFunction) {
        return withReadLock(writeLockMonoFunction, null);
    }

    default  Mono withReadLock(Function, Mono> writeLockMonoFunction, Supplier defaultValueProvider) {
        return withReadLock(writeLockMonoFunction, DEFAULT_TIMEOUT, defaultValueProvider);
    }

    default  Mono withWriteLock(Mono mono) {
        return withWriteLock(mono, null);
    }

    default  Mono withWriteLock(Mono mono, Supplier defaultValueProvider) {
        return withWriteLock(mono, DEFAULT_TIMEOUT, defaultValueProvider);
    }

     Mono withReadLock(Function, Mono> writeLockMonoFunction, Duration timeout, Supplier defaultValueProvider);

     Mono withWriteLock(Mono mono, Duration timeout, Supplier defaultValueProvider);

    static ReentrantExecutor create() {

        final var lockManager = new LockManager();

        return new ReentrantExecutor() {

            @FunctionalInterface
            interface ResourceManager {
                default Mono using(Mono lockProvider, Mono mono) {
                    return using(lockProvider, __ -> mono);
                }

                Mono using(Mono lockProvider, Function> monoSupplier);
            }

            @Override
            public  Mono withReadLock(Function, Mono> writeLockMonoFunction, Duration timeout, Supplier defaultValueProvider) {
                return with(writeLockMonoFunction, LockManager::acquireReadLock, timeout, defaultValueProvider);
            }

            @Override
            public  Mono withWriteLock(Mono mono, Duration timeout, Supplier defaultValueProvider) {
                return with(__ -> mono, LockManager::acquireWriteLock, timeout, defaultValueProvider);
            }

            private  Mono with(
                    Function, Mono> writeLockMonoFunction,
                    Function> lockAcquisitionStrategy,
                    Duration timeout,
                    Supplier defaultValueProvider) {

                final Mono defaultMono = nullToEmpty(defaultValueProvider);

                final ResourceManager resourceManager = (lockProvider, monoSupplier) -> usingWhen(
                        lockProvider,
                        lock -> monoSupplier.apply(lock).timeout(timeout, defaultMono),
                        Lock::release);

                return resourceManager.using(
                        lockAcquisitionStrategy.apply(lockManager),
                        lock -> writeLockMonoFunction.apply(mono -> resourceManager.using(lockManager.toWriteLock(lock), mono)));
            }
        };
    }
}