/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.gui.navigation.resource; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.resource.Agent; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.flyweight.AutoGroupCompositeFlyweight; import org.rhq.core.domain.resource.flyweight.MembersAvailabilityHint; import org.rhq.core.domain.resource.flyweight.MembersCategoryHint; import org.rhq.core.domain.resource.flyweight.ResourceFlyweight; import org.rhq.core.domain.resource.flyweight.ResourceTypeFlyweight; import org.rhq.core.domain.util.PageControl; import org.rhq.core.gui.util.FacesContextUtility; import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility; import org.rhq.enterprise.server.core.AgentManagerLocal; import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.util.HibernatePerformanceMonitor; import org.rhq.enterprise.server.util.LookupUtil; /** * Backing bean for the left navigation tree for resources * * @author Greg Hinkle */ public class ResourceTreeModelUIBean { private static final Log log = LogFactory.getLog(ResourceTreeModelUIBean.class); private List<ResourceTreeNode> roots = new ArrayList<ResourceTreeNode>(); private ResourceTreeNode rootNode = null; private ResourceManagerLocal resourceManager = LookupUtil.getResourceManager(); private AgentManagerLocal agentManager = LookupUtil.getAgentManager(); private String nodeTitle; private void loadTree() { int searchId; Resource currentResource = EnterpriseFacesContextUtility.getResourceIfExists(); if (currentResource == null) { searchId = Integer.parseInt(FacesContextUtility.getOptionalRequestParameter("parent")); } else { searchId = currentResource.getId(); } Subject user = EnterpriseFacesContextUtility.getSubject(); long start = System.currentTimeMillis(); long monitorId = HibernatePerformanceMonitor.get().start(); Resource rootResource = resourceManager.getRootResourceForResource(searchId); long end = System.currentTimeMillis(); HibernatePerformanceMonitor.get().stop(monitorId, "ResourceTree root resource"); log.debug("Found root resource in " + (end - start)); Agent agent = agentManager.getAgentByResourceId(LookupUtil.getSubjectManager().getOverlord(), rootResource .getId()); start = System.currentTimeMillis(); monitorId = HibernatePerformanceMonitor.get().start(); List<ResourceFlyweight> resources = resourceManager.findResourcesByAgent(user, agent.getId(), PageControl .getUnlimitedInstance()); end = System.currentTimeMillis(); HibernatePerformanceMonitor.get().stop(monitorId, "ResourceTree agent resource"); log.debug("Loaded " + resources.size() + " raw resources in " + (end - start)); start = System.currentTimeMillis(); monitorId = HibernatePerformanceMonitor.get().start(); rootNode = load(rootResource.getId(), resources); end = System.currentTimeMillis(); HibernatePerformanceMonitor.get().stop(monitorId, "ResourceTree tree construction"); log.debug("Constructed tree in " + (end - start)); } public static ResourceTreeNode load(int rootId, List<ResourceFlyweight> resources) { ResourceFlyweight found = null; for (ResourceFlyweight res : resources) { if (res.getId() == rootId) { found = res; } } ResourceTreeNode root = new ResourceTreeNode(found); load(root); return root; } 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 String 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().getName(), 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 String) { nodeData = new AutoGroupCompositeFlyweight(avail, parentResource, (String) 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 //BZ1069545 This functionality is no longer needed since portal-war is no longer needed. //&& 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 String) { nodeData = new AutoGroupCompositeFlyweight(avail, compositeParent.getParentResource(), (String) 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); } } } } } } 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 ResourceTreeNode getTreeNode() { if (rootNode == null) { long start = System.currentTimeMillis(); loadTree(); log.debug("Loaded full tree in " + (System.currentTimeMillis() - start)); } return rootNode; } public List<ResourceTreeNode> getRoots() { if (roots.isEmpty()) { roots.add(getTreeNode()); } return roots; } public String getNodeTitle() { return nodeTitle; } public void setNodeTitle(String nodeTitle) { this.nodeTitle = nodeTitle; } private static Set<String> getDuplicateResourceTypeNames(Map<Object, List<ResourceFlyweight>> children) { Set<String> resourceTypeNames = new HashSet<String>(); Set<String> dupResourceTypeNames = new HashSet<String>(); for (Object rsc : children.keySet()) { if (rsc instanceof ResourceTypeFlyweight) { String resourceTypeName = ((ResourceTypeFlyweight) rsc).getName(); if (resourceTypeNames.contains(resourceTypeName)) { dupResourceTypeNames.add(resourceTypeName); } resourceTypeNames.add(resourceTypeName); } } return dupResourceTypeNames; } private static <K, V> void addToList(Map<K, List<V>> mapOfLists, K key, V value) { List<V> list = mapOfLists.get(key); if (list == null) { list = new ArrayList<V>(); mapOfLists.put(key, list); } list.add(value); } }