View Javadoc

1   // ========================================================================
2   // Copyright (c) Webtide LLC
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   //
8   // The Eclipse Public License is available at 
9   // http://www.eclipse.org/legal/epl-v10.html
10  //
11  // The Apache License v2.0 is available at
12  // http://www.apache.org/licenses/LICENSE-2.0.txt
13  //
14  // You may elect to redistribute this code under either of these licenses. 
15  // ========================================================================
16  package org.eclipse.jetty.deploy.graph;
17  
18  import java.util.HashSet;
19  import java.util.Set;
20  import java.util.concurrent.CopyOnWriteArrayList;
21  
22  /**
23   * Basic directed graph implementation
24   */
25  public class Graph
26  {
27      private Set<Node> _nodes = new HashSet<Node>();
28      private Set<Edge> _edges = new HashSet<Edge>();
29  
30      public void addEdge(Edge edge)
31      {
32          Node fromNode = getNodeByName(edge.getFrom().getName());
33          if (fromNode==null)
34              addNode(fromNode=edge.getFrom());
35          Node toNode = getNodeByName(edge.getTo().getName());
36          if (toNode==null)
37              addNode(toNode=edge.getTo());
38          
39          // replace edge with normalized edge
40          if (edge.getFrom()!=fromNode || edge.getTo()!=toNode)
41              edge=new Edge(fromNode,toNode);
42          
43          this._edges.add(edge);
44      }
45  
46      public void addEdge(String from, String to)
47      {
48          Node fromNode = getNodeByName(from);
49          if (fromNode==null)
50          {
51              fromNode = new Node(from);
52              addNode(fromNode);
53          }
54              
55          Node toNode = getNodeByName(to);
56          if (toNode==null)
57          {
58              toNode = new Node(to);
59              addNode(toNode);
60          }
61  
62          addEdge(fromNode,toNode);
63      }
64  
65      private void addEdge(Node fromNode, Node toNode)
66      {
67          Edge edge = new Edge(fromNode,toNode);
68          addEdge(edge);
69      }
70  
71      public void addNode(Node node)
72      {
73          this._nodes.add(node);
74      }
75  
76      /**
77       * Convenience method for {@link #insertNode(Edge, Node)}
78       * 
79       * @param edge
80       *            the edge to split and insert a node into
81       * @param nodeName
82       *            the name of the node to insert along the edge
83       */
84      public void insertNode(Edge edge, String nodeName)
85      {
86          Node node = getNodeByName(nodeName);
87          if (node==null)
88          {
89              node = new Node(nodeName);
90          }
91  
92          insertNode(edge,node);
93      }
94  
95      /**
96       * Insert an arbitrary node on an existing edge.
97       * 
98       * @param edge
99       *            the edge to split and insert a node into
100      * @param node
101      *            the node to insert along the edge
102      */
103     public void insertNode(Edge edge, Node node)
104     {
105         // Remove existing edge
106         removeEdge(edge);
107         // Ensure node is added
108         addNode(node);
109         // Add start edge
110         addEdge(edge.getFrom(),node);
111         // Add second edge
112         addEdge(node,edge.getTo());
113     }
114 
115     /**
116      * Find all edges that are connected to the specific node, both as an outgoing {@link Edge#getFrom()} or incoming
117      * {@link Edge#getTo()} end point.
118      * 
119      * @param node
120      *            the node with potential end points
121      * @return the set of edges connected to the node
122      */
123     public Set<Edge> findEdges(Node node)
124     {
125         Set<Edge> fromedges = new HashSet<Edge>();
126 
127         for (Edge edge : this._edges)
128         {
129             if ((edge.getFrom() == node) || (edge.getTo() == node))
130             {
131                 fromedges.add(edge);
132             }
133         }
134 
135         return fromedges;
136     }
137 
138     /**
139      * Find all edges that are connected {@link Edge#getFrom()} the specific node.
140      * 
141      * @param from
142      *            the node with potential edges from it
143      * @return the set of edges from the node
144      */
145     public Set<Edge> findEdgesFrom(Node from)
146     {
147         Set<Edge> fromedges = new HashSet<Edge>();
148 
149         for (Edge edge : this._edges)
150         {
151             if (edge.getFrom() == from)
152             {
153                 fromedges.add(edge);
154             }
155         }
156 
157         return fromedges;
158     }
159 
160     /**
161      * Convenience method for {@link #getPath(Node, Node)}
162      * 
163      * @param nodeNameOrigin
164      *            the name of the node to the path origin.
165      * @param nodeNameDest
166      *            the name of the node to the path destination.
167      * @return the path to take
168      */
169     public Path getPath(String nodeNameOrigin, String nodeNameDest)
170     {
171         if (nodeNameOrigin.equals(nodeNameDest))
172         {
173             return new Path();
174         }
175 
176         Node from = getNodeByName(nodeNameOrigin);
177         Node to = getNodeByName(nodeNameDest);
178         return getPath(from,to);
179     }
180 
181     /**
182      * Using BFS (Breadth First Search) return the path from a any arbitrary node to any other.
183      * 
184      * @param from
185      *            the node from
186      * @param to
187      *            the node to
188      * @return the path to take or null if there is no path.
189      */
190     public Path getPath(Node from, Node to)
191     {
192         if (from == to)
193         {
194             return new Path();
195         }
196 
197         // Perform a Breadth First Search (BFS) of the tree.
198         Path path = breadthFirst(from,to,new CopyOnWriteArrayList<Path>(),new HashSet<Edge>());
199         return path;
200     }
201     
202 
203     private Path breadthFirst(Node from, Node destination, CopyOnWriteArrayList<Path> paths, Set<Edge> seen)
204     {
205         // Add next unseen segments to paths.
206         boolean edgesAdded = false;
207         if (paths.size()==0)
208             paths.add(new Path());
209 
210         for (Path path : paths)
211         {
212             Set<Edge> next = findEdgesFrom(path.nodes()==0?from:path.lastNode());
213             if (next.size() == 0)
214                 continue; // no new edges
215 
216             // Split path for other edges
217             int splits=0;
218             for (Edge edge:next)
219             {
220                 if (seen.contains(edge))
221                     continue;
222                 seen.add(edge);
223                 Path nextPath = (++splits==next.size())?path:path.forkPath();
224                 // Add segment to split'd path
225                 nextPath.add(edge);
226                 
227                 // Are we there yet?
228                 if (destination.equals(edge.getTo()))
229                     return nextPath;
230 
231                 edgesAdded = true;
232                 
233                 // Add to extra paths
234                 if (nextPath!=path)
235                     paths.add(nextPath);
236             }
237         }
238 
239         if (edgesAdded)
240             return breadthFirst(from,destination,paths,seen);
241         return null;
242     }
243 
244 
245     public Set<Edge> getEdges()
246     {
247         return _edges;
248     }
249 
250     /**
251      * Get the Node by Name.
252      * 
253      * @param name
254      *            the name to lookup
255      * @return the node if found or null if not found.
256      */
257     public Node getNodeByName(String name)
258     {
259         for (Node node : _nodes)
260         {
261             if (node.getName().equals(name))
262             {
263                 return node;
264             }
265         }
266         return null;
267     }
268 
269     public Set<Node> getNodes()
270     {
271         return _nodes;
272     }
273 
274     public void removeEdge(Edge edge)
275     {
276         this._edges.remove(edge);
277     }
278 
279     public void removeEdge(String fromNodeName, String toNodeName)
280     {
281         Node fromNode = getNodeByName(fromNodeName);
282         Node toNode = getNodeByName(toNodeName);
283         Edge edge = new Edge(fromNode,toNode);
284         removeEdge(edge);
285     }
286 
287     public void removeNode(Node node)
288     {
289         this._nodes.remove(node);
290     }
291 
292     public void setEdges(Set<Edge> edges)
293     {
294         this._edges = edges;
295     }
296 
297     public void setNodes(Set<Node> nodes)
298     {
299         this._nodes = nodes;
300     }
301 }