From 11f6ecc4d425878e32aadac1271fb08af287a65c Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 11 Aug 2015 12:56:18 +0100 Subject: [PATCH 1/5] Added unit test for CompositionStrategy. --- .../ShellBuilders/CompositionStrategyTests.cs | 109 ++++++++++++++++++ .../TestDependencies/AlphaDependency.cs | 8 ++ .../TestDependencies/BetaDependency.cs | 13 +++ .../Orchard.Framework.Tests.csproj | 3 + .../ShellBuilders/CompositionStrategy.cs | 2 +- 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/Orchard.Tests/Environment/ShellBuilders/CompositionStrategyTests.cs create mode 100644 src/Orchard.Tests/Environment/TestDependencies/AlphaDependency.cs create mode 100644 src/Orchard.Tests/Environment/TestDependencies/BetaDependency.cs diff --git a/src/Orchard.Tests/Environment/ShellBuilders/CompositionStrategyTests.cs b/src/Orchard.Tests/Environment/ShellBuilders/CompositionStrategyTests.cs new file mode 100644 index 000000000..d41f5d087 --- /dev/null +++ b/src/Orchard.Tests/Environment/ShellBuilders/CompositionStrategyTests.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autofac; +using Moq; +using NUnit.Framework; +using Orchard.Environment.Configuration; +using Orchard.Environment.Descriptor.Models; +using Orchard.Environment.Extensions; +using Orchard.Environment.Extensions.Models; +using Orchard.Environment.ShellBuilders; +using Orchard.Tests.Environment.TestDependencies; +using Orchard.Utility; +using Orchard.Utility.Extensions; + +namespace Orchard.Tests.Environment.ShellBuilders { + [TestFixture] + public class CompositionStrategyTests : ContainerTestBase { + private CompositionStrategy _compositionStrategy; + private Mock _extensionManager; + + protected override void Register(ContainerBuilder builder) { + _extensionManager = new Mock(MockBehavior.Loose); + + builder.RegisterType().AsSelf(); + builder.RegisterInstance(_extensionManager.Object); + } + + protected override void Resolve(ILifetimeScope container) { + _compositionStrategy = container.Resolve(); + + var alphaExtension = new ExtensionDescriptor { + Id = "Alpha", + Name = "Alpha", + ExtensionType = "Module" + }; + + var alphaFeatureDescriptor = new FeatureDescriptor { + Id = "Alpha", + Name = "Alpha", + Extension = alphaExtension + }; + + var betaFeatureDescriptor = new FeatureDescriptor { + Id = "Beta", + Name = "Beta", + Extension = alphaExtension, + Dependencies = new List { + "Alpha" + } + }; + + alphaExtension.Features = new List { + alphaFeatureDescriptor, + betaFeatureDescriptor + }; + + var features = new List { + new Feature { + Descriptor = alphaFeatureDescriptor, + ExportedTypes = new List { + typeof(AlphaDependency) + } + }, + new Feature { + Descriptor = betaFeatureDescriptor, + ExportedTypes = new List { + typeof(BetaDependency) + } + } + }; + + _extensionManager.Setup(x => x.AvailableExtensions()).Returns(new List { + alphaExtension + }); + + _extensionManager.Setup(x => x.AvailableFeatures()).Returns( + _extensionManager.Object.AvailableExtensions() + .SelectMany(ext => ext.Features) + .ToReadOnlyCollection()); + + _extensionManager.Setup(x => x.LoadFeatures(It.IsAny>())).Returns(features); + } + + [Test] + public void ComposeReturnsBlueprintWithExpectedDependencies() { + var shellSettings = CreateShell(); + var shellDescriptor = CreateShellDescriptor("Alpha", "Beta"); + var shellBlueprint = _compositionStrategy.Compose(shellSettings, shellDescriptor); + + Assert.That(shellBlueprint.Dependencies.Count(x => x.Type == typeof (AlphaDependency)), Is.EqualTo(1)); + Assert.That(shellBlueprint.Dependencies.Count(x => x.Type == typeof(BetaDependency)), Is.EqualTo(1)); + } + + private ShellSettings CreateShell() { + return new ShellSettings(); + } + + private ShellDescriptor CreateShellDescriptor(params string[] enabledFeatures) { + var shellDescriptor = new ShellDescriptor { + Features = enabledFeatures.Select(x => new ShellFeature { + Name = x + }) + }; + + return shellDescriptor; + } + } +} diff --git a/src/Orchard.Tests/Environment/TestDependencies/AlphaDependency.cs b/src/Orchard.Tests/Environment/TestDependencies/AlphaDependency.cs new file mode 100644 index 000000000..d27fa3183 --- /dev/null +++ b/src/Orchard.Tests/Environment/TestDependencies/AlphaDependency.cs @@ -0,0 +1,8 @@ +namespace Orchard.Tests.Environment.TestDependencies { + + public interface IAlphaDependency : IDependency { + } + + public class AlphaDependency : IAlphaDependency { + } +} diff --git a/src/Orchard.Tests/Environment/TestDependencies/BetaDependency.cs b/src/Orchard.Tests/Environment/TestDependencies/BetaDependency.cs new file mode 100644 index 000000000..2e4974c04 --- /dev/null +++ b/src/Orchard.Tests/Environment/TestDependencies/BetaDependency.cs @@ -0,0 +1,13 @@ +namespace Orchard.Tests.Environment.TestDependencies { + + public interface IBetaDependency : IDependency { + } + + public class BetaDependency : IBetaDependency { + public IAlphaDependency Alpha { get; set; } + + public BetaDependency(IAlphaDependency alpha) { + Alpha = alpha; + } + } +} diff --git a/src/Orchard.Tests/Orchard.Framework.Tests.csproj b/src/Orchard.Tests/Orchard.Framework.Tests.csproj index d677ff37d..187ce8ec0 100644 --- a/src/Orchard.Tests/Orchard.Framework.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Framework.Tests.csproj @@ -243,9 +243,12 @@ + + + diff --git a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs index 247a1040a..1d91cae30 100644 --- a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs +++ b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs @@ -63,7 +63,7 @@ namespace Orchard.Environment.ShellBuilders { Records = records, }; - Logger.Debug("Done composing blueprint"); + Logger.Debug("Done composing blueprint."); return result; } From f39b27355801e164611d015e59193ed7d8ff7180 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 12 Aug 2015 14:47:24 +0100 Subject: [PATCH 2/5] Fixed some typos and corrected TinyMce dependency listings. --- src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs | 3 --- .../Extensions/ExtensionLoaderCoordinatorTests.cs | 8 ++++---- .../Environment/Extensions/ExtensionManagerTests.cs | 4 ++-- src/Orchard.Web/Modules/Orchard.Layouts/Module.txt | 2 +- src/Orchard/Environment/DefaultOrchardHost.cs | 2 +- .../Environment/Descriptor/IShellDescriptorManager.cs | 2 +- src/Orchard/Environment/ViewsBackgroundCompilation.cs | 2 +- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs b/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs index 301a1e703..24594d570 100644 --- a/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs +++ b/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs @@ -25,7 +25,6 @@ using Orchard.Tests.Stubs; using Orchard.Tests.Utility; using Orchard.WebApi.Routes; using IModelBinderProvider = Orchard.Mvc.ModelBinders.IModelBinderProvider; -using Orchard.Tasks; namespace Orchard.Tests.Environment { [TestFixture] @@ -139,8 +138,6 @@ namespace Orchard.Tests.Environment { } } - - [Test, Ignore("containers are disposed when calling BeginRequest, maybe by the StubVirtualPathMonitor")] public void NormalDependenciesShouldBeUniquePerRequestContainer() { var host = _lifetime.Resolve(); diff --git a/src/Orchard.Tests/Environment/Extensions/ExtensionLoaderCoordinatorTests.cs b/src/Orchard.Tests/Environment/Extensions/ExtensionLoaderCoordinatorTests.cs index 94f07fb6d..a087c3554 100644 --- a/src/Orchard.Tests/Environment/Extensions/ExtensionLoaderCoordinatorTests.cs +++ b/src/Orchard.Tests/Environment/Extensions/ExtensionLoaderCoordinatorTests.cs @@ -206,7 +206,7 @@ Features: Category: Content types AnotherWiki Editor: Description: A rich editor for wiki contents. - Dependencies: TinyMCE, AnotherWiki + Dependencies: TinyMce, AnotherWiki Category: Input methods AnotherWiki DistributionList: Description: Sends e-mail alerts when wiki contents gets published. @@ -241,7 +241,7 @@ Features: Assert.That(featureDescriptor.Description, Is.EqualTo("A rich editor for wiki contents.")); Assert.That(featureDescriptor.Category, Is.EqualTo("Input methods")); Assert.That(featureDescriptor.Dependencies.Count(), Is.EqualTo(2)); - Assert.That(featureDescriptor.Dependencies.Contains("TinyMCE")); + Assert.That(featureDescriptor.Dependencies.Contains("TinyMce")); Assert.That(featureDescriptor.Dependencies.Contains("AnotherWiki")); break; case "AnotherWiki DistributionList": @@ -287,7 +287,7 @@ Category: Content types Features: AnotherWiki Editor: Description: A rich editor for wiki contents. - Dependencies: TinyMCE, AnotherWiki + Dependencies: TinyMce, AnotherWiki Category: Input methods AnotherWiki DistributionList: Description: Sends e-mail alerts when wiki contents gets published. @@ -323,7 +323,7 @@ Features: Assert.That(featureDescriptor.Description, Is.EqualTo("A rich editor for wiki contents.")); Assert.That(featureDescriptor.Category, Is.EqualTo("Input methods")); Assert.That(featureDescriptor.Dependencies.Count(), Is.EqualTo(2)); - Assert.That(featureDescriptor.Dependencies.Contains("TinyMCE")); + Assert.That(featureDescriptor.Dependencies.Contains("TinyMce")); Assert.That(featureDescriptor.Dependencies.Contains("AnotherWiki")); break; case "AnotherWiki DistributionList": diff --git a/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs b/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs index f9926e01b..75a1d8ece 100644 --- a/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs +++ b/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs @@ -207,7 +207,7 @@ Features: Category: Content types AnotherWiki Editor: Description: A rich editor for wiki contents. - Dependencies: TinyMCE, AnotherWiki + Dependencies: TinyMce, AnotherWiki Category: Input methods AnotherWiki DistributionList: Description: Sends e-mail alerts when wiki contents gets published. @@ -243,7 +243,7 @@ Features: Assert.That(featureDescriptor.Description, Is.EqualTo("A rich editor for wiki contents.")); Assert.That(featureDescriptor.Category, Is.EqualTo("Input methods")); Assert.That(featureDescriptor.Dependencies.Count(), Is.EqualTo(2)); - Assert.That(featureDescriptor.Dependencies.Contains("TinyMCE")); + Assert.That(featureDescriptor.Dependencies.Contains("TinyMce")); Assert.That(featureDescriptor.Dependencies.Contains("AnotherWiki")); break; case "AnotherWiki DistributionList": diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt b/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt index 8bc8503b6..10617a485 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt @@ -10,7 +10,7 @@ Features: Orchard.Layouts: Name: Layouts Description: Provides tools to create layouts. - Dependencies: Common, Orchard.jQuery, Orchard.Forms, Orchard.Tokens, Orchard.MediaLibrary, TinyMCE + Dependencies: Common, Orchard.jQuery, Orchard.Forms, Orchard.Tokens, Orchard.MediaLibrary, TinyMce Category: Layout Orchard.Layouts.Snippets: Name: Layout Snippets diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index 2e10d25d2..a1e70d003 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -15,7 +15,7 @@ using Orchard.Logging; using Orchard.Utility.Extensions; namespace Orchard.Environment { - // All the event handlers that DefaultOrchardHost implements have to be declared in OrchardStarter + // All the event handlers that DefaultOrchardHost implements have to be declared in OrchardStarter. public class DefaultOrchardHost : IOrchardHost, IShellSettingsManagerEventHandler, IShellDescriptorManagerEventHandler { private readonly IHostLocalRestart _hostLocalRestart; private readonly IShellSettingsManager _shellSettingsManager; diff --git a/src/Orchard/Environment/Descriptor/IShellDescriptorManager.cs b/src/Orchard/Environment/Descriptor/IShellDescriptorManager.cs index 68437f97f..c39356695 100644 --- a/src/Orchard/Environment/Descriptor/IShellDescriptorManager.cs +++ b/src/Orchard/Environment/Descriptor/IShellDescriptorManager.cs @@ -16,7 +16,7 @@ namespace Orchard.Environment.Descriptor { /// /// Alters databased information to match information passed as arguments. - /// Prior SerialNumber used for optomistic concurrency, and an exception + /// Prior SerialNumber used for optimistic concurrency, and an exception /// should be thrown if the number in storage doesn't match what's provided. /// void UpdateShellDescriptor( diff --git a/src/Orchard/Environment/ViewsBackgroundCompilation.cs b/src/Orchard/Environment/ViewsBackgroundCompilation.cs index 67ae7ac1f..919fc9bd2 100644 --- a/src/Orchard/Environment/ViewsBackgroundCompilation.cs +++ b/src/Orchard/Environment/ViewsBackgroundCompilation.cs @@ -119,7 +119,7 @@ namespace Orchard.Environment { } private void CompileDirectory(CompilationContext context, string viewDirectory) { - // Prevent processing of the same directories multiple times (sligh performance optimization, + // Prevent processing of the same directories multiple times (slight performance optimization, // as the build manager second call to compile a view is essentially a "no-op". if (context.ProcessedDirectories.Contains(viewDirectory)) return; From 4cd88cb9c9015d92fbaa078f9b2734ef047413b3 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 12 Aug 2015 15:07:15 +0100 Subject: [PATCH 3/5] Minor cleanup and formatting. --- .../Environment/DefaultOrchardShell.cs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Orchard/Environment/DefaultOrchardShell.cs b/src/Orchard/Environment/DefaultOrchardShell.cs index 91379dce8..400c0399f 100644 --- a/src/Orchard/Environment/DefaultOrchardShell.cs +++ b/src/Orchard/Environment/DefaultOrchardShell.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using Autofac.Features.OwnedInstances; using Microsoft.Owin.Builder; using Orchard.Environment.Configuration; @@ -12,7 +11,6 @@ using Orchard.Owin; using Orchard.Tasks; using Orchard.UI; using Orchard.WebApi.Routes; -using Owin; using IModelBinderProvider = Orchard.Mvc.ModelBinders.IModelBinderProvider; namespace Orchard.Environment { @@ -37,6 +35,7 @@ namespace Orchard.Environment { ISweepGenerator sweepGenerator, IEnumerable owinMiddlewareProviders, ShellSettings shellSettings) { + _eventsFactory = eventsFactory; _routeProviders = routeProviders; _httpRouteProviders = httpRouteProviders; @@ -53,7 +52,7 @@ namespace Orchard.Environment { public ILogger Logger { get; set; } public void Activate() { - IAppBuilder appBuilder = new AppBuilder(); + var appBuilder = new AppBuilder(); appBuilder.Properties["host.AppName"] = _shellSettings.Name; var orderedMiddlewares = _owinMiddlewareProviders @@ -64,11 +63,10 @@ namespace Orchard.Environment { middleware.Configure(appBuilder); } - // register the Orchard middleware after all others + // Register the Orchard middleware after all others. appBuilder.UseOrchard(); - Func, Task> pipeline = appBuilder.Build(); - + var pipeline = appBuilder.Build(); var allRoutes = new List(); allRoutes.AddRange(_routeProviders.SelectMany(provider => provider.GetRoutes())); allRoutes.AddRange(_httpRouteProviders.SelectMany(provider => provider.GetRoutes())); @@ -79,16 +77,17 @@ namespace Orchard.Environment { using (var events = _eventsFactory()) { events.Value.Activated(); } - + _sweepGenerator.Activate(); } public void Terminate() { SafelyTerminate(() => { - using (var events = _eventsFactory()) { - SafelyTerminate(() => events.Value.Terminating()); - } - }); + using (var events = _eventsFactory()) { + var localEvents = events; + SafelyTerminate(() => localEvents.Value.Terminating()); + } + }); SafelyTerminate(() => _sweepGenerator.Terminate()); } From 08a3285e4f66e96c2a26d0bbfd256bc70aee3ba7 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 12 Aug 2015 15:13:03 +0100 Subject: [PATCH 4/5] #3132: Auto-enabling dependency features. This makes sure that any dependency of a feature that is currently not enabled gets enabled automatically before the shell is activated. This prevents potential autofac resolution issues if one service depends on another service provided by a feature that is disabled. Fixes #3132 --- .../ShellBuilders/CompositionStrategyTests.cs | 11 +++- .../Extensions/IExtensionManager.cs | 6 +- .../ShellBuilders/CompositionStrategy.cs | 58 ++++++++++++------- .../ShellBuilders/ICompositionStrategy.cs | 16 +++++ src/Orchard/Orchard.Framework.csproj | 1 + 5 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 src/Orchard/Environment/ShellBuilders/ICompositionStrategy.cs diff --git a/src/Orchard.Tests/Environment/ShellBuilders/CompositionStrategyTests.cs b/src/Orchard.Tests/Environment/ShellBuilders/CompositionStrategyTests.cs index d41f5d087..bb6780415 100644 --- a/src/Orchard.Tests/Environment/ShellBuilders/CompositionStrategyTests.cs +++ b/src/Orchard.Tests/Environment/ShellBuilders/CompositionStrategyTests.cs @@ -10,7 +10,6 @@ using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Models; using Orchard.Environment.ShellBuilders; using Orchard.Tests.Environment.TestDependencies; -using Orchard.Utility; using Orchard.Utility.Extensions; namespace Orchard.Tests.Environment.ShellBuilders { @@ -92,6 +91,16 @@ namespace Orchard.Tests.Environment.ShellBuilders { Assert.That(shellBlueprint.Dependencies.Count(x => x.Type == typeof(BetaDependency)), Is.EqualTo(1)); } + [Test] + public void ComposeReturnsBlueprintWithAutoEnabledDependencyFeatures() { + var shellSettings = CreateShell(); + var shellDescriptor = CreateShellDescriptor("Beta"); // Beta has a dependency on Alpha, but is not enabled initially. + var shellBlueprint = _compositionStrategy.Compose(shellSettings, shellDescriptor); + + Assert.That(shellBlueprint.Dependencies.Count(x => x.Type == typeof(AlphaDependency)), Is.EqualTo(1)); + Assert.That(shellDescriptor.Features.Count(x => x.Name == "Alpha"), Is.EqualTo(1)); + } + private ShellSettings CreateShell() { return new ShellSettings(); } diff --git a/src/Orchard/Environment/Extensions/IExtensionManager.cs b/src/Orchard/Environment/Extensions/IExtensionManager.cs index b79f0b95c..97fdbadea 100644 --- a/src/Orchard/Environment/Extensions/IExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/IExtensionManager.cs @@ -15,7 +15,11 @@ namespace Orchard.Environment.Extensions { public static class ExtensionManagerExtensions { public static IEnumerable EnabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor) { - return extensionManager.AvailableFeatures().Where(fd => descriptor.Features.Any(sf => sf.Name == fd.Id)); + return EnabledFeatures(extensionManager, descriptor.Features); + } + + public static IEnumerable EnabledFeatures(this IExtensionManager extensionManager, IEnumerable features) { + return extensionManager.AvailableFeatures().Where(fd => features.Any(sf => sf.Name == fd.Id)); } } } diff --git a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs index 1d91cae30..f0aebbbda 100644 --- a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs +++ b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Web.Http.Controllers; using System.Web.Mvc; using Autofac.Core; @@ -15,17 +14,6 @@ using Orchard.Environment.ShellBuilders.Models; using Orchard.Logging; namespace Orchard.Environment.ShellBuilders { - /// - /// Service at the host level to transform the cachable descriptor into the loadable blueprint. - /// - public interface ICompositionStrategy { - /// - /// Using information from the IExtensionManager, transforms and populates all of the - /// blueprint model the shell builders will need to correctly initialize a tenant IoC container. - /// - ShellBlueprint Compose(ShellSettings settings, ShellDescriptor descriptor); - } - public class CompositionStrategy : ICompositionStrategy { private readonly IExtensionManager _extensionManager; @@ -40,14 +28,19 @@ namespace Orchard.Environment.ShellBuilders { public ShellBlueprint Compose(ShellSettings settings, ShellDescriptor descriptor) { Logger.Debug("Composing blueprint"); - var enabledFeatures = _extensionManager.EnabledFeatures(descriptor); - var features = _extensionManager.LoadFeatures(enabledFeatures); + var builtinFeatures = BuiltinFeatures().ToList(); + var builtinFeatureDescriptors = builtinFeatures.Select(x => x.Descriptor).ToList(); + var availableFeatures = _extensionManager.AvailableFeatures().Concat(builtinFeatureDescriptors).ToDictionary(x => x.Id); + var enabledFeatures = _extensionManager.EnabledFeatures(descriptor).Select(x => x.Id).ToList(); + var expandedFeatures = ExpandDependencies(availableFeatures, descriptor.Features.Select(x => x.Name)).ToList(); + var autoEnabledDependencyFeatures = expandedFeatures.Except(enabledFeatures).Except(builtinFeatureDescriptors.Select(x => x.Id)).ToList(); + var featureDescriptors = _extensionManager.EnabledFeatures(expandedFeatures.Select(x => new ShellFeature { Name = x})).ToList(); + var features = _extensionManager.LoadFeatures(featureDescriptors); if (descriptor.Features.Any(feature => feature.Name == "Orchard.Framework")) - features = BuiltinFeatures().Concat(features); + features = builtinFeatures.Concat(features); var excludedTypes = GetExcludedTypes(features); - var modules = BuildBlueprint(features, IsModule, BuildModule, excludedTypes); var dependencies = BuildBlueprint(features, IsDependency, (t, f) => BuildDependency(t, f, descriptor), excludedTypes); var controllers = BuildBlueprint(features, IsController, BuildController, excludedTypes); @@ -64,15 +57,40 @@ namespace Orchard.Environment.ShellBuilders { }; Logger.Debug("Done composing blueprint."); + + if (autoEnabledDependencyFeatures.Any()) { + // Add any dependencies previously not enabled to the shell descriptor. + descriptor.Features = descriptor.Features.Concat(autoEnabledDependencyFeatures.Select(x => new ShellFeature { Name = x })).ToList(); + Logger.Information("Automatically enabled the following dependency features: {0}.", String.Join(", ", autoEnabledDependencyFeatures)); + } + return result; } + private IEnumerable ExpandDependencies(IDictionary availableFeatures, IEnumerable features) { + return ExpandDependenciesInternal(availableFeatures, features).Distinct(); + } + + private IEnumerable ExpandDependenciesInternal(IDictionary availableFeatures, IEnumerable features) { + foreach (var shellFeature in features) { + var feature = availableFeatures[shellFeature]; + + foreach (var childDependency in ExpandDependenciesInternal(availableFeatures, feature.Dependencies)) + yield return childDependency; + + foreach (var dependency in feature.Dependencies) + yield return dependency; + + yield return shellFeature; + } + } + private static IEnumerable GetExcludedTypes(IEnumerable features) { var excludedTypes = new HashSet(); - // Identify replaced types - foreach (Feature feature in features) { - foreach (Type type in feature.ExportedTypes) { + // Identify replaced types. + foreach (var feature in features) { + foreach (var type in feature.ExportedTypes) { foreach (OrchardSuppressDependencyAttribute replacedType in type.GetCustomAttributes(typeof(OrchardSuppressDependencyAttribute), false)) { excludedTypes.Add(replacedType.FullName); } @@ -159,7 +177,7 @@ namespace Orchard.Environment.ShellBuilders { private static bool IsRecord(Type type) { return ((type.Namespace ?? "").EndsWith(".Models") || (type.Namespace ?? "").EndsWith(".Records")) && type.GetProperty("Id") != null && - (type.GetProperty("Id").GetAccessors() ?? Enumerable.Empty()).All(x => x.IsVirtual) && + (type.GetProperty("Id").GetAccessors()).All(x => x.IsVirtual) && !type.IsSealed && !type.IsAbstract && (!typeof(IContent).IsAssignableFrom(type) || typeof(ContentPartRecord).IsAssignableFrom(type)); diff --git a/src/Orchard/Environment/ShellBuilders/ICompositionStrategy.cs b/src/Orchard/Environment/ShellBuilders/ICompositionStrategy.cs new file mode 100644 index 000000000..449dcd15e --- /dev/null +++ b/src/Orchard/Environment/ShellBuilders/ICompositionStrategy.cs @@ -0,0 +1,16 @@ +using Orchard.Environment.Configuration; +using Orchard.Environment.Descriptor.Models; +using Orchard.Environment.ShellBuilders.Models; + +namespace Orchard.Environment.ShellBuilders { + /// + /// Service at the host level to transform the cachable descriptor into the loadable blueprint. + /// + public interface ICompositionStrategy { + /// + /// Using information from the IExtensionManager, transforms and populates all of the + /// blueprint model the shell builders will need to correctly initialize a tenant IoC container. + /// + ShellBlueprint Compose(ShellSettings settings, ShellDescriptor descriptor); + } +} \ No newline at end of file diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index ee62487ba..050544824 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -148,6 +148,7 @@ + From 7d7340fbab2ae95b72d930547f80f691a6ca7c1d Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 12 Aug 2015 15:33:10 +0100 Subject: [PATCH 5/5] Resolved merge conflicts. The dev branch had the ExtensionManagerExtensions class as a separate file while the 1.9.x branch had this class in the same file as IExtensionManager.cs. --- .../Helpers/ExtensionManagerExtensions.cs | 16 ---------------- .../Environment/Extensions/IExtensionManager.cs | 6 ++++++ src/Orchard/Orchard.Framework.csproj | 2 +- 3 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 src/Orchard/Environment/Extensions/Helpers/ExtensionManagerExtensions.cs diff --git a/src/Orchard/Environment/Extensions/Helpers/ExtensionManagerExtensions.cs b/src/Orchard/Environment/Extensions/Helpers/ExtensionManagerExtensions.cs deleted file mode 100644 index 87ea5790b..000000000 --- a/src/Orchard/Environment/Extensions/Helpers/ExtensionManagerExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Orchard.Environment.Descriptor.Models; -using Orchard.Environment.Extensions.Models; - -namespace Orchard.Environment.Extensions.Helpers { - public static class ExtensionManagerExtensions { - public static IEnumerable EnabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor) { - return extensionManager.AvailableFeatures().Where(fd => descriptor.Features.Any(sf => sf.Name == fd.Id)); - } - - public static IEnumerable DisabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor) { - return extensionManager.AvailableFeatures().Where(fd => descriptor.Features.All(sf => sf.Name != fd.Id)); - } - } -} \ No newline at end of file diff --git a/src/Orchard/Environment/Extensions/IExtensionManager.cs b/src/Orchard/Environment/Extensions/IExtensionManager.cs index 2709939e0..6f54b9774 100644 --- a/src/Orchard/Environment/Extensions/IExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/IExtensionManager.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Linq; +using Orchard.Environment.Descriptor.Models; using Orchard.Environment.Extensions.Models; namespace Orchard.Environment.Extensions { @@ -19,5 +21,9 @@ namespace Orchard.Environment.Extensions { public static IEnumerable EnabledFeatures(this IExtensionManager extensionManager, IEnumerable features) { return extensionManager.AvailableFeatures().Where(fd => features.Any(sf => sf.Name == fd.Id)); } + + public static IEnumerable DisabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor) { + return extensionManager.AvailableFeatures().Where(fd => descriptor.Features.All(sf => sf.Name != fd.Id)); + } } } diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 216323343..17eac64da 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -149,8 +149,8 @@ - +