Clover coverage report - ActiveCluster - 1.1-SNAPSHOT
Coverage timestamp: Tue May 24 2005 08:48:28 BST
file stats: LOC: 331   Methods: 28
NCLOC: 209   Classes: 1
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
GroupModel.java 0% 0% 0% 0%
coverage
 1   
 /**
 2   
  * 
 3   
  * Copyright 2004 Protique Ltd
 4   
  * 
 5   
  * Licensed under the Apache License, Version 2.0 (the "License"); 
 6   
  * you may not use this file except in compliance with the License. 
 7   
  * You may obtain a copy of the License at 
 8   
  * 
 9   
  * http://www.apache.org/licenses/LICENSE-2.0
 10   
  * 
 11   
  * Unless required by applicable law or agreed to in writing, software
 12   
  * distributed under the License is distributed on an "AS IS" BASIS, 
 13   
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 14   
  * See the License for the specific language governing permissions and 
 15   
  * limitations under the License. 
 16   
  * 
 17   
  **/
 18   
 package org.activecluster.group;
 19   
 
 20   
 import org.activecluster.Node;
 21   
 
 22   
 import java.util.ArrayList;
 23   
 import java.util.HashMap;
 24   
 import java.util.Iterator;
 25   
 import java.util.LinkedList;
 26   
 import java.util.List;
 27   
 import java.util.Map;
 28   
 
 29   
 /**
 30   
  * Represents a collection of zero or more groups in a cluster.
 31   
  * The default implementation will create groups as nodes are added to the cluster; filling
 32   
  * the groups with its required number of buddies / slaves until a new group can be created.
 33   
  * <p/>
 34   
  * Nodes which are not allowed to be master nodes will be kept around in a pool ready to be added
 35   
  * as slaves when a new master arrives and forces the creation of a group.
 36   
  *
 37   
  * @version $Revision: 1.1 $
 38   
  * @see Group
 39   
  */
 40   
 public class GroupModel {
 41   
     private int maximumGroups = -1;
 42   
     private int minimumMemberCount = 2;
 43   
     private int maximumMemberCount = 3;
 44   
     private List groups = new ArrayList();
 45   
     private LinkedList incompleteGroups = new LinkedList();
 46   
     private LinkedList completeGroups = new LinkedList();
 47   
     private LinkedList fullGroups = new LinkedList();
 48   
     private LinkedList unusedNodes = new LinkedList();
 49   
     private NodeFilter masterFilter;
 50   
     private Map nodeMemberships = new HashMap();
 51   
 
 52   
     // allow a node to be a master and 2 buddies
 53   
     private int maximumWeighting = 10;
 54   
 
 55   
     /**
 56   
      * Adds the new node to this group model; we assume the node has not been added before.
 57   
      *
 58   
      * @param node
 59   
      */
 60  0
     public synchronized void addNode(Node node) {
 61  0
         if (!addToExistingGroup(node)) {
 62  0
             Group group = makeNewGroup(node);
 63  0
             if (group == null) {
 64  0
                 addToUnusedNodes(node);
 65   
             }
 66   
             else {
 67  0
                 addGroup(group);
 68   
             }
 69   
         }
 70   
     }
 71   
 
 72   
     /**
 73   
      * Removes the node from the group model
 74   
      *
 75   
      * @param node
 76   
      */
 77  0
     public synchronized void removeNode(Node node) {
 78  0
         unusedNodes.remove(node);
 79   
 
 80   
         // lets remove the node from each group
 81  0
         for (Iterator iter = groups.iterator(); iter.hasNext();) {
 82  0
             Group group = (Group) iter.next();
 83  0
             boolean wasFull = group.isFull();
 84  0
             boolean wasUsable = group.isUsable();
 85   
 
 86  0
             if (removeNodeFromGroup(group, node)) {
 87  0
                 updateGroupCollections(group, wasFull, wasUsable);
 88   
             }
 89   
         }
 90   
     }
 91   
 
 92   
     // Properties
 93   
     //-------------------------------------------------------------------------
 94   
 
 95   
     /**
 96   
      * Returns a snapshot of the groups currently available
 97   
      */
 98  0
     public synchronized List getGroups() {
 99  0
         return new ArrayList(groups);
 100   
     }
 101   
 
 102  0
     public NodeFilter getMasterFilter() {
 103  0
         return masterFilter;
 104   
     }
 105   
 
 106  0
     public void setMasterFilter(NodeFilter masterFilter) {
 107  0
         this.masterFilter = masterFilter;
 108   
     }
 109   
 
 110  0
     public int getMaximumGroups() {
 111  0
         return maximumGroups;
 112   
     }
 113   
 
 114  0
     public void setMaximumGroups(int maximumGroups) {
 115  0
         this.maximumGroups = maximumGroups;
 116   
     }
 117   
 
 118  0
     public int getMaximumMemberCount() {
 119  0
         return maximumMemberCount;
 120   
     }
 121   
 
 122  0
     public void setMaximumMemberCount(int maximumMemberCount) {
 123  0
         this.maximumMemberCount = maximumMemberCount;
 124   
     }
 125   
 
 126  0
     public int getMinimumMemberCount() {
 127  0
         return minimumMemberCount;
 128   
     }
 129   
 
 130  0
     public void setMinimumMemberCount(int minimumMemberCount) {
 131  0
         this.minimumMemberCount = minimumMemberCount;
 132   
     }
 133   
 
 134  0
     public int getMaximumWeighting() {
 135  0
         return maximumWeighting;
 136   
     }
 137   
 
 138  0
     public void setMaximumWeighting(int maximumWeighting) {
 139  0
         this.maximumWeighting = maximumWeighting;
 140   
     }
 141   
 
 142   
 
 143   
     // Implementation methods
 144   
     //-------------------------------------------------------------------------
 145   
 
 146   
 
 147   
     /**
 148   
      * Attempt to make a new group with the current node as the master
 149   
      * or if the node cannot be a master node
 150   
      *
 151   
      * @return the newly created group or false if none was created.
 152   
      */
 153  0
     protected Group makeNewGroup(Node node) {
 154   
         // no pending groups available so lets try and create a new group
 155  0
         if (canCreateGroup(node)) {
 156  0
             Group group = createGroup(node);
 157  0
             addNodeToGroup(group, node);
 158  0
             return group;
 159   
         }
 160   
         else {
 161  0
             return null;
 162   
         }
 163   
     }
 164   
 
 165  0
     protected void tryToFillGroupWithBuddies(Group group) {
 166  0
         boolean continueFillingGroups = true;
 167  0
         while (!group.isUsable() && continueFillingGroups) {
 168  0
             continueFillingGroups = tryToAddBuddy(group);
 169   
         }
 170   
 
 171  0
         if (continueFillingGroups) {
 172   
             // lets try fill more unfilled nodes
 173  0
             for (Iterator iter = new ArrayList(incompleteGroups).iterator(); iter.hasNext() && continueFillingGroups;) {
 174  0
                 group = (Group) iter.next();
 175   
 
 176  0
                 boolean wasFull = group.isFull();
 177  0
                 boolean wasUsable = group.isUsable();
 178   
 
 179  0
                 while (!group.isUsable() && continueFillingGroups) {
 180  0
                     continueFillingGroups = tryToAddBuddy(group);
 181   
                 }
 182   
 
 183  0
                 if (group.isUsable()) {
 184  0
                     updateGroupCollections(group, wasFull, wasUsable);
 185   
                 }
 186   
             }
 187   
         }
 188   
     }
 189   
 
 190  0
     protected boolean tryToAddBuddy(Group group) {
 191  0
         boolean continueFillingGroups = true;
 192   
         // TODO we could make this much faster using a weighting-sorted collection
 193  0
         NodeMemberships lowest = null;
 194  0
         int lowestWeight = 0;
 195  0
         for (Iterator iter = nodeMemberships.values().iterator(); iter.hasNext();) {
 196  0
             NodeMemberships memberships = (NodeMemberships) iter.next();
 197  0
             if (!memberships.isMember(group)) {
 198  0
                 int weighting = memberships.getWeighting();
 199  0
                 if ((lowest == null || weighting < lowestWeight) && weighting < maximumWeighting) {
 200  0
                     lowest = memberships;
 201  0
                     lowestWeight = weighting;
 202   
                 }
 203   
             }
 204   
         }
 205  0
         if (lowest == null) {
 206  0
             continueFillingGroups = false;
 207   
         }
 208   
         else {
 209  0
             addNodeToGroup(group, lowest.getNode());
 210   
         }
 211  0
         return continueFillingGroups;
 212   
     }
 213   
 
 214   
     /**
 215   
      * Lets move the group from its current state collection to the new collection if its
 216   
      * state has changed
 217   
      */
 218  0
     protected void updateGroupCollections(Group group, boolean wasFull, boolean wasUsable) {
 219  0
         boolean full = group.isFull();
 220  0
         if (wasFull && !full) {
 221  0
             fullGroups.remove(group);
 222   
         }
 223  0
         boolean usable = group.isUsable();
 224  0
         if (wasUsable && !usable) {
 225  0
             completeGroups.remove(group);
 226   
         }
 227  0
         if ((!usable || !full) && (wasFull || wasUsable)) {
 228  0
             incompleteGroups.add(group);
 229   
         }
 230   
     }
 231   
 
 232  0
     protected void addToUnusedNodes(Node node) {
 233   
         // lets add the node to the pool ready to be used if a node fails
 234  0
         unusedNodes.add(node);
 235   
     }
 236   
 
 237   
     /**
 238   
      * Attempts to add the node to an incomplete group, or
 239   
      * a not-full group and returns true if its possible - else returns false
 240   
      *
 241   
      * @return true if the node has been added to a groupu
 242   
      */
 243  0
     protected boolean addToExistingGroup(Node node) {
 244  0
         if (!addToIncompleteGroup(node)) {
 245  0
             if (!addToNotFullGroup(node)) {
 246  0
                 return false;
 247   
             }
 248   
         }
 249  0
         return true;
 250   
     }
 251   
 
 252  0
     protected boolean addToNotFullGroup(Node node) {
 253  0
         return addToPendingGroup(completeGroups, node);
 254   
     }
 255   
 
 256  0
     protected boolean addToIncompleteGroup(Node node) {
 257  0
         return addToPendingGroup(incompleteGroups, node);
 258   
     }
 259   
 
 260   
     /**
 261   
      * Adds the given node to the first pending group if possible
 262   
      *
 263   
      * @return true if the node was added to the first available group
 264   
      */
 265  0
     protected boolean addToPendingGroup(LinkedList list, Node node) {
 266  0
         if (!list.isEmpty()) {
 267  0
             Group group = (Group) list.getFirst();
 268  0
             addNodeToGroup(group, node);
 269  0
             if (group.isFull()) {
 270  0
                 list.removeFirst();
 271  0
                 fullGroups.add(group);
 272   
             }
 273  0
             else if (group.isUsable()) {
 274  0
                 list.removeFirst();
 275  0
                 completeGroups.add(group);
 276   
             }
 277  0
             return true;
 278   
         }
 279  0
         return false;
 280   
     }
 281   
 
 282  0
     protected void addNodeToGroup(Group group, Node node) {
 283  0
         NodeMemberships memberships = (NodeMemberships) nodeMemberships.get(node);
 284  0
         if (memberships == null) {
 285  0
             memberships = new NodeMemberships(node);
 286  0
             nodeMemberships.put(node, memberships);
 287   
         }
 288  0
         memberships.addToGroup(group);
 289   
     }
 290   
 
 291  0
     protected boolean removeNodeFromGroup(Group group, Node node) {
 292  0
         NodeMemberships memberships = (NodeMemberships) nodeMemberships.get(node);
 293  0
         if (memberships != null) {
 294  0
             return memberships.removeFromGroup(group);
 295   
         }
 296  0
         return false;
 297   
     }
 298   
 
 299   
 
 300  0
     protected void addGroup(Group group) {
 301  0
         groups.add(group);
 302  0
         if (group.isFull()) {
 303  0
             fullGroups.add(group);
 304   
         }
 305  0
         else if (group.isUsable()) {
 306  0
             completeGroups.add(group);
 307   
         }
 308   
         else {
 309  0
             incompleteGroups.add(group);
 310   
         }
 311   
     }
 312   
 
 313  0
     protected Group createGroup(Node node) {
 314  0
         return new Group(minimumMemberCount, maximumMemberCount);
 315   
     }
 316   
 
 317   
     /**
 318   
      * Returns true if we can add a new group to the cluster
 319   
      */
 320  0
     protected boolean canCreateGroup(Node node) {
 321  0
         return (maximumGroups < 0 || groups.size() < maximumGroups) && canBeMaster(node);
 322   
     }
 323   
 
 324   
     /**
 325   
      * Returns true if the given node can be a master
 326   
      */
 327  0
     protected boolean canBeMaster(Node node) {
 328  0
         return masterFilter == null || masterFilter.evaluate(node);
 329   
     }
 330   
 }
 331