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 }