ConfigurationSetProcessorBase.cs (10614B)
1 // ----------------------------------------------------------------------------- 2 // <copyright file="ConfigurationSetProcessorBase.cs" company="Microsoft Corporation"> 3 // Copyright (c) Microsoft Corporation. Licensed under the MIT License. 4 // </copyright> 5 // ----------------------------------------------------------------------------- 6 7 namespace Microsoft.Management.Configuration.Processor.Set 8 { 9 using System; 10 using System.Collections.Generic; 11 using System.Runtime.CompilerServices; 12 using Microsoft.Management.Configuration.Processor.Extensions; 13 using Microsoft.Management.Configuration.Processor.Factory; 14 using Microsoft.Management.Configuration.Processor.Unit; 15 16 /// <summary> 17 /// IConfigurationSetProcessor base implementation. 18 /// </summary> 19 internal abstract partial class ConfigurationSetProcessorBase 20 { 21 private readonly ConfigurationSet? configurationSet; 22 private List<ConfigurationUnit> limitUnitList = new List<ConfigurationUnit>(); 23 24 /// <summary> 25 /// Initializes a new instance of the <see cref="ConfigurationSetProcessorBase"/> class. 26 /// </summary> 27 /// <param name="configurationSet">Configuration set.</param> 28 /// <param name="isLimitMode">Whether the set processor should work in limitation mode.</param> 29 public ConfigurationSetProcessorBase(ConfigurationSet? configurationSet, bool isLimitMode) 30 { 31 this.configurationSet = configurationSet; 32 this.IsLimitMode = isLimitMode; 33 34 // In limit mode, configurationSet is the limitation set to be used. It cannot be null. 35 if (this.IsLimitMode) 36 { 37 if (this.configurationSet == null) 38 { 39 throw new ArgumentNullException(nameof(configurationSet), "configurationSet is required in limit mode."); 40 } 41 42 foreach (var unit in this.configurationSet.Units) 43 { 44 this.limitUnitList.Add(unit); 45 } 46 } 47 } 48 49 /// <summary> 50 /// Gets or initializes the set processor factory. 51 /// </summary> 52 internal ConfigurationSetProcessorFactoryBase? SetProcessorFactory { get; init; } 53 54 /// <summary> 55 /// Gets a value indicating whether the set processor is running in limit mode. 56 /// </summary> 57 internal bool IsLimitMode { get; private set; } 58 59 /// <summary> 60 /// Gets the configuration set for this processor. 61 /// </summary> 62 protected ConfigurationSet? ConfigurationSet 63 { 64 get { return this.configurationSet; } 65 } 66 67 /// <summary> 68 /// Creates a configuration unit processor for the given unit. 69 /// </summary> 70 /// <param name="incomingUnit">Configuration unit.</param> 71 /// <returns>A configuration unit processor.</returns> 72 public IConfigurationUnitProcessor CreateUnitProcessor(ConfigurationUnit incomingUnit) 73 { 74 try 75 { 76 this.OnDiagnostics(DiagnosticLevel.Informational, $"GetUnitProcessorDetails is running in limit mode: {this.IsLimitMode}."); 77 78 // CreateUnitProcessor can only be called once on each configuration unit in limit mode. 79 var unit = this.GetConfigurationUnit(incomingUnit, true); 80 81 IConfigurationUnitProcessor result = this.CreateUnitProcessorInternal(unit); 82 83 this.OnDiagnostics(DiagnosticLevel.Verbose, "... done creating unit processor."); 84 85 return result; 86 } 87 catch (Exception ex) 88 { 89 this.OnDiagnostics(DiagnosticLevel.Error, ex.ToString()); 90 throw; 91 } 92 } 93 94 /// <summary> 95 /// Gets the configuration unit processor details for the given unit. 96 /// </summary> 97 /// <param name="incomingUnit">Configuration unit.</param> 98 /// <param name="detailFlags">Detail flags.</param> 99 /// <returns>Configuration unit processor details.</returns> 100 public IConfigurationUnitProcessorDetails? GetUnitProcessorDetails(ConfigurationUnit incomingUnit, ConfigurationUnitDetailFlags detailFlags) 101 { 102 try 103 { 104 this.OnDiagnostics(DiagnosticLevel.Informational, $"GetUnitProcessorDetails is running in limit mode: {this.IsLimitMode}."); 105 106 // GetUnitProcessorDetails can be invoked multiple times on each configuration unit in limit mode. 107 var unit = this.GetConfigurationUnit(incomingUnit); 108 109 return this.GetUnitProcessorDetailsInternal(unit, detailFlags); 110 } 111 catch (Exception ex) 112 { 113 this.OnDiagnostics(DiagnosticLevel.Error, ex.ToString()); 114 throw; 115 } 116 } 117 118 /// <summary> 119 /// Gets all configuration units for the given unit type. 120 /// Returned units may be of types other than the one passed in. 121 /// </summary> 122 /// <param name="findOptions">Find unit processors options.</param> 123 /// <returns>A list of unit processor details.</returns> 124 public IList<IConfigurationUnitProcessorDetails> FindUnitProcessors(FindUnitProcessorsOptions findOptions) 125 { 126 try 127 { 128 this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `FindUnitProcessors` ..."); 129 130 return this.FindUnitProcessorsInternal(findOptions); 131 } 132 catch (Exception ex) 133 { 134 this.OnDiagnostics(DiagnosticLevel.Error, ex.ToString()); 135 throw; 136 } 137 } 138 139 /// <summary> 140 /// Creates a configuration unit processor for the given unit. 141 /// </summary> 142 /// <param name="unit">Configuration unit.</param> 143 /// <returns>A configuration unit processor.</returns> 144 protected abstract IConfigurationUnitProcessor CreateUnitProcessorInternal(ConfigurationUnit unit); 145 146 /// <summary> 147 /// Gets the configuration unit processor details for the given unit. 148 /// </summary> 149 /// <param name="unit">Configuration unit.</param> 150 /// <param name="detailFlags">Detail flags.</param> 151 /// <returns>Configuration unit processor details.</returns> 152 protected abstract IConfigurationUnitProcessorDetails? GetUnitProcessorDetailsInternal(ConfigurationUnit unit, ConfigurationUnitDetailFlags detailFlags); 153 154 /// <summary> 155 /// Finds unit processors based on the input FindUnitProcessorsOptions. 156 /// Derive from IFindUnitProcessorsSetProcessor and implement an override to support this. 157 /// </summary> 158 /// <param name="findOptions">Find unit processors options.</param> 159 /// <returns>A list of unit processor details.</returns> 160 protected virtual IList<IConfigurationUnitProcessorDetails> FindUnitProcessorsInternal(FindUnitProcessorsOptions findOptions) 161 { 162 throw new NotImplementedException("Configuration set processor did not implement FindUnitProcessorsInternal."); 163 } 164 165 /// <summary> 166 /// Sends diagnostics to factory. 167 /// </summary> 168 /// <param name="level">The level of this diagnostic message.</param> 169 /// <param name="message">The diagnostic message.</param> 170 protected void OnDiagnostics(DiagnosticLevel level, string message) 171 { 172 this.SetProcessorFactory?.OnDiagnostics(level, message); 173 } 174 175 private static bool ConfigurationUnitEquals(ConfigurationUnit first, ConfigurationUnit second) 176 { 177 var firstIdentifier = first.Identifier; 178 var firstIntent = first.Intent; 179 var firstType = first.Type; 180 var secondIdentifier = second.Identifier; 181 var secondType = second.Type; 182 var secondIntent = second.Intent; 183 184 if (firstIdentifier != secondIdentifier || 185 firstType != secondType || 186 firstIntent != secondIntent) 187 { 188 return false; 189 } 190 191 var firstEnvironment = first.Environment; 192 var secondEnvironment = second.Environment; 193 if (firstEnvironment.Context != secondEnvironment.Context || 194 firstEnvironment.ProcessorIdentifier != secondEnvironment.ProcessorIdentifier || 195 !firstEnvironment.ProcessorProperties.ContentEquals(secondEnvironment.ProcessorProperties)) 196 { 197 return false; 198 } 199 200 if (!first.Settings.ContentEquals(second.Settings)) 201 { 202 return false; 203 } 204 205 if (!first.Metadata.ContentEquals(second.Metadata)) 206 { 207 return false; 208 } 209 210 // Note: Consider group units logic when group units are supported. 211 return true; 212 } 213 214 [MethodImpl(MethodImplOptions.Synchronized)] 215 private ConfigurationUnit GetConfigurationUnit(ConfigurationUnit incomingUnit, bool useLimitList = false) 216 { 217 if (this.IsLimitMode) 218 { 219 if (this.configurationSet == null) 220 { 221 throw new InvalidOperationException("Configuration set should not be null in limit mode."); 222 } 223 224 var unitList = useLimitList ? this.limitUnitList : this.configurationSet.Units; 225 226 for (int i = 0; i < unitList.Count; i++) 227 { 228 var unit = unitList[i]; 229 if (ConfigurationUnitEquals(incomingUnit, unit)) 230 { 231 if (useLimitList) 232 { 233 this.limitUnitList.RemoveAt(i); 234 } 235 236 return unit; 237 } 238 239 // Note: Consider group units logic when group units are supported. 240 } 241 242 this.OnDiagnostics(DiagnosticLevel.Error, "Configuration unit not found in limit mode."); 243 throw new InvalidOperationException("Configuration unit not found in limit mode."); 244 } 245 else 246 { 247 return incomingUnit; 248 } 249 } 250 } 251 }