package uk.ac.imperial.lsds.seep.comm;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.imperial.lsds.seep.comm.protocol.SeepCommand;
import uk.ac.imperial.lsds.seep.comm.serialization.Serializer;
import uk.ac.imperial.lsds.seep.util.ExtendedObjectOutputStream;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Output;
public class IOComm implements Comm {
final private Logger LOG = LoggerFactory.getLogger(IOComm.class.getName());
private Serializer s;
private ExecutorService e;
public IOComm(Serializer s, ExecutorService e){
this.s = s;
this.e = e;
}
@Override
public boolean send_sync(byte[] data, Connection c) {
try {
Socket connection = c.getOpenSocket();
DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
dos.writeInt(data.length);
dos.write(data);
String ack = in.readLine();
if(! ack.equals("ACK")){
// retry or something...
dos.close();
in.close();
return false;
}
dos.close();
in.close();
}
catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
public void send_async(byte[] data, Connection c) {
try {
Socket connection = c.getOpenSocket();
DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
dos.writeInt(data.length);
dos.write(data);
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void send_sync(byte[] data, Set<Connection> cs) {
for(Connection c : cs){
this.send_sync(data, c);
}
}
@Override
public void send_async(byte[] data, Set<Connection> cs) {
for(Connection c : cs){
this.send_async(data, c);
}
}
@Override
public boolean send_sync_parallel(byte[] data, Set<Connection> cs) {
Set<SyncSend> tasks = new HashSet<>();
List<Future<SendResult>> results = new ArrayList<>();
final IOComm cu = this;
for(Connection c : cs){
SyncSend ss = new SyncSend(data, c, cu);
tasks.add(ss);
}
try {
results = e.invokeAll(tasks);
for(Future<SendResult> f : results){
try {
if(! f.get().isDone())
return false;
}
catch (ExecutionException e1) {
e1.printStackTrace();
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
class SyncSend implements Callable<SendResult>{
private byte[] data;
private Connection c;
private IOComm cu;
public SyncSend(byte[] data, Connection c, IOComm cu){
this.data = data;
this.c = c;
this.cu = cu;
}
@Override
public SendResult call() throws Exception {
cu.send_sync(data, c);
return null;
}
}
class SendResult implements Future<SendResult>{
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public boolean isCancelled() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isDone() {
// TODO Auto-generated method stub
return false;
}
@Override
public SendResult get() throws InterruptedException, ExecutionException {
// TODO Auto-generated method stub
return null;
}
@Override
public SendResult get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException,
TimeoutException {
// TODO Auto-generated method stub
return null;
}
}
@Override
public void send_async_parallel(byte[] data, Set<Connection> cs) {
final IOComm cu = this;
for(Connection c : cs){
e.execute(new Runnable(){
@Override
public void run() {
cu.send_async(data, c);
}
});
}
}
@Override
public void send_sync(Object data, Connection c) {
byte[] d = s.serialize(data);
this.send_sync(d, c);
}
@Override
public void send_async(Object data, Connection c) {
byte[] d = s.serialize(data);
this.send_async(d, c);
}
@Override
public void send_sync(Object data, Set<Connection> cs) {
byte[] d = s.serialize(data);
this.send_sync(d, cs);
}
@Override
public void send_async(Object data, Set<Connection> cs) {
byte[] d = s.serialize(data);
this.send_async(d, cs);
}
@Override
public void send_sync_parallel(Object data, Set<Connection> cs) {
byte[] d = s.serialize(data);
this.send_sync_parallel(d, cs);
}
@Override
public void send_async_parallel(Object data, Set<Connection> cs) {
byte[] d = s.serialize(data);
this.send_async_parallel(d, cs);
}
@Override
public void send_sync(String data, Connection c) {
byte[] d = s.serialize(data);
this.send_sync(d, c);
}
@Override
public void send_async(String data, Connection c) {
byte[] d = s.serialize(data);
this.send_async(d, c);
}
@Override
public void send_sync(String data, Set<Connection> cs) {
byte[] d = s.serialize(data);
this.send_sync(d, cs);
}
@Override
public void send_async(String data, Set<Connection> cs) {
byte[] d = s.serialize(data);
this.send_async(d, cs);
}
@Override
public void send_sync_parallel(String data, Set<Connection> cs) {
byte[] d = s.serialize(data);
this.send_sync_parallel(d, cs);
}
@Override
public void send_async_parallel(String data, Set<Connection> cs) {
byte[] d = s.serialize(data);
this.send_async_parallel(d, cs);
}
@Override
public boolean send_object_sync(Object data, Connection c) {
ExtendedObjectOutputStream oos = null;
BufferedReader in = null;
try {
Socket connection = c.getOpenSocket();
oos = new ExtendedObjectOutputStream(connection.getOutputStream());
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
oos.writeClassDescriptor(ObjectStreamClass.lookup(data.getClass()));
oos.writeObject(data);
String ack = in.readLine();
if(! ack.equals("ACK")){
// retry or something...
oos.close();
in.close();
return false;
}
oos.close();
in.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
@Override
public void send_object_async(Object data, Connection c) {
ExtendedObjectOutputStream oos = null;
try {
Socket connection = c.getOpenSocket();
oos = new ExtendedObjectOutputStream(connection.getOutputStream());
oos.writeClassDescriptor(ObjectStreamClass.lookup(data.getClass()));
oos.writeObject(data);
oos.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void send_object_sync(Object data, Set<Connection> cs) {
for(Connection c : cs){
this.send_object_sync(data, c);
}
}
@Override
public void send_object_async(Object data, Set<Connection> cs) {
for(Connection c : cs){
this.send_object_async(data, c);
}
}
@Override
public boolean send_object_sync_parallel(Object data, Set<Connection> cs) {
try {
throw new Exception("NOT IMPLEMENTED");
} catch (Exception e) {
System.out.println(e.getMessage());
}
return false;
}
@Override
public void send_object_async_parallel(Object data, Set<Connection> cs) {
try {
throw new Exception("NOT IMPLEMENTED");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
@Override
public boolean send_object_sync(SeepCommand co, Connection c, Kryo k) {
try {
Socket s = c.getOpenSocket();
OutputStream bos = s.getOutputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
Output o = new Output(bos);
k.writeObject(o, co);
o.flush(); // this line
String ack = in.readLine();
if(!ack.equals("ack")) {
in.close();
o.close();
return false;
}
o.close();
return true;
}
catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean send_object_async(SeepCommand co, Connection c, Kryo k, int numRetries, int reconnectBackoff) {
for (int i = 0; i < numRetries; i++) {
try {
Socket s = c.getOpenSocket();
OutputStream bos = s.getOutputStream();
Output o = new Output(bos);
k.writeObject(o, co);
o.close();
return true;
}
catch (IOException e) {
LOG.error("Failed connection attempt {}", i);
}
try {
LOG.info("Reconnecting in {}", reconnectBackoff+"...");
Thread.sleep(reconnectBackoff);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
return false;
}
@Override
public boolean send_object_sync(SeepCommand co, Set<Connection> cs, Kryo k) {
for(Connection c : cs){
LOG.trace("Send to: {}", c.toString());
boolean success = this.send_object_sync(co, c, k);
if(!success)
return false;
}
return true;
}
@Override
public boolean send_object_async(SeepCommand co, Set<Connection> cs, Kryo k) {
try {
throw new Exception("NOT IMPLEMENTED");
} catch (Exception e) {
System.out.println(e.getMessage());
}
return false;
}
@Override
public boolean send_object_sync_parallel(SeepCommand data, Set<Connection> cs, Kryo k) {
try {
throw new Exception("NOT IMPLEMENTED");
} catch (Exception e) {
System.out.println(e.getMessage());
}
return false;
}
@Override
public void send_object_async_parallel(SeepCommand data, Set<Connection> cs, Kryo k) {
try {
throw new Exception("NOT IMPLEMENTED");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}