/*
* 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.Default
{
using System;
using Apache.Avalon.Framework;
using Apache.Avalon.Meta;
using Apache.Avalon.Composition.Model;
using Apache.Avalon.Composition.Data;
/// Default implementation of the deplendency model.
///
///
/// Avalon Development Team
///
/// $Revision: 1.3 $ $Date: 2004/03/07 22:06:40 $
///
public class DefaultDependencyModel : DefaultDependent, IDependencyModel
{
//--------------------------------------------------------------
// static
//--------------------------------------------------------------
//--------------------------------------------------------------
// immutable state
//--------------------------------------------------------------
private DependencyDescriptor m_descriptor;
private DependencyDirective m_directive;
private String m_partition;
private String m_name;
private String m_source;
//--------------------------------------------------------------
// constructor
//--------------------------------------------------------------
/// Creation of a new dependency model.
///
///
/// the logging channel
///
/// the partition
///
/// the name
///
/// the dependency descriptor
///
/// the dependency directive (possibly null)
///
public DefaultDependencyModel(ILogger logger, String partition, String name, DependencyDescriptor descriptor, DependencyDirective directive):base(logger)
{
if (descriptor == null)
throw new System.ArgumentNullException("descriptor");
m_descriptor = descriptor;
m_directive = directive;
m_partition = partition;
m_name = name;
//
// a dependency directive is either declaring an explicitly
// identified provider, or, it is delcaring 0 or more selection
// constraints - if its a an absolute source declaration then
// add it to the table to paths keyed by depedency key names
//
if (directive != null)
{
if ((System.Object) directive.Source != null)
{
m_source = resolvePath(partition, directive.Source);
String message = "dependency.path.debug" + " " + m_source + " " + directive.Key;
Logger.Debug(message);
}
else
{
m_source = null;
}
}
else
{
m_source = null;
}
}
//--------------------------------------------------------------
// IDependencyModel
//--------------------------------------------------------------
/// Return the dependency descriptor.
///
///
/// the descriptor
///
public virtual DependencyDescriptor Dependency
{
get
{
return m_descriptor;
}
}
/// Return an explicit path to a supplier component.
/// If a dependency directive has been declared
/// and the directive contains a source declaration, the value
/// returned is the result of parsing the source value relative
/// to the absolute address of the implementing component.
///
/// the explicit path
///
public virtual String Path
{
get
{
return m_source;
}
}
/// Filter a set of candidate service descriptors and return the
/// set of acceptable service as a ordered sequence.
///
///
/// the set of candidate services for the dependency
/// matching the supplied key
///
/// the accepted candidates in ranked order
///
/// IllegalArgumentException if the key is unknown
///
public virtual ServiceDescriptor[] Filter(ServiceDescriptor[] candidates)
{
if (m_directive != null)
{
if ((System.Object) m_directive.Source == null)
{
return Filter(m_directive, candidates);
}
}
return candidates;
}
/// Filter a set of candidate service descriptors and return the
/// set of acceptable service as a ordered sequence.
///
///
/// the dependency directive
///
/// the set of candidate services for the dependency
///
/// the accepted candidates in ranked order
///
private ServiceDescriptor[] Filter(DependencyDirective directive, ServiceDescriptor[] services)
{
SelectionDirective[] filters = GetFilters(directive);
System.Collections.ArrayList list = new System.Collections.ArrayList();
for (int i = 0; i < services.Length; i++)
{
ServiceDescriptor service = services[i];
if (IsaCandidate(service, filters))
{
list.Add(service);
}
}
ServiceDescriptor[] candidates = (ServiceDescriptor[]) list.ToArray( typeof(ServiceDescriptor) );
//
// TODO: include ranking of candidates
//
return candidates;
}
private bool IsaCandidate(ServiceDescriptor service, SelectionDirective[] filters)
{
for (int i = 0; i < filters.Length; i++)
{
SelectionDirective filter = filters[i];
if (!IsaCandidate(service, filter))
{
return false;
}
}
return true;
}
private bool IsaCandidate(ServiceDescriptor service, SelectionDirective filter)
{
String feature = filter.Feature;
String value_Renamed = filter.Value;
String criteria = filter.Criteria;
if (criteria.Equals(SelectionDirective.EQUALS))
{
return value_Renamed.Equals(service.GetAttribute(feature));
}
else if (criteria.Equals(SelectionDirective.EXISTS))
{
return service.GetAttribute(feature) != null;
}
else if (criteria.Equals(SelectionDirective.INCLUDES))
{
String v = service.GetAttribute(feature);
if ((System.Object) v != null)
{
return v.IndexOf(value_Renamed) > - 1;
}
else
{
return false;
}
}
else
{
String error = "dependency.invalid-criteria.error" + " " + criteria + " " + feature;
throw new System.ArgumentException(error);
}
}
private String resolvePath(String partition, String path)
{
if (path.StartsWith("/"))
{
return path;
}
else if (path.StartsWith("../"))
{
String parent = GetParenPath(partition);
return resolvePath(parent, path.Substring(3));
}
else if (path.StartsWith("./"))
{
return resolvePath(partition, path.Substring(2));
}
else
{
return partition + path;
}
}
private String GetParenPath(String partition)
{
int n = partition.LastIndexOf("/");
if (n > 0)
{
int index = partition.Substring(0, (n - 1) - (0)).LastIndexOf("/");
if (index == 0)
{
return "/";
}
else
{
return partition.Substring(0, (index) - (0)) + "/";
}
}
else
{
String error = "Illegal attempt to reference a containment context above the root context.";
throw new System.ArgumentException(error);
}
}
/// Return the required selection constraints.
/// the dependency directive
///
/// the set of required selection directives
///
private SelectionDirective[] GetFilters(DependencyDirective directive)
{
System.Collections.ArrayList list = new System.Collections.ArrayList();
SelectionDirective[] selections = directive.SelectionDirectives;
for (int i = 0; i < selections.Length; i++)
{
SelectionDirective selection = selections[i];
if (selection.Required)
{
list.Add(selection);
}
}
return (SelectionDirective[]) list.ToArray( typeof(SelectionDirective) );
}
}
}