Added prototype factory - a factory which created instances by cloning a prototype instance; redesigned the service manager to query types from an ITypeLister interface instead of tightly coupling it with the PluginRepository class; added type listers that list all assemblies in an app domain, in a PluginRepository and in a predefined list; renamed the IProgressTrackingService to IProgressCollectingService to make it perfectly clear which service is for which purpose; added Instancing.None to disallow the service manager from providing a certain contract; added CPL headers where they were missing
git-svn-id: file:///srv/devel/repo-conversion/nusu@140 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
4e2beb71b8
commit
c9d9810c28
|
@ -118,11 +118,31 @@
|
|||
<Compile Include="Source\Collections\ReverseComparer.Test.cs">
|
||||
<DependentUpon>ReverseComparer.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Plugins\PrototypeFactory.cs" />
|
||||
<Compile Include="Source\Plugins\PrototypeFactory.Test.cs">
|
||||
<DependentUpon>PrototypeFactory.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\AppDomainTypeLister.cs" />
|
||||
<Compile Include="Source\Services\AppDomainTypeLister.Test.cs">
|
||||
<DependentUpon>AppDomainTypeLister.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\AssemblyTypeLister.cs" />
|
||||
<Compile Include="Source\Services\AssemblyTypeLister.Test.cs">
|
||||
<DependentUpon>AssemblyTypeLister.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\Instancing.cs" />
|
||||
<Compile Include="Source\Services\ITypeLister.cs" />
|
||||
<Compile Include="Source\Services\PredefinedTypeLister.Test.cs">
|
||||
<DependentUpon>PredefinedTypeLister.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\ProgressTracking\IProgressPublishingService.cs" />
|
||||
<Compile Include="Source\Services\ProgressTracking\IProgressTrackingService.cs" />
|
||||
<Compile Include="Source\Services\ProgressTracking\IProgressCollectingService.cs" />
|
||||
<Compile Include="Source\Services\ProgressTracking\ITrackedProcess.cs" />
|
||||
<Compile Include="Source\Services\ProgressTracking\ProgressTrackingComponent.cs" />
|
||||
<Compile Include="Source\Services\RepositoryTypeLister.cs" />
|
||||
<Compile Include="Source\Services\RepositoryTypeLister.Test.cs">
|
||||
<DependentUpon>RepositoryTypeLister.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\ServiceManager.cs" />
|
||||
<Compile Include="Source\Services\ServiceManager.For.cs">
|
||||
<DependentUpon>ServiceManager.cs</DependentUpon>
|
||||
|
@ -233,6 +253,10 @@
|
|||
<Compile Include="Source\Scheduling\ThreadOperation.Test.cs">
|
||||
<DependentUpon>ThreadOperation.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\ServiceManager.Test.cs">
|
||||
<DependentUpon>ServiceManager.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\PredefinedTypeLister.cs" />
|
||||
<Compile Include="Source\Shared.cs" />
|
||||
<Compile Include="Source\Shared.Test.cs">
|
||||
<DependentUpon>Shared.cs</DependentUpon>
|
||||
|
|
|
@ -100,11 +100,31 @@
|
|||
<Compile Include="Source\Collections\ReverseComparer.Test.cs">
|
||||
<DependentUpon>ReverseComparer.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Plugins\PrototypeFactory.cs" />
|
||||
<Compile Include="Source\Plugins\PrototypeFactory.Test.cs">
|
||||
<DependentUpon>PrototypeFactory.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\AppDomainTypeLister.cs" />
|
||||
<Compile Include="Source\Services\AppDomainTypeLister.Test.cs">
|
||||
<DependentUpon>AppDomainTypeLister.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\AssemblyTypeLister.cs" />
|
||||
<Compile Include="Source\Services\AssemblyTypeLister.Test.cs">
|
||||
<DependentUpon>AssemblyTypeLister.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\Instancing.cs" />
|
||||
<Compile Include="Source\Services\ITypeLister.cs" />
|
||||
<Compile Include="Source\Services\PredefinedTypeLister.Test.cs">
|
||||
<DependentUpon>PredefinedTypeLister.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\ProgressTracking\IProgressPublishingService.cs" />
|
||||
<Compile Include="Source\Services\ProgressTracking\IProgressTrackingService.cs" />
|
||||
<Compile Include="Source\Services\ProgressTracking\IProgressCollectingService.cs" />
|
||||
<Compile Include="Source\Services\ProgressTracking\ITrackedProcess.cs" />
|
||||
<Compile Include="Source\Services\ProgressTracking\ProgressTrackingComponent.cs" />
|
||||
<Compile Include="Source\Services\RepositoryTypeLister.cs" />
|
||||
<Compile Include="Source\Services\RepositoryTypeLister.Test.cs">
|
||||
<DependentUpon>RepositoryTypeLister.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\ServiceManager.cs" />
|
||||
<Compile Include="Source\Services\ServiceManager.For.cs">
|
||||
<DependentUpon>ServiceManager.cs</DependentUpon>
|
||||
|
@ -215,6 +235,10 @@
|
|||
<Compile Include="Source\Scheduling\ThreadOperation.Test.cs">
|
||||
<DependentUpon>ThreadOperation.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\ServiceManager.Test.cs">
|
||||
<DependentUpon>ServiceManager.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Services\PredefinedTypeLister.cs" />
|
||||
<Compile Include="Source\Shared.cs" />
|
||||
<Compile Include="Source\Shared.Test.cs">
|
||||
<DependentUpon>Shared.cs</DependentUpon>
|
||||
|
|
141
Source/Plugins/PrototypeFactory.Test.cs
Normal file
141
Source/Plugins/PrototypeFactory.Test.cs
Normal file
|
@ -0,0 +1,141 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Plugins {
|
||||
|
||||
/// <summary>Unit Test for the prototype-based factory class</summary>
|
||||
[TestFixture]
|
||||
public class PrototypeFactoryTest {
|
||||
|
||||
#region interface IProduct
|
||||
|
||||
/// <summary>Interface used for the product in the unit test</summary>
|
||||
private interface IProduct {
|
||||
/// <summary>Some value associated with the product</summary>
|
||||
int Value { get; }
|
||||
}
|
||||
|
||||
#endregion // interface IProduct
|
||||
|
||||
#region class ConcretePrototype
|
||||
|
||||
/// <summary>
|
||||
/// Class derived from the abstract base to serve as concrete product for
|
||||
/// testing the factory employer
|
||||
/// </summary>
|
||||
private class ConcretePrototype : IProduct, ICloneable, IDisposable {
|
||||
|
||||
/// <summary>Initializes a new instance of the prototype product</summary>
|
||||
/// <param name="value">Value that will be associated with this instance</param>
|
||||
public ConcretePrototype(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/// <summary>Immediately releases all resources owned by the instance</summary>
|
||||
public void Dispose() {
|
||||
this.disposed = true;
|
||||
}
|
||||
|
||||
/// <summary>Value the product has been associated with</summary>
|
||||
public int Value { get { return this.value; } }
|
||||
|
||||
/// <summary>Whether the prototype instance has been disposed</summary>
|
||||
public bool IsDisposed {
|
||||
get { return this.disposed; }
|
||||
}
|
||||
|
||||
/// <summary>Creates an identical copy of the instance</summary>
|
||||
/// <returns>An identical copy of the instance</returns>
|
||||
object ICloneable.Clone() {
|
||||
return new ConcretePrototype(this.value);
|
||||
}
|
||||
|
||||
/// <summary>Value associated with the product</summary>
|
||||
private int value;
|
||||
/// <summary>Whether the instance has been disposed</summary>
|
||||
private bool disposed;
|
||||
|
||||
}
|
||||
|
||||
#endregion // class ConcretePrototype
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the prototype-based factory behaves correctly by creating
|
||||
/// new instances of its product using clones of its assigned prototype.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGenericInstanceCreation() {
|
||||
ConcretePrototype template = new ConcretePrototype(42);
|
||||
|
||||
IAbstractFactory<IProduct> factory = new PrototypeFactory<
|
||||
IProduct, ConcretePrototype
|
||||
>(template);
|
||||
|
||||
IProduct factoryCreatedProduct = factory.CreateInstance();
|
||||
|
||||
Assert.AreEqual(template.Value, factoryCreatedProduct.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the prototype-based factory behaves correctly by creating
|
||||
/// new instances of its product using clones of its assigned prototype.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestInstanceCreation() {
|
||||
ConcretePrototype template = new ConcretePrototype(42);
|
||||
|
||||
IAbstractFactory factory = new PrototypeFactory<
|
||||
IProduct, ConcretePrototype
|
||||
>(template);
|
||||
|
||||
IProduct factoryCreatedProduct = (IProduct)factory.CreateInstance();
|
||||
|
||||
Assert.AreEqual(template.Value, factoryCreatedProduct.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the prototype is disposed if it implements the IDisposable
|
||||
/// interface and the factory is explicitely disposed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestPrototypeDisposal() {
|
||||
ConcretePrototype template = new ConcretePrototype(42);
|
||||
|
||||
PrototypeFactory<IProduct, ConcretePrototype> factory = new PrototypeFactory<
|
||||
IProduct, ConcretePrototype
|
||||
>(template);
|
||||
|
||||
Assert.IsFalse(template.IsDisposed);
|
||||
factory.Dispose();
|
||||
Assert.IsTrue(template.IsDisposed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Plugins
|
||||
|
||||
#endif // UNITTEST
|
54
Source/Plugins/PrototypeFactory.cs
Normal file
54
Source/Plugins/PrototypeFactory.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Nuclex.Support.Plugins {
|
||||
|
||||
/// <summary>Factory that creates instances by cloning a prototype</summary>
|
||||
/// <typeparam name="ProductType">Type of product created by the factory</typeparam>
|
||||
/// <typeparam name="ConcreteType">Type of the prototype that will be cloned</typeparam>
|
||||
public class PrototypeFactory<ProductType, ConcreteType> :
|
||||
IAbstractFactory<ProductType>, IAbstractFactory, IDisposable
|
||||
where ProductType : class
|
||||
where ConcreteType : class, ICloneable {
|
||||
|
||||
/// <summary>Initializes a new prototype based factory</summary>
|
||||
/// <param name="prototype">Prototype instance that will be cloned</param>
|
||||
public PrototypeFactory(ConcreteType prototype) {
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the type to which the factory is specialized
|
||||
/// </summary>
|
||||
/// <returns>The newly created instance</returns>
|
||||
public ProductType CreateInstance() {
|
||||
return (ProductType)this.prototype.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the type to which the factory is specialized
|
||||
/// </summary>
|
||||
/// <returns>The newly created instance</returns>
|
||||
object IAbstractFactory.CreateInstance() {
|
||||
return this.prototype.Clone();
|
||||
}
|
||||
|
||||
/// <summary>Immediately releases all resources owned by the instance</summary>
|
||||
public void Dispose() {
|
||||
if(this.prototype != null) {
|
||||
IDisposable disposablePrototype = this.prototype as IDisposable;
|
||||
if(disposablePrototype != null) {
|
||||
disposablePrototype.Dispose();
|
||||
}
|
||||
|
||||
this.prototype = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The prototype object</summary>
|
||||
private ConcreteType prototype;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Plugins
|
73
Source/Services/AppDomainTypeLister.Test.cs
Normal file
73
Source/Services/AppDomainTypeLister.Test.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>Unit Test for the cached app domain type lister</summary>
|
||||
[TestFixture]
|
||||
public class AppDomainTypeListerTest {
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the assembly type list is generated correctly for
|
||||
/// the default constructor (using the calling app domain)
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDefaultConstructur() {
|
||||
AppDomainTypeLister testLister = new AppDomainTypeLister();
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(),
|
||||
Has.Member(typeof(AppDomainTypeListerTest)).And.Member(typeof(Assembly))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the assembly type list is generated correctly for
|
||||
/// the full constructor
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestFullConstructur() {
|
||||
AppDomain newAppDomain = AppDomain.CreateDomain("AppDomainTypeListerTest.Domain");
|
||||
try {
|
||||
AppDomainTypeLister testLister = new AppDomainTypeLister(newAppDomain);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(),
|
||||
Has.Member(typeof(Assembly)).And.No.Member(typeof(AppDomainTypeListerTest))
|
||||
);
|
||||
}
|
||||
finally {
|
||||
AppDomain.Unload(newAppDomain);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
||||
|
||||
#endif // UNITTEST
|
59
Source/Services/AppDomainTypeLister.cs
Normal file
59
Source/Services/AppDomainTypeLister.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
#if !XBOX360
|
||||
|
||||
/// <summary>Lists the types of all assemblies in an application domain</summary>
|
||||
public class AppDomainTypeLister : AssemblyTypeLister {
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new application domain type lister using the application domain
|
||||
/// of the calling method
|
||||
/// </summary>
|
||||
public AppDomainTypeLister() : this(AppDomain.CurrentDomain) { }
|
||||
|
||||
/// <summary>Initializes a new application domain type lister</summary>
|
||||
/// <param name="appDomain">Application domain whose types will be listed</param>
|
||||
public AppDomainTypeLister(AppDomain appDomain) {
|
||||
this.appDomain = appDomain;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains an enumerable list of all assemblies in the application domain
|
||||
/// </summary>
|
||||
/// <returns>An enumerable list of the assemblies in the application domain</returns>
|
||||
protected override IEnumerable<Assembly> GetAssemblies() {
|
||||
return this.appDomain.GetAssemblies();
|
||||
}
|
||||
|
||||
/// <summary>Application domain whose types the lister works on</summary>
|
||||
private AppDomain appDomain;
|
||||
|
||||
}
|
||||
|
||||
#endif // !XBOX360
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
138
Source/Services/AssemblyTypeLister.Test.cs
Normal file
138
Source/Services/AssemblyTypeLister.Test.cs
Normal file
|
@ -0,0 +1,138 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>Unit Test for the cached assembly type lister</summary>
|
||||
[TestFixture]
|
||||
public class AssemblyTypeListerTest {
|
||||
|
||||
#region class TestAssemblyTypeLister
|
||||
|
||||
/// <summary>Test implementation of a cached assembly type lister</summary>
|
||||
private class TestAssemblyTypeLister : AssemblyTypeLister {
|
||||
|
||||
/// <summary>Initializes a new test assembly type lister</summary>
|
||||
/// <param name="assemblies">Assemblies whose types will be listed</param>
|
||||
public TestAssemblyTypeLister(params Assembly[] assemblies) {
|
||||
ReplaceAssemblyList(assemblies);
|
||||
}
|
||||
|
||||
/// <summary>Replaces the list of assemblies whose types to list</summary>
|
||||
/// <param name="assemblies">Assemblies whose types will be listed</param>
|
||||
public void ReplaceAssemblyList(params Assembly[] assemblies) {
|
||||
this.assemblies = assemblies;
|
||||
}
|
||||
|
||||
/// <summary>Obtains a list of any assemblies whose types should be listed</summary>
|
||||
/// <returns>A list of any assemblies whose types to list</returns>
|
||||
protected override IEnumerable<Assembly> GetAssemblies() {
|
||||
return this.assemblies;
|
||||
}
|
||||
|
||||
/// <summary>Assemblies whose types the test assembly type lister lists</summary>
|
||||
private Assembly[] assemblies;
|
||||
|
||||
}
|
||||
|
||||
#endregion // class TestAssemblyTypeLister
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the assembly type list is generated correctly
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAssemblyListGeneration() {
|
||||
TestAssemblyTypeLister testLister = new TestAssemblyTypeLister(
|
||||
typeof(AssemblyTypeListerTest).Assembly
|
||||
);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(), Has.Member(typeof(AssemblyTypeListerTest))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the assembly type list is updated when list of assemblies
|
||||
/// changes inbetween calls
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAssemblyListReplacement() {
|
||||
TestAssemblyTypeLister testLister = new TestAssemblyTypeLister(
|
||||
typeof(Assembly).Assembly,
|
||||
typeof(TestAttribute).Assembly
|
||||
);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(),
|
||||
Has.Member(typeof(TestAttribute)).And.Not.Member(typeof(AssemblyTypeListerTest))
|
||||
);
|
||||
|
||||
testLister.ReplaceAssemblyList(
|
||||
typeof(Assembly).Assembly,
|
||||
typeof(AssemblyTypeListerTest).Assembly
|
||||
);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(),
|
||||
Has.Member(typeof(AssemblyTypeListerTest)).And.Not.Member(typeof(TestAttribute))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the assembly type list is updated when an assembly is removed
|
||||
/// from the list inbetween calls
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAssemblyListRemoval() {
|
||||
TestAssemblyTypeLister testLister = new TestAssemblyTypeLister(
|
||||
typeof(Assembly).Assembly,
|
||||
typeof(TestAttribute).Assembly,
|
||||
typeof(AssemblyTypeListerTest).Assembly
|
||||
);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(),
|
||||
Has.Member(typeof(TestAttribute)).And.Member(typeof(AssemblyTypeListerTest))
|
||||
);
|
||||
|
||||
testLister.ReplaceAssemblyList(
|
||||
typeof(Assembly).Assembly,
|
||||
typeof(AssemblyTypeListerTest).Assembly
|
||||
);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(),
|
||||
Has.Member(typeof(AssemblyTypeListerTest)).And.Not.Member(typeof(TestAttribute))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
||||
|
||||
#endif // UNITTEST
|
143
Source/Services/AssemblyTypeLister.cs
Normal file
143
Source/Services/AssemblyTypeLister.cs
Normal file
|
@ -0,0 +1,143 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>Lists all types in a changing set of assemblies</summary>
|
||||
public abstract class AssemblyTypeLister : ITypeLister {
|
||||
|
||||
#region class AssemblyTypes
|
||||
|
||||
/// <summary>Caches the list of types types for an assembly</summary>
|
||||
private class AssemblyTypes {
|
||||
|
||||
/// <summary>Initializes a new cached assembly types list</summary>
|
||||
/// <param name="assembly">Assembly the types are found in</param>
|
||||
/// <param name="types">Types defined in the assembly</param>
|
||||
public AssemblyTypes(Assembly assembly, Type[] types) {
|
||||
this.Assembly = assembly;
|
||||
this.Types = types;
|
||||
}
|
||||
|
||||
/// <summary>Assembly the types are found in</summary>
|
||||
public Assembly Assembly;
|
||||
/// <summary>Types defined in the assembly</summary>
|
||||
public Type[] Types;
|
||||
|
||||
}
|
||||
|
||||
#endregion // class AssemblyTypes
|
||||
|
||||
/// <summary>Initializes a new assembly type lister</summary>
|
||||
public AssemblyTypeLister() {
|
||||
this.assemblyTypes = new LinkedList<AssemblyTypes>();
|
||||
}
|
||||
|
||||
/// <summary>Enumerates all types in the lister's assembly set</summary>
|
||||
/// <returns>An enumerator over all types in the lister's assembly set</returns>
|
||||
public IEnumerable<Type> GetTypes() {
|
||||
|
||||
// Make sure the assembly list is filled and up-to-date
|
||||
if(this.assemblyTypes.Count == 0) {
|
||||
enlistAssembliesFirstTime();
|
||||
} else {
|
||||
updateAssemblyList();
|
||||
}
|
||||
|
||||
// Iterate over all types in all assemblies
|
||||
LinkedListNode<AssemblyTypes> node = this.assemblyTypes.First;
|
||||
while(node != null) {
|
||||
Type[] types = node.Value.Types;
|
||||
for(int index = 0; index < types.Length; ++index) {
|
||||
yield return types[index];
|
||||
}
|
||||
|
||||
node = node.Next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Called when the assemblies set is queried for the first time</summary>
|
||||
private void enlistAssembliesFirstTime() {
|
||||
foreach(Assembly assembly in GetAssemblies()) {
|
||||
this.assemblyTypes.AddLast(new AssemblyTypes(assembly, assembly.GetTypes()));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Called to update the assembly list if it has changed</summary>
|
||||
private void updateAssemblyList() {
|
||||
LinkedListNode<AssemblyTypes> node = this.assemblyTypes.First;
|
||||
|
||||
foreach(Assembly assembly in GetAssemblies()) {
|
||||
|
||||
// If we reached the end of the cache, this automatically becomes a new entry
|
||||
if(node == null) {
|
||||
this.assemblyTypes.AddLast(new AssemblyTypes(assembly, assembly.GetTypes()));
|
||||
} else { // Otherwise, figure out whether the assembly list has changed
|
||||
|
||||
// Try to locate the cached entry for this assembly. If we have to skip entries,
|
||||
// we know that an assembly might have been removed from the set.
|
||||
LinkedListNode<AssemblyTypes> existingNode = node;
|
||||
while(existingNode.Value.Assembly != assembly) {
|
||||
existingNode = existingNode.Next;
|
||||
if(existingNode == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this assembly wasn't found in the cache, add it in the same order
|
||||
// it was returned by the enumerator.
|
||||
if(existingNode == null) {
|
||||
this.assemblyTypes.AddBefore(
|
||||
node, new AssemblyTypes(assembly, assembly.GetTypes())
|
||||
);
|
||||
} else if(existingNode != node) { // Cached assemblies were skipped, reorder
|
||||
this.assemblyTypes.Remove(existingNode);
|
||||
this.assemblyTypes.AddBefore(node, existingNode);
|
||||
} else { // Everything as expected
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Any nodes behind the last checked node contain cached type lists for assemblies
|
||||
// that are no longer in the set, so these will be removed.
|
||||
while(node != null) {
|
||||
LinkedListNode<AssemblyTypes> nextNode = node.Next;
|
||||
this.assemblyTypes.Remove(node);
|
||||
node = nextNode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Obtains a list of any assemblies whose types should be listed</summary>
|
||||
/// <returns>A list of any assemblies whose types to list</returns>
|
||||
protected abstract IEnumerable<Assembly> GetAssemblies();
|
||||
|
||||
/// <summary>Cached assembly type lists</summary>
|
||||
private LinkedList<AssemblyTypes> assemblyTypes;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
42
Source/Services/ITypeLister.cs
Normal file
42
Source/Services/ITypeLister.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using Nuclex.Support.Plugins;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>
|
||||
/// Provides a type list the service manager uses to locate components
|
||||
/// </summary>
|
||||
public interface ITypeLister {
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerable list of types that will be checked by the service manager
|
||||
/// </summary>
|
||||
/// <returns>An enumerable list of types for the service manager</returns>
|
||||
IEnumerable<Type> GetTypes();
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
|
@ -1,4 +1,24 @@
|
|||
using System;
|
||||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Nuclex.Support.Plugins;
|
||||
|
@ -7,12 +27,19 @@ namespace Nuclex.Support.Services {
|
|||
|
||||
/// <summary>Modes in which services can be instantiated</summary>
|
||||
public enum Instancing {
|
||||
|
||||
/// <summary>Disallow any service from being created for a contract</summary>
|
||||
Never,
|
||||
|
||||
/// <summary>There will only be one service in the whole process</summary>
|
||||
Singleton,
|
||||
|
||||
/// <summary>Each thread will be assigned its own service</summary>
|
||||
InstancePerThread,
|
||||
|
||||
/// <summary>A new service will be created each time it is queried for</summary>
|
||||
Factory
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.DependencyInjection
|
||||
} // namespace Nuclex.Support.Services
|
||||
|
|
103
Source/Services/PredefinedTypeLister.Test.cs
Normal file
103
Source/Services/PredefinedTypeLister.Test.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>Unit Test for the predefined type lister</summary>
|
||||
[TestFixture]
|
||||
public class PredefinedTypeListerTest {
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the type lister correctly takes over a list of types
|
||||
/// supplied manually to the constructor
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestPredefinedTypesFromParams() {
|
||||
ITypeLister testLister = new PredefinedTypeLister(
|
||||
typeof(PredefinedTypeListerTest), typeof(TestAttribute)
|
||||
);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(),
|
||||
Has.Member(typeof(PredefinedTypeListerTest)).And.Member(typeof(TestAttribute))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the type lister correctly takes over a list of types
|
||||
/// supplied as an enumerable list to the constructor
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestPredefinedTypesFromEnumerable() {
|
||||
IEnumerable<Type> types = typeof(PredefinedTypeListerTest).Assembly.GetTypes();
|
||||
ITypeLister testLister = new PredefinedTypeLister(types);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(), Has.Member(typeof(PredefinedTypeListerTest))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that types can be removed from the type lister
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRemoveTypesFromLister() {
|
||||
PredefinedTypeLister testLister = new PredefinedTypeLister(
|
||||
typeof(PredefinedTypeListerTest).Assembly.GetTypes()
|
||||
);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(), Has.Member(typeof(PredefinedTypeListerTest))
|
||||
);
|
||||
testLister.Types.Remove(typeof(PredefinedTypeListerTest));
|
||||
Assert.That(
|
||||
testLister.GetTypes(), Has.No.Member(typeof(PredefinedTypeListerTest))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that types can be added to the type lister
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAddTypesToLister() {
|
||||
PredefinedTypeLister testLister = new PredefinedTypeLister();
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(), Has.No.Member(typeof(TestAttribute))
|
||||
);
|
||||
testLister.Types.Add(typeof(TestAttribute));
|
||||
Assert.That(
|
||||
testLister.GetTypes(), Has.Member(typeof(TestAttribute))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
||||
|
||||
#endif // UNITTEST
|
60
Source/Services/PredefinedTypeLister.cs
Normal file
60
Source/Services/PredefinedTypeLister.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>Type lister that returns a predefined list of types</summary>
|
||||
public class PredefinedTypeLister : ITypeLister {
|
||||
|
||||
/// <summary>Initializes a new predefined type lister</summary>
|
||||
/// <param name="types">Types the predefined type lister will list</param>
|
||||
public PredefinedTypeLister(params Type[] types) {
|
||||
this.types = new List<Type>(types);
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new predefined type lister</summary>
|
||||
/// <param name="types">Types the predefined type lister will list</param>
|
||||
public PredefinedTypeLister(IEnumerable<Type> types) {
|
||||
this.types = new List<Type>(types);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerable list of types that will be checked by the service manager
|
||||
/// </summary>
|
||||
/// <returns>An enumerable list of types for the service manager</returns>
|
||||
public IEnumerable<Type> GetTypes() {
|
||||
return this.types;
|
||||
}
|
||||
|
||||
/// <summary>Predefined list of types the lister will list</summary>
|
||||
public List<Type> Types {
|
||||
get { return this.types; }
|
||||
}
|
||||
|
||||
/// <summary>The predefined list of types</summary>
|
||||
private List<Type> types;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
|
@ -1,4 +1,24 @@
|
|||
using System;
|
||||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Nuclex.Support.Tracking;
|
||||
|
@ -6,7 +26,7 @@ using Nuclex.Support.Tracking;
|
|||
namespace Nuclex.Support.Services.ProgressTracking {
|
||||
|
||||
/// <summary>Allows application-wide tracking of progress</summary>
|
||||
interface IProgressTrackingService {
|
||||
interface IProgressCollectingService {
|
||||
|
||||
/// <summary>Tracks the progress of the specified transaction</summary>
|
||||
/// <param name="transaction">
|
||||
|
@ -62,7 +82,7 @@ namespace Nuclex.Support.Services.ProgressTracking {
|
|||
/// at all, dispite adding it to the progress tracking service).
|
||||
/// </remarks>
|
||||
void Untrack(Transaction transaction);
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.DependencyInjection.ProgressTracking
|
|
@ -1,4 +1,24 @@
|
|||
using System;
|
||||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Nuclex.Support.Tracking;
|
||||
|
|
|
@ -1,4 +1,24 @@
|
|||
using System;
|
||||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Nuclex.Support.Tracking;
|
||||
|
|
|
@ -1,4 +1,24 @@
|
|||
using System;
|
||||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Nuclex.Support.Tracking;
|
||||
|
@ -8,7 +28,7 @@ namespace Nuclex.Support.Services.ProgressTracking {
|
|||
#if false
|
||||
/// <summary>Tracks the progress of running background processes</summary>
|
||||
public class ProgressTrackingComponent :
|
||||
IProgressTrackingService,
|
||||
IProgressCollectingService,
|
||||
IProgressPublishingService {
|
||||
|
||||
/// <summary>Fired when the overall progress changes</summary>
|
||||
|
|
63
Source/Services/RepositoryTypeLister.Test.cs
Normal file
63
Source/Services/RepositoryTypeLister.Test.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>Unit Test for the cached assembly repository type lister</summary>
|
||||
[TestFixture]
|
||||
public class RepositoryTypeListerTest {
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the repository lister can cope with an empty repository
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestEmptyLister() {
|
||||
RepositoryTypeLister testLister = new RepositoryTypeLister();
|
||||
|
||||
Assert.That(testLister.GetTypes(), Is.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the repository lister notices an updated repository
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestLateAdd() {
|
||||
RepositoryTypeLister testLister = new RepositoryTypeLister();
|
||||
testLister.Repository.AddAssembly(typeof(RepositoryTypeListerTest).Assembly);
|
||||
|
||||
Assert.That(
|
||||
testLister.GetTypes(),
|
||||
Has.Member(typeof(RepositoryTypeListerTest))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
||||
|
||||
#endif // UNITTEST
|
72
Source/Services/RepositoryTypeLister.cs
Normal file
72
Source/Services/RepositoryTypeLister.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using Nuclex.Support.Plugins;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>
|
||||
/// Lists the types of all assemblies contained in an assembly repository
|
||||
/// </summary>
|
||||
public class RepositoryTypeLister : AssemblyTypeLister {
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new repository type lister using a new repository
|
||||
/// </summary>
|
||||
public RepositoryTypeLister() : this(new PluginRepository()) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new repository type lister using an existing repository
|
||||
/// </summary>
|
||||
/// <param name="repository">
|
||||
/// Repository containing the assemblies whose types will be listed
|
||||
/// </param>
|
||||
public RepositoryTypeLister(PluginRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerable list of the assemblies in the repository
|
||||
/// </summary>
|
||||
/// <returns>An enumerable list of the assemblies in the repository</returns>
|
||||
protected override IEnumerable<Assembly> GetAssemblies() {
|
||||
return this.repository.LoadedAssemblies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The assembly repository containing the assemblies whose types the lister
|
||||
/// operates on.
|
||||
/// </summary>
|
||||
public PluginRepository Repository {
|
||||
get { return this.repository; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repository containing the assemblies with the type lister's types
|
||||
/// </summary>
|
||||
private PluginRepository repository;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
|
@ -1,4 +1,24 @@
|
|||
using System;
|
||||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
@ -9,7 +29,6 @@ namespace Nuclex.Support.Services {
|
|||
|
||||
#region class ForContext
|
||||
|
||||
// TODO: Rename to "On" to avoid confusion with concept of for loop?
|
||||
/// <summary>Manages the context of the "For" modifier</summary>
|
||||
public class ForContext {
|
||||
|
||||
|
@ -52,7 +71,6 @@ namespace Nuclex.Support.Services {
|
|||
|
||||
#region class ForContext<>
|
||||
|
||||
// TODO: Rename to "On" to avoid confusion with concept of for loop?
|
||||
/// <summary>Manages the context of the "For" modifier</summary>
|
||||
public class ForContext<ContractType> : ForContext {
|
||||
|
||||
|
@ -93,4 +111,4 @@ namespace Nuclex.Support.Services {
|
|||
}
|
||||
#endif
|
||||
|
||||
} // namespace Nuclex.Support.DependencyInjection
|
||||
} // namespace Nuclex.Support.Services
|
||||
|
|
191
Source/Services/ServiceManager.Test.cs
Normal file
191
Source/Services/ServiceManager.Test.cs
Normal file
|
@ -0,0 +1,191 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
/// <summary>Unit Test for the service manager class</summary>
|
||||
[TestFixture]
|
||||
public class ServiceManagerTest {
|
||||
|
||||
#region interface IHelloContract
|
||||
|
||||
/// <summary>A simple contract interface used for testing</summary>
|
||||
public interface IHelloContract { }
|
||||
|
||||
#endregion // interface IHelloContract
|
||||
|
||||
#region interface IWorldContract
|
||||
|
||||
/// <summary>Another simple contract interface used for testing</summary>
|
||||
public interface IWorldContract { }
|
||||
|
||||
#endregion // interface IWorldContract
|
||||
|
||||
#region interface IHaveNoImplementation
|
||||
|
||||
/// <summary>A contract interface that is not implementated anywhere</summary>
|
||||
public interface IHaveNoImplementation { }
|
||||
|
||||
#endregion // interface IHaveNoImplementation
|
||||
|
||||
#region class HelloComponent
|
||||
|
||||
/// <summary>Test component that implements the hello contract</summary>
|
||||
public class HelloComponent : IHelloContract { }
|
||||
|
||||
#endregion // class HelloComponent
|
||||
|
||||
#region class WorldComponent
|
||||
|
||||
/// <summary>
|
||||
/// Test component that implements the world contract and requires
|
||||
/// an implementation of the hello contract
|
||||
/// </summary>
|
||||
public class WorldComponent : IWorldContract, IHelloContract {
|
||||
/// <summary>Initializes a new world component</summary>
|
||||
/// <param name="helloContracts">
|
||||
/// Array of hello contract implementations that will be used
|
||||
/// </param>
|
||||
public WorldComponent(IHelloContract[] helloContracts) { }
|
||||
}
|
||||
|
||||
#endregion // class WorldComponent
|
||||
|
||||
#region class IncompleteComponent
|
||||
|
||||
/// <summary>
|
||||
/// Test component that requires an implementation of a contract that has
|
||||
/// no implementation available
|
||||
/// </summary>
|
||||
public class IncompleteComponent : IWorldContract {
|
||||
/// <summary>Initializes the component</summary>
|
||||
/// <param name="noImplementation">
|
||||
/// Implementation of the unimplemented interface (:P) to use
|
||||
/// </param>
|
||||
public IncompleteComponent(IHaveNoImplementation noImplementation) { }
|
||||
}
|
||||
|
||||
#endregion // class IncompleteComponent
|
||||
|
||||
#region class NeedHello
|
||||
|
||||
/// <summary>Component that needs an implementation of the hello contract</summary>
|
||||
public class NeedHello : IWorldContract {
|
||||
/// <summary>Initializes the component</summary>
|
||||
/// <param name="helloContract">
|
||||
/// Implementation of the hello contract that will be used
|
||||
/// </param>
|
||||
public NeedHello(IHelloContract helloContract) { }
|
||||
}
|
||||
|
||||
#endregion // class NeedHello
|
||||
|
||||
#region class NeedWorld
|
||||
|
||||
/// <summary>Component that needs an implementation of the world contract</summary>
|
||||
public class NeedWorld : IHelloContract {
|
||||
/// <summary>Initializes the component</summary>
|
||||
/// <param name="worldContract">
|
||||
/// Implementation of the world contract that will be used
|
||||
/// </param>
|
||||
public NeedWorld(IWorldContract worldContract) { }
|
||||
}
|
||||
|
||||
#endregion // class NeedWorld
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Tests whether the GetComponents() method behaves correctly if it is used
|
||||
/// without any assemblies loaded
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGetComponentsWithoutAssembly() {
|
||||
ServiceManager serviceManager = new ServiceManager();
|
||||
Assert.That(serviceManager.GetComponents<IDisposable>(), Is.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the GetComponents() method can locate a simple component
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGetComponents() {
|
||||
ServiceManager serviceManager = new ServiceManager();
|
||||
serviceManager.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly);
|
||||
|
||||
Assert.That(
|
||||
serviceManager.GetComponents<IHelloContract>(),
|
||||
Has.Member(typeof(HelloComponent)).And.Member(typeof(WorldComponent))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the GetComponents() method correctly determines which
|
||||
/// components can have their dependencies completely provided.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestFilteredGetComponents() {
|
||||
ServiceManager serviceManager = new ServiceManager();
|
||||
serviceManager.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly);
|
||||
|
||||
Assert.That(
|
||||
serviceManager.GetComponents<IWorldContract>(false),
|
||||
Has.Member(typeof(WorldComponent)).And.Member(typeof(IncompleteComponent))
|
||||
);
|
||||
Assert.That(
|
||||
serviceManager.GetComponents<IWorldContract>(true),
|
||||
Has.Member(typeof(WorldComponent)).And.No.Member(typeof(IncompleteComponent))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the GetComponents() method can cope with two components
|
||||
/// that have a circular dependency through their services.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCircularDependency() {
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the right exception is thrown if the non-generic GetService()
|
||||
/// is used on a value type
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGetComponentOnValueType() {
|
||||
ServiceManager serviceManager = new ServiceManager();
|
||||
serviceManager.Repository.AddAssembly(typeof(int).Assembly);
|
||||
|
||||
Assert.Throws<ArgumentException>(
|
||||
delegate() { serviceManager.GetService(typeof(int)); }
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Services
|
||||
|
||||
#endif // UNITTEST
|
|
@ -1,12 +1,40 @@
|
|||
using System;
|
||||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
using Nuclex.Support.Plugins;
|
||||
|
||||
namespace Nuclex.Support.Services {
|
||||
|
||||
#if false
|
||||
|
||||
// Allow Dependency on Container
|
||||
// public Foo(IServiceProvider serviceProvider)
|
||||
// public Foo(IserviceLocator serviceLocator)
|
||||
// public Foo(Container container)
|
||||
|
||||
/// <summary>
|
||||
/// Inversion of Control container that manages the services of an application
|
||||
/// </summary>
|
||||
|
@ -56,9 +84,110 @@ namespace Nuclex.Support.Services {
|
|||
/// </remarks>
|
||||
public partial class ServiceManager : IServiceProvider {
|
||||
|
||||
#region class Contract
|
||||
|
||||
/// <summary>Stores the settings for an individual contract</summary>
|
||||
private class Contract {
|
||||
|
||||
/// <summary>
|
||||
/// Factory by which instances of the contract implementation can be created
|
||||
/// </summary>
|
||||
public IAbstractFactory Factory;
|
||||
|
||||
/// <summary>How instances of the implementation are to be managed</summary>
|
||||
public Instancing Instancing;
|
||||
|
||||
/// <summary>Single global instance of the contract implementation</summary>
|
||||
/// <remarks>
|
||||
/// Used only if <paramref name="Instancing" /> is set to Singleton
|
||||
/// </remarks>
|
||||
public object SingletonInstance;
|
||||
|
||||
/// <summary>Thread-local instance of the contract implementation</summary>
|
||||
/// <remarks>
|
||||
/// Used only if <paramref name="Instancing" />is set to InstancePerThread
|
||||
/// </remarks>
|
||||
public object ThreadLocalInstance {
|
||||
get {
|
||||
initializeThreadLocalData();
|
||||
return Thread.GetData(this.threadLocalDataSlot);
|
||||
}
|
||||
set {
|
||||
initializeThreadLocalData();
|
||||
Thread.SetData(this.threadLocalDataSlot, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Initializes the thread-local data slot</summary>
|
||||
private void initializeThreadLocalData() {
|
||||
if(this.threadLocalDataSlot == null) {
|
||||
lock(this) {
|
||||
if(this.threadLocalDataSlot == null) {
|
||||
this.threadLocalDataSlot = Thread.AllocateDataSlot();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Arguments to be passed to the component constructor</summary>
|
||||
private Dictionary<string, object> arguments;
|
||||
|
||||
/// <summary>Data slot for thread local storage</summary>
|
||||
/// <remarks>
|
||||
/// We're using an explicit data slot because the ThreadStaticAttribute class
|
||||
/// can only be used on static fields and also because this class is not
|
||||
/// supported by the .NET Compact Framework.
|
||||
/// </remarks>
|
||||
private volatile LocalDataStoreSlot threadLocalDataSlot;
|
||||
|
||||
}
|
||||
|
||||
#endregion // class Contract
|
||||
|
||||
#if !XBOX360
|
||||
|
||||
/// <summary>Initializes a new service manager</summary>
|
||||
public ServiceManager() {
|
||||
this.pluginRepository = new PluginRepository();
|
||||
/// <remarks>
|
||||
/// This overload will automatically use a type lister that causes all types
|
||||
/// in all loaded assemblies of the calling app domain to be considered
|
||||
/// by the service manager for obtaining contract implementations.
|
||||
/// </remarks>
|
||||
public ServiceManager() : this(new AppDomainTypeLister()) { }
|
||||
|
||||
#endif // !XBOX360
|
||||
|
||||
/// <summary>Initializes a new service manager</summary>
|
||||
/// <param name="typeLister">
|
||||
/// Type lister providing the types considered by the service manager for
|
||||
/// obtaining contract implementations.
|
||||
/// </param>
|
||||
public ServiceManager(ITypeLister typeLister) {
|
||||
this.typeLister = typeLister;
|
||||
|
||||
resolveContractMethod = GetType().GetMethod(
|
||||
"resolve", BindingFlags.NonPublic | BindingFlags.Instance
|
||||
);
|
||||
Debug.Assert(this.resolveContractMethod.IsGenericMethodDefinition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all available implementations for the specified contract
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A new enumerator for the available contract implementations
|
||||
/// </returns>
|
||||
public IEnumerable<Type> GetComponents<ContractType>() where ContractType : class {
|
||||
Type contractType = typeof(ContractType);
|
||||
|
||||
foreach(Type checkedType in this.typeLister.GetTypes()) {
|
||||
bool isImplementationOfContract =
|
||||
(!checkedType.IsAbstract) &&
|
||||
contractType.IsAssignableFrom(checkedType);
|
||||
|
||||
if(isImplementationOfContract) {
|
||||
yield return checkedType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -71,31 +200,30 @@ namespace Nuclex.Support.Services {
|
|||
/// <returns>
|
||||
/// A new enumerator for the available contract implementations
|
||||
/// </returns>
|
||||
IEnumerable<ContractType> GetImplementations<ContractType>(bool completeOnly)
|
||||
public IEnumerable<Type> GetComponents<ContractType>(bool completeOnly)
|
||||
where ContractType : class {
|
||||
Type contractType = typeof(ContractType);
|
||||
if(completeOnly) {
|
||||
return filterCompleteComponents(GetComponents<ContractType>());
|
||||
} else {
|
||||
return GetComponents<ContractType>();
|
||||
}
|
||||
}
|
||||
|
||||
Assembly[] loadedAssemblies = this.pluginRepository.LoadedAssemblies.ToArray();
|
||||
for(int index = 0; index < loadedAssemblies.Length; ++index) {
|
||||
Type[] assemblyTypes = loadedAssemblies[index].GetTypes();
|
||||
|
||||
for(int typeIndex = 0; typeIndex < assemblyTypes.Length; ++typeIndex) {
|
||||
Type checkedType = assemblyTypes[typeIndex];
|
||||
if(contractType.IsAssignableFrom(checkedType)) {
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Filters a list of components so only components whose dependencies can be
|
||||
/// completely provided are enumerated
|
||||
/// </summary>
|
||||
/// <param name="types">Enumerable type list that will be filtered</param>
|
||||
/// <returns>
|
||||
/// Only those components whose dependencies can be completely provided
|
||||
/// </returns>
|
||||
private IEnumerable<Type> filterCompleteComponents(IEnumerable<Type> types) {
|
||||
foreach(Type type in types) {
|
||||
yield return type;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
yield break;
|
||||
}
|
||||
|
||||
private struct CachedContractLookUp {
|
||||
public Type[] ValidComponents;
|
||||
public int Version;
|
||||
}
|
||||
private Dictionary<Type, CachedContractLookUp> cachedContracts;
|
||||
private int version;
|
||||
|
||||
/// <summary>
|
||||
/// Allows the adjustment of the container's behavior in regard to
|
||||
|
@ -127,11 +255,11 @@ namespace Nuclex.Support.Services {
|
|||
return new ForContext(this, contractType);
|
||||
}
|
||||
|
||||
// Allow Dependency on Container
|
||||
// public Foo(IServiceProvider serviceProvider)
|
||||
// public Foo(IserviceLocator serviceLocator)
|
||||
// public Foo(Container container)
|
||||
|
||||
/// <summary>Retrieves the service of the specified type</summary>
|
||||
/// <param name="contractType">
|
||||
/// Contract for which the service will be retrieved
|
||||
/// </param>
|
||||
/// <returns>The service for the specified contract</returns>
|
||||
public ContractType GetService<ContractType>() where ContractType : class {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -141,16 +269,44 @@ namespace Nuclex.Support.Services {
|
|||
/// Contract for which the service will be retrieved
|
||||
/// </param>
|
||||
/// <returns>The service for the specified contract</returns>
|
||||
object IServiceProvider.GetService(Type contractType) {
|
||||
throw new NotImplementedException();
|
||||
public object GetService(Type contractType) {
|
||||
MethodInfo methodInstance = this.resolveContractMethod.MakeGenericMethod(
|
||||
new Type[] { contractType }
|
||||
);
|
||||
return methodInstance.Invoke(this, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains all assemblies partaking in the dependency injection scheme
|
||||
/// Resolves all dependencies required to create a service for a contract
|
||||
/// </summary>
|
||||
private PluginRepository pluginRepository;
|
||||
/// <typeparam name="ContractType">
|
||||
/// Type of contract for which to resolve the implementation
|
||||
/// </typeparam>
|
||||
/// <returns>The settings for the contract including a valid factory</returns>
|
||||
private Contract resolveContract<ContractType>() where ContractType : class {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Contract resolveContract(Type contractType) {
|
||||
Contract contract;
|
||||
if(this.contracts.TryGetValue(contractType, out contract)) {
|
||||
return contract;
|
||||
}
|
||||
|
||||
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>MethodInfo for the resolve() method of this instance</summary>
|
||||
private MethodInfo resolveContractMethod;
|
||||
/// <summary>Lists all types partaking in the dependency injection</summary>
|
||||
private ITypeLister typeLister;
|
||||
/// <summary>Dictionary with settings for each individual contract</summary>
|
||||
private Dictionary<Type, Contract> contracts;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Nuclex.Support.DependencyInjection
|
||||
} // namespace Nuclex.Support.Services
|
||||
|
|
Loading…
Reference in New Issue
Block a user