package classes.holonControlUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import classes.AbstractCanvasObject; import classes.Edge; import classes.GroupNode; import classes.Holon; import classes.HolonObject; import classes.HolonSwitch; import classes.Node; import classes.holonControlUnit.messages.NeighborhoodMsg; import classes.holonControlUnit.messages.OrderMsg; import classes.holonControlUnit.messages.SplitMsg; import classes.holonControlUnit.messages.SplitMsg.SenderRealtion; import classes.holonControlUnit.messages.StateMsg; import classes.holonControlUnit.messages.MergeMsg; import classes.holonControlUnit.messages.MergeOrderMsg; import classes.holonControlUnit.messages.Message; public class HierarchyControlUnit { private HolonControlUnit hcu; private String superHolon; private ArrayList subHolons; private ArrayList physicalNeighbors; private ArrayList virtualNeighbors; private ArrayList> receivedMergeRequests; //store merge requests for each timestep private ArrayList> sendMergeRequests; public HierarchyControlUnit(HolonControlUnit hcu) { this.hcu = hcu; this.subHolons = new ArrayList<>(); this.physicalNeighbors = new ArrayList<>(); this.virtualNeighbors = new ArrayList<>(); this.receivedMergeRequests = new ArrayList>(); this.sendMergeRequests = new ArrayList>(); } public ArrayList getPhysicalNeighbors() { return physicalNeighbors; } public void setPhysicalNeighbors(ArrayList physicalNeighbors) { this.physicalNeighbors = physicalNeighbors; } public void addPhysicalNeighbor(String physicalNeighbor) { if(!this.physicalNeighbors.contains(physicalNeighbor)) { this.physicalNeighbors.add(physicalNeighbor); } } public ArrayList getVirtualNeighbors() { return virtualNeighbors; } public void setVirtualNeighbors(ArrayList virtualNeighbors) { this.virtualNeighbors = virtualNeighbors; } public void resetVirtualNeighbors() { this.virtualNeighbors.clear(); } public void addSubHolon(String subHolon) { if(this.subHolons.contains(subHolon)) return; //propagate new virtual neighbor for all subholons ArrayList list = new ArrayList(); list.add(subHolon); String body = this.hcu.getCommunicator().getGson().toJson(new NeighborhoodMsg(NeighborhoodMsg.Type.NEW_VIRTUAL_NEIGHBOR, list)); for(String sub : this.subHolons) { this.hcu.getCommunicator().sendMsg(sub, Message.Type.NEIGHBORHOOD, body); } if(this.subHolons.size() > 0) { body = this.hcu.getCommunicator().getGson().toJson(new NeighborhoodMsg(NeighborhoodMsg.Type.NEW_VIRTUAL_NEIGHBOR, this.subHolons)); this.hcu.getCommunicator().sendMsg(subHolon, Message.Type.NEIGHBORHOOD, body); } this.subHolons.add(subHolon); } public void removeSubHolon(String subHolon) { if(!this.subHolons.remove(subHolon)) { System.err.println(this.hcu.getHolon().getUniqueID()+" could not remove sub holon "+subHolon+"\n\t"+subHolons); return; } ArrayList list = new ArrayList(); list.add(subHolon); String body = this.hcu.getCommunicator().getGson().toJson(new NeighborhoodMsg(NeighborhoodMsg.Type.REMOVE_VIRTUAL_NEIGHBOR, list)); for(String sub : this.subHolons) { this.hcu.getCommunicator().sendMsg(sub, Message.Type.NEIGHBORHOOD, body); } } public String getSuperHolon() { return this.superHolon; } public void setSuperHolon(String parent) { this.superHolon = parent; } public ArrayList getSubHolons() { return this.subHolons; } public ArrayList> getMergeRequests() { return receivedMergeRequests; } public ArrayList getMergeRequestsForTimeStep(int timeStep){ if(timeStep >= 0 && timeStep < this.receivedMergeRequests.size()) { return this.receivedMergeRequests.get(timeStep); } return new ArrayList(); } public void addVirtualNeighbor(String virtualNeighbor) { if(!this.virtualNeighbors.contains(virtualNeighbor)) { this.virtualNeighbors.add(virtualNeighbor); } } public void addVirtualNeighbors(ArrayList virtualNeighbors) { for(int i=0; i virtualNeighbor) { this.virtualNeighbors.removeAll(virtualNeighbor); } public void addEdgeTo(AbstractCanvasObject b) { if(b instanceof HolonObject && ((HolonObject)b).holon != null) { //add holon of b as physical neighbor Holon ho = ((HolonObject) b).holon; if(!this.physicalNeighbors.contains(ho.getUniqueID())) { this.physicalNeighbors.add(ho.getUniqueID()); } } else if(b instanceof HolonSwitch) { //get edges of b and add them if switch is open HolonSwitch hs = (HolonSwitch) b; if(!this.physicalNeighbors.contains(hs.getUniqueID())) { this.physicalNeighbors.add(hs.getUniqueID()); } } else if(b instanceof Node) { Node n = (Node) b; if(!this.physicalNeighbors.contains(n.getUniqueID())) this.physicalNeighbors.add(n.getUniqueID()); } else if (b instanceof GroupNode) { GroupNode n = (GroupNode) b; if(!this.physicalNeighbors.contains(n.getUniqueID())) this.physicalNeighbors.add(n.getUniqueID()); } } public void removeEdgeTo(AbstractCanvasObject b) { if(b instanceof HolonObject) { //remove holon of b as physical neighbor Holon ho = ((HolonObject) b).holon; this.physicalNeighbors.remove(ho.getUniqueID()); } else if(b instanceof HolonSwitch) { //get edges of b and add them if switch is open HolonSwitch hs = (HolonSwitch) b; this.physicalNeighbors.remove(hs.getUniqueID()); } else if(b instanceof Node) { Node n = (Node) b; this.physicalNeighbors.remove(n.getUniqueID()); } else if (b instanceof GroupNode) { GroupNode n = (GroupNode) b; this.physicalNeighbors.remove(n.getUniqueID()); } } public void removeEdge(Edge e) { AbstractCanvasObject a = e.getA(); AbstractCanvasObject b = e.getB(); if(a.equals(this.hcu.getHolon().getHolonObject())) { removeEdgeTo(b); } else { removeEdgeTo(a); } //check if connection to super or subholon is affected Holon h = this.hcu.getHolon(); if(h.getLayer() > 1 && h.getParent().getPathsToChildren().get(h).contains(e)) { //path to superholon is affected h.merge("State Holon", true); } Map> set = Map.copyOf(h.getPathsToChildren()); for(Holon c : set.keySet()) { if(set.get(c).contains(e)) { //path to subholon c is affected c.merge("State Holon", true); } } } public void receiveMergeReq(MergeMsg msg, String sender) { if(!canMerge(msg.getRequester(), msg.getPower())) { return; } int timeStep = msg.getTimeStep(); if(timeStep >= 0) { if(timeStep >= this.receivedMergeRequests.size() && timeStep <= this.hcu.getHolon().model.getIterations()) { for(int i=this.receivedMergeRequests.size(); i<=timeStep; i++) { this.receivedMergeRequests.add(new ArrayList()); } } if(this.receivedMergeRequests.get(timeStep) == null) this.receivedMergeRequests.add(new ArrayList()); for(MergeMsg m : this.receivedMergeRequests.get(timeStep)) { if(m.getPower() == msg.getPower() && m.getRequester() == msg.getRequester() && m.getPredictedPowerUsage() == msg.getPredictedPowerUsage() && m.getNetThroughput() == msg.getNetThroughput()) { if (m.getTimeStep() < msg.getTimeStep()) { m = msg; } System.err.println("duplicate"); return; } } this.receivedMergeRequests.get(timeStep).add(msg); } } public void receiveMergeAck(MergeMsg msg, String sender) { // float requiredPower = this.hcu.getStateAssembler().getDesiredPowerUsage() - this.hcu.getStateEstimator().getPowerUsage(); if(this.superHolon.equals(sender) || this.subHolons.contains(sender) || !canMerge(msg.getRequester(), msg.getPower())) { // || !this.hcu.decreasesPowerUsage(msg.getPredictedPowerUsage(), this.hcu.getStateEstimator().getPowerUsage(), // this.hcu.getStateEstimator().getPredictedPowerUsage(), requiredPower)) { return; } // HashMap map = this.sendMergeRequests.get(msg.getTimeStep()-1); // if(map.containsKey(sender) && this.hcu.matchPowerRange(map.get(sender).getPower(), msg.getPower()) // && true) { // //tell sender that we are still interested in merging // map.clear(); //delete all merge request for this timestep so we dont merge with two holons at a time // StateMsg state = new StateMsg(this.hcu.getStateEstimator().getPowerUsage(), this.hcu.getStateEstimator().getNetThroughput(), // this.hcu.getStateEstimator().getPredictedPowerUsage(), this.hcu.getStateEstimator().getStateIndicator()); // MergeMsg m = new MergeMsg(MergeMsg.Type.ACK_II, msg.getPower(), this.hcu.getStateEstimator().getNetThroughput(), // msg.getPredictedPowerUsage(), this.hcu.getHolon().getUniqueID(), msg.getTimeStep(), state, msg.getRedirectedBy()); // String body = this.hcu.getCommunicator().getGson().toJson(m, MergeMsg.class); // this.hcu.getCommunicator().sendMsg(sender, Message.Type.MERGE, body); // return; // } int i = msg.getRedirectedBy().size(); if(msg.getTimeStep() < 1 || msg.getTimeStep()-1-i < 0) return; String red = i > 0 ? msg.getRedirectedBy().get(0) : sender; HashMap map = this.sendMergeRequests.get(msg.getTimeStep()-1-i); if(red != null && map.containsKey(red) && this.hcu.matchPowerRange(map.get(red).getPower(), msg.getPower())) { //tell sender that we are still interested in merging map.clear(); //delete all merge request for this timestep so we dont merge with two holons at a time StateMsg state = new StateMsg(this.hcu.getStateEstimator().getPowerUsage(), this.hcu.getStateEstimator().getNetThroughput(), this.hcu.getStateEstimator().getPredictedPowerUsage(), this.hcu.getStateEstimator().getStateIndicator()); MergeMsg m = new MergeMsg(MergeMsg.Type.ACK_II, msg.getPower(), this.hcu.getStateEstimator().getNetThroughput(), msg.getPredictedPowerUsage(), this.hcu.getHolon().getUniqueID(), msg.getTimeStep(), state, msg.getRedirectedBy(), msg.isAllowOccupiedPath()); String body = this.hcu.getCommunicator().getGson().toJson(m, MergeMsg.class); this.hcu.getCommunicator().sendMsg(sender, Message.Type.MERGE, body); } } public void receiveMergeAckII(MergeMsg msg, String sender) { if(!canMerge(msg.getRequester(), msg.getPower())) { return; } if(msg.getRedirectedBy() == null || msg.getRedirectedBy().size() == 0) { this.hcu.getHolon().merge(sender, msg.isAllowOccupiedPath()); this.hcu.getStateEstimator().receiveState(sender, msg.getState()); } else { MergeOrderMsg m = new MergeOrderMsg(msg, this.hcu.getHolon().getUniqueID()); String body = this.hcu.getCommunicator().getGson().toJson(m, MergeOrderMsg.class); this.hcu.getCommunicator().sendMsg(msg.getRedirectedBy().get(0), Message.Type.MERGE_ORDER, body); } } public void receiveMergeOrder(MergeOrderMsg msg, String sender) { MergeMsg merge = msg.getOrginalMergeMsg(); // System.out.println(this.hcu.getHolon().getUniqueID()+" I have to merge :( "+merge.getRedirectedBy()); if(!this.hcu.getHolon().isASuperiorHolon(sender) || !canMerge(merge.getRequester(),merge.getPower())) return; this.hcu.getHolon().merge(merge.getRequester(), merge.isAllowOccupiedPath()); this.hcu.getStateEstimator().receiveState(merge.getRequester(), merge.getState()); OrderMsg order = new OrderMsg(merge.getPower(), this.hcu.getHolon().model.getCurIteration()); this.hcu.getCommunicator().sendMsg(merge.getRequester(), Message.Type.ORDER, this.hcu.getCommunicator().getGson().toJson(order)); } public void sendMergeReq(float powerUsage, ArrayList predictedPowerUsage, int timeStep, String physicalNeighbor) { MergeMsg msg = new MergeMsg(MergeMsg.Type.REQ, powerUsage, this.hcu.getStateEstimator().getNetThroughput(), predictedPowerUsage, this.hcu.getHolon().getUniqueID(), timeStep, null, new ArrayList<>(), true); if(this.sendMergeRequests.size() <= timeStep) { for(int i=this.sendMergeRequests.size(); i<=timeStep; i++) { this.sendMergeRequests.add(new HashMap<>()); } } this.sendMergeRequests.get(timeStep).put(physicalNeighbor, msg); String body = this.hcu.getCommunicator().getGson().toJson(msg, MergeMsg.class); this.hcu.getCommunicator().sendMsg(physicalNeighbor, Message.Type.MERGE, body); } public void sendMergeAck(int timeStep, MergeMsg req, boolean allowOccupiedPath) { MergeMsg msg = new MergeMsg(MergeMsg.Type.ACK, req.getPower(), this.hcu.getStateEstimator().getNetThroughput(), req.getPredictedPowerUsage(), this.hcu.getHolon().getUniqueID(), timeStep, req.getState(), req.getRedirectedBy(), allowOccupiedPath); String body = this.hcu.getCommunicator().getGson().toJson(msg, MergeMsg.class); this.hcu.getCommunicator().sendMsg(req.getRequester(), Message.Type.MERGE, body); } public void propagateMergeReqToParent(int timeStep) { if(timeStep < 0 || timeStep >= this.hcu.getHolon().model.getIterations() || timeStep >= this.receivedMergeRequests.size() || this.hcu.getHolon().getLayer() <= 1) return; for(MergeMsg req : this.receivedMergeRequests.get(timeStep)) { if(req.getRequester().equals(this.hcu.getHolon().getUniqueID()) || req.getRequester().equals(this.superHolon) || req.getRedirectedBy().contains(this.hcu.getHolon().getUniqueID()) || req.getRedirectedBy().contains(this.superHolon)) continue; req.getRedirectedBy().add(this.hcu.getHolon().getUniqueID()); String body = this.hcu.getCommunicator().getGson().toJson(req, MergeMsg.class); this.hcu.getCommunicator().sendMsg(this.superHolon, Message.Type.MERGE, body); } } public void splitSubHolon(String id, int timeStep) { if(!this.subHolons.contains(id)) return; SplitMsg msg = new SplitMsg(SenderRealtion.SUPERHOLON, timeStep); String body = this.hcu.getCommunicator().getGson().toJson(msg, SplitMsg.class); this.hcu.getCommunicator().sendMsg(id, Message.Type.SPLIT, body); this.hcu.getHolon().splitById(id); } public void splitSuperHolon(int timeStep) { SplitMsg msg = new SplitMsg(SenderRealtion.SUBHOLON, timeStep); String body = this.hcu.getCommunicator().getGson().toJson(msg, SplitMsg.class); this.hcu.getCommunicator().sendMsg(this.superHolon, Message.Type.SPLIT, body); this.hcu.getHolon().split(null, true); } public void receiveSplitMsg(SplitMsg msg, String sender) { if(msg.getType() == SenderRealtion.SUPERHOLON && this.superHolon.equals(sender)) { // System.out.println(this.hcu.getHolon().getUniqueID()+" my super holon kicked me out :("); } else if (msg.getType() == SenderRealtion.SUBHOLON && this.subHolons.contains(sender)) { // System.out.println(this.hcu.getHolon().getUniqueID()+" my child holon abandoned me :("); } } /** * get all physical neighbors that are not subholons (or a subholon of a subholon) and not virtual neighbors * @return */ public ArrayList getPhysicalNeighborsFromOtherHolarchy(){ ArrayList neighbors = new ArrayList(); for(String s : this.physicalNeighbors) { if(!s.contains("Switch") && !s.contains("Node") && !s.contains("Group Node") && !s.equals(this.superHolon) && !this.subHolons.contains(s) && !this.virtualNeighbors.contains(s)) { neighbors.add(s); } else if(s.contains("Switch") || s.contains("Node") || s.contains("Group Node")) { ArrayList potNeighbors = this.hcu.getHolon().model.getAllConnectionsFromObject(s, this.hcu.getHolon().getUniqueID()); for(String s2 : potNeighbors) { if(!s2.equals(this.superHolon) && !this.subHolons.contains(s2) && !this.virtualNeighbors.contains(s2)) { neighbors.add(s2); } } } } return neighbors; } /** * checks if the other holon is a subholon (or subholon of subholon), this superholon or if the added throughput would burn any edges * @param other * @param addedThroughput * @return */ public boolean canMerge(String other, float addedThroughput) { Holon thisHolon = this.hcu.getHolon(); Holon otherHolon = thisHolon.model.getHolonsByID().get(other); if(other.equals(thisHolon.getUniqueID()) || !thisHolon.model.checkHolonObjectsAreConnected(thisHolon, otherHolon, addedThroughput) || thisHolon.isASuperiorHolon(other) || otherHolon.isASuperiorHolon(this.hcu.getHolon().getUniqueID())) { // this holon and the other holon can not merge because: // a) this holon and other holon are the same or // b) other holon is not connected to this holon or the new throughput would burn a cable or // c) other holon is a superior holon of this holon or // d) this holon is a superior holon of other holon return false; } return true; } }