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