|
@@ -9,6 +9,8 @@ import java.util.UUID;
|
|
|
import classes.holonControlUnit.HolonControlUnit;
|
|
|
import ui.controller.Control;
|
|
|
import ui.model.DecoratedNetwork;
|
|
|
+import ui.model.IntermediateCableWithState;
|
|
|
+import ui.model.MinimumModel;
|
|
|
import ui.model.Model;
|
|
|
|
|
|
public class Holon {
|
|
@@ -22,22 +24,27 @@ public class Holon {
|
|
|
public HolonControlUnit holonControlUnit;
|
|
|
private String uniqueID;
|
|
|
public Model model;
|
|
|
+ private MinimumModel minModel;
|
|
|
+ /** stores whether the part between this holon and the child is occupied by the superholon */
|
|
|
+ private boolean canRunIndependentFromParent;
|
|
|
|
|
|
public Holon(String name, Model model) {
|
|
|
this.name = name;
|
|
|
+ this.parent = parent;
|
|
|
this.holonObject = null;
|
|
|
isPhysical = false;
|
|
|
- this.holonControlUnit = new HolonControlUnit(this);
|
|
|
this.uniqueID = UUID.randomUUID().toString();
|
|
|
this.model = model;
|
|
|
-// System.out.println("Created new Holon "+name+" "+this.uniqueID);
|
|
|
+ this.holonControlUnit = new HolonControlUnit(this);
|
|
|
+ this.minModel = new MinimumModel(new ArrayList<AbstractCanvasObject>(), new ArrayList<Edge>());
|
|
|
+ this.canRunIndependentFromParent = true;
|
|
|
}
|
|
|
|
|
|
public Holon(HolonObject object, Model model) {
|
|
|
holonObject = object;
|
|
|
object.holon = this;
|
|
|
+ this.parent = parent;
|
|
|
name = object.getName();
|
|
|
- this.holonControlUnit = new HolonControlUnit(this);
|
|
|
elements.addAll(object.getElements());
|
|
|
for(HolonElement ele : elements) {
|
|
|
ele.holon = this;
|
|
@@ -45,7 +52,11 @@ public class Holon {
|
|
|
isPhysical = true;
|
|
|
this.uniqueID = UUID.randomUUID().toString();
|
|
|
this.model = model;
|
|
|
-// System.out.println("Created new Holon "+name+" "+this.uniqueID);
|
|
|
+ this.holonControlUnit = new HolonControlUnit(this);
|
|
|
+ ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
|
|
|
+ list.add(object);
|
|
|
+ this.minModel = new MinimumModel(list, new ArrayList<Edge>());
|
|
|
+ this.canRunIndependentFromParent = true;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -62,31 +73,33 @@ public class Holon {
|
|
|
}
|
|
|
|
|
|
public void addChild(Holon child) {
|
|
|
- if(!this.model.getHolonsByID().containsKey(child.getUniqueID()))
|
|
|
- return;
|
|
|
- child.parent = this;
|
|
|
- childHolons.add(child);
|
|
|
+ if(!this.childHolons.contains(child)) {
|
|
|
+ child.parent = this;
|
|
|
+ this.childHolons.add(child);
|
|
|
+ }
|
|
|
this.holonControlUnit.addSubHolon(child);
|
|
|
-// System.out.println("Holon "+this.name+" added new child holon "+child.name);
|
|
|
}
|
|
|
|
|
|
public void addChildHolon(Holon child, int index) {
|
|
|
- child.parent = this;
|
|
|
- childHolons.add(index, child);
|
|
|
+ if(!this.childHolons.contains(child)) {
|
|
|
+ child.parent = this;
|
|
|
+ childHolons.add(index, child);
|
|
|
+ }
|
|
|
this.holonControlUnit.addSubHolon(child);
|
|
|
-// System.out.println("Holon "+this.name+" added new child holon "+child.name);
|
|
|
}
|
|
|
|
|
|
public void removeChildHolon(Holon child) {
|
|
|
child.parent = null;
|
|
|
childHolons.remove(child);
|
|
|
this.holonControlUnit.getHierarchyController().removeSubHolon(child.getUniqueID());
|
|
|
+ revalidateMinModel();
|
|
|
}
|
|
|
|
|
|
public void removeFromParent() {
|
|
|
if(parent != null) {
|
|
|
parent.removeChildHolon(this);
|
|
|
}
|
|
|
+ parent = model.getStateHolon();
|
|
|
}
|
|
|
|
|
|
|
|
@@ -99,9 +112,8 @@ public class Holon {
|
|
|
}
|
|
|
|
|
|
public void setParent(Holon parent) {
|
|
|
-// System.out.println("Holon "+this.name+" replaced parent "+this.parent.name+" with "+parent.name);
|
|
|
this.parent = parent;
|
|
|
- this.holonControlUnit.setSuperHolon(parent);
|
|
|
+ this.holonControlUnit.getHierarchyController().setSuperHolon(parent.getUniqueID());
|
|
|
}
|
|
|
|
|
|
public HolonObject getHolonObject() {
|
|
@@ -125,7 +137,7 @@ public class Holon {
|
|
|
|
|
|
public void reassignAllChildren(Holon other) {
|
|
|
for(Holon child: this.childHolons) {
|
|
|
- other.addChild(child);
|
|
|
+ other.merge(child);
|
|
|
}
|
|
|
childHolons.clear();
|
|
|
}
|
|
@@ -195,21 +207,20 @@ public class Holon {
|
|
|
if(isPureAbstract) {
|
|
|
continue;
|
|
|
}
|
|
|
- boolean isPhysicalConnected = table.get(first) == table.get(otherHolonObject);
|
|
|
+ boolean isPhysicalConnected = model.checkHolonObjectsAreConnected(this, other);
|
|
|
if(!isPhysicalConnected) {
|
|
|
removeList.add(other);
|
|
|
}
|
|
|
}
|
|
|
//Remove holons
|
|
|
for(Holon holon : removeList) {
|
|
|
- holon.removeFromParent();
|
|
|
- stateHolon.addChild(holon);
|
|
|
+ holon.split(stateHolon);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public void addNewVirtualNeighbor(String virtualNeighbor) {
|
|
|
- if(!this.equals(virtualNeighbor)) {
|
|
|
+ if(!this.uniqueID.equals(virtualNeighbor)) {
|
|
|
this.holonControlUnit.addNewVirtualNeighbor(virtualNeighbor);
|
|
|
}
|
|
|
}
|
|
@@ -218,6 +229,253 @@ public class Holon {
|
|
|
return uniqueID;
|
|
|
}
|
|
|
|
|
|
-}
|
|
|
-
|
|
|
+ public ArrayList<HolonObject> getAllHolonObjects() {
|
|
|
+ ArrayList<HolonObject> list = new ArrayList<HolonObject>();
|
|
|
+ for(Holon h : this.childHolons) {
|
|
|
+ list.addAll(h.getAllHolonObjects());
|
|
|
+ }
|
|
|
+ if(this.holonObject != null) {
|
|
|
+ list.add(this.holonObject);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ public MinimumModel getMinimumModel() {
|
|
|
+ return this.minModel;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void merge(Holon child) {
|
|
|
+ if(!this.model.getHolonsByID().containsKey(child.getUniqueID())) {
|
|
|
+ System.err.println("could not find: "+child.getHolonObject());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.childHolons.contains(child)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.getLayer() == 0) {
|
|
|
+ this.addChild(child);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //check if path between this holon and child holon is already occupied
|
|
|
+ ArrayList<HolonObject> holarchy = getAllHolonObjects();
|
|
|
+ holarchy.addAll(child.getAllHolonObjects());
|
|
|
+ HashMap<Float, ArrayList<Edge>> paths = this.model.getShortestPathToHolarchy(this.minModel, child.getMinimumModel(), holarchy);
|
|
|
+ HashMap<Float, ArrayList<Edge>> free_paths = new HashMap<Float, ArrayList<Edge>>();
|
|
|
+ HashMap<Float, ArrayList<Edge>> occ_paths = new HashMap<Float, ArrayList<Edge>>();
|
|
|
+ HashMap<ArrayList<Edge>, Holon> occ_by = new HashMap<ArrayList<Edge>, Holon>();
|
|
|
+
|
|
|
+ for(Float f : paths.keySet()) {
|
|
|
+ ArrayList<Edge> path = paths.get(f);
|
|
|
+ Holon holder = isPathOccupied(path);
|
|
|
+ if(holder == null || holder.getLayer() == 0 || holder.equals(this.parent)) {
|
|
|
+ free_paths.put(f, path);
|
|
|
+ } else {
|
|
|
+ occ_paths.put(f, path);
|
|
|
+ occ_by.put(path, holder);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(free_paths.size() > 0) {
|
|
|
+ //there is a free path, take it and add child directly
|
|
|
+ this.addChild(child);
|
|
|
+ this.addChildToMinModel(child, free_paths.get(getShortestPath(free_paths)));
|
|
|
+ if(this.getLayer() > 1) {
|
|
|
+ this.parent.recalculateMinModel();
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(occ_paths.size() < 1) {
|
|
|
+ System.err.println("something went wrong when looking for shortest path while merging "+this.uniqueID+" and "+child.getUniqueID());
|
|
|
+ }
|
|
|
+ ArrayList<ArrayList<Edge>> shortestPaths = sortPaths(occ_paths);
|
|
|
+ for(int i=0; i< shortestPaths.size(); i++) {
|
|
|
+ //check if holon should merge with holder of this path
|
|
|
+ ArrayList<Edge> path = shortestPaths.get(i);
|
|
|
+ Holon holder = occ_by.get(path);
|
|
|
+ //if true try to merge with holon which is using the path
|
|
|
+ if(holder != null && holder.getLayer() > 0) {
|
|
|
+ this.split(holder);
|
|
|
+ this.addChild(child);
|
|
|
+ this.addChildToMinModel(child, path);
|
|
|
+ if(this.parent != null && this.getLayer() > 1) {
|
|
|
+ this.parent.recalculateMinModel();
|
|
|
+ }
|
|
|
+ this.canRunIndependentFromParent = false;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * checks whether a path is occupied
|
|
|
+ * if true returns the holon in which the path is located
|
|
|
+ * @param path
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Holon isPathOccupied(ArrayList<Edge> path) {
|
|
|
+ Holon h = this.parent;
|
|
|
+ Holon r = this;
|
|
|
+ Holon holder = null;
|
|
|
+ while(h != null) {
|
|
|
+ holder = h.containsPath(path, r);
|
|
|
+ if(holder != null) {
|
|
|
+ //found a holon which contains the path
|
|
|
+ return holder;
|
|
|
+ }
|
|
|
+ r = h;
|
|
|
+ h = h.parent;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ArrayList<ArrayList<Edge>> sortPaths(HashMap<Float, ArrayList<Edge>> paths) {
|
|
|
+ ArrayList<ArrayList<Edge>> shortestPaths = new ArrayList<ArrayList<Edge>>();
|
|
|
+
|
|
|
+ while(paths.size() > 0) {
|
|
|
+ shortestPaths.add(paths.remove(getShortestPath(paths)));
|
|
|
+ }
|
|
|
+
|
|
|
+ return shortestPaths;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Float getShortestPath(HashMap<Float, ArrayList<Edge>> paths){
|
|
|
+ float min = Float.MAX_VALUE;
|
|
|
+ for(Float f : paths.keySet()) {
|
|
|
+ if(f < min) {
|
|
|
+ min = f;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return min;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * removes this holon from current superholon and merge with new superholon
|
|
|
+ */
|
|
|
+ public void split(Holon newParent) {
|
|
|
+ if(newParent == null) {
|
|
|
+ System.err.println("can not split without new super holon");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //ensure that this holarchy can run independent(path is not occupied by superholon) from the superholon
|
|
|
+ if(!this.canRunIndependentFromParent) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.parent != null) {
|
|
|
+ this.parent.removeChildHolon(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ newParent.merge(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * recalculates the min model after a holon was added to a subholon
|
|
|
+ * does NOT recalculate the shortest paths between its subholons
|
|
|
+ */
|
|
|
+ public void recalculateMinModel() {
|
|
|
+ ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
|
|
|
+ ArrayList<Edge> edges = new ArrayList<Edge>();
|
|
|
+ for(Holon child : this.childHolons) {
|
|
|
+ MinimumModel cmm = child.getMinimumModel();
|
|
|
+ objects.addAll(cmm.getHolonObjectList());
|
|
|
+ objects.addAll(cmm.getNodeList());
|
|
|
+ objects.addAll(cmm.getSwitchList());
|
|
|
+ for(IntermediateCableWithState icws : cmm.getEdgeList()) {
|
|
|
+ edges.add(icws.getModel());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //go through the edge list and add all edges connecting the subholons
|
|
|
+ for(IntermediateCableWithState icws : this.minModel.getEdgeList()) {
|
|
|
+ if(!edges.contains(icws.getModel())) {
|
|
|
+ edges.add(icws.getModel());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.minModel = new MinimumModel(objects, edges);
|
|
|
+
|
|
|
+ //notify superholon to recalculate its minModel
|
|
|
+ if(this.parent != null && this.getLayer() > 0) {
|
|
|
+ this.parent.recalculateMinModel();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * adds a child and its min model (incl. all its subholons) to this min model
|
|
|
+ * @param child
|
|
|
+ */
|
|
|
+ private void addChildToMinModel(Holon child, ArrayList<Edge> path) {
|
|
|
+ if(this.minModel.getHolonObjectList().contains(child.getHolonObject()) || getLayer() == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ArrayList<Edge> edgeList = new ArrayList<Edge>();
|
|
|
+ //add all holon objects that are part of this holarchy
|
|
|
+ ArrayList<HolonObject> holarchy = getAllHolonObjects();
|
|
|
+ holarchy.addAll(child.getAllHolonObjects());
|
|
|
+ edgeList.addAll(path);
|
|
|
+ for(IntermediateCableWithState icws : this.minModel.getEdgeList()) {
|
|
|
+ edgeList.add(icws.getModel());
|
|
|
+ }
|
|
|
+ for(IntermediateCableWithState icws : child.minModel.getEdgeList()) {
|
|
|
+ edgeList.add(icws.getModel());
|
|
|
+ }
|
|
|
+ //aggregate all objects
|
|
|
+ ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
|
|
|
+ for(Edge e : edgeList) {
|
|
|
+ AbstractCanvasObject a = e.getA();
|
|
|
+ AbstractCanvasObject b = e.getB();
|
|
|
+ if(!objects.contains(a)) {
|
|
|
+ objects.add(a);
|
|
|
+ }
|
|
|
+ if(!objects.contains(b)) {
|
|
|
+ objects.add(b);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.minModel = new MinimumModel(objects, edgeList);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * revalidate this min model after a subholon was removed
|
|
|
+ */
|
|
|
+ public void revalidateMinModel() {
|
|
|
+ if(getLayer() == 0)
|
|
|
+ return;
|
|
|
|
|
|
+ this.canRunIndependentFromParent = true;
|
|
|
+ ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
|
|
|
+ list.add(this.holonObject);
|
|
|
+ this.minModel = new MinimumModel(list, new ArrayList<Edge>());
|
|
|
+ for(int i=0; i< this.childHolons.size(); i++) {
|
|
|
+ Holon child = this.childHolons.remove(0);
|
|
|
+ this.merge(child);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.parent != null) {
|
|
|
+ this.parent.revalidateMinModel();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * returns the holon which uses the specified path if it is included in min model, otherwise null
|
|
|
+ */
|
|
|
+ public Holon containsPath(ArrayList<Edge> path, Holon requester) {
|
|
|
+ if(this.minModel.containsPath(path) || this.getLayer() == 0) {
|
|
|
+ for(Holon child : this.childHolons) {
|
|
|
+ if(child.equals(requester))
|
|
|
+ continue;
|
|
|
+ Holon h = child.containsPath(path, this);
|
|
|
+ if(h != null) {
|
|
|
+ return h;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+}
|