View Javadoc
1   package org.codehaus.plexus.util.dag;
2   
3   /*
4    * Copyright The Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.Serializable;
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  /**
27   * DAG = Directed Acyclic Graph
28   *
29   * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
30   *
31   * TODO this class should be renamed from DAG to Dag
32   */
33  public class DAG
34      implements Cloneable, Serializable
35  {
36      // ------------------------------------------------------------
37      // Fields
38      // ------------------------------------------------------------
39      /**
40       * Nodes will be kept in two data structures at the same time for faster processing
41       */
42      /**
43       * Maps vertex's label to vertex
44       */
45      private Map<String, Vertex> vertexMap = new HashMap<>();
46  
47      /**
48       * Conatin list of all vertices
49       */
50      private List<Vertex> vertexList = new ArrayList<>();
51  
52      // ------------------------------------------------------------
53      // Constructors
54      // ------------------------------------------------------------
55  
56      /**
57       *
58       */
59      public DAG()
60      {
61          super();
62      }
63  
64      // ------------------------------------------------------------
65      // Accessors
66      // ------------------------------------------------------------
67  
68      /**
69       * @return the vertices
70       */
71      public List<Vertex> getVertices()
72      {
73          return vertexList;
74      }
75  
76      /**
77       * @deprecated instead use {@link #getVertices()}
78       * @return the vertices
79       */
80      @Deprecated
81      public List<Vertex> getVerticies()
82      {
83          return getVertices();
84      }
85  
86      public Set<String> getLabels()
87      {
88          return vertexMap.keySet();
89      }
90  
91      // ------------------------------------------------------------
92      // Implementation
93      // ------------------------------------------------------------
94  
95      /**
96       * Adds vertex to DAG. If vertex of given label already exist in DAG no vertex is added
97       *
98       * @param label The label of the Vertex
99       * @return New vertex if vertex of given label was not present in the DAG or existing vertex if vertex of given
100      *         label was already added to DAG
101      */
102     public Vertex addVertex( final String label )
103     {
104         Vertex retValue = null;
105 
106         // check if vertex is already in DAG
107         if ( vertexMap.containsKey( label ) )
108         {
109             retValue = vertexMap.get( label );
110         }
111         else
112         {
113             retValue = new Vertex( label );
114 
115             vertexMap.put( label, retValue );
116 
117             vertexList.add( retValue );
118         }
119 
120         return retValue;
121     }
122 
123     public void addEdge( final String from, final String to )
124         throws CycleDetectedException
125     {
126         final Vertex v1 = addVertex( from );
127 
128         final Vertex v2 = addVertex( to );
129 
130         addEdge( v1, v2 );
131     }
132 
133     public void addEdge( final Vertex from, final Vertex to )
134         throws CycleDetectedException
135     {
136 
137         from.addEdgeTo( to );
138 
139         to.addEdgeFrom( from );
140 
141         final List<String> cycle = CycleDetector.introducesCycle( to );
142 
143         if ( cycle != null )
144         {
145             // remove edge which introduced cycle
146 
147             removeEdge( from, to );
148 
149             final String msg = "Edge between '" + from + "' and '" + to + "' introduces to cycle in the graph";
150 
151             throw new CycleDetectedException( msg, cycle );
152         }
153     }
154 
155     public void removeEdge( final String from, final String to )
156     {
157         final Vertex v1 = addVertex( from );
158 
159         final Vertex v2 = addVertex( to );
160 
161         removeEdge( v1, v2 );
162     }
163 
164     public void removeEdge( final Vertex from, final Vertex to )
165     {
166         from.removeEdgeTo( to );
167 
168         to.removeEdgeFrom( from );
169     }
170 
171     public Vertex getVertex( final String label )
172     {
173         final Vertex retValue = vertexMap.get( label );
174 
175         return retValue;
176     }
177 
178     public boolean hasEdge( final String label1, final String label2 )
179     {
180         final Vertex v1 = getVertex( label1 );
181 
182         final Vertex v2 = getVertex( label2 );
183 
184         final boolean retValue = v1.getChildren().contains( v2 );
185 
186         return retValue;
187 
188     }
189 
190     /**
191      * @param label see name
192      * @return the childs
193      */
194     public List<String> getChildLabels( final String label )
195     {
196         final Vertex vertex = getVertex( label );
197 
198         return vertex.getChildLabels();
199     }
200 
201     /**
202      * @param label see name
203      * @return the parents
204      */
205     public List<String> getParentLabels( final String label )
206     {
207         final Vertex vertex = getVertex( label );
208 
209         return vertex.getParentLabels();
210     }
211 
212     /**
213      * @see java.lang.Object#clone()
214      */
215     @Override
216     public Object clone()
217         throws CloneNotSupportedException
218     {
219         // this is what's failing..
220         final Object retValue = super.clone();
221 
222         return retValue;
223     }
224 
225     /**
226      * Indicates if there is at least one edge leading to or from vertex of given label
227      * @param label the label
228      * @return <code>true</code> if this vertex is connected with other vertex,<code>false</code> otherwise
229      */
230     public boolean isConnected( final String label )
231     {
232         final Vertex vertex = getVertex( label );
233 
234         final boolean retValue = vertex.isConnected();
235 
236         return retValue;
237 
238     }
239 
240     /**
241      * Return the list of labels of successor in order decided by topological sort
242      *
243      * @param label The label of the vertex whose predecessors are searched
244      * @return The list of labels. Returned list contains also the label passed as parameter to this method. This label
245      *         should always be the last item in the list.
246      */
247     public List<String> getSuccessorLabels( final String label )
248     {
249         final Vertex vertex = getVertex( label );
250 
251         final List<String> retValue;
252 
253         // optimization.
254         if ( vertex.isLeaf() )
255         {
256             retValue = new ArrayList<>( 1 );
257 
258             retValue.add( label );
259         }
260         else
261         {
262             retValue = TopologicalSorter.sort( vertex );
263         }
264 
265         return retValue;
266     }
267 
268 }