public static boolean recursivelyLocked(ResourceTreeNode node) {
    if (node.getData() instanceof ResourceFlyweight
        && !((ResourceFlyweight) node.getData()).isLocked()) {
      return false;
    }

    boolean allLocked = true;
    for (ResourceTreeNode child : node.getChildren()) {
      if (!recursivelyLocked(child)) allLocked = false;
    }
    return allLocked;
  }
  public static void load(ResourceTreeNode parentNode) {
    if (parentNode.getData() instanceof ResourceFlyweight) {
      ResourceFlyweight parentResource = (ResourceFlyweight) parentNode.getData();

      Map<Object, List<ResourceFlyweight>> children =
          new HashMap<Object, List<ResourceFlyweight>>();
      for (ResourceFlyweight res : parentResource.getChildResources()) {
        if (res.getResourceType().getSubCategory() != null) {
          // These are children that have subcategories
          // Split them by if they are a sub-sub category or just a category
          ResourceSubCategoryFlyweight categoryKey =
              res.getResourceType().getSubCategory().getParentSubCategory();
          if (categoryKey == null) {
            categoryKey = res.getResourceType().getSubCategory();
          }
          addToList(children, categoryKey, res);
        } else {
          // These are children without categories of the parent resource
          // - Add them into groupings by their resource type
          addToList(children, res.getResourceType(), res);
        }
      }

      Set<String> dupResourceTypeNames = getDuplicateResourceTypeNames(children);

      for (Map.Entry<Object, List<ResourceFlyweight>> entry : children.entrySet()) {
        Object key = entry.getKey();
        List<ResourceFlyweight> resources = entry.getValue();

        double avail = 0;
        for (ResourceFlyweight res : resources) {
          avail +=
              res.getCurrentAvailability().getAvailabilityType() == AvailabilityType.UP ? 1 : 0;
        }
        avail = avail / resources.size();

        Object nodeData = null;
        if (key instanceof ResourceSubCategoryFlyweight) {
          nodeData =
              new AutoGroupCompositeFlyweight(
                  avail, parentResource, (ResourceSubCategoryFlyweight) key, resources.size());
        } else if (key instanceof ResourceTypeFlyweight) {
          ResourceTypeFlyweight typeKey = (ResourceTypeFlyweight) key;

          if (typeKey.isSingleton()) {
            nodeData = resources.get(0);
          } else {
            boolean isDupResourceTypeName = dupResourceTypeNames.contains(typeKey.getName());
            nodeData =
                new AutoGroupCompositeFlyweight(
                    avail, parentResource, typeKey, resources.size(), isDupResourceTypeName);
          }
        }
        ResourceTreeNode node = new ResourceTreeNode(nodeData, parentNode);
        load(node);

        if (!recursivelyLocked(node)) {
          parentNode.getChildren().add(node);
        }
      }
    } else {
      // #####################################################################################

      AutoGroupCompositeFlyweight compositeParent =
          (AutoGroupCompositeFlyweight) parentNode.getData();

      Map<Object, List<ResourceFlyweight>> children =
          new HashMap<Object, List<ResourceFlyweight>>();
      log.debug("composite parent" + compositeParent);
      if (compositeParent != null) {

        MembersCategoryHint membersCategory = MembersCategoryHint.NONE;
        MembersAvailabilityHint membersAvailabilityHint = MembersAvailabilityHint.UP;

        for (ResourceFlyweight res : compositeParent.getParentResource().getChildResources()) {
          boolean process = false;
          if (compositeParent.getSubcategory() != null) {
            // parent is a sub category
            if (res.getResourceType().getSubCategory() != null
                && compositeParent
                    .getSubcategory()
                    .equals(res.getResourceType().getSubCategory().getParentSubCategory())
                && compositeParent.getParentResource().equals(res.getParentResource())) {

              // A subSubCategory in a subcategory
              addToList(children, res.getResourceType().getSubCategory(), res);
              process = true;
            } else if (compositeParent
                    .getSubcategory()
                    .equals(res.getResourceType().getSubCategory())
                && compositeParent.getParentResource().equals(res.getParentResource())) {
              // Direct entries in a subcategory... now group them by autogroup (type)
              addToList(children, res.getResourceType(), res);
              process = true;
            }
          } else if (compositeParent.getResourceType() != null) {
            if (compositeParent.getResourceType().equals(res.getResourceType())
                && compositeParent.getParentResource().getId() == res.getParentResource().getId()) {

              addToList(children, res.getResourceType(), res);
              process = true;
            }
          }

          if (process) {
            // amend the overall category of all the members of the auto group.
            switch (membersCategory) {
              case NONE: // this is the first child, so let's use its category as a starting point
                membersCategory =
                    MembersCategoryHint.fromResourceCategory(res.getResourceType().getCategory());
                break;
              case MIXED: // this is the "final" state. The children type is not going to change
                          // from this.
                break;
              default: // check if this child has the same category as its previous siblings.
                if (MembersCategoryHint.fromResourceCategory(res.getResourceType().getCategory())
                    != membersCategory) {
                  membersCategory = MembersCategoryHint.MIXED;
                }
            }

            // amend the availability hint of the autogroup. If all resources are up, the hint is
            // UP, if some of the resources
            // are down, the hint is DOWN, if some of the resources' avail state is unknown, the
            // hint is UNKNOWN.
            // The down state has the highest priority.
            switch (membersAvailabilityHint) {
              case UP:
                membersAvailabilityHint =
                    MembersAvailabilityHint.fromAvailabilityType(
                        res.getCurrentAvailability().getAvailabilityType());
                break;
              case UNKNOWN:
                if (res.getCurrentAvailability().getAvailabilityType() == AvailabilityType.DOWN) {
                  membersAvailabilityHint = MembersAvailabilityHint.DOWN;
                }
                break;
              case DOWN:; // a "terminal" state... if some resource is down, the overall state is
                          // going to be down as that is the most important information.
            }
          }
        }

        compositeParent.setMembersCategoryHint(membersCategory);
        compositeParent.setMembersAvailabilityHint(membersAvailabilityHint);
      }

      AutoGroupCompositeFlyweight compositeParentNode =
          (AutoGroupCompositeFlyweight) parentNode.getData();

      for (Map.Entry<Object, List<ResourceFlyweight>> entry : children.entrySet()) {
        Object key = entry.getKey();
        List<ResourceFlyweight> resources = entry.getValue();

        if (compositeParentNode.getSubcategory() != null) {
          double avail = 0;
          for (ResourceFlyweight res : resources) {
            avail +=
                res.getCurrentAvailability().getAvailabilityType() == AvailabilityType.UP ? 1 : 0;
          }
          avail = avail / resources.size();

          Object nodeData = null;
          if (key instanceof ResourceSubCategoryFlyweight) {
            nodeData =
                new AutoGroupCompositeFlyweight(
                    avail,
                    compositeParent.getParentResource(),
                    (ResourceSubCategoryFlyweight) key,
                    resources.size());
          } else if (key instanceof ResourceTypeFlyweight) {
            ResourceTypeFlyweight typeKey = (ResourceTypeFlyweight) key;
            if (typeKey.isSingleton()) {
              nodeData = resources.get(0);
            } else {
              nodeData =
                  new AutoGroupCompositeFlyweight(
                      avail, compositeParent.getParentResource(), typeKey, resources.size(), false);
            }
          }
          ResourceTreeNode node = new ResourceTreeNode(nodeData, parentNode);
          load(node);

          if (!recursivelyLocked(node)) {
            parentNode.getChildren().add(node);
          }
        } else {
          for (ResourceFlyweight res : resources) {
            ResourceTreeNode node = new ResourceTreeNode(res, parentNode);
            load(node);
            if (!recursivelyLocked(node)) {
              parentNode.getChildren().add(node);
            }
          }
        }
      }
    }
  }