/* * Copyright 2005-2007 WSO2, Inc. (http://wso2.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wso2.carbon.mediation.dependency.mgt; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.Set; import java.util.HashSet; import java.util.ArrayList; import java.util.List; /** * This is the data structure which acts as the dependency tree for Synapse * configuration items. It keeps track of configuration objects (sequences, endpoints etc) * and the inter dependencies among them. In effect this functions as a directed graph * which consists of a set of vertices and a set of directed edges. A vertex represents a * unique configuration item and an edge from vertex 'A' to vertex 'B' indicates that item * 'A' is a dependency for 'B'. */ class DependencyGraph { private static final Log log = LogFactory.getLog(DependencyGraph.class); private final Set<ConfigurationObject> vertices = new HashSet<ConfigurationObject>(); private final Set<DirectedEdge> edges = new HashSet<DirectedEdge>(); public boolean add(ConfigurationObject o) { if (o == null) { throw new NullPointerException("null objects cannot be added to the dependency graph"); } return vertices.add(o); } public boolean remove(int type, String id) { ConfigurationObject o = find(type, id); if (o != null) { if (hasDependents(o)) { // If this object has any dependents we mark it as unknown // This object will be resolved when we add an item by the same name o.setType(ConfigurationObject.TYPE_UNKNOWN); } else { // This is an orphan - with no dependents // So simply remove it - Nobody should care remove(o); } } return false; } private boolean remove(ConfigurationObject o) { if (vertices.remove(o)) { List<DirectedEdge> deletedEdges = new ArrayList<DirectedEdge>(); for (DirectedEdge e : edges) { if (e.getStart() == o || e.getEnd() == o) { deletedEdges.add(e); } } for (DirectedEdge e : deletedEdges) { edges.remove(e); } // Deleting a vertex may introduce some orphan unknown objects // We need to remove them from the graph cleanupUnknownObjects(); return true; } return false; } private void cleanupUnknownObjects() { List<ConfigurationObject> deletedVertices = new ArrayList<ConfigurationObject>(); for (ConfigurationObject v : vertices) { if (v.getType() == ConfigurationObject.TYPE_UNKNOWN) { boolean edgeFound = false; for (DirectedEdge e : edges) { if (e.getStart() == v || e.getEnd() == v) { edgeFound = true; break; } } // If the vertex is of the type 'UNKNOWN' and is not connected to any edges // there is no point in keeping it any longer.... if (!edgeFound) { deletedVertices.add(v); } } } for (ConfigurationObject v : deletedVertices) { vertices.remove(v); } } public boolean createEdge(ConfigurationObject start, ConfigurationObject end) { add(start); add(end); for (DirectedEdge e : edges) { if (e.getStart() == start && e.getEnd() == end) { return false; } } edges.add(new DirectedEdge(start, end)); if (log.isDebugEnabled()) { log.debug("Dependency detected: {" + start.getTypeName() + ":" + start.getId() + "}" + " ---> {" + end.getTypeName() + ":" + end.getId() + "}, Tracking..."); } return true; } public ConfigurationObject find(int type, String Id) { for (ConfigurationObject o : vertices) { if (o.getId() !=null) { //default type doesnt have ID if (o.getType() == type && o.getId() != null && o.getId().equals(Id)) { return o; } } } return null; } public boolean hasDependents(ConfigurationObject o) { for (DirectedEdge e : edges) { if (e.getStart() == o) { return true; } } return false; } public boolean hasActiveDependents(ConfigurationObject o) { for (DirectedEdge e : edges) { if (e.getStart() == o && e.getEnd().getType() != ConfigurationObject.TYPE_UNKNOWN) { return true; } } return false; } public ConfigurationObject[] getDependents(ConfigurationObject o) { List<ConfigurationObject> dependents = new ArrayList<ConfigurationObject>(); for (DirectedEdge e : edges) { if (e.getStart() == o) { dependents.add(e.getEnd()); } } if (dependents.size() > 0) { return dependents.toArray(new ConfigurationObject[dependents.size()]); } return null; } public void resolveObject(ConfigurationObject o, int type) { o.setType(type); if (log.isDebugEnabled()) { log.debug("Configuration object resolved: key : " + o.getId() + ", type : " + o.getTypeName()); } } public void removeDependencies(ConfigurationObject o) { List<DirectedEdge> dependencies = new ArrayList<DirectedEdge>(); for (DirectedEdge e : edges) { if (e.getEnd() == o) { dependencies.add(e); } } for (DirectedEdge e : dependencies) { edges.remove(e); } } }