001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.kernel.basic; 019 020 import org.apache.geronimo.gbean.AbstractName; 021 import org.apache.geronimo.gbean.AbstractNameQuery; 022 import org.apache.geronimo.kernel.DependencyManager; 023 import org.apache.geronimo.kernel.lifecycle.LifecycleAdapter; 024 import org.apache.geronimo.kernel.lifecycle.LifecycleListener; 025 import org.apache.geronimo.kernel.lifecycle.LifecycleMonitor; 026 027 import javax.management.ObjectName; 028 import java.util.Collections; 029 import java.util.HashMap; 030 import java.util.HashSet; 031 import java.util.Iterator; 032 import java.util.Map; 033 import java.util.Set; 034 035 /** 036 * DependencyManager is the record keeper of the dependencies in Geronimo. The DependencyManager 037 * does not enforce any dependencies, it is simply a place where components can register their intent 038 * to be dependent on another component. Since a JMX Component can pretty much do whatever it wants 039 * a component must watch the components it depends on to assure that they are following the 040 * J2EE-Management state machine. 041 * <p/> 042 * The DependencyManager uses the nomenclature of parent-child where a child is dependent on a parent. 043 * The names parent and child have no other meaning are just a convience to make the code readable. 044 * 045 * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $ 046 */ 047 public class BasicDependencyManager implements DependencyManager { 048 /** 049 * The lifecycleMonitor informs us when gbeans go off line, 050 * so we can clean up the lingering dependencies. 051 */ 052 private final LifecycleMonitor lifecycleMonitor; 053 054 /** 055 * Listenes for GBeans to unregister and removes all dependencies associated with the dependency 056 */ 057 private final LifecycleListener lifecycleListener = new DependencyManagerLifecycleListener(); 058 059 /** 060 * A map from child names to a list of parents. 061 */ 062 private final Map childToParentMap = new HashMap(); 063 064 /** 065 * A map from parent back to a list of its children. 066 */ 067 private final Map parentToChildMap = new HashMap(); 068 069 public BasicDependencyManager(LifecycleMonitor lifecycleMonitor) throws Exception { 070 assert lifecycleMonitor != null; 071 this.lifecycleMonitor = lifecycleMonitor; 072 lifecycleMonitor.addLifecycleListener(lifecycleListener, new AbstractNameQuery(null, Collections.EMPTY_MAP, Collections.EMPTY_SET)); 073 } 074 075 public synchronized void close() { 076 lifecycleMonitor.removeLifecycleListener(lifecycleListener); 077 childToParentMap.clear(); 078 parentToChildMap.clear(); 079 } 080 081 /** 082 * Declares a dependency from a child to a parent. 083 * 084 * @param child the dependent component 085 * @param parent the component the child is depending on 086 */ 087 public synchronized void addDependency(AbstractName child, AbstractName parent) { 088 Set parents = (Set) childToParentMap.get(child); 089 if (parents == null) { 090 parents = new HashSet(); 091 childToParentMap.put(child, parents); 092 } 093 parents.add(parent); 094 095 Set children = (Set) parentToChildMap.get(parent); 096 if (children == null) { 097 children = new HashSet(); 098 parentToChildMap.put(parent, children); 099 } 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 }