package de.tum.in.www1.jReto.routing;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashSet;
import java.util.Set;
import de.tum.in.www1.jReto.module.api.Connection;
/**
* A MulticastConnection acts like a normal underlying connection, but sends all data written to it using a set of subconnections.
* Data received from any subconnection is reported to the delegate.
*/
public class MulticastConnection implements Connection, Connection.Handler {
private Connection.Handler handler;
/** The subconnections used with this connection */
private final Set<Connection> subconnections = new HashSet<Connection>();
/** Stores the number of dataSent calls yet to be received. Once all are received, the delegate's didSendData can be called. */
private int dataSentCallbacksToBeReceived = 0;
/** The number of data packets that have been sent in total. */
private int dataPacketsSent = 0;
/** Adds a subconnection. */
public void addSubconnection(Connection connection) {
this.subconnections.add(connection);
connection.setHandler(this);
}
public Set<Connection> getSubconnections() {
return this.subconnections;
}
@Override
public void setHandler(Handler handler) {
this.handler = handler;
}
@Override
public Handler getHandler() {
return this.handler;
}
@Override
public boolean isConnected() {
boolean isConnected = true;
for (Connection subconnection : this.subconnections) isConnected &= subconnection.isConnected();
return isConnected;
}
@Override
public int getRecommendedPacketSize() {
int recommendedPacketSize = 32 * 1024;
for (Connection subconnection : this.subconnections) recommendedPacketSize = Math.min(recommendedPacketSize, subconnection.getRecommendedPacketSize());
return recommendedPacketSize;
}
@Override
public void connect() {
for (Connection subconnection : this.subconnections) subconnection.connect();
}
@Override
public void close() {
for (Connection subconnection : this.subconnections) subconnection.close();
}
@Override
public void writeData(ByteBuffer data) {
if (dataSentCallbacksToBeReceived != 0) {
this.dataPacketsSent++;
} else {
this.dataSentCallbacksToBeReceived = this.subconnections.size();
}
for (Connection subconnection : this.subconnections) {
subconnection.writeData(data.slice().order(ByteOrder.LITTLE_ENDIAN));
}
}
@Override
public void onConnect(Connection connection) {
if (this.isConnected()) handler.onConnect(this);
}
@Override
public void onClose(Connection connection) {
for (Connection subconnection : this.subconnections) {
if (subconnection == connection) continue;
subconnection.close();
}
if (this.handler != null) this.handler.onClose(this);
}
@Override
public void onDataReceived(Connection connection, ByteBuffer data) {
this.handler.onDataReceived(this, data);
}
@Override
public void onDataSent(Connection connection) {
if (this.dataSentCallbacksToBeReceived == 0) {
System.err.println("Received unexpected onDataSent call!");
return;
}
this.dataSentCallbacksToBeReceived--;
if (this.dataSentCallbacksToBeReceived == 0) {
if (this.dataPacketsSent != 0) {
this.dataPacketsSent--;
this.dataSentCallbacksToBeReceived = this.subconnections.size();
}
this.handler.onDataSent(this);
}
}
}