1 /** 2 * 3 * Copyright 2003-2004 The Apache Software Foundation 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.apache.geronimo.kernel.basic; 19 20 import org.apache.geronimo.gbean.AbstractName; 21 import org.apache.geronimo.gbean.AbstractNameQuery; 22 import org.apache.geronimo.kernel.DependencyManager; 23 import org.apache.geronimo.kernel.lifecycle.LifecycleAdapter; 24 import org.apache.geronimo.kernel.lifecycle.LifecycleListener; 25 import org.apache.geronimo.kernel.lifecycle.LifecycleMonitor; 26 27 import javax.management.ObjectName; 28 import java.util.Collections; 29 import java.util.HashMap; 30 import java.util.HashSet; 31 import java.util.Iterator; 32 import java.util.Map; 33 import java.util.Set; 34 35 /** 36 * DependencyManager is the record keeper of the dependencies in Geronimo. The DependencyManager 37 * does not enforce any dependencies, it is simply a place where components can register their intent 38 * to be dependent on another component. Since a JMX Component can pretty much do whatever it wants 39 * a component must watch the components it depends on to assure that they are following the 40 * J2EE-Management state machine. 41 * <p/> 42 * The DependencyManager uses the nomenclature of parent-child where a child is dependent on a parent. 43 * The names parent and child have no other meaning are just a convience to make the code readable. 44 * 45 * @version $Rev: 384351 $ $Date: 2006-03-08 14:28:35 -0800 (Wed, 08 Mar 2006) $ 46 */ 47 public class BasicDependencyManager implements DependencyManager { 48 /** 49 * The lifecycleMonitor informs us when gbeans go off line, 50 * so we can clean up the lingering dependencies. 51 */ 52 private final LifecycleMonitor lifecycleMonitor; 53 54 /** 55 * Listenes for GBeans to unregister and removes all dependencies associated with the dependency 56 */ 57 private final LifecycleListener lifecycleListener = new DependencyManagerLifecycleListener(); 58 59 /** 60 * A map from child names to a list of parents. 61 */ 62 private final Map childToParentMap = new HashMap(); 63 64 /** 65 * A map from parent back to a list of its children. 66 */ 67 private final Map parentToChildMap = new HashMap(); 68 69 public BasicDependencyManager(LifecycleMonitor lifecycleMonitor) throws Exception { 70 assert lifecycleMonitor != null; 71 this.lifecycleMonitor = lifecycleMonitor; 72 lifecycleMonitor.addLifecycleListener(lifecycleListener, new AbstractNameQuery(null, Collections.EMPTY_MAP, Collections.EMPTY_SET)); 73 } 74 75 public synchronized void close() { 76 lifecycleMonitor.removeLifecycleListener(lifecycleListener); 77 childToParentMap.clear(); 78 parentToChildMap.clear(); 79 } 80 81 /** 82 * Declares a dependency from a child to a parent. 83 * 84 * @param child the dependent component 85 * @param parent the component the child is depending on 86 */ 87 public synchronized void addDependency(AbstractName child, AbstractName parent) { 88 Set parents = (Set) childToParentMap.get(child); 89 if (parents == null) { 90 parents = new HashSet(); 91 childToParentMap.put(child, parents); 92 } 93 parents.add(parent); 94 95 Set children = (Set) parentToChildMap.get(parent); 96 if (children == null) { 97 children = new HashSet(); 98 parentToChildMap.put(parent, children); 99 } 100 children.add(child); 101 } 102 103 /** 104 * Removes a dependency from a child to a parent 105 * 106 * @param child the dependnet component 107 * @param parent the component that the child wil no longer depend on 108 */ 109 public synchronized void removeDependency(AbstractName child, AbstractName parent) { 110 Set parents = (Set) childToParentMap.get(child); 111 if (parents != null) { 112 parents.remove(parent); 113 } 114 115 Set children = (Set) parentToChildMap.get(parent); 116 if (children != null) { 117 children.remove(child); 118 } 119 } 120 121 /** 122 * Removes all dependencies for a child 123 * 124 * @param child the component that will no longer depend on anything 125 */ 126 public synchronized void removeAllDependencies(AbstractName child) { 127 Set parents = (Set) childToParentMap.remove(child); 128 if (parents == null) { 129 return; 130 } 131 for (Iterator iterator = parents.iterator(); iterator.hasNext();) { 132 ObjectName parent = (ObjectName) iterator.next(); 133 Set children = (Set) parentToChildMap.get(parent); 134 if (children != null) { 135 children.remove(child); 136 } 137 138 } 139 } 140 141 /** 142 * Adds dependencies from the child to every parent in the parents set 143 * 144 * @param child the dependent component 145 * @param parents the set of components the child is depending on 146 */ 147 public synchronized void addDependencies(AbstractName child, Set parents) { 148 Set existingParents = (Set) childToParentMap.get(child); 149 if (existingParents == null) { 150 existingParents = new HashSet(parents); 151 childToParentMap.put(child, existingParents); 152 } else { 153 existingParents.addAll(parents); 154 } 155 156 for (Iterator i = parents.iterator(); i.hasNext();) { 157 Object startParent = i.next(); 158 Set children = (Set) parentToChildMap.get(startParent); 159 if (children == null) { 160 children = new HashSet(); 161 parentToChildMap.put(startParent, children); 162 } 163 children.add(child); 164 } 165 } 166 167 /** 168 * Gets the set of parents that the child is depending on 169 * 170 * @param child the dependent component 171 * @return a collection containing all of the components the child depends on; will never be null 172 */ 173 public synchronized Set getParents(AbstractName child) { 174 Set parents = (Set) childToParentMap.get(child); 175 if (parents == null) { 176 return Collections.EMPTY_SET; 177 } 178 return new HashSet(parents); 179 } 180 181 /** 182 * Gets all of the MBeans that have a dependency on the specified startParent. 183 * 184 * @param parent the component the returned childen set depend on 185 * @return a collection containing all of the components that depend on the parent; will never be null 186 */ 187 public synchronized Set getChildren(AbstractName parent) { 188 Set children = (Set) parentToChildMap.get(parent); 189 if (children == null) { 190 return Collections.EMPTY_SET; 191 } 192 return new HashSet(children); 193 } 194 195 196 private class DependencyManagerLifecycleListener extends LifecycleAdapter { 197 public void unloaded(AbstractName abstractName) { 198 synchronized (BasicDependencyManager.this) { 199 removeAllDependencies(abstractName); 200 } 201 202 } 203 } 204 }