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 }