001    /**
002     *
003     * Copyright 2003-2004 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  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: 384351 $ $Date: 2006-03-08 14:28:35 -0800 (Wed, 08 Mar 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    }