/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004-2008], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.hq.appdef.shared; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import org.hyperic.hq.appdef.AppService; /** * A DependencyTree has child DependencyNodes (who in turn my have children * of their own), structurally, it's a list of lists. */ public class DependencyTree implements Serializable { // all the entry point nodes private List _nodes; // the application to which this tree applies private ApplicationValue _appValue; // an empty tree public DependencyTree(ApplicationValue appValue) { _appValue = appValue; _nodes = new ArrayList(); } // get the app value public ApplicationValue getApplication() { return _appValue; } public Integer getAppPK() { return getApplication().getId(); } /** * Adds a top level DependencyNode */ private void addNode(DependencyNode aNode) { _nodes.add(aNode); } /** * Returns a List of top level DependencyNodes */ public List<DependencyNode> getNodes() { return _nodes; } /** * Adds an AppService <code>depSvc</code> as a child of another * AppService <code>appSvc</code>. If the <code>appSvc</code> does * not exist, it will be created as a toplevel node. */ public void addNode(AppService appSvc, AppService depSvc) { // find the item in the list which matches the source appservice DependencyNode aNode = null; try { aNode = findAppService(appSvc); } catch (NoSuchElementException e) { // looks like we need to create the node and add it to the list aNode = new DependencyNode(appSvc, new ArrayList()); // only add the node if its a new one addNode(aNode); } aNode.addChild(depSvc); } /** * Add a node with no dependents */ public void addNode(AppService appSvc) { try { // find it first findAppService(appSvc); } catch (NoSuchElementException e) { // not there, add it DependencyNode aNode = new DependencyNode(appSvc, null); addNode(aNode); } } /** * Returns a top level DependencyNode */ public DependencyNode findAppService(AppService aService) throws NoSuchElementException { // iterate over the nodes in the list, match by app service, // since a single app service should exist only once at the top level for (int i = 0; i < _nodes.size(); i++) { DependencyNode aNode = (DependencyNode) _nodes.get(i); if (aNode.getAppService().equals(aService)) { return aNode; } } throw new NoSuchElementException(aService + " was not found in tree"); } public DependencyNode findAppService(AppdefResourceValue aResource) throws NoSuchElementException { // iterate over nodes in the list for (int i = 0; i < _nodes.size(); i++) { DependencyNode aNode = (DependencyNode) _nodes.get(i); if (aNode.getEntityId().equals(aResource.getEntityId())) { return aNode; } } throw new NoSuchElementException(aResource + " was not found in tree"); } /** * Check if the app service represents an entry point within this * tree. An entry point is defined as an AppService which is not a * dependee in any point in the tree * @return int */ public boolean isEntryPoint(AppService appService) throws NoSuchElementException { boolean isEntry = true; for(int i = 0; i < _nodes.size(); i++) { DependencyNode aNode = (DependencyNode)getNodes().get(i); // if any of the children include the appservice in question, // we know its not an entry point if(aNode.getChildren().contains(appService)) { isEntry = false; } } return isEntry; } public String toString() { StringBuffer sb = new StringBuffer(DependencyTree.class.getName()); sb.append("["); sb.append(" parentAppId=").append(_appValue.getId()); sb.append(" parentAppName=").append(_appValue.getName()); sb.append(" nodes={\n"); for (Iterator iter = _nodes.iterator(); iter.hasNext();) { DependencyNode node = (DependencyNode) iter.next(); sb.append(node.toString()); } sb.append("\n}]\n"); return sb.toString(); } /* * If <code>o</code> is not a DependencyTree, returns false. * If <code>o</code>'s set of nodes are equal, returns true. */ public boolean equals(Object o) { if (! (o instanceof DependencyTree)) return false; DependencyTree aTree= (DependencyTree)o; if (aTree.comparable().equals(comparable())) return true; return false; } private HashSet comparable() { return new HashSet(_nodes); } public static boolean nodeHasChild(DependencyNode node, Integer appSvcId) { for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) { AppService appSvc = (AppService) iter.next(); if (appSvc.getId().equals(appSvcId)) return true; } return false; } public static DependencyNode findAppServiceById(DependencyTree tree, Integer appSvcId) { List children = tree.getNodes(); DependencyNode returnNode = null; for (Iterator iter = children.iterator(); iter.hasNext();) { DependencyNode node = (DependencyNode) iter.next(); if (node.getAppService().getId().equals(appSvcId)) { returnNode = node; break; } } return returnNode; } public static DependencyNode findServiceById(DependencyTree tree, Integer serviceId) { List children = tree.getNodes(); DependencyNode returnNode = null; for (Iterator iter = children.iterator(); iter.hasNext();) { DependencyNode node = (DependencyNode) iter.next(); if (node.getService().getId().equals(serviceId)) { returnNode = node; break; } } return returnNode; } public static Map<AppdefEntityID,AppdefResourceValue> mapServices(List services) { Map<AppdefEntityID, AppdefResourceValue> serviceMap = new LinkedHashMap<AppdefEntityID, AppdefResourceValue>(); for (Iterator serviceIter = services.iterator(); serviceIter.hasNext();) { AppdefResourceValue service = (AppdefResourceValue) serviceIter.next(); serviceMap.put(service.getEntityId(), service); } return serviceMap; } /** * Method findDependees. * * Returns a list of application services that on a given dependency * element * * @param services * @return List a list of AppServiceNodeBeans */ public static List<AppServiceNodeBean> findDependees(DependencyTree tree, DependencyNode appSvcNode, List services) { List<AppServiceNodeBean> returnList = new ArrayList<AppServiceNodeBean>(); Map serviceMap = DependencyTree.mapServices(services); for (Iterator iter = appSvcNode.getChildren().iterator(); iter.hasNext();) { AppService appSvc = (AppService) iter.next(); AppdefEntityID contained ; if(appSvc.isIsGroup()) contained = AppdefEntityID.newGroupID(appSvc.getResourceGroup() .getId()); else contained = appSvc.getService().getEntityId(); if (serviceMap.containsKey(contained)) { DependencyNode node = DependencyTree.findAppServiceById(tree, appSvc.getId()); returnList.add(new AppServiceNodeBean( (AppdefResourceValue) serviceMap.get(contained), node)); } } return returnList; } /** * Method findDependers. * * Performs a search for DependencyNodes that have the current * one (identified by the appSvcId) among its children i.e. our current * one depends on all of the ones returned * * @param tree the DependencyTree * @param appSvcId the current ApplicationService * @param services a list of ServiceValues associated with the application * @return List a list of AppServiceNodeBeans */ public static List<AppServiceNodeBean> findDependers(DependencyTree tree, Integer appSvcId, List services) { List<AppServiceNodeBean> returnList = new ArrayList<AppServiceNodeBean>(); Map serviceMap = DependencyTree.mapServices(services); for (Iterator iter = tree.getNodes().iterator(); iter.hasNext();) { DependencyNode node = (DependencyNode) iter.next(); // look at who depends on this node by cycling through the // list of AppServices and checking for appSvcId for (Iterator i = node.getChildren().iterator(); i.hasNext();) { AppService appSvc = (AppService) i.next(); if (appSvc.getId().equals(appSvcId)) { returnList.add(new AppServiceNodeBean( (AppdefResourceValue)serviceMap.get( node.getEntityId()),node)); } } } return returnList; } /** * * The criteria for qualifying AppServices as potential dependees for a * given node are * the following: * <ol> * <li>The candidate AppService is in the DependencyTree already, * i.e. it has a DependencyNode already. * <li>A candidate's node cannot be the given node, self dependencies * are disallowed. * <li>The candidate AppService is not already a dependee, defining a * dependency twice is disallowed. * <i>It may depend on indirectly already i.e. if something it already * depends on currently depends on another node, that does not disqualify * the other node. * <li>A candidate's node cannot have the given node as a depender * either directly or indirectly, circular dependencies are disallowed. * </ol> * * @param tree * @param currentNode * @param services * @return */ public static List<DependencyNode> findPotentialDependees(DependencyTree tree, DependencyNode currentNode, List services) { // id of the current node's AppService Integer appSvcId = currentNode.getAppService().getId(); // any DependencyNodes left in this list when we're done disqualify // candidates is what we'll return List candidateNodes = new ArrayList(tree.getNodes()); // disqualify self for (Iterator iter = candidateNodes.iterator(); iter.hasNext();) { DependencyNode aNode= (DependencyNode) iter.next(); if (aNode.getAppService().getId().equals(appSvcId)) { iter.remove(); } } ArrayList filtered = new ArrayList(); // disqualify existing dependencies for (Iterator iter = candidateNodes.iterator(); iter.hasNext();) { DependencyNode aNode= (DependencyNode) iter.next(); Integer anAppSvcId = aNode.getAppService().getId(); for (Iterator appSvcIter = currentNode.getChildren().iterator(); appSvcIter.hasNext();) { AppService currentDependeeAppSvc = (AppService) appSvcIter.next(); if (currentDependeeAppSvc.getId().equals(anAppSvcId)) { //iter.remove(); filtered.add(aNode); } } } candidateNodes.removeAll(filtered); filtered.clear(); // build a map of the nodes keyed on the AppService's id Map nodeMap = new LinkedHashMap(); for (Iterator iter = candidateNodes.iterator(); iter.hasNext();) { DependencyNode aNode= (DependencyNode) iter.next(); nodeMap.put(aNode.getAppService().getId(), aNode); } // disqualify current dependers by doing a two level check for (Iterator iter = candidateNodes.iterator(); iter.hasNext();) { DependencyNode aNode= (DependencyNode) iter.next(); // see if the node directly or indirectly depends on the currentNode for (Iterator appSvcIter = aNode.getChildren().iterator(); appSvcIter.hasNext();) { AppService anAppSvc = (AppService) appSvcIter.next(); // see if the node directly depends on the currentNode if (appSvcId.equals(anAppSvc.getId())) { // disqualify the candidate for directly depending on the // currentNode filtered.add(aNode); //iter.remove(); break; } // now see if the node indirectly depends on the currentNode by // checking it's children (with this data structure, we only // need to check two levels instead of a fully recursive check) for (Iterator childAppSvcIter = aNode.getChildren().iterator(); childAppSvcIter .hasNext();) { AppService childAppSvc = (AppService) childAppSvcIter .next(); // see if the node directly depends on the currentNode if (appSvcId.equals(childAppSvc.getId())) { filtered.add(aNode); //iter.remove(); break; } } } } candidateNodes.removeAll(filtered); filtered.clear(); return candidateNodes; } }