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 }