Holon.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. package classes;
  2. import java.util.ArrayList;
  3. import java.util.Collections;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.UUID;
  7. import classes.holonControlUnit.HolonControlUnit;
  8. import ui.controller.Control;
  9. import ui.model.DecoratedNetwork;
  10. import ui.model.IntermediateCableWithState;
  11. import ui.model.MinimumModel;
  12. import ui.model.Model;
  13. public class Holon {
  14. public String name = new String();
  15. private Holon parent = null;
  16. public ArrayList<Holon> childHolons = new ArrayList<Holon>();
  17. private List<HolonElement> elements = new ArrayList<HolonElement>();
  18. //HolonObject is the lowest representation of a holon.
  19. private final HolonObject holonObject;
  20. public final boolean isPhysical;
  21. public HolonControlUnit holonControlUnit;
  22. private String uniqueID;
  23. public Model model;
  24. private MinimumModel minModel;
  25. /** stores whether the part between this holon and the child is occupied by the superholon */
  26. private HashMap<Holon, ArrayList<Edge>> pathsToChildren;
  27. public Holon(String name, Model model) {
  28. this.name = name;
  29. this.holonObject = null;
  30. isPhysical = false;
  31. this.uniqueID = UUID.randomUUID().toString();
  32. this.model = model;
  33. this.holonControlUnit = new HolonControlUnit(this);
  34. this.minModel = new MinimumModel(new ArrayList<AbstractCanvasObject>(), new ArrayList<Edge>());
  35. this.pathsToChildren = new HashMap<Holon, ArrayList<Edge>>();
  36. }
  37. public Holon(HolonObject object, Model model) {
  38. holonObject = object;
  39. object.holon = this;
  40. name = object.getName();
  41. elements.addAll(object.getElements());
  42. for(HolonElement ele : elements) {
  43. ele.holon = this;
  44. }
  45. isPhysical = true;
  46. this.uniqueID = UUID.randomUUID().toString();
  47. this.model = model;
  48. this.holonControlUnit = new HolonControlUnit(this);
  49. ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
  50. list.add(object);
  51. this.minModel = new MinimumModel(list, new ArrayList<Edge>());
  52. this.pathsToChildren = new HashMap<Holon, ArrayList<Edge>>();
  53. }
  54. public void addElement(HolonElement element) {
  55. element.holon = this;
  56. elements.add(element);
  57. }
  58. public void removeElement(HolonElement element) {
  59. element.holon = null;
  60. elements.remove(element);
  61. }
  62. public int elementsCount() {
  63. return elements.size();
  64. }
  65. public void addChild(Holon child) {
  66. if(child.equals(this)) {
  67. System.err.println(this.uniqueID+" wants to merge itself");
  68. }
  69. if(!this.childHolons.contains(child)) {
  70. child.setParent(this);
  71. this.childHolons.add(child);
  72. }
  73. if(this.parent != null) {
  74. this.holonControlUnit.addSubHolon(child);
  75. }
  76. }
  77. public void addChildHolon(Holon child, int index) {
  78. if(!this.childHolons.contains(child)) {
  79. child.setParent(this);
  80. childHolons.add(index, child);
  81. }
  82. if(this.parent != null) {
  83. this.holonControlUnit.addSubHolon(child);
  84. }
  85. }
  86. public void removeChildHolon(Holon child) {
  87. child.setParent(null);
  88. childHolons.remove(child);
  89. if(this.parent == null)
  90. return;
  91. this.holonControlUnit.getHierarchyController().removeSubHolon(child.getUniqueID());
  92. this.pathsToChildren.remove(child);
  93. revalidateMinModel();
  94. }
  95. public void removeFromParent() {
  96. if(parent != null) {
  97. parent.removeChildHolon(this);
  98. }
  99. this.setParent(model.getStateHolon());
  100. }
  101. public int getChildCount() {
  102. return childHolons.size();
  103. }
  104. public Holon getParent() {
  105. return parent;
  106. }
  107. public void setParent(Holon parent) {
  108. this.parent = parent;
  109. if(parent != null) {
  110. this.holonControlUnit.getHierarchyController().setSuperHolon(parent.getUniqueID());
  111. }
  112. }
  113. public HolonObject getHolonObject() {
  114. return holonObject;
  115. }
  116. public List<Holon> getChildView(){
  117. return Collections.unmodifiableList(childHolons);
  118. }
  119. public List<HolonElement> getElementView(){
  120. return Collections.unmodifiableList(elements);
  121. }
  122. @Override
  123. public String toString() {
  124. return name;
  125. }
  126. public void reassignAllChildren(Holon other) {
  127. for(Holon child: this.childHolons) {
  128. other.merge(child);
  129. }
  130. childHolons.clear();
  131. }
  132. public void removeAllRefrences() {
  133. this.setParent(null);
  134. this.childHolons.clear();
  135. this.elements.clear();
  136. }
  137. public int getLayer() {
  138. if(this.parent == null)
  139. return 0;
  140. if(this.parent.equals(this)) {
  141. return 0;
  142. }
  143. return parent != null ? parent.getLayer() + 1 : 0;
  144. }
  145. public Holon cloneWithoutParent() {
  146. Holon cloned = new Holon(this.name, this.model);
  147. model.getHolonsByID().put(cloned.getUniqueID(), cloned);
  148. cloned.childHolons = this.childHolons;
  149. cloned.elements = this.elements;
  150. return cloned;
  151. }
  152. public boolean checkHolonArePhysicalConnected(Holon other, Control control) {
  153. HashMap<HolonObject, DecoratedNetwork> table = control.getSimManager().getActualDecorState().getHolonObjectNetworkTable();
  154. HolonObject a = tryGetAPhysicalHolon();
  155. HolonObject b = other.tryGetAPhysicalHolon();
  156. boolean aHolonIsPureAbstract = a == null || b == null;
  157. return aHolonIsPureAbstract || table.get(a) == table.get(b);
  158. }
  159. private HolonObject tryGetAPhysicalHolon() {
  160. if(holonObject != null) {
  161. return holonObject;
  162. }
  163. for(Holon holon : childHolons) {
  164. HolonObject object = holon.tryGetAPhysicalHolon();
  165. if(object != null) {
  166. return object;
  167. }
  168. }
  169. return null;
  170. }
  171. @Deprecated
  172. public void checkRepairHolarchy(HashMap<HolonObject, DecoratedNetwork> table, Holon stateHolon) {
  173. if(childHolons.isEmpty()) {
  174. return;
  175. }
  176. //To establish the invariant that all child holons are repaired
  177. for(Holon other : childHolons) {
  178. other.checkRepairHolarchy(table, stateHolon);
  179. }
  180. //Repair this Holon
  181. HolonObject first = tryGetAPhysicalHolon();
  182. if(first == null) {
  183. return;
  184. }
  185. List<Holon> removeList = new ArrayList<Holon>();
  186. for(Holon other : childHolons) {
  187. HolonObject otherHolonObject = other.tryGetAPhysicalHolon();
  188. boolean isPureAbstract = otherHolonObject == null;
  189. if(isPureAbstract) {
  190. continue;
  191. }
  192. boolean isPhysicalConnected = model.checkHolonObjectsAreConnected(this, other, 0f);
  193. if(!isPhysicalConnected) {
  194. removeList.add(other);
  195. }
  196. }
  197. //Remove holons
  198. for(Holon holon : removeList) {
  199. holon.split(stateHolon);
  200. }
  201. }
  202. public void addNewVirtualNeighbor(String virtualNeighbor) {
  203. if(!this.uniqueID.equals(virtualNeighbor)) {
  204. this.holonControlUnit.addNewVirtualNeighbor(virtualNeighbor);
  205. }
  206. }
  207. public String getUniqueID() {
  208. return uniqueID;
  209. }
  210. public ArrayList<HolonObject> getAllHolonObjects() {
  211. ArrayList<HolonObject> list = new ArrayList<HolonObject>();
  212. for(Holon h : this.childHolons) {
  213. list.addAll(h.getAllHolonObjects());
  214. }
  215. if(this.holonObject != null) {
  216. list.add(this.holonObject);
  217. }
  218. return list;
  219. }
  220. public ArrayList<AbstractCanvasObject> getAllObjects(){
  221. ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
  222. list.addAll(this.minModel.getHolonObjectList());
  223. list.addAll(this.minModel.getNodeList());
  224. list.addAll(this.minModel.getSwitchList());
  225. list.addAll(this.minModel.getUppderNodeList());
  226. return list;
  227. }
  228. public MinimumModel getMinimumModel() {
  229. return this.minModel;
  230. }
  231. public HashMap<Holon, ArrayList<Edge>> getPathsToChildren() {
  232. return pathsToChildren;
  233. }
  234. /**
  235. * merge this holon as a child with the holon specified by the id
  236. * @param id
  237. */
  238. public void merge(String id) {
  239. if(id.equals("State Holon")) {
  240. this.split(this.model.getStateHolon());
  241. return;
  242. }
  243. Holon h = this.model.getHolonsByID().get(id);
  244. if(h != null) {
  245. h.split(this);
  246. }
  247. }
  248. /**
  249. * merge this holon with the specified child holon
  250. * @param child
  251. */
  252. public void merge(Holon child) {
  253. if(!this.model.getHolonsByID().containsKey(child.getUniqueID())) {
  254. System.err.println("could not find: "+child.getHolonObject());
  255. return;
  256. }
  257. if(this.childHolons.contains(child)) {
  258. return;
  259. }
  260. if(this.parent == null) {
  261. this.addChild(child);
  262. return;
  263. }
  264. HashMap<Float, ArrayList<Edge>> paths = this.model.getShortestPathToHolarchy(this.minModel, child.getMinimumModel());
  265. HashMap<Float, ArrayList<Edge>> free_paths = new HashMap<Float, ArrayList<Edge>>();
  266. HashMap<Float, ArrayList<Edge>> occ_paths = new HashMap<Float, ArrayList<Edge>>();
  267. HashMap<ArrayList<Edge>, Holon> occ_by = new HashMap<ArrayList<Edge>, Holon>();
  268. for(Float f : paths.keySet()) {
  269. ArrayList<Edge> path = paths.get(f);
  270. Holon holder = isPathOccupied(path);
  271. if(holder == null || holder.getParent() == null || holder.equals(this) || holder.equals(this.parent)) {
  272. //path between this holon and child holon is free
  273. free_paths.put(f, path);
  274. } else {
  275. //path between this holon and child holon is already occupied
  276. occ_paths.put(f, path);
  277. occ_by.put(path, holder);
  278. }
  279. }
  280. if(free_paths.size() > 0) {
  281. //there is a free path, take it and add child directly to sub holons
  282. ArrayList<Edge> path = free_paths.get(getShortestPath(free_paths));
  283. Holon holder = this.containsPath(path, this);
  284. if(holder != null && !holder.equals(this)) {
  285. //the path already used by a child holon
  286. holder.merge(child);
  287. return;
  288. }
  289. this.addChild(child);
  290. this.addChildToMinModel(child, path);
  291. this.pathsToChildren.put(child, path);
  292. if(this.parent != null && this.parent.getParent() != null) {
  293. this.parent.recalculateMinModel();
  294. }
  295. return;
  296. }
  297. if(occ_paths.size() < 1) {
  298. System.err.println("something went wrong when looking for shortest path while merging "+this.uniqueID+" and "+child.getUniqueID());
  299. }
  300. ArrayList<ArrayList<Edge>> shortestPaths = sortPaths(occ_paths);
  301. //take the shortest path occupied by another holon
  302. ArrayList<Edge> path = shortestPaths.get(0);
  303. Holon holder = occ_by.get(path);
  304. if(holder != null && holder.getParent() != null) {
  305. this.split(holder);
  306. this.addChild(child);
  307. this.addChildToMinModel(child, path);
  308. this.pathsToChildren.put(child, path);
  309. if(this.parent != null && this.parent.getParent() != null) {
  310. this.parent.recalculateMinModel();
  311. }
  312. }
  313. }
  314. /**
  315. * checks whether a path is occupied
  316. * if true returns the holon in which the path is located
  317. * @param path
  318. * @return
  319. */
  320. private Holon isPathOccupied(ArrayList<Edge> path) {
  321. Holon h = this.parent;
  322. Holon r = this;
  323. Holon holder = null;
  324. while(h != null) {
  325. holder = h.containsPath(path, r);
  326. if(holder != null) {
  327. //found a holon which contains the path
  328. return holder;
  329. }
  330. r = h;
  331. h = h.parent;
  332. }
  333. return null;
  334. }
  335. private ArrayList<ArrayList<Edge>> sortPaths(HashMap<Float, ArrayList<Edge>> paths) {
  336. ArrayList<ArrayList<Edge>> shortestPaths = new ArrayList<ArrayList<Edge>>();
  337. while(paths.size() > 0) {
  338. shortestPaths.add(paths.remove(getShortestPath(paths)));
  339. }
  340. return shortestPaths;
  341. }
  342. private Float getShortestPath(HashMap<Float, ArrayList<Edge>> paths){
  343. float min = Float.MAX_VALUE;
  344. for(Float f : paths.keySet()) {
  345. if(f < min) {
  346. min = f;
  347. }
  348. }
  349. return min;
  350. }
  351. /**
  352. * removes this holon from current superholon and merge with new superholon
  353. */
  354. public void split(Holon newParent) {
  355. //ensure that this holarchy can run independent(path is not occupied by superholon) from the superholon
  356. if(!this.parent.canRunIndependent(this)) {
  357. return;
  358. }
  359. if(newParent == null) {
  360. newParent = this.model.getStateHolon();
  361. }
  362. if(this.parent != null) {
  363. this.parent.removeChildHolon(this);
  364. }
  365. this.holonControlUnit.getHierarchyController().resetVirtualNeighbors();
  366. newParent.merge(this);
  367. }
  368. public void splitById(String id) {
  369. this.model.getHolonsByID().get(id).split(null);
  370. }
  371. /**
  372. * recalculates the min model after a holon was added to a subholon
  373. * does NOT recalculate the shortest paths between its subholons
  374. */
  375. public void recalculateMinModel() {
  376. ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
  377. ArrayList<Edge> edges = new ArrayList<Edge>();
  378. for(Holon child : this.childHolons) {
  379. MinimumModel cmm = child.getMinimumModel();
  380. objects.addAll(cmm.getHolonObjectList());
  381. objects.addAll(cmm.getNodeList());
  382. objects.addAll(cmm.getSwitchList());
  383. for(IntermediateCableWithState icws : cmm.getEdgeList()) {
  384. edges.add(icws.getModel());
  385. }
  386. }
  387. //go through the edge list and add all edges connecting the subholons
  388. for(IntermediateCableWithState icws : this.minModel.getEdgeList()) {
  389. if(!edges.contains(icws.getModel())) {
  390. edges.add(icws.getModel());
  391. }
  392. }
  393. this.minModel = new MinimumModel(objects, edges);
  394. //notify superholon to recalculate its minModel
  395. if(this.parent != null && this.parent.getParent() != null && this.parent != this) {
  396. this.parent.recalculateMinModel();
  397. }
  398. }
  399. /**
  400. * adds a child and its min model (incl. all its subholons) to this min model
  401. * @param child
  402. */
  403. private void addChildToMinModel(Holon child, ArrayList<Edge> path) {
  404. if(this.minModel.getHolonObjectList().contains(child.getHolonObject()) || this.parent == null)
  405. return;
  406. ArrayList<Edge> edgeList = new ArrayList<Edge>();
  407. //add all holon objects that are part of this holarchy
  408. ArrayList<HolonObject> holarchy = getAllHolonObjects();
  409. holarchy.addAll(child.getAllHolonObjects());
  410. edgeList.addAll(path);
  411. for(IntermediateCableWithState icws : this.minModel.getEdgeList()) {
  412. edgeList.add(icws.getModel());
  413. }
  414. for(IntermediateCableWithState icws : child.minModel.getEdgeList()) {
  415. edgeList.add(icws.getModel());
  416. }
  417. //aggregate all objects
  418. ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
  419. for(Edge e : edgeList) {
  420. AbstractCanvasObject a = e.getA();
  421. AbstractCanvasObject b = e.getB();
  422. if(!objects.contains(a)) {
  423. objects.add(a);
  424. }
  425. if(!objects.contains(b)) {
  426. objects.add(b);
  427. }
  428. }
  429. this.minModel = new MinimumModel(objects, edgeList);
  430. }
  431. /**
  432. * revalidate this min model after a subholon was removed
  433. */
  434. public void revalidateMinModel() {
  435. if(this.parent == null)
  436. return;
  437. ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
  438. list.add(this.holonObject);
  439. this.minModel = new MinimumModel(list, new ArrayList<Edge>());
  440. for(int i=0; i< this.childHolons.size(); i++) {
  441. Holon child = this.childHolons.remove(0);
  442. if(this.model.checkHolonObjectsAreConnected(this, child, this.holonControlUnit.getStateEstimator().getNetThroughput())) {
  443. this.merge(child);
  444. }
  445. }
  446. if(this.parent != null) {
  447. this.parent.revalidateMinModel();
  448. }
  449. }
  450. public void revalidateMinModelAfterLoad() {
  451. if(this.childHolons.size() == 0) {
  452. this.revalidateMinModel();
  453. } else {
  454. List<Holon> list = List.copyOf(this.childHolons);
  455. for(Holon child : list) {
  456. child.revalidateMinModelAfterLoad();
  457. }
  458. }
  459. }
  460. /**
  461. * returns the holon which uses the specified path if it is included in min model, otherwise null
  462. */
  463. public Holon containsPath(ArrayList<Edge> path, Holon requester) {
  464. if(this.minModel.containsPath(path) || this.parent == null) {
  465. for(Holon child : this.childHolons) {
  466. if(child.equals(requester))
  467. continue;
  468. Holon h = child.containsPath(path, this);
  469. if(h != null) {
  470. return h;
  471. }
  472. }
  473. return this;
  474. }
  475. for(Edge e : path) {
  476. AbstractCanvasObject a = e.getA();
  477. AbstractCanvasObject b = e.getB();
  478. if(a instanceof HolonObject && this.childHolons.contains(((HolonObject) a).holon))
  479. return ((HolonObject) a).holon;
  480. if(b instanceof HolonObject && this.childHolons.contains(((HolonObject) b).holon))
  481. return ((HolonObject) b).holon;
  482. if(this.getAllObjects().contains(a) || this.getAllObjects().contains(b))
  483. return this;
  484. }
  485. return null;
  486. }
  487. /**
  488. * checks whether the requester can run without this holon (none of the paths inside the requesters model is occupied by this model)
  489. * @param requester
  490. * @return
  491. */
  492. public boolean canRunIndependent(Holon requester) {
  493. if(this.parent == null || this.parent.getParent() == null)
  494. return true;
  495. ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
  496. objects.addAll(requester.getMinimumModel().getHolonObjectList());
  497. objects.addAll(requester.getMinimumModel().getNodeList());
  498. objects.addAll(requester.getMinimumModel().getSwitchList());
  499. for(Holon child : this.childHolons) {
  500. if(child.equals(requester))
  501. continue;
  502. ArrayList<Edge> path = this.pathsToChildren.get(child);
  503. ArrayList<AbstractCanvasObject> pathObjects = new ArrayList<AbstractCanvasObject>();
  504. for(Edge e : path) {
  505. AbstractCanvasObject a = e.getA();
  506. AbstractCanvasObject b = e.getB();
  507. if(!pathObjects.contains(a))
  508. pathObjects.add(a);
  509. if(!pathObjects.contains(b))
  510. pathObjects.add(b);
  511. }
  512. for(AbstractCanvasObject aco : pathObjects) {
  513. if(objects.contains(aco))
  514. return false;
  515. }
  516. }
  517. return true;
  518. }
  519. public boolean isASuperiorHolon(String holon) {
  520. return this.parent != null ? (this.parent.getUniqueID().equals(holon) || this.parent.isASuperiorHolon(holon)) : false;
  521. }
  522. }