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

org.catools.common.concurrent.CStorage Maven / Gradle / Ivy

package org.catools.common.concurrent;

import org.catools.common.collections.CList;
import org.catools.common.date.CDate;
import org.catools.common.exception.CStorageEmptyInitException;
import org.catools.common.utils.CSleeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class CStorage {
    private final Object lock = new Object();

    private final CList available = new CList<>();
    private final CList borrowed = new CList<>();

    private final Logger logger;
    private final int requestIntervalInSeconds;
    private final int requestTimeoutInSeconds;

    public CStorage(String name, int requestIntervalInSeconds, int requestTimeoutInSeconds) {
        this.logger = LoggerFactory.getLogger("Storage " + name);
        this.requestIntervalInSeconds = requestIntervalInSeconds;
        this.requestTimeoutInSeconds = requestTimeoutInSeconds;
    }

    public void init(CList initialObjects) {
        logger.info("Storage initiation...");
        if (initialObjects.isEmpty()) {
            throw new CStorageEmptyInitException("Attempt to initiate storage with empty list.");
        }

        performActionOnQueue(() -> {
            available.addAll(initialObjects);
            return true;
        });
        logger.info("Storage initiated.");
    }

    public  R performAction(String borrower, Function action) {
        return performAction(borrower, t -> true, action);
    }

    public  R performAction(String borrower, Predicate predicate, Function action) {
        T t = null;
        try {
            t = borrow(borrower, predicate);
            return action.apply(t);
        } finally {
            if (t != null) {
                release(t);
            }
        }
    }

    public T borrow(String borrower) {
        return borrow(borrower, t -> true);
    }

    public T borrow(String borrower, Predicate predicate) {
        performActionOnQueue(() -> {
            logger.trace("Attempt to borrow object for " + borrower);
            logger.trace("Storage contains {} available and {} borrowed objects", available.size(), borrowed.size());
            return true;
        });
        Request request = new Request(borrower, requestTimeoutInSeconds, predicate);
        return waitForObjectToBeAvailable(request);
    }

    public boolean release(T t) {
        if (t != null) {
            return performActionOnQueue(() -> {
                logger.trace("Object returned to storage. " + t.toString());
                borrowed.remove(t);
                available.add(t);
                logger.trace("Storage contains {} available and {} borrowed objects", available.size(), borrowed.size());
                return true;
            });
        }
        return false;
    }

    private T waitForObjectToBeAvailable(Request request) {
        do {
            T response = performActionOnQueue(() -> {
                T firstOrElse = available.isEmpty() ? null : (T) available.getFirstOrNull(request.predicate);
                if (firstOrElse != null) {
                    available.remove(firstOrElse);
                    borrowed.add(firstOrElse);
                    return firstOrElse;
                }
                if (request.isTimeOuted()) {
                    throw new RuntimeException("Request Timeout triggered for TestCase:" + request.borrower);
                }
                return null;
            });

            if (response != null) {
                return response;
            }

            CSleeper.sleepTightInSeconds(requestIntervalInSeconds);
        } while (true);
    }

    private synchronized  T performActionOnQueue(Supplier supplier) {
        synchronized (lock) {
            return supplier.get();
        }
    }

    static class Request {
        private final Date timeoutAt;
        private final String borrower;
        private final Predicate predicate;

        public Request(String borrower, int timeoutInSeconds, Predicate predicate) {
            this.timeoutAt = CDate.now().addSeconds(timeoutInSeconds);
            this.predicate = predicate;
            this.borrower = borrower;
        }

        public boolean isTimeOuted() {
            return timeoutAt.before(new Date());
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy