/*
* Copyright 2003-2004 The Apache Software Foundation
* 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.
*/
namespace Apache.Avalon.Composition.Model
{
using System;
///
Utility class to aquire an ordered graph of
/// consumers and providers models.
///
///
/// Avalon Development Team
///
/// $Revision: 1.1 $ $Date: 2004/02/28 22:15:43 $
///
public class DependencyGraph
{
private void InitBlock()
{
m_models = new System.Collections.ArrayList();
m_children = new System.Collections.ArrayList();
}
/// Get the serilized graph of {@link IDeploymentModel} objects
/// required when starting up the target. This makes sure
/// that all providers are established before their coresponding
/// consumers in the graph.
///
///
/// the ordered list of models
///
public virtual IDeploymentModel[] StartupGraph
{
get
{
try
{
return WalkGraph(true);
}
catch (System.Exception e)
{
System.String error = "Unexpect error while resolving startup graph.";
throw new ModelRuntimeException(error, e);
}
}
}
/// Get the serilized graph of {@link IDeploymentModel} instances
/// required when shutting down all the components. This makes
/// sure that all consumer shutdown actions occur before their
/// coresponding providers in graph.
///
///
/// the ordered list of model instances
///
public virtual IDeploymentModel[] ShutdownGraph
{
get
{
try
{
return WalkGraph(false);
}
catch (System.Exception e)
{
System.String error = "Unexpect error while resolving shutdown graph.";
throw new ModelRuntimeException(error, e);
}
}
}
/// Parent Map. Components in the parent
/// Map are potential Providers for services
/// if no model in the current graph satisfies
/// a dependency.
///
private DependencyGraph m_parent;
/// The set of models declared by the container as available.
/// Used when searching for providers/consumers.
///
private System.Collections.ArrayList m_models;
/// The child {@link DependencyGraph} objects.
/// Possible consumers of services in this assembly.
///
private System.Collections.ArrayList m_children;
/// Creation of a new empty dependency graph.
public DependencyGraph():this(null)
{
}
/// Creation of a new dependecy graph holding a reference to a parent
/// graph. IDeploymentModel instances in the parent graph are potential providers
/// for services if no model in current assembly satisfies a dependency.
///
///
/// the parent graph
///
public DependencyGraph(DependencyGraph parent)
{
InitBlock();
m_parent = parent;
}
/// Addition of a consumer dependency graph.
///
///
/// the child map
///
public virtual void AddChild(DependencyGraph child)
{
m_children.Add(child);
}
/// Removal of a consumer dependency graph.
///
///
/// the child map
///
public virtual void RemoveChild(DependencyGraph child)
{
m_children.Remove(child);
}
/// Add a model to current dependency graph.
///
///
/// the model to add to the graph
///
public virtual void Add(IDeploymentModel model)
{
if (!m_models.Contains(model))
{
m_models.Add(model);
}
}
/// Remove a model from the dependency graph.
///
///
/// the model to remove
///
public virtual void Remove(IDeploymentModel model)
{
m_models.Remove(model);
}
/// Get the serilized graph of {@link IDeploymentModel} instances
/// that use services of the specified model.
///
///
/// the model
///
/// the ordered list of consumer model instances
///
public virtual IDeploymentModel[] GetConsumerGraph(IDeploymentModel model)
{
if (m_parent != null)
return m_parent.GetConsumerGraph(model);
try
{
IDeploymentModel[] graph = GetComponentGraph(model, false);
return ReferencedModels(model, graph);
}
catch (System.Exception e)
{
System.String error = "Unexpect error while resolving consumer graph for model: " + model;
throw new ModelRuntimeException(error, e);
}
}
/// Get the serilized graph of {@link IDeploymentModel} istances
/// that provide specified model with services.
///
///
/// the model
///
/// the ordered list of providers
///
public virtual IDeploymentModel[] GetProviderGraph(IDeploymentModel model)
{
try
{
return ReferencedModels(model, GetComponentGraph(model, true));
}
catch (System.Exception e)
{
System.String error = "Unexpect error while resolving provider graph for: " + model;
throw new ModelRuntimeException(error, e);
}
}
/// Return an model array that does not include the provided model.
private IDeploymentModel[] ReferencedModels(IDeploymentModel model, IDeploymentModel[] models)
{
System.Collections.ArrayList list = new System.Collections.ArrayList();
for (int i = 0; i < models.Length; i++)
{
if (!models[i].Equals(model))
{
list.Add(models[i]);
}
}
return (IDeploymentModel[]) list.ToArray( typeof(IDeploymentModel) );
}
/// Get the graph of a single model.
///
///
/// the target model
///
/// true if traversing providers, false if consumers
///
/// the list of models
///
private IDeploymentModel[] GetComponentGraph(IDeploymentModel model, bool providers)
{
System.Collections.ArrayList result = new System.Collections.ArrayList();
Visitcomponent(model, providers, new System.Collections.ArrayList(), result);
return (IDeploymentModel[]) result.ToArray( typeof(IDeploymentModel) );
}
/// Method to generate an ordering of nodes to traverse.
/// It is expected that the specified components have passed
/// verification tests and are well formed.
///
///
/// true if forward dependencys traced, false if
/// dependencies reversed
///
/// the ordered model list
///
private IDeploymentModel[] WalkGraph(bool direction)
{
System.Collections.ArrayList result = new System.Collections.ArrayList();
System.Collections.ArrayList done = new System.Collections.ArrayList();
int size = m_models.Count;
for (int i = 0; i < size; i++)
{
IDeploymentModel model = (IDeploymentModel) m_models[i];
Visitcomponent(model, direction, done, result);
}
return (IDeploymentModel[]) result.ToArray( typeof(IDeploymentModel) );
}
/// Visit a model when traversing dependencies.
///
///
/// the model
///
/// true if walking tree looking for providers, else false
///
/// those nodes already traversed
///
/// the order in which nodes have already been
/// traversed
///
private void Visitcomponent(IDeploymentModel model, bool direction, System.Collections.ArrayList done, System.Collections.ArrayList order)
{
//If already visited this model return
if (done.Contains(model))
return ;
done.Add(model);
if (direction)
{
VisitProviders(model, done, order);
}
else
{
VisitConsumers(model, done, order);
}
order.Add(model);
}
/// Traverse graph of components that provide services to
/// the specified model.
///
/// the model
///
private void VisitProviders(IDeploymentModel model, System.Collections.ArrayList done, System.Collections.ArrayList order)
{
IDeploymentModel[] providers = model.Providers;
for (int i = (providers.Length - 1); i > - 1; i--)
{
Visitcomponent(providers[i], true, done, order);
}
}
/// Traverse all consumers of a model. I.e. all models that use
/// service provided by the supplied model.
///
/// the IDeploymentModel
///
private void VisitConsumers(IDeploymentModel model, System.Collections.ArrayList done, System.Collections.ArrayList order)
{
int size = m_models.Count;
for (int i = 0; i < size; i++)
{
IDeploymentModel other = (IDeploymentModel) m_models[i];
IDeploymentModel[] providers = other.Providers;
for (int j = 0; j < providers.Length; j++)
{
IDeploymentModel provider = providers[j];
if (provider.Equals(model))
{
Visitcomponent(other, false, done, order);
}
}
}
int childCount = m_children.Count;
for (int i = 0; i < childCount; i++)
{
DependencyGraph map = (DependencyGraph) m_children[i];
map.VisitConsumers(model, done, order);
}
}
}
}