![JAR search and dependency download from the Maven repository](/logo.png)
com.manoelcampos.gossipsimulator.GossipNodeSimple Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gossip-simulator Show documentation
Show all versions of gossip-simulator Show documentation
An API for creation of applications to simulate the Gossip Protocol
package com.manoelcampos.gossipsimulator;
import java.util.*;
import static java.util.Objects.requireNonNull;
/**
* A basic implementation of a {@link GossipNode}.
* @param the type of the data the node shares
*/
public class GossipNodeSimple implements GossipNode {
private final GossipSimulator simulator;
private final Set> neighbours;
private T message;
private long id;
public GossipNodeSimple(final long id, final GossipSimulator simulator) {
this.simulator = requireNonNull(simulator);
this.id = id;
this.neighbours = new HashSet<>();
simulator.addNode(this);
}
@Override
public long getId() {
return id;
}
private GossipConfig config(){
return simulator.getConfig();
}
@Override
public boolean sendMessage() {
if(message == null){
LOGGER.warn("{} has no stored message to send", this);
return false;
}
if(neighbours.isEmpty()){
LOGGER.warn("{} has no neighbours to send messages to", this);
return false;
}
/*If the number of known neighbours is lower than the number of random neighbours to select,
* it doesn't make sense to select neighbours randomly.
* If we have 2 neighbours and the fanout is 4, we just select all the existing neighbours to
* send messages to.*/
final boolean sendToAllNeighbours = neighbours.size() < config().getFanout();
final Collection> selected = sendToAllNeighbours ? neighbours : getRandomNodes();
LOGGER.info(
"{} is going to send a message to {} {} {}{}",
this, formatCount(selected.size()), sendToAllNeighbours ? "existing" : "randomly selected",
selected.size() > 1 ? "neighbours" : "neighbour",
sendToAllNeighbours ? "" : " from total of " + formatCount(neighbours.size()));
selected.forEach(node -> node.receiveMessage(this, message));
return true;
}
private String formatCount(final int count) {
final int digits = String.valueOf(simulator.getNodesCount()).length();
return String.format("%" + digits + "d", count);
}
private Collection> getRandomNodes() {
return simulator.randomNodes(neighbours, config().getFanout());
}
@Override
public void receiveMessage(final GossipNode source, final T data) {
//Updates the set of neighbour nodes
neighbours.add(source);
this.message = data;
LOGGER.debug("{} received message from {}", this, source);
}
@Override
public boolean addNeighbour(final GossipNode neighbour) {
if(this.equals(neighbour))
return false;
return neighbours.add(requireNonNull(neighbour));
}
@Override
public boolean addNeighbours(final Collection> newNeighbours) {
return neighbours.addAll(requireNonNull(newNeighbours));
}
@Override
public Set> getNeighbours() {
return Collections.unmodifiableSet(neighbours);
}
@Override
public int getNeighbourhoodSize() {
return neighbours.size();
}
@Override
public T getMessage() {
return message;
}
@Override
public void setMessage(final T message) {
this.message = message;
}
@Override
public boolean isInfected() {
return message != null;
}
@Override
public String toString() {
final int len = String.valueOf(simulator.getNodesCount()).length();
return String.format("GossipNode %"+len+"d%s", id, isInfected() ? " 🐞" : " 💚");
}
@Override
public boolean equals(final Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final GossipNodeSimple> that = (GossipNodeSimple>) o;
return id == that.id && simulator.equals(that.simulator);
}
@Override
public int hashCode() {
return Objects.hash(simulator, id);
}
@Override
public int compareTo(final GossipNode o) {
return Long.compare(this.id, o.getId());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy