// /* ============================================================================
// Copyright 2014 Hewlett Packard
//
// 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 Openstack.Common.ServiceLocation
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
///
internal class ServiceLocationAssemblyScanner : IServiceLocationAssemblyScanner
{
private IServiceLocationRegistrarFactory ServiceRegistrarFactory { get; set; }
private readonly List _registrars = new List();
private readonly List _assemblies = new List();
///
/// Gets and sets a list of assemblies that have been scanned.
///
internal Func> GetAllAssemblies { get; set; }
///
/// Creates a new instance of the ServiceLocationAssemblyScanner class.
///
public ServiceLocationAssemblyScanner()
{
this.GetAllAssemblies = this.InternalGetAllAssemblies;
this.ServiceRegistrarFactory = new ServiceLocationRegistrarFactory();
}
///
/// Gets a list of all assemblies in the current application domain.
///
/// A list of assembly objects.
internal IEnumerable InternalGetAllAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies();
}
///
public bool HasNewAssemblies()
{
var assemblies = this.GetAllAssemblies().ToList();
this._assemblies.All(assemblies.Remove);
this._assemblies.AddRange(assemblies);
return assemblies.Any();
}
///
public IEnumerable GetRegistrars()
{
var newRegistrars = new List();
if (this.HasNewAssemblies())
{
newRegistrars = this.GetRegistrarTypes().ToList();
}
this._registrars.All(newRegistrars.Remove);
this._registrars.AddRange(newRegistrars);
var objects = (from t in this._registrars
select ServiceRegistrarFactory.Create(t)).ToList();
return objects;
}
///
/// Gets a list of types for any services registrars in the current application domain.
///
/// A list of types.
internal IEnumerable GetRegistrarTypes()
{
var comparer = new AssemblyNameEqualityComparer();
var rawTypes = new List();
var scansedAssemblies = this.GetAllAssemblies();
var workingAssemblies = (from s in scansedAssemblies
where s.GetReferencedAssemblies().Contains(typeof(IServiceLocationRegistrar).Assembly.GetName(), comparer)
select s).ToList();
workingAssemblies.Add(this.GetType().Assembly);
foreach (var assembly in workingAssemblies)
{
try
{
rawTypes.AddRange(assembly.GetTypes());
}
catch (ReflectionTypeLoadException loadEx)
{
var foundTypes = (from t in loadEx.Types where t != null select t).ToList();
rawTypes.AddRange(foundTypes);
}
}
var unorderedTypes = new Queue();
foreach (var type in rawTypes)
{
if (type.IsInterface)
{
continue;
}
if (typeof(IServiceLocationRegistrar).IsAssignableFrom(type) && !ReferenceEquals(type.GetConstructor(new Type[0]), null))
{
unorderedTypes.Enqueue(type);
}
}
var registrarTypes = new List();
while (unorderedTypes.Count > 0)
{
var type = unorderedTypes.Dequeue();
var addToTypesList = true;
foreach (var stackType in unorderedTypes)
{
if (!type.Assembly.GetReferencedAssemblies().Contains(stackType.Assembly.GetName(), comparer))
{
continue;
}
addToTypesList = false;
unorderedTypes.Enqueue(type);
break;
}
if (addToTypesList)
{
registrarTypes.Add(type);
}
}
return registrarTypes;
}
}
}