public IYodiiEngineResult SetDiscoveredInfo(IDiscoveredInfo info) { if (info == null) { throw new ArgumentNullException("info"); } if (info == _discoveredInfo) { return(_successResult); } if (IsRunning) { var r = ConfigurationSolver.CreateAndApplyStaticResolution(this, _manager.FinalConfiguration, info, false, false, false); if (r.Item1 != null) { Debug.Assert(!r.Item1.Success, "Not null means necessarily an error."); Debug.Assert(r.Item1.Engine == this); return(r.Item1); } return(DoDynamicResolution(r.Item2, null, null, () => DiscoveredInfo = info)); } else { DiscoveredInfo = info; } return(_successResult); }
public YodiiEngine(IYodiiEngineHost host) { if (host == null) { throw new ArgumentNullException("host"); } _successResult = new SuccessYodiiEngineResult(this); _host = host; _discoveredInfo = EmptyDiscoveredInfo.Empty; _manager = new ConfigurationManager(this); _yodiiCommands = new YodiiCommandList(); _liveInfo = new LiveInfo(this); }
/// <summary> /// Checks that this IDiscoveredInfo obeys to integrity constraints (see remarks). /// </summary> /// <param name="this">This discovered information.</param> /// <returns>True if data is valid, false otherwise.</returns> /// <remarks> /// IDiscoveredInfo constraints checked here : /// - IServiceInfo and IPluginInfo names are unique, in both collections (A service cannot have a plugin name, and vice-versa). /// - IServiceInfo generalizations do not specialize this IServiceInfo (Generalization loop). /// - IPluginInfo contains valid service references (cannot reference a service of its own family, outside its own tree). /// </remarks> public static bool IsValid(this IDiscoveredInfo @this) { // Check plugin and service identifiers HashSet <string> pluginOrServiceIds = new HashSet <string>(); foreach (var service in @this.ServiceInfos) { if (!pluginOrServiceIds.Add(service.ServiceFullName)) { return(false); // Service name appears twice. } // Check if service is contained in its generalization tree (generalization loop) List <IServiceInfo> visitedServices = new List <IServiceInfo>(); IServiceInfo g = service.Generalization; visitedServices.Add(service); while (g != null) { if (visitedServices.Contains(g)) { return(false); // This service is contained in its generalization tree. } visitedServices.Add(g); g = g.Generalization; } } foreach (var plugin in @this.PluginInfos) { if (!pluginOrServiceIds.Add(plugin.PluginFullName)) { return(false); // Plugin name is already used. } foreach (var serviceRef in plugin.ServiceReferences) { if (!plugin.CanReference(serviceRef.Reference)) { return(false); // Service reference points to a service that cannot be run (same family, different branch). } } } return(true); }
/// <summary> /// Asserts that both DiscoveredInfo are equivalent. /// </summary> /// <param name="a">A</param> /// <param name="b">B</param> public static void AssertDiscoveredInfoEquivalence(IDiscoveredInfo a, IDiscoveredInfo b) { Assert.That(a.PluginInfos.Count == b.PluginInfos.Count); Assert.That(a.ServiceInfos.Count == b.ServiceInfos.Count); foreach (var sA in a.ServiceInfos) { var sB = b.ServiceInfos.First(s => sA.ServiceFullName == s.ServiceFullName); AssertServiceEquivalence(sA, sB, true); } foreach (var pA in a.PluginInfos) { var pB = b.PluginInfos.First(p => pA.PluginFullName == p.PluginFullName); AssertPluginEquivalence(pA, pB, true); } Assert.That(a.IsValid() == b.IsValid()); }
/// <summary> /// Asserts that both DiscoveredInfo are equivalent. /// </summary> /// <param name="a">A</param> /// <param name="b">B</param> public static void AssertDiscoveredInfoEquivalence( IDiscoveredInfo a, IDiscoveredInfo b ) { Assert.That( a.PluginInfos.Count == b.PluginInfos.Count ); Assert.That( a.ServiceInfos.Count == b.ServiceInfos.Count ); foreach( var sA in a.ServiceInfos ) { var sB = b.ServiceInfos.First( s => sA.ServiceFullName == s.ServiceFullName ); AssertServiceEquivalence( sA, sB, true ); } foreach( var pA in a.PluginInfos ) { var pB = b.PluginInfos.First( p => pA.PluginFullName == p.PluginFullName ); AssertPluginEquivalence( pA, pB, true ); } Assert.That( a.IsValid() == b.IsValid() ); }
IYodiiEngineStaticOnlyResult StaticResolution( FinalConfiguration finalConfig, IDiscoveredInfo info, bool createStaticSolvedConfigOnSuccess ) { // Registering all Services. Step = Engine.ConfigurationSolverStep.RegisterServices; { // In order to be deterministic, works on an ordered list of IServiceInfo to build the graph. List<IServiceInfo> orderedServicesInfo = info.ServiceInfos.Where( s => s != null && !String.IsNullOrWhiteSpace( s.ServiceFullName ) ).OrderBy( s => s.ServiceFullName ).ToList(); if( _revertServicesOrder ) orderedServicesInfo.Reverse(); foreach( IServiceInfo sI in orderedServicesInfo ) { // This creates services and applies solved configuration to them: directly disabled services // and specializations disabled by their generalizations' configuration are handled. RegisterService( finalConfig, sI ); } _orderedServices = orderedServicesInfo.Select( s => _services[s.ServiceFullName] ).ToArray(); } // Service trees have been built. // We can now instantiate plugin data. Step = Engine.ConfigurationSolverStep.RegisterPlugins; { // In order to be deterministic, works on an ordered list of IPluginInfo to build the graph. List<IPluginInfo> orderedPluginsInfo = info.PluginInfos.Where( p => p != null ).OrderBy( p => p.PluginFullName ).ToList(); if( _revertPluginsOrder ) orderedPluginsInfo.Reverse(); foreach( IPluginInfo p in orderedPluginsInfo ) { RegisterPlugin( finalConfig, p ); } _orderedPlugins = orderedPluginsInfo.Select( p => _plugins[p.PluginFullName] ).ToArray(); } // All possible plugins are registered. Services without any available plugins are de facto disabled. // Propagation for each service is deferred. Step = Engine.ConfigurationSolverStep.OnAllPluginsAdded; { foreach( var f in _serviceFamilies ) { f.OnAllPluginsAdded(); } ProcessDeferredPropagations(); } // Now, we apply ServiceReference Running constraints from every plugins to their referenced services. Step = ConfigurationSolverStep.PropagatePluginStatus; { foreach( PluginData p in _orderedPlugins ) { if( p.FinalConfigSolvedStatus == SolvedConfigurationStatus.Running ) { p.PropagateRunningStatus(); } } ProcessDeferredPropagations(); } // Finalizes static resolution by computing final Runnable statuses per impact for Optional and Runnable plugins or services. Step = ConfigurationSolverStep.InitializeFinalStartableStatus; { foreach( ServiceData s in _orderedServices ) s.InitializeFinalStartableStatus(); foreach( PluginData p in _orderedPlugins ) p.InitializeFinalStartableStatus(); } List<PluginData> blockingPlugins = null; List<ServiceData> blockingServices = null; Step = ConfigurationSolverStep.BlockingDetection; { // Time to conclude about configuration and to initialize dynamic resolution. // Any Plugin that has a ConfigOriginalStatus greater or equal to Runnable and is Disabled leads to an impossible configuration. foreach( PluginData p in _orderedPlugins ) { if( p.Disabled ) { if( p.ConfigOriginalStatus >= ConfigurationStatus.Runnable ) { if( blockingPlugins == null ) blockingPlugins = new List<PluginData>(); blockingPlugins.Add( p ); } } } // Any Service that has a ConfigOriginalStatus greater or equal to Runnable and is Disabled leads to an impossible configuration. foreach( ServiceData s in _orderedServices ) { if( s.Disabled ) { if( s.ConfigOriginalStatus >= ConfigurationStatus.Runnable ) { if( blockingServices == null ) blockingServices = new List<ServiceData>(); blockingServices.Add( s ); } } } } if( blockingPlugins != null || blockingServices != null ) { Step = ConfigurationSolverStep.StaticError; return new YodiiEngineResult( this, blockingPlugins, blockingServices, _engine ); } Step = ConfigurationSolverStep.WaitingForDynamicResolution; if( createStaticSolvedConfigOnSuccess ) { return new YodiiEngineResult( this, _engine ); } return null; }
internal static Tuple<IYodiiEngineStaticOnlyResult, ConfigurationSolver> CreateAndApplyStaticResolution( YodiiEngine engine, FinalConfiguration finalConfiguration, IDiscoveredInfo discoveredInfo, bool revertServices, bool revertPlugins, bool createStaticSolvedConfigOnSuccess ) { ConfigurationSolver temporarySolver = new ConfigurationSolver( engine,revertServices, revertPlugins ); IYodiiEngineStaticOnlyResult result = temporarySolver.StaticResolution( finalConfiguration, discoveredInfo, createStaticSolvedConfigOnSuccess ); // StaticResolution returns null on success. // If there is a result, it is either an error or createStaticSolvedConfigOnSuccess is true and this is a StaticResolutionOnly: in both // case we do not need to keep the temporary solver. if( result != null ) temporarySolver = null; return Tuple.Create( result, temporarySolver ); }
internal static Tuple <IYodiiEngineStaticOnlyResult, ConfigurationSolver> CreateAndApplyStaticResolution(YodiiEngine engine, FinalConfiguration finalConfiguration, IDiscoveredInfo discoveredInfo, bool revertServices, bool revertPlugins, bool createStaticSolvedConfigOnSuccess) { ConfigurationSolver temporarySolver = new ConfigurationSolver(engine, revertServices, revertPlugins); IYodiiEngineStaticOnlyResult result = temporarySolver.StaticResolution(finalConfiguration, discoveredInfo, createStaticSolvedConfigOnSuccess); // StaticResolution returns null on success. // If there is a result, it is either an error or createStaticSolvedConfigOnSuccess is true and this is a StaticResolutionOnly: in both // case we do not need to keep the temporary solver. if (result != null) { temporarySolver = null; } return(Tuple.Create(result, temporarySolver)); }
IYodiiEngineStaticOnlyResult StaticResolution(FinalConfiguration finalConfig, IDiscoveredInfo info, bool createStaticSolvedConfigOnSuccess) { // Registering all Services. Step = Engine.ConfigurationSolverStep.RegisterServices; { // In order to be deterministic, works on an ordered list of IServiceInfo to build the graph. List <IServiceInfo> orderedServicesInfo = info.ServiceInfos.Where(s => s != null && !String.IsNullOrWhiteSpace(s.ServiceFullName)).OrderBy(s => s.ServiceFullName).ToList(); if (_revertServicesOrder) { orderedServicesInfo.Reverse(); } foreach (IServiceInfo sI in orderedServicesInfo) { // This creates services and applies solved configuration to them: directly disabled services // and specializations disabled by their generalizations' configuration are handled. RegisterService(finalConfig, sI); } _orderedServices = orderedServicesInfo.Select(s => _services[s.ServiceFullName]).ToArray(); } // Service trees have been built. // We can now instantiate plugin data. Step = Engine.ConfigurationSolverStep.RegisterPlugins; { // In order to be deterministic, works on an ordered list of IPluginInfo to build the graph. List <IPluginInfo> orderedPluginsInfo = info.PluginInfos.Where(p => p != null).OrderBy(p => p.PluginFullName).ToList(); if (_revertPluginsOrder) { orderedPluginsInfo.Reverse(); } foreach (IPluginInfo p in orderedPluginsInfo) { RegisterPlugin(finalConfig, p); } _orderedPlugins = orderedPluginsInfo.Select(p => _plugins[p.PluginFullName]).ToArray(); } // All possible plugins are registered. Services without any available plugins are de facto disabled. // Propagation for each service is deferred. Step = Engine.ConfigurationSolverStep.OnAllPluginsAdded; { foreach (var f in _serviceFamilies) { f.OnAllPluginsAdded(); } ProcessDeferredPropagations(); } // Now, we apply ServiceReference Running constraints from every plugins to their referenced services. Step = ConfigurationSolverStep.PropagatePluginStatus; { foreach (PluginData p in _orderedPlugins) { if (p.FinalConfigSolvedStatus == SolvedConfigurationStatus.Running) { p.PropagateRunningStatus(); } } ProcessDeferredPropagations(); } // Finalizes static resolution by computing final Runnable statuses per impact for Optional and Runnable plugins or services. Step = ConfigurationSolverStep.InitializeFinalStartableStatus; { foreach (ServiceData s in _orderedServices) { s.InitializeFinalStartableStatus(); } foreach (PluginData p in _orderedPlugins) { p.InitializeFinalStartableStatus(); } } List <PluginData> blockingPlugins = null; List <ServiceData> blockingServices = null; Step = ConfigurationSolverStep.BlockingDetection; { // Time to conclude about configuration and to initialize dynamic resolution. // Any Plugin that has a ConfigOriginalStatus greater or equal to Runnable and is Disabled leads to an impossible configuration. foreach (PluginData p in _orderedPlugins) { if (p.Disabled) { if (p.ConfigOriginalStatus >= ConfigurationStatus.Runnable) { if (blockingPlugins == null) { blockingPlugins = new List <PluginData>(); } blockingPlugins.Add(p); } } } // Any Service that has a ConfigOriginalStatus greater or equal to Runnable and is Disabled leads to an impossible configuration. foreach (ServiceData s in _orderedServices) { if (s.Disabled) { if (s.ConfigOriginalStatus >= ConfigurationStatus.Runnable) { if (blockingServices == null) { blockingServices = new List <ServiceData>(); } blockingServices.Add(s); } } } } if (blockingPlugins != null || blockingServices != null) { Step = ConfigurationSolverStep.StaticError; return(new YodiiEngineResult(this, blockingPlugins, blockingServices, _engine)); } Step = ConfigurationSolverStep.WaitingForDynamicResolution; if (createStaticSolvedConfigOnSuccess) { return(new YodiiEngineResult(this, _engine)); } return(null); }