internal RequirementLayerSnapshot(RequirementLayer l) { LayerName = l.LayerName; var plugins = l.PluginRequirements.Select((r, idx) => new PluginRequirementIdentifier() { PluginId = r.PluginId, Requirement = r.Requirement }).ToArray(); PluginRequirements = new ReadOnlyCollectionOnICollection <PluginRequirementIdentifier>(plugins); var services = l.ServiceRequirements.Select((r, idx) => new ServiceRequirementIdentifier() { AssemblyQualifiedName = r.AssemblyQualifiedName, Requirement = r.Requirement }).ToArray(); ServiceRequirements = new ReadOnlyCollectionOnICollection <ServiceRequirementIdentifier>(services); }
/// <summary> /// Attempts to execute a plan. /// </summary> /// <param name="disabledPluginKeys">Plugins that must be disabled.</param> /// <param name="stoppedPluginKeys">Plugins that must be stopped.</param> /// <param name="runningPluginKeys">Plugins that must be running.</param> /// <returns>A <see cref="IExecutionPlanError"/> that details the error if any.</returns> public IExecutionPlanResult Execute( IEnumerable<IPluginInfo> disabledPluginKeys, IEnumerable<IPluginInfo> stoppedPluginKeys, IEnumerable<IPluginInfo> runningPluginKeys ) { if( PluginCreator == null ) throw new InvalidOperationException( R.PluginCreatorIsNull ); if( ServiceReferencesBinder == null ) throw new InvalidOperationException( R.PluginConfiguratorIsNull ); int nbIntersect; nbIntersect = disabledPluginKeys.Intersect( stoppedPluginKeys ).Count(); if( nbIntersect != 0 ) throw new CKException( R.DisabledAndStoppedPluginsIntersect, nbIntersect ); nbIntersect = disabledPluginKeys.Intersect( runningPluginKeys ).Count(); if( nbIntersect != 0 ) throw new CKException( R.DisabledAndRunningPluginsIntersect, nbIntersect ); nbIntersect = stoppedPluginKeys.Intersect( runningPluginKeys ).Count(); if( nbIntersect != 0 ) throw new CKException( R.StoppedAndRunningPluginsIntersect, nbIntersect ); List<PluginProxy> toDisable = new List<PluginProxy>(); List<PluginProxy> toStop = new List<PluginProxy>(); List<PluginProxy> toStart = new List<PluginProxy>(); foreach( IPluginInfo k in disabledPluginKeys ) { PluginProxy p = EnsureProxy( k ); if( p.Status != RunningStatus.Disabled ) { toDisable.Add( p ); if( p.Status != RunningStatus.Stopped ) { toStop.Add( p ); } } } foreach( IPluginInfo k in stoppedPluginKeys ) { PluginProxy p = EnsureProxy( k ); if( p.Status != RunningStatus.Stopped ) { toStop.Add( p ); } } // The lists toDisable and toStop are correctly filled. // A plugin can be in both lists if it must be stopped and then disabled. // Now, we attempt to activate the plugins that must run: if an error occurs, // we leave and return the error since we did not change anything. foreach( IPluginInfo k in runningPluginKeys ) { PluginProxy p = EnsureProxy( k ); if( !p.IsLoaded ) { if( !p.TryLoad( _serviceHost, PluginCreator ) ) { Debug.Assert( p.LoadError != null ); _serviceHost.LogMethodError( PluginCreator.Method, p.LoadError ); // Unable to load the plugin: leave now. return new ExecutionPlanResult() { Culprit = p.PluginKey, Status = ExecutionPlanResultStatus.LoadError }; } Debug.Assert( p.LoadError == null ); Debug.Assert( p.Status == RunningStatus.Disabled ); _newlyLoadedPlugins.Add( p ); } if( p.Status != RunningStatus.Started ) { toStart.Add( p ); } } // The toStart list is ready: plugins inside are loaded without error. // We stop all "toStop" plugin. // Their "stop" methods will be called. foreach( PluginProxy p in toStop ) { if( p.Status > RunningStatus.Stopped ) { try { SetPluginStatus( p, RunningStatus.Stopping ); p.RealPlugin.Stop(); _log.Debug( String.Format( "The {0} plugin has been successfully stopped.", p.PublicName ) ); } catch( Exception ex ) { #if DEBUG //Helps the developper identify the culprit of exception Debugger.Break(); #endif _log.ErrorFormat( "There has been a problem when stopping the {0} plugin.", ex, p.PublicName ); _serviceHost.LogMethodError( p.GetImplMethodInfoStop(), ex ); } } } // We un-initialize all "toStop" plugin. // Their "Teardown" methods will be called. // After that, they are all "stopped". foreach( PluginProxy p in toStop ) { try { if( p.Status > RunningStatus.Stopped ) { SetPluginStatus( p, RunningStatus.Stopped ); p.RealPlugin.Teardown(); _log.Debug( String.Format( "The {0} plugin has been successfully torn down.", p.PublicName ) ); } } catch( Exception ex ) { #if DEBUG //Helps the developper identify the culprit of exceptions Debugger.Break(); #endif _log.ErrorFormat( "There has been a problem when tearing down the {0} plugin.", ex, p.PublicName ); _serviceHost.LogMethodError( p.GetImplMethodInfoTeardown(), ex ); } } Debug.Assert( toStop.All( p => p.Status <= RunningStatus.Stopped ) ); // Prepares the plugins to start so that they become the implementation // of their Service and are at least stopped (instead of disabled). foreach( PluginProxy p in toStart ) { ServiceProxyBase service = p.Service; // The call to service.SetImplementation, sets the implementation and takes // the _status of the service into account: this status is at most Stopped // since we necessarily stopped the previous implementation (if any) above. if( service != null ) { Debug.Assert( service.Status <= RunningStatus.Stopped ); service.SetPluginImplementation( p ); } // This call will trigger an update of the service status. if( p.Status == RunningStatus.Disabled ) SetPluginStatus( p, RunningStatus.Stopped ); } // Now that services have been associated to their new implementation (in Stopped status), we // can disable the plugins that must be disabled. foreach( PluginProxy p in toDisable ) { SetPluginStatus( p, RunningStatus.Disabled ); try { p.DisposeIfDisposable(); } catch( Exception ex ) { #if DEBUG //Helps the developper identify the culprit of exceptions Debugger.Break(); #endif _log.ErrorFormat( "There has been a problem when disposing the {0} plugin.", ex, p.PublicName ); _serviceHost.LogMethodError( p.GetImplMethodInfoDispose(), ex ); } } // Before starting for( int i = 0; i < toStart.Count; i++ ) { PluginProxy p = toStart[i]; // We configure plugin's edition properties. if( PluginConfigurator != null ) PluginConfigurator( p ); SetPluginStatus( p, RunningStatus.Starting ); IPluginSetupInfo info = new IPluginSetupInfo(); try { p.RealPlugin.Setup( info ); info.Clear(); _log.Debug( String.Format( "The {0} plugin has been successfully set up.", p.PublicName ) ); } catch( Exception ex ) { #if DEBUG //Helps the developper identify the culprit of exceptions Debugger.Break(); #endif _log.ErrorFormat( "There has been a problem when setting up the {0} plugin.", ex, p.PublicName ); _serviceHost.LogMethodError( p.GetImplMethodInfoSetup(), ex ); // Revoking the call to Setup for all plugins that haven't been started yet. //Will pass the plugin to states : Stopping and then Stopped for( int j = 0; j <= i; j++ ) { RevokeSetupCall( toStart[j] ); } info.Error = ex; return new ExecutionPlanResult() { Culprit = p.PluginKey, Status = ExecutionPlanResultStatus.SetupError, SetupInfo = info }; } } // Since we are now ready to start new plugins, it is now time to make the external world // aware of the existence of any new plugins and configure them to run. foreach( PluginProxy p in _newlyLoadedPlugins ) { _loadedPlugins.Add( p.PluginKey.UniqueId, p ); } Debug.Assert( ServiceReferencesBinder != null ); try { var listNew = new ReadOnlyCollectionOnICollection<PluginProxy>( _newlyLoadedPlugins ); //var disabled = new ReadOnlyCollectionAdapter<IPluginProxy, PluginProxy>( toDisable ); ServiceReferencesBinder( listNew ); } catch( Exception ex ) { _serviceHost.LogMethodError( ServiceReferencesBinder.Method, ex ); } _newlyLoadedPlugins.Clear(); for( int i = 0; i < toStart.Count; i++ ) { PluginProxy p = toStart[i]; try { SetPluginStatus( p, RunningStatus.Started ); p.RealPlugin.Start(); _log.Debug( String.Format( "The {0} plugin has been successfully started.", p.PublicName ) ); } catch( Exception ex ) { // Emitted as low level log. _log.ErrorFormat( "There has been a problem when starting the {0} plugin.", ex, p.PublicName ); // Emitted as a log event. _serviceHost.LogMethodError( p.GetImplMethodInfoStart(), ex ); //All the plugins already started when the exception was thrown have to be stopped + teardown (including this one in exception) for( int j = 0; j <= i; j++ ) { RevokeStartCall( toStart[j] ); } // Revoking the call to Setup for all plugins that hadn't been started when the exception occured. for( int j = i + 1; j < toStart.Count; j++ ) { RevokeSetupCall( toStart[j] ); } return new ExecutionPlanResult() { Culprit = p.PluginKey, Status = ExecutionPlanResultStatus.LoadError, Error = ex }; } } return new ExecutionPlanResult(); }
internal PluginStatusCollection( ConfigurationBase holder ) { _holder = holder; _pluginStatusDic = new Dictionary<Guid, PluginStatus>(); _pluginStatusReadOnlyCollection = new ReadOnlyCollectionOnICollection<PluginStatus>( _pluginStatusDic.Values ); }
internal PluginStatusCollection(ConfigurationBase holder) { _holder = holder; _pluginStatusDic = new Dictionary <Guid, PluginStatus>(); _pluginStatusReadOnlyCollection = new ReadOnlyCollectionOnICollection <PluginStatus>(_pluginStatusDic.Values); }
/// <summary> /// Attempts to execute a plan. /// </summary> /// <param name="disabledPluginKeys">Plugins that must be disabled.</param> /// <param name="stoppedPluginKeys">Plugins that must be stopped.</param> /// <param name="runningPluginKeys">Plugins that must be running.</param> /// <returns>A <see cref="IExecutionPlanError"/> that details the error if any.</returns> public IExecutionPlanResult Execute(IEnumerable <IPluginInfo> disabledPluginKeys, IEnumerable <IPluginInfo> stoppedPluginKeys, IEnumerable <IPluginInfo> runningPluginKeys) { if (PluginCreator == null) { throw new InvalidOperationException(R.PluginCreatorIsNull); } if (ServiceReferencesBinder == null) { throw new InvalidOperationException(R.PluginConfiguratorIsNull); } int nbIntersect; nbIntersect = disabledPluginKeys.Intersect(stoppedPluginKeys).Count(); if (nbIntersect != 0) { throw new CKException(R.DisabledAndStoppedPluginsIntersect, nbIntersect); } nbIntersect = disabledPluginKeys.Intersect(runningPluginKeys).Count(); if (nbIntersect != 0) { throw new CKException(R.DisabledAndRunningPluginsIntersect, nbIntersect); } nbIntersect = stoppedPluginKeys.Intersect(runningPluginKeys).Count(); if (nbIntersect != 0) { throw new CKException(R.StoppedAndRunningPluginsIntersect, nbIntersect); } List <PluginProxy> toDisable = new List <PluginProxy>(); List <PluginProxy> toStop = new List <PluginProxy>(); List <PluginProxy> toStart = new List <PluginProxy>(); foreach (IPluginInfo k in disabledPluginKeys) { PluginProxy p = EnsureProxy(k); if (p.Status != RunningStatus.Disabled) { toDisable.Add(p); if (p.Status != RunningStatus.Stopped) { toStop.Add(p); } } } foreach (IPluginInfo k in stoppedPluginKeys) { PluginProxy p = EnsureProxy(k); if (p.Status != RunningStatus.Stopped) { toStop.Add(p); } } // The lists toDisable and toStop are correctly filled. // A plugin can be in both lists if it must be stopped and then disabled. // Now, we attempt to activate the plugins that must run: if an error occurs, // we leave and return the error since we did not change anything. foreach (IPluginInfo k in runningPluginKeys) { PluginProxy p = EnsureProxy(k); if (!p.IsLoaded) { if (!p.TryLoad(_serviceHost, PluginCreator)) { Debug.Assert(p.LoadError != null); _serviceHost.LogMethodError(PluginCreator.Method, p.LoadError); // Unable to load the plugin: leave now. return(new ExecutionPlanResult() { Culprit = p.PluginKey, Status = ExecutionPlanResultStatus.LoadError }); } Debug.Assert(p.LoadError == null); Debug.Assert(p.Status == RunningStatus.Disabled); _newlyLoadedPlugins.Add(p); } if (p.Status != RunningStatus.Started) { toStart.Add(p); } } // The toStart list is ready: plugins inside are loaded without error. // We stop all "toStop" plugin. // Their "stop" methods will be called. foreach (PluginProxy p in toStop) { if (p.Status > RunningStatus.Stopped) { try { SetPluginStatus(p, RunningStatus.Stopping); p.RealPlugin.Stop(); _log.Debug(String.Format("The {0} plugin has been successfully stopped.", p.PublicName)); } catch (Exception ex) { #if DEBUG //Helps the developper identify the culprit of exception Debugger.Break(); #endif _log.ErrorFormat("There has been a problem when stopping the {0} plugin.", ex, p.PublicName); _serviceHost.LogMethodError(p.GetImplMethodInfoStop(), ex); } } } // We un-initialize all "toStop" plugin. // Their "Teardown" methods will be called. // After that, they are all "stopped". foreach (PluginProxy p in toStop) { try { if (p.Status > RunningStatus.Stopped) { SetPluginStatus(p, RunningStatus.Stopped); p.RealPlugin.Teardown(); _log.Debug(String.Format("The {0} plugin has been successfully torn down.", p.PublicName)); } } catch (Exception ex) { #if DEBUG //Helps the developper identify the culprit of exceptions Debugger.Break(); #endif _log.ErrorFormat("There has been a problem when tearing down the {0} plugin.", ex, p.PublicName); _serviceHost.LogMethodError(p.GetImplMethodInfoTeardown(), ex); } } Debug.Assert(toStop.All(p => p.Status <= RunningStatus.Stopped)); // Prepares the plugins to start so that they become the implementation // of their Service and are at least stopped (instead of disabled). foreach (PluginProxy p in toStart) { ServiceProxyBase service = p.Service; // The call to service.SetImplementation, sets the implementation and takes // the _status of the service into account: this status is at most Stopped // since we necessarily stopped the previous implementation (if any) above. if (service != null) { Debug.Assert(service.Status <= RunningStatus.Stopped); service.SetPluginImplementation(p); } // This call will trigger an update of the service status. if (p.Status == RunningStatus.Disabled) { SetPluginStatus(p, RunningStatus.Stopped); } } // Now that services have been associated to their new implementation (in Stopped status), we // can disable the plugins that must be disabled. foreach (PluginProxy p in toDisable) { SetPluginStatus(p, RunningStatus.Disabled); try { p.DisposeIfDisposable(); } catch (Exception ex) { #if DEBUG //Helps the developper identify the culprit of exceptions Debugger.Break(); #endif _log.ErrorFormat("There has been a problem when disposing the {0} plugin.", ex, p.PublicName); _serviceHost.LogMethodError(p.GetImplMethodInfoDispose(), ex); } } // Before starting for (int i = 0; i < toStart.Count; i++) { PluginProxy p = toStart[i]; // We configure plugin's edition properties. if (PluginConfigurator != null) { PluginConfigurator(p); } SetPluginStatus(p, RunningStatus.Starting); IPluginSetupInfo info = new IPluginSetupInfo(); try { p.RealPlugin.Setup(info); info.Clear(); _log.Debug(String.Format("The {0} plugin has been successfully set up.", p.PublicName)); } catch (Exception ex) { #if DEBUG //Helps the developper identify the culprit of exceptions Debugger.Break(); #endif _log.ErrorFormat("There has been a problem when setting up the {0} plugin.", ex, p.PublicName); _serviceHost.LogMethodError(p.GetImplMethodInfoSetup(), ex); // Revoking the call to Setup for all plugins that haven't been started yet. //Will pass the plugin to states : Stopping and then Stopped for (int j = 0; j <= i; j++) { RevokeSetupCall(toStart[j]); } info.Error = ex; return(new ExecutionPlanResult() { Culprit = p.PluginKey, Status = ExecutionPlanResultStatus.SetupError, SetupInfo = info }); } } // Since we are now ready to start new plugins, it is now time to make the external world // aware of the existence of any new plugins and configure them to run. foreach (PluginProxy p in _newlyLoadedPlugins) { _loadedPlugins.Add(p.PluginKey.UniqueId, p); } Debug.Assert(ServiceReferencesBinder != null); try { var listNew = new ReadOnlyCollectionOnICollection <PluginProxy>(_newlyLoadedPlugins); //var disabled = new ReadOnlyCollectionAdapter<IPluginProxy, PluginProxy>( toDisable ); ServiceReferencesBinder(listNew); } catch (Exception ex) { _serviceHost.LogMethodError(ServiceReferencesBinder.Method, ex); } _newlyLoadedPlugins.Clear(); for (int i = 0; i < toStart.Count; i++) { PluginProxy p = toStart[i]; try { SetPluginStatus(p, RunningStatus.Started); p.RealPlugin.Start(); _log.Debug(String.Format("The {0} plugin has been successfully started.", p.PublicName)); } catch (Exception ex) { // Emitted as low level log. _log.ErrorFormat("There has been a problem when starting the {0} plugin.", ex, p.PublicName); // Emitted as a log event. _serviceHost.LogMethodError(p.GetImplMethodInfoStart(), ex); //All the plugins already started when the exception was thrown have to be stopped + teardown (including this one in exception) for (int j = 0; j <= i; j++) { RevokeStartCall(toStart[j]); } // Revoking the call to Setup for all plugins that hadn't been started when the exception occured. for (int j = i + 1; j < toStart.Count; j++) { RevokeSetupCall(toStart[j]); } return(new ExecutionPlanResult() { Culprit = p.PluginKey, Status = ExecutionPlanResultStatus.LoadError, Error = ex }); } } return(new ExecutionPlanResult()); }