View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  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,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.config.util;
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  /**
26   * Vertex is used to track dependencies and each node in a graph.  Typical
27   * uses would be to ensure components are started up and torn down in the
28   * proper order, or bundles were loaded and unloaded in the proper order, etc.
29   *
30   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
31   * @version CVS $ Revision: 1.1 $
32   */
33  public final class Vertex<T> implements Comparable<Vertex<T>>
34  {
35      private final String m_name;
36      private final T m_node;
37      private int m_order;
38  
39      /** Flag used to keep track of whether or not a given vertex has been
40       *   seen by the resolveOrder methods. */
41      private boolean m_seen;
42  
43      /** List of all direct dependent Vertices. */
44      private final List< Vertex<T> > m_dependencies;
45  
46      /**
47       * A vertex wraps a node, which can be anything.
48       *
49       * @param node  The wrapped node.
50       */
51      public Vertex(final T node)
52      {
53          this(node.toString(), node);
54      }
55  
56      /**
57       * A vertex wraps a node, which can be anything.
58       *
59       * @param name  A name for the node which will be used to produce useful errors.
60       * @param node  The wrapped node.
61       */
62      public Vertex(final String name, final T node)
63      {
64          m_name = name;
65          m_node = node;
66          m_dependencies = new ArrayList< Vertex<T> >();
67          reset();
68      }
69  
70      /**
71       * Reset the Vertex so that all the flags and runtime states are set back
72       * to the original values.
73       */
74      public void reset()
75      {
76          m_order = 0;
77          m_seen = false;
78      }
79  
80      /**
81       * Returns the name of the Vertex.
82       *
83       * @return The name of the Vertex.
84       */
85      public String getName()
86      {
87          return m_name;
88      }
89  
90      /**
91       * Get the wrapped node that this Vertex represents.
92       *
93       * @return the node
94       */
95      public T getNode()
96      {
97          return m_node;
98      }
99  
100     /**
101      * Add a dependecy to this Vertex.  The Vertex that this one depends on will
102      * be marked as referenced and then added to the list of dependencies.  The
103      * list is checked before the dependency is added.
104      *
105      * @param v  The vertex we depend on.
106      */
107     public void addDependency(Vertex<T> v)
108     {
109         if (!m_dependencies.contains(v))
110         {
111             m_dependencies.add(v);
112         }
113     }
114 
115     /**
116      * Recurse through the tree from this vertex assigning an order to each
117      *  and at the same time checking for any cyclic dependencies.
118      *
119      * @throws CyclicDependencyException If a cyclic dependency is discovered.
120      */
121     public void resolveOrder() throws CyclicDependencyException
122     {
123         resolveOrder(getName());
124     }
125 
126     /**
127      * Recursively searches for cycles by travelling down the dependency lists
128      *  of this vertex, looking for the start vertex.
129      *
130      * @param path The path to the Vertex.  It is worth the load as it makes a
131      *             descriptive error message possible.
132      *
133      * @return The highest order of any of the dependent vertices.
134      *
135      * @throws CyclicDependencyException If a cyclic dependency is discovered.
136      */
137     private int resolveOrder(String path) throws CyclicDependencyException
138     {
139         m_seen = true;
140         try
141         {
142             int highOrder = -1;
143             for (Vertex<T> dv : m_dependencies)
144             {
145                 if (dv.m_seen)
146                 {
147                     throw new CyclicDependencyException(path + " -> "
148                             + dv.getName());
149                 }
150                 else
151                 {
152                     highOrder = Math.max(highOrder, dv.resolveOrder(path
153                             + " -> " + dv.getName()));
154                 }
155             }
156 
157             // Set this order so it is one higher than the highest dependency.
158             m_order = highOrder + 1;
159             return m_order;
160         }
161         finally
162         {
163             m_seen = false;
164         }
165     }
166 
167     /**
168      * Get the list of dependencies.
169      *
170      * @return  The list of dependencies.
171      */
172     public List< Vertex<T> > getDependencies()
173     {
174         return m_dependencies;
175     }
176 
177     /**
178      * Used in the sort algorithm to sort all the Vertices so that they respect
179      * the ordinal they were given during the topological sort.
180      *
181      * @param o  The other Vertex to compare with
182      * @return -1 if this < o, 0 if this == o, or 1 if this > o
183      */
184     public int compareTo(final Vertex<T> o)
185     {
186         int orderInd;
187 
188         if (m_order < o.m_order)
189         {
190             orderInd = -1;
191         }
192         else if (m_order > o.m_order)
193         {
194             orderInd = 1;
195         }
196         else
197         {
198             orderInd = 0;
199         }
200 
201         return orderInd;
202     }
203 
204     /**
205      * Get the ordinal for this vertex.
206      *
207      * @return  the order.
208      */
209     public int getOrder()
210     {
211         return m_order;
212     }
213 }