blob: 32f9a910f4d68ec4ffb23238632a7a0a5c259b08 [file] [log] [blame]
/**
*
* Copyright 2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gbean.kernel.simple;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.ObjectName;
import org.gbean.kernel.Kernel;
import org.gbean.kernel.DependencyManager;
import org.gbean.kernel.LifecycleListener;
import org.gbean.kernel.LifecycleAdapter;
import org.gbean.kernel.ServiceName;
/**
* DependencyManager is the record keeper of the dependencies in the kernel. The DependencyManager
* does not enforce any dependencies, it is simply a place where components can register their intent
* to be dependent on another component. Since a service can pretty much do whatever it wants
* a service must watch the services it depends on to assure that they are following the
* lifecycle contract.
* <p/>
* The DependencyManager uses the nomenclature of parent-child where a child is dependent on a parent.
* The names parent and child have no other meaning are just a convience to make the code readable.
*
* @version $Rev: 124822 $ $Date: 2005-01-10 11:01:13 -0800 (Mon, 10 Jan 2005) $
*/
public class SimpleDependencyManager implements DependencyManager {
/**
* The lifecycleMonitor informs us when services go off line,
* so we can clean up the lingering dependencies.
*/
private final Kernel kernel;
/**
* Listenes for services to unregister and removes all dependencies associated with the dependency
*/
private final LifecycleListener lifecycleListener = new DependencyManagerLifecycleListener();
/**
* A map from child names to a list of parents.
*/
private final Map childToParentMap = new HashMap();
/**
* A map from parent back to a list of its children.
*/
private final Map parentToChildMap = new HashMap();
/**
* A map from a component's ObjectName to the list of ObjectPatterns that the component is blocking
* from starting.
*/
private final Map startHoldsMap = new HashMap();
private static final ObjectName ALL = ServiceName.createName("*:*");
public SimpleDependencyManager(Kernel kernel) {
assert kernel != null;
this.kernel = kernel;
}
// todo throw illegal state from all methods when not started
public synchronized void start() {
this.kernel.addLifecycleListener(lifecycleListener, ALL);
}
public synchronized void stop() {
kernel.removeLifecycleListener(lifecycleListener);
childToParentMap.clear();
parentToChildMap.clear();
startHoldsMap.clear();
}
/**
* Declares a dependency from a child to a parent.
*
* @param child the dependent component
* @param parent the component the child is depending on
*/
public synchronized void addDependency(ObjectName child, ObjectName parent) {
Set parents = (Set) childToParentMap.get(child);
if (parents == null) {
parents = new HashSet();
childToParentMap.put(child, parents);
}
parents.add(parent);
Set children = (Set) parentToChildMap.get(parent);
if (children == null) {
children = new HashSet();
parentToChildMap.put(parent, children);
}
children.add(child);
}
/**
* Removes a dependency from a child to a parent
*
* @param child the dependnet component
* @param parent the component that the child wil no longer depend on
*/
public synchronized void removeDependency(ObjectName child, ObjectName parent) {
Set parents = (Set) childToParentMap.get(child);
if (parents != null) {
parents.remove(parent);
}
Set children = (Set) parentToChildMap.get(parent);
if (children != null) {
children.remove(child);
}
}
/**
* Removes all dependencies for a child
*
* @param child the component that will no longer depend on anything
*/
public synchronized void removeAllDependencies(ObjectName child) {
Set parents = (Set) childToParentMap.remove(child);
if (parents == null) {
return;
}
for (Iterator iterator = parents.iterator(); iterator.hasNext();) {
ObjectName parent = (ObjectName) iterator.next();
Set children = (Set) parentToChildMap.get(parent);
if (children != null) {
children.remove(child);
}
}
}
/**
* Adds dependencies from the child to every parent in the parents set
*
* @param child the dependent component
* @param parents the set of components the child is depending on
*/
public synchronized void addDependencies(ObjectName child, Set parents) {
Set existingParents = (Set) childToParentMap.get(child);
if (existingParents == null) {
existingParents = new HashSet(parents);
childToParentMap.put(child, existingParents);
} else {
existingParents.addAll(parents);
}
for (Iterator i = parents.iterator(); i.hasNext();) {
Object startParent = i.next();
Set children = (Set) parentToChildMap.get(startParent);
if (children == null) {
children = new HashSet();
parentToChildMap.put(startParent, children);
}
children.add(child);
}
}
/**
* Gets the set of parents that the child is depending on
*
* @param child the dependent component
* @return a collection containing all of the components the child depends on; will never be null
*/
public synchronized Set getParents(ObjectName child) {
Set parents = (Set) childToParentMap.get(child);
if (parents == null) {
return Collections.EMPTY_SET;
}
return new HashSet(parents);
}
/**
* Gets all of the services that have a dependency on the specified startParent.
*
* @param parent the component the returned childen set depend on
* @return a collection containing all of the components that depend on the parent; will never be null
*/
public synchronized Set getChildren(ObjectName parent) {
Set children = (Set) parentToChildMap.get(parent);
if (children == null) {
return Collections.EMPTY_SET;
}
return new HashSet(children);
}
/**
* Adds a hold on a collection of object name patterns. If the name of a component matches an object name
* pattern in the collection, the component should not start.
*
* @param objectName the name of the component placing the holds
* @param holds a collection of object name patterns which should not start
*/
public synchronized void addStartHolds(ObjectName objectName, Collection holds) {
Collection currentHolds = (Collection) startHoldsMap.get(objectName);
if (currentHolds == null) {
currentHolds = new LinkedList(holds);
startHoldsMap.put(objectName, currentHolds);
} else {
currentHolds.addAll(holds);
}
}
/**
* Removes a collection of holds.
*
* @param objectName the object name of the components owning the holds
* @param holds a collection of the holds to remove
*/
public synchronized void removeStartHolds(ObjectName objectName, Collection holds) {
Collection currentHolds = (Collection) startHoldsMap.get(objectName);
if (currentHolds != null) {
currentHolds.removeAll(holds);
}
}
/**
* Removes all of the holds owned by a component.
*
* @param objectName the object name of the component that will no longer have any holds
*/
public synchronized void removeAllStartHolds(ObjectName objectName) {
startHoldsMap.remove(objectName);
}
/**
* Gets the object name of the service blocking the start specified service.
*
* @param objectName the service to check for blockers
* @return the service blocking the specified service, or null if there are no blockers
*/
public synchronized ObjectName checkBlocker(ObjectName objectName) {
// check if objectName name is on one of the hold lists
for (Iterator iterator = startHoldsMap.keySet().iterator(); iterator.hasNext();) {
ObjectName blocker = (ObjectName) iterator.next();
List holds = (List) startHoldsMap.get(blocker);
for (Iterator holdsIterator = holds.iterator(); holdsIterator.hasNext();) {
ObjectName pattern = (ObjectName) holdsIterator.next();
if (pattern.apply(objectName)) {
return blocker;
}
}
}
return null;
}
private class DependencyManagerLifecycleListener extends LifecycleAdapter {
public void unloaded(ObjectName objectName) {
synchronized (SimpleDependencyManager.this) {
removeAllDependencies(objectName);
removeAllStartHolds(objectName);
}
}
}
}