Clover coverage report - Code Coverage for hivemind release 1.0-beta-2
Coverage timestamp: Sun Aug 1 2004 14:03:45 EDT
file stats: LOC: 375   Methods: 18
NCLOC: 258   Classes: 2
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
Orderer.java 100% 97.3% 100% 98.3%
coverage coverage
 1   
 //  Copyright 2004 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.hivemind.order;
 16   
 
 17   
 import java.util.ArrayList;
 18   
 import java.util.Collections;
 19   
 import java.util.HashMap;
 20   
 import java.util.Iterator;
 21   
 import java.util.List;
 22   
 import java.util.Map;
 23   
 
 24   
 import org.apache.commons.logging.Log;
 25   
 import org.apache.commons.logging.LogFactory;
 26   
 import org.apache.hivemind.ApplicationRuntimeException;
 27   
 import org.apache.hivemind.ErrorHandler;
 28   
 import org.apache.hivemind.HiveMind;
 29   
 import org.apache.hivemind.util.StringUtils;
 30   
 
 31   
 /**
 32   
  * Used to order objects into an "execution" order. Each object must have a name. It may specify a
 33   
  * list of pre-requisites and a list of post-requisites.
 34   
  * 
 35   
  * @author Howard Lewis Ship
 36   
  */
 37   
 public class Orderer
 38   
 {
 39   
     private final Log _log;
 40   
     private final ErrorHandler _errorHandler;
 41   
     private final String _objectType;
 42   
     private List _orderingsList = null;
 43   
     private Map _orderingsMap = null;
 44   
     private Map _nodeMap = null;
 45   
     private Node _leader;
 46   
     private Node _trailer;
 47   
 
 48   
     /**
 49   
      * Creates an instance using <code>org.apache.hivemind.order.Orderer</code> as the Log.
 50   
      */
 51  10
     public Orderer(ErrorHandler errorHandler, String objectType)
 52   
     {
 53  10
         this(LogFactory.getLog(Orderer.class), errorHandler, objectType);
 54   
     }
 55   
 
 56   
     /**
 57   
      * Creates a new instance, but directs all debug and error logging output to the provided log.
 58   
      * 
 59   
      * @param log
 60   
      *            Used for logging any errors
 61   
      * @param objectType
 62   
      *            user presentable name for the type of object to be ordered; used in some error
 63   
      *            messages
 64   
      */
 65  30
     public Orderer(Log log, ErrorHandler errorHandler, String objectType)
 66   
     {
 67  30
         _log = log;
 68  30
         _errorHandler = errorHandler;
 69  30
         _objectType = objectType;
 70   
 
 71  30
         HiveMind.checkNullParameter("log", log);
 72  30
         HiveMind.checkNullParameter("errorHandler", errorHandler);
 73  30
         HiveMind.checkNullParameter("objectType", objectType);
 74   
     }
 75   
 
 76   
     /**
 77   
      * Adds a new object. All invocations of {@link #add(Object, String, String, String)}should
 78   
      * occur before invoking {@link #getOrderedObjects()}.
 79   
      * 
 80   
      * @param object
 81   
      *            an object to be sorted into order based on prereqs and postreqs
 82   
      * @param name
 83   
      *            a unique name for the
 84   
      * @param prereqs
 85   
      *            a comma-separated list of the names of objects that should precede this object in
 86   
      *            the list (or null)
 87   
      * @param postreqs
 88   
      *            a comma-separated list of the names of objects that should follow this object in
 89   
      *            the list (or null)
 90   
      */
 91  74
     public void add(Object object, String name, String prereqs, String postreqs)
 92   
     {
 93  74
         if (_orderingsMap == null)
 94   
         {
 95  29
             _orderingsMap = new HashMap();
 96  29
             _orderingsList = new ArrayList();
 97   
         }
 98   
 
 99  74
         ObjectOrdering o = getOrderable(name);
 100   
 
 101  74
         if (o != null)
 102   
         {
 103  1
             _errorHandler.error(_log, OrdererMessages.duplicateName(_objectType, name, object, o
 104   
                     .getObject()), HiveMind.getLocation(object), null);
 105   
 
 106  1
             return;
 107   
         }
 108   
 
 109  73
         o = new ObjectOrdering(object, name, prereqs, postreqs);
 110   
 
 111  73
         _orderingsMap.put(name, o);
 112  73
         _orderingsList.add(o);
 113   
     }
 114   
 
 115  187
     private ObjectOrdering getOrderable(String name)
 116   
     {
 117  187
         return (ObjectOrdering) _orderingsMap.get(name);
 118   
     }
 119   
 
 120   
     /**
 121   
      * Uses the information provided by {@link #add(Object, String, String, String)}to order the
 122   
      * objects into an appropriate order based on the pre- and post-reqts provided. Errors such as
 123   
      * cyclic dependencies or unrecognized names are logged and ignored.
 124   
      */
 125  30
     public List getOrderedObjects()
 126   
     {
 127  30
         if (_orderingsMap == null)
 128  1
             return Collections.EMPTY_LIST;
 129   
 
 130  29
         try
 131   
         {
 132  29
             _nodeMap = new HashMap();
 133   
 
 134  29
             initializeGraph();
 135   
 
 136  29
             return _trailer.getOrder();
 137   
         }
 138   
         finally
 139   
         {
 140  29
             _nodeMap = null;
 141  29
             _leader = null;
 142  29
             _trailer = null;
 143   
         }
 144   
     }
 145   
 
 146  29
     private void initializeGraph()
 147   
     {
 148  29
         addNodes();
 149   
 
 150  29
         if (_leader == null)
 151  25
             _leader = new Node(null, "*-leader-*");
 152   
 
 153  29
         if (_trailer == null)
 154  27
             _trailer = new Node(null, "*-trailer-*");
 155   
 
 156  29
         addDependencies();
 157   
     }
 158   
 
 159  111
     private Node getNode(String name)
 160   
     {
 161  111
         return (Node) _nodeMap.get(getOrderable(name));
 162   
     }
 163   
 
 164  29
     private void addNodes()
 165   
     {
 166  29
         Iterator i = _orderingsList.iterator();
 167   
 
 168  29
         while (i.hasNext())
 169   
         {
 170  73
             ObjectOrdering o = (ObjectOrdering) i.next();
 171   
 
 172  73
             Node node = new Node(o.getObject(), o.getName());
 173   
 
 174  73
             _nodeMap.put(o, node);
 175   
 
 176  73
             if ("*".equals(o.getPostreqs()))
 177   
             {
 178  5
                 if (_leader == null)
 179  4
                     _leader = node;
 180   
                 else
 181  1
                     _errorHandler.error(_log, OrdererMessages.dupeLeader(_objectType, o,
 182   
                             getOrderable(_leader.getName())), HiveMind.getLocation(o.getObject()),
 183   
                             null);
 184   
             }
 185   
 
 186  73
             if ("*".equals(o.getPrereqs()))
 187   
             {
 188  3
                 if (_trailer == null)
 189  2
                     _trailer = node;
 190   
                 else
 191  1
                     _errorHandler.error(_log, OrdererMessages.dupeTrailer(_objectType, o,
 192   
                             getOrderable(_trailer.getName())), HiveMind.getLocation(o.getObject()),
 193   
                             null);
 194   
             }
 195   
 
 196   
         }
 197   
     }
 198   
 
 199  29
     private void addDependencies()
 200   
     {
 201  29
         Iterator i = _orderingsList.iterator();
 202   
 
 203  29
         while (i.hasNext())
 204   
         {
 205  73
             ObjectOrdering o = (ObjectOrdering) i.next();
 206   
 
 207  73
             addDependencies(o, getNode(o.getName()));
 208   
         }
 209   
     }
 210   
 
 211  73
     private void addDependencies(ObjectOrdering orderable, Node node)
 212   
     {
 213  73
         addPreRequisites(orderable, node);
 214  73
         addPostRequisites(orderable, node);
 215   
 
 216  73
         try
 217   
         {
 218  73
             if (node != _leader)
 219  69
                 node.addDependency(_leader);
 220   
 
 221  73
             if (node != _trailer)
 222  71
                 _trailer.addDependency(node);
 223   
         }
 224   
         catch (ApplicationRuntimeException ex)
 225   
         {
 226   
             // This code is unreachable ... but nonetheless.
 227   
 
 228  0
             String name = node.getName();
 229  0
             ObjectOrdering trigger = getOrderable(name);
 230   
 
 231  0
             _errorHandler.error(_log, OrdererMessages.dependencyCycle(_objectType, orderable, ex),
 232   
                     HiveMind.getLocation(trigger.getObject()), ex);
 233   
         }
 234   
     }
 235   
 
 236  73
     private void addPreRequisites(ObjectOrdering ordering, Node node)
 237   
     {
 238  73
         String prereqs = ordering.getPrereqs();
 239   
 
 240  73
         if ("*".equals(prereqs))
 241  3
             return;
 242   
 
 243  70
         String[] names = StringUtils.split(prereqs);
 244   
 
 245  70
         for (int i = 0; i < names.length; i++)
 246   
         {
 247  14
             String prename = names[i];
 248   
 
 249  14
             Node prenode = getNode(prename);
 250   
 
 251  14
             if (prenode == null)
 252   
             {
 253  1
                 _errorHandler.error(_log, OrdererMessages.badDependency(_objectType, prename,
 254   
                         ordering), HiveMind.getLocation(ordering.getObject()), null);
 255  1
                 continue;
 256   
             }
 257   
             else
 258   
             {
 259  13
                 try
 260   
                 {
 261  13
                     node.addDependency(prenode);
 262   
                 }
 263   
                 catch (ApplicationRuntimeException ex)
 264   
                 {
 265  1
                     _errorHandler.error(_log, OrdererMessages.dependencyCycle(_objectType,
 266   
                             ordering, ex), HiveMind.getLocation(ordering.getObject()), ex);
 267   
                 }
 268   
             }
 269   
         }
 270   
     }
 271   
 
 272  73
     private void addPostRequisites(ObjectOrdering ordering, Node node)
 273   
     {
 274  73
         String postreqs = ordering.getPostreqs();
 275   
 
 276  73
         if ("*".equals(postreqs))
 277  5
             return;
 278   
 
 279  68
         String[] names = StringUtils.split(postreqs);
 280   
 
 281  68
         for (int i = 0; i < names.length; i++)
 282   
         {
 283  24
             String postname = names[i];
 284   
 
 285  24
             Node postnode = getNode(postname);
 286   
 
 287  24
             if (postnode == null)
 288   
             {
 289  1
                 _errorHandler.error(_log, OrdererMessages.badDependency(_objectType, postname,
 290   
                         ordering), HiveMind.getLocation(ordering.getObject()), null);
 291   
             }
 292   
             else
 293   
             {
 294  23
                 try
 295   
                 {
 296  23
                     postnode.addDependency(node);
 297   
                 }
 298   
                 catch (ApplicationRuntimeException ex)
 299   
                 {
 300  1
                     _errorHandler.error(_log, OrdererMessages.dependencyCycle(_objectType,
 301   
                             ordering, ex), HiveMind.getLocation(ordering.getObject()), ex);
 302   
                 }
 303   
             }
 304   
         }
 305   
     }
 306   
 
 307   
     private class Node
 308   
     {
 309   
         private Object _object;
 310   
         private String _name;
 311   
         private List _dependencies;
 312   
 
 313  125
         public Node(Object o, String name)
 314   
         {
 315  125
             _object = o;
 316  125
             _name = name;
 317  125
             _dependencies = new ArrayList();
 318   
         }
 319   
 
 320  2
         public String getName()
 321   
         {
 322  2
             return _name;
 323   
         }
 324   
 
 325  176
         public void addDependency(Node n)
 326   
         {
 327  176
             if (n.isReachable(this))
 328  2
                 throw new ApplicationRuntimeException(
 329   
                         "A cycle has been detected from the initial object [" + _name + "]",
 330   
                         HiveMind.getLocation(_object), null);
 331   
             else
 332  174
                 _dependencies.add(n);
 333   
         }
 334   
 
 335  368
         private boolean isReachable(Node n)
 336   
         {
 337  368
             boolean reachable = (n == this);
 338  368
             Iterator i = _dependencies.iterator();
 339   
 
 340  368
             while (i.hasNext() && !reachable)
 341   
             {
 342  194
                 Node dep = (Node) i.next();
 343  194
                 reachable = (dep == n) ? true : dep.isReachable(n);
 344   
             }
 345   
 
 346  368
             return reachable;
 347   
         }
 348   
 
 349  29
         public List getOrder()
 350   
         {
 351  29
             List result = new ArrayList();
 352  29
             fillOrder(result);
 353   
 
 354  29
             return result;
 355   
         }
 356   
 
 357  203
         private void fillOrder(List result)
 358   
         {
 359  203
             if (result.contains(_object))
 360  44
                 return;
 361   
 
 362  159
             Iterator i = _dependencies.iterator();
 363   
 
 364  159
             while (i.hasNext())
 365   
             {
 366  174
                 Node dep = (Node) i.next();
 367  174
                 dep.fillOrder(result);
 368   
             }
 369   
 
 370  159
             if (_object != null)
 371  73
                 result.add(_object);
 372   
         }
 373   
     }
 374   
 
 375   
 }