package alien4cloud.it.utils.websocket; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; /** * A convenient simple callback to retrieve data from stomp connection without having to manage concurrency * * @author Minh Khang VU */ @Slf4j public class StompCallback<T> implements IStompCallback<T>, IStompDataFuture<T> { private ReentrantLock finishLock; private Condition finishCondition; private List<StompData> dataList; private AtomicReference<Throwable> exception; private AtomicInteger dataToBeRetrieved; private Class<T> dataType; public StompCallback(Class<T> dataType) { this.exception = new AtomicReference<>(); this.finishLock = new ReentrantLock(); this.finishCondition = this.finishLock.newCondition(); this.dataList = new ArrayList<>(); this.dataType = dataType; } @Override public Class<T> getExpectedDataType() { return this.dataType; } @Override public void onData(String topic, T data) { try { finishLock.lock(); dataList.add(new StompData(topic, data)); if (log.isDebugEnabled()) { log.debug("Received {}th data with content {}", dataList.size(), data); } if (dataToBeRetrieved != null && dataList.size() >= dataToBeRetrieved.get()) { finishCondition.signal(); } } finally { finishLock.unlock(); } } @Override public void onError(Throwable error) { try { finishLock.lock(); exception.set(error); finishCondition.signal(); } finally { finishLock.unlock(); } } @SneakyThrows(Throwable.class) public StompData<T>[] getData(int minimumNumberOfData, long timeout, TimeUnit timeUnit) { try { this.finishLock.lock(); if (this.dataToBeRetrieved != null) { throw new IllegalStateException("Cannot handle concurrent consumers"); } if (this.exception.get() != null) { throw this.exception.get(); } this.dataToBeRetrieved = new AtomicInteger(minimumNumberOfData); if (this.dataList.size() < this.dataToBeRetrieved.get()) { this.finishCondition.await(timeout, timeUnit); } if (this.exception.get() != null) { throw this.exception.get(); } return this.dataList.toArray(new StompData[this.dataList.size()]); } finally { this.dataList.clear(); this.dataToBeRetrieved = null; this.finishLock.unlock(); } } }