1. /*
  2. * @(#)GraphImpl.java 1.5 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.corba.se.impl.orbutil.graph ;
  8. import java.util.Collection ;
  9. import java.util.AbstractSet ;
  10. import java.util.Iterator ;
  11. import java.util.Map ;
  12. import java.util.HashMap ;
  13. import java.util.Set ;
  14. import java.util.HashSet ;
  15. public class GraphImpl extends AbstractSet implements Graph
  16. {
  17. private Map /* Map<Node,NodeData> */ nodeToData ;
  18. public GraphImpl()
  19. {
  20. nodeToData = new HashMap() ;
  21. }
  22. public GraphImpl( Collection coll )
  23. {
  24. this() ;
  25. addAll( coll ) ;
  26. }
  27. /***********************************************************************************/
  28. /************ AbstractSet implementation *******************************************/
  29. /***********************************************************************************/
  30. // Required for AbstractSet
  31. public boolean add( Object obj ) // obj must be a Node
  32. {
  33. if (!(obj instanceof Node))
  34. throw new IllegalArgumentException( "Graphs must contain only Node instances" ) ;
  35. Node node = (Node)obj ;
  36. boolean found = nodeToData.keySet().contains( obj ) ;
  37. if (!found) {
  38. NodeData nd = new NodeData() ;
  39. nodeToData.put( node, nd ) ;
  40. }
  41. return !found ;
  42. }
  43. // Required for AbstractSet
  44. public Iterator iterator()
  45. {
  46. return nodeToData.keySet().iterator() ;
  47. }
  48. // Required for AbstractSet
  49. public int size()
  50. {
  51. return nodeToData.keySet().size() ;
  52. }
  53. /***********************************************************************************/
  54. public NodeData getNodeData( Node node )
  55. {
  56. return (NodeData)nodeToData.get( node ) ;
  57. }
  58. private void clearNodeData()
  59. {
  60. // Clear every node
  61. Iterator iter = nodeToData.entrySet().iterator() ;
  62. while (iter.hasNext()) {
  63. Map.Entry entry = (Map.Entry)iter.next() ;
  64. NodeData nd = (NodeData)(entry.getValue()) ;
  65. nd.clear( ) ;
  66. }
  67. }
  68. interface NodeVisitor
  69. {
  70. void visit( Graph graph, Node node, NodeData nd ) ;
  71. }
  72. // This visits every node in the graph exactly once. A
  73. // visitor is allowed to modify the graph during the
  74. // traversal.
  75. void visitAll( NodeVisitor nv )
  76. {
  77. boolean done = false ;
  78. // Repeat the traversal until every node has been visited. Since
  79. // it takes one pass to determine whether or not each node has
  80. // already been visited, this loop always runs at least once.
  81. do {
  82. done = true ;
  83. // Copy entries to array to avoid concurrent modification
  84. // problem with iterator if the visitor is updating the graph.
  85. Map.Entry[] entries =
  86. (Map.Entry[])nodeToData.entrySet().toArray( new Map.Entry[0] ) ;
  87. // Visit each node in the graph that has not already been visited.
  88. // If any node is visited in this pass, we must run at least one more
  89. // pass.
  90. for (int ctr=0; ctr<entries.length; ctr++) {
  91. Map.Entry current = entries[ctr] ;
  92. Node node = (Node)current.getKey() ;
  93. NodeData nd = (NodeData)current.getValue() ;
  94. if (!nd.isVisited()) {
  95. nd.visited() ;
  96. done = false ;
  97. nv.visit( this, node, nd ) ;
  98. }
  99. }
  100. } while (!done) ;
  101. }
  102. private void markNonRoots()
  103. {
  104. visitAll(
  105. new NodeVisitor() {
  106. public void visit( Graph graph, Node node, NodeData nd )
  107. {
  108. Iterator iter = node.getChildren().iterator() ; // Iterator<Node>
  109. while (iter.hasNext()) {
  110. Node child = (Node)iter.next() ;
  111. // Make sure the child is in the graph so it can be
  112. // visited later if necessary.
  113. graph.add( child ) ;
  114. // Mark the child as a non-root, since a child is never a root.
  115. NodeData cnd = graph.getNodeData( child ) ;
  116. cnd.notRoot() ;
  117. }
  118. }
  119. } ) ;
  120. }
  121. private Set collectRootSet()
  122. {
  123. final Set result = new HashSet() ;
  124. Iterator iter = nodeToData.entrySet().iterator() ;
  125. while (iter.hasNext()) {
  126. Map.Entry entry = (Map.Entry)iter.next() ;
  127. Node node = (Node)entry.getKey() ;
  128. NodeData nd = (NodeData)entry.getValue() ;
  129. if (nd.isRoot())
  130. result.add( node ) ;
  131. }
  132. return result ;
  133. }
  134. public Set /* Set<Node> */ getRoots()
  135. {
  136. clearNodeData() ;
  137. markNonRoots() ;
  138. return collectRootSet() ;
  139. }
  140. }