org.async.rmi.client.ClientResultSet Maven / Gradle / Ivy
package org.async.rmi.client;
import org.async.rmi.Connection;
import org.async.rmi.ResultSet;
import org.async.rmi.messages.Message;
import org.async.rmi.messages.ResultSetRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by Barak Bar Orion
* 7/19/15.
*/
public class ClientResultSet implements ResultSet {
private static final Logger logger = LoggerFactory.getLogger(ClientResultSet.class);
private final CompletableFuture> connectionFuture;
private final List values;
private final AtomicBoolean closed = new AtomicBoolean(false);
private final CompletableFuture readyFuture;
private int index = -1;
final Lock lock = new ReentrantLock();
final Condition notEmpty = lock.newCondition();
public ClientResultSet(CompletableFuture> connectionFuture) {
this.connectionFuture = connectionFuture;
values = new LinkedList<>();
this.readyFuture = new CompletableFuture<>();
}
@Override
public boolean next() {
lock.lock();
try {
index += 1;
if (hasElement()) {
return true;
} else {
connectionFuture.get().send(new ResultSetRequest());
while (!closed.get() && !hasElement()) {
notEmpty.await();
}
return !closed.get();
}
} catch (Throwable e) {
logger.error(e.toString(), e);
return false;
} finally {
lock.unlock();
}
}
private boolean hasElement() {
if (!values.isEmpty() && values.get(0).length <= index) {
values.remove(0);
index = 0;
}
return !values.isEmpty() && index < values.get(0).length;
}
@Override
public V get() {
return values.get(0)[index];
}
@Override
public void close() throws Exception {
close(true);
}
private void close(boolean fromClient) throws Exception {
if (closed.compareAndSet(false, true)) {
if (fromClient) {
connectionFuture.get().send(new ResultSetRequest(true));
}
connectionFuture.get().clearAttachment();
connectionFuture.get().free();
if (!readyFuture.isDone()) {
readyFuture.complete(null);
}
}
}
public void onConnectionClosed() {
try {
close(false);
}catch(Exception ignored){
}
}
public void feed(Object value) {
lock.lock();
try {
if (value == null) {
try {
close();
} catch (Throwable t) {
logger.error(t.toString(), t);
}
}
//noinspection unchecked
values.add((V[]) value);
if (!readyFuture.isDone()) {
readyFuture.complete(null);
}
notEmpty.signal();
} finally {
lock.unlock();
}
}
public CompletableFuture readyFuture() {
return readyFuture;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
close(true);
}
}