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);
        }
Example #2
0
        /// <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 );
 }
Example #4
0
 internal PluginStatusCollection(ConfigurationBase holder)
 {
     _holder          = holder;
     _pluginStatusDic = new Dictionary <Guid, PluginStatus>();
     _pluginStatusReadOnlyCollection = new ReadOnlyCollectionOnICollection <PluginStatus>(_pluginStatusDic.Values);
 }
Example #5
0
        /// <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());
        }