PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Orchard/Environment/Features/FeatureManager.cs

http://associativy.codeplex.com
C# | 202 lines | 121 code | 35 blank | 46 comment | 19 complexity | b960ffb3c728755bd3ad4cbffe0af9aa MD5 | raw file
Possible License(s): LGPL-2.1, MIT, BSD-3-Clause, Apache-2.0, CPL-1.0, CC-BY-SA-3.0, GPL-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Orchard.Environment.Descriptor;
  5. using Orchard.Environment.Descriptor.Models;
  6. using Orchard.Environment.Extensions;
  7. using Orchard.Environment.Extensions.Models;
  8. using Orchard.Localization;
  9. using Orchard.Logging;
  10. namespace Orchard.Environment.Features {
  11. public class FeatureManager : IFeatureManager {
  12. private readonly IExtensionManager _extensionManager;
  13. private readonly IShellDescriptorManager _shellDescriptorManager;
  14. /// <summary>
  15. /// Delegate to notify about feature dependencies.
  16. /// </summary>
  17. public FeatureDependencyNotificationHandler FeatureDependencyNotification { get; set; }
  18. public FeatureManager(
  19. IExtensionManager extensionManager,
  20. IShellDescriptorManager shellDescriptorManager) {
  21. _extensionManager = extensionManager;
  22. _shellDescriptorManager = shellDescriptorManager;
  23. T = NullLocalizer.Instance;
  24. Logger = NullLogger.Instance;
  25. }
  26. public Localizer T { get; set; }
  27. public ILogger Logger { get; set; }
  28. /// <summary>
  29. /// Retrieves the available features.
  30. /// </summary>
  31. /// <returns>An enumeration of feature descriptors for the available features.</returns>
  32. public IEnumerable<FeatureDescriptor> GetAvailableFeatures() {
  33. return _extensionManager.AvailableFeatures();
  34. }
  35. /// <summary>
  36. /// Retrieves the enabled features.
  37. /// </summary>
  38. /// <returns>An enumeration of feature descriptors for the enabled features.</returns>
  39. public IEnumerable<FeatureDescriptor> GetEnabledFeatures() {
  40. var currentShellDescriptor = _shellDescriptorManager.GetShellDescriptor();
  41. return _extensionManager.EnabledFeatures(currentShellDescriptor);
  42. }
  43. /// <summary>
  44. /// Enables a list of features.
  45. /// </summary>
  46. /// <param name="featureIds">The IDs for the features to be enabled.</param>
  47. public IEnumerable<string> EnableFeatures(IEnumerable<string> featureIds) {
  48. return EnableFeatures(featureIds, false);
  49. }
  50. /// <summary>
  51. /// Enables a list of features.
  52. /// </summary>
  53. /// <param name="featureIds">The IDs for the features to be enabled.</param>
  54. /// <param name="force">Boolean parameter indicating if the feature should enable it's dependencies if required or fail otherwise.</param>
  55. public IEnumerable<string> EnableFeatures(IEnumerable<string> featureIds, bool force) {
  56. ShellDescriptor shellDescriptor = _shellDescriptorManager.GetShellDescriptor();
  57. List<ShellFeature> enabledFeatures = shellDescriptor.Features.ToList();
  58. IDictionary<FeatureDescriptor, bool> availableFeatures = GetAvailableFeatures()
  59. .ToDictionary(featureDescriptor => featureDescriptor,
  60. featureDescriptor => enabledFeatures.FirstOrDefault(shellFeature => shellFeature.Name == featureDescriptor.Id) != null);
  61. IEnumerable<string> featuresToEnable = featureIds
  62. .Select(featureId => EnableFeature(featureId, availableFeatures, force)).ToList()
  63. .SelectMany(ies => ies.Select(s => s));
  64. if (featuresToEnable.Count() > 0) {
  65. foreach (string featureId in featuresToEnable) {
  66. string id = featureId;
  67. enabledFeatures.Add(new ShellFeature { Name = id });
  68. Logger.Information("{0} was enabled", featureId);
  69. }
  70. _shellDescriptorManager.UpdateShellDescriptor(shellDescriptor.SerialNumber, enabledFeatures,
  71. shellDescriptor.Parameters);
  72. }
  73. return featuresToEnable;
  74. }
  75. /// <summary>
  76. /// Disables a list of features.
  77. /// </summary>
  78. /// <param name="featureIds">The IDs for the features to be disabled.</param>
  79. /// <returns>An enumeration with the disabled feature IDs.</returns>
  80. public IEnumerable<string> DisableFeatures(IEnumerable<string> featureIds) {
  81. return DisableFeatures(featureIds, false);
  82. }
  83. /// <summary>
  84. /// Disables a list of features.
  85. /// </summary>
  86. /// <param name="featureIds">The IDs for the features to be disabled.</param>
  87. /// <param name="force">Boolean parameter indicating if the feature should disable the features which depend on it if required or fail otherwise.</param>
  88. /// <returns>An enumeration with the disabled feature IDs.</returns>
  89. public IEnumerable<string> DisableFeatures(IEnumerable<string> featureIds, bool force) {
  90. ShellDescriptor shellDescriptor = _shellDescriptorManager.GetShellDescriptor();
  91. List<ShellFeature> enabledFeatures = shellDescriptor.Features.ToList();
  92. IDictionary<FeatureDescriptor, bool> availableFeatures = GetAvailableFeatures()
  93. .ToDictionary(featureDescriptor => featureDescriptor,
  94. featureDescriptor => enabledFeatures.FirstOrDefault(shellFeature => shellFeature.Name.Equals(featureDescriptor.Id)) != null);
  95. IEnumerable<string> featuresToDisable = featureIds
  96. .Select(featureId => DisableFeature(featureId, availableFeatures, force)).ToList()
  97. .SelectMany(ies => ies.Select(s => s));
  98. if (featuresToDisable.Any()) {
  99. foreach (string featureId in featuresToDisable) {
  100. string id = featureId;
  101. enabledFeatures.RemoveAll(shellFeature => shellFeature.Name == id);
  102. Logger.Information("{0} was disabled", featureId);
  103. }
  104. _shellDescriptorManager.UpdateShellDescriptor(shellDescriptor.SerialNumber, enabledFeatures,
  105. shellDescriptor.Parameters);
  106. }
  107. return featuresToDisable;
  108. }
  109. /// <summary>
  110. /// Enables a feature.
  111. /// </summary>
  112. /// <param name="featureId">The ID of the feature to be enabled.</param>
  113. /// <param name="availableFeatures">A dictionary of the available feature descriptors and their current state (enabled / disabled).</param>
  114. /// <param name="force">Boolean parameter indicating if the feature should enable it's dependencies if required or fail otherwise.</param>
  115. /// <returns>An enumeration of the enabled features.</returns>
  116. private IEnumerable<string> EnableFeature(string featureId, IDictionary<FeatureDescriptor, bool> availableFeatures, bool force) {
  117. var getDisabledDependencies =
  118. new Func<string, IDictionary<FeatureDescriptor, bool>, IDictionary<FeatureDescriptor, bool>>(
  119. (currentFeatureId, featuresState) => {
  120. KeyValuePair<FeatureDescriptor, bool> feature = featuresState.Single(featureState => featureState.Key.Id.Equals(currentFeatureId, StringComparison.OrdinalIgnoreCase));
  121. // Retrieve disabled dependencies for the current feature
  122. return feature.Key.Dependencies
  123. .Select(fId => featuresState.Single(featureState => featureState.Key.Id.Equals(fId, StringComparison.OrdinalIgnoreCase)))
  124. .Where(featureState => !featureState.Value)
  125. .ToDictionary(f => f.Key, f => f.Value);
  126. });
  127. IEnumerable<string> featuresToEnable = GetAffectedFeatures(featureId, availableFeatures, getDisabledDependencies);
  128. if (featuresToEnable.Count() > 1 && !force) {
  129. Logger.Warning("Additional features need to be enabled.");
  130. if (FeatureDependencyNotification != null) {
  131. FeatureDependencyNotification("If {0} is enabled, then you'll also need to enable {1}.", featureId, featuresToEnable.Where(fId => fId != featureId));
  132. }
  133. return Enumerable.Empty<string>();
  134. }
  135. return featuresToEnable;
  136. }
  137. /// <summary>
  138. /// Disables a feature.
  139. /// </summary>
  140. /// <param name="featureId">The ID of the feature to be enabled.</param>
  141. /// <param name="availableFeatures"></param>
  142. /// <param name="force">Boolean parameter indicating if the feature should enable it's dependencies if required or fail otherwise.</param>
  143. /// <returns>An enumeration of the disabled features.</returns>
  144. private IEnumerable<string> DisableFeature(string featureId, IDictionary<FeatureDescriptor, bool> availableFeatures, bool force) {
  145. var getEnabledDependants =
  146. new Func<string, IDictionary<FeatureDescriptor, bool>, IDictionary<FeatureDescriptor, bool>>(
  147. (currentFeatureId, fs) => fs.Where(f => f.Value && f.Key.Dependencies != null && f.Key.Dependencies.Select(s => s.ToLowerInvariant()).Contains(currentFeatureId.ToLowerInvariant()))
  148. .ToDictionary(f => f.Key, f => f.Value));
  149. IEnumerable<string> featuresToDisable = GetAffectedFeatures(featureId, availableFeatures, getEnabledDependants);
  150. if (featuresToDisable.Count() > 1 && !force) {
  151. Logger.Warning("Additional features need to be disabled.");
  152. if (FeatureDependencyNotification != null) {
  153. FeatureDependencyNotification("If {0} is disabled, then you'll also need to disable {1}.", featureId, featuresToDisable.Where(fId => fId != featureId));
  154. }
  155. return Enumerable.Empty<string>();
  156. }
  157. return featuresToDisable;
  158. }
  159. private static IEnumerable<string> GetAffectedFeatures(string featureId, IDictionary<FeatureDescriptor, bool> features, Func<string, IDictionary<FeatureDescriptor, bool>, IDictionary<FeatureDescriptor, bool>> getAffectedDependencies) {
  160. var dependencies = new List<string> { featureId };
  161. foreach (KeyValuePair<FeatureDescriptor, bool> dependency in getAffectedDependencies(featureId, features)) {
  162. dependencies.AddRange(GetAffectedFeatures(dependency.Key.Id, features, getAffectedDependencies));
  163. }
  164. return dependencies;
  165. }
  166. }
  167. }