package csx55.overlay.wireformats; import java.io.*; import java.util.ArrayList; import java.util.Random; import csx55.overlay.util.OverlayCreator; /** * This is a wireformat used by the registry to send the list of links in the system to all of the * messaging nodes. The link weights follow the format host:port host:port weight. It follows the same format * as all of the other wireformats and is built using the provided example in the slides. This wireformat accepts * the number of links and an array of the links in the system as one constructor and intializes * the instance variables. Another constructor takes in the byte stream and unmarshalls the information * sent by the node. It also implemnts the getBytes() method from the Event interface, which marshalls * the variables for this wireformat. The first constructor is used when creating an instance of the class * and the second is used by the event factory to create a new instance and return a class that the bytes * unmarshalled. The getBytes() is used before the data is sent using the sender thread. */ public class LinkWeights implements Event { private int type; private int numLinks; private ArrayList links; //takes in the topolgy defined by OverlayCreator and assigns weights based on those public LinkWeights(OverlayCreator.Node[] topology) { Random rand = new Random(); this.links = new ArrayList<>(); this.type = Protocol.LINK_WEIGHTS; //getting the total number of links for (OverlayCreator.Node n: topology) { this.numLinks += n.getNumNeighbors(); } //adding links to the links array list in the format ip:port ip:port weight for (OverlayCreator.Node n: topology) { for (String neighbor: n.getNeighbors()) { links.add(n.connectionInfo + " " + neighbor + " " + Integer.toString(rand.nextInt(10) + 1)); } } } public LinkWeights(byte[] marshalledByte) throws IOException { ByteArrayInputStream baInputStream = new ByteArrayInputStream(marshalledByte); DataInputStream din = new DataInputStream(new BufferedInputStream(baInputStream)); this.type = din.readInt(); this.numLinks = din.readInt(); int listSize = din.readInt(); this.links = new ArrayList<>(listSize); for (int i = 0; i < listSize; i++) { int size = din.readInt(); byte[] linkBytes = new byte[size]; din.readFully(linkBytes); this.links.add(i, new String(linkBytes)); } baInputStream.close(); din.close(); } @Override public int getType() { return this.type; } @Override public byte[] getBytes() throws IOException { byte[] marshalledBytes = null; ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(baOutputStream)); dout.writeInt(type); dout.writeInt(numLinks); dout.writeInt(links.size()); for (String s: links) { byte[] linkBytes = s.getBytes(); dout.writeInt(linkBytes.length); dout.write(linkBytes); } dout.flush(); marshalledBytes = baOutputStream.toByteArray(); baOutputStream.close(); dout.close(); return marshalledBytes; } //return number of links in the overlay public int getNumLinks() { return this.numLinks; } //return the list of links in the overlay public ArrayList getLinks() { return this.links; } //searches the links arraylist to see if both the current and next nodes are present //allows both nodes to access the weight regardless of wether they are current or next public String getWeight(String curr, String next) { String str = ""; for (int i = 0; i < links.size(); i++) { String link = links.get(i); if (link.contains(curr) && link.contains(next)) { str = link.split("\\s+")[2];//split on spaces } } return str; } }