예제 #1
0
        internal void Initialize( PluginDiscoverer.Merger merger, Runner.PluginInfo r )
        {
            base.Initialize( r );
            
            _pluginId = r.PluginId;
            _name = r.PublicName;
            _pluginFullName = r.PluginFullName;
            _desc = r.Description;
            _url = r.RefUrl;
            _version = r.Version;
            _iconUri = r.IconUri;
            _isOldVersion = r.IsOldVersion;
            _assemblyInfo = merger.FindOrCreate( r.AssemblyInfo );

            Debug.Assert( r.Categories != null );
            _categoriesCollection = r.Categories;
            _categories = new ReadOnlyListOnIList<string>( _categoriesCollection );

            if( r.EditorsInfo != null )
            {
                _editorsCollection = new List<PluginConfigAccessorInfo>();
                foreach( Runner.PluginConfigAccessorInfo editor in r.EditorsInfo )
                    _editorsCollection.Add( merger.FindOrCreate( editor ) );
            }

            _servicesReferencesCollection = new List<ServiceReferenceInfo>();
            _dicServiceReferences = new Dictionary<Runner.ServiceReferenceInfo, ServiceReferenceInfo>();
            foreach( Runner.ServiceReferenceInfo service in r.ServiceReferences )
                _servicesReferencesCollection.Add( FindOrCreate( merger, service ) );

            if( r.Service != null )
            {
                _service = merger.FindOrCreate( r.Service );
            }
            _editableByCollection = new List<PluginConfigAccessorInfo>();
            foreach( Runner.PluginConfigAccessorInfo editor in r.EditableBy )
                _editableByCollection.Add( merger.FindOrCreate( editor ) );

            _serviceReferences = new ReadOnlyListOnIList<ServiceReferenceInfo>( _dicServiceReferences.Values.ToList() );
            _editorsInfo = new ReadOnlyListOnIList<PluginConfigAccessorInfo>( _editorsCollection );
            _editableBy = new ReadOnlyListOnIList<PluginConfigAccessorInfo>( _editableByCollection );
            _serviceReferences = new ReadOnlyListOnIList<ServiceReferenceInfo>( _dicServiceReferences.Values.ToList() );
            _editorsInfo = new ReadOnlyListOnIList<PluginConfigAccessorInfo>( _editorsCollection );
        }
예제 #2
0
            internal PluginInfo FindOrCreate(Runner.PluginInfo plugin)
            {
                PluginInfo f;

                if (!_dicPlugins.TryGetValue(new KeyValuePair <Guid, Version>(plugin.PluginId, plugin.Version), out f))
                {
                    if (plugin.IsOldVersion ||
                        !_discoverer._pluginsById.TryGetValue(plugin.PluginId, out f) ||
                        f.Version > plugin.Version)
                    {
                        f = new PluginInfo(_discoverer);
                        _dicPlugins.Add(new KeyValuePair <Guid, Version>(plugin.PluginId, plugin.Version), f);
                        _hasBeenDiscovered.Add(f);
                        f.Initialize(this, plugin);

                        if (plugin.IsOldVersion)
                        {
                            _newOldPlugins.Add(f);
                        }
                        else
                        {
                            _newPlugins.Add(f);
                        }

                        if (!plugin.HasError && !plugin.IsOldVersion)
                        {
                            _discoverer._plugins.Add(f);
                            if (!_discoverer._pluginsById.ContainsKey(f.PluginId))
                            {
                                _discoverer._pluginsById.Add(f.PluginId, f);
                            }
                            else
                            {
                                _discoverer._pluginsById[f.PluginId] = f;
                            }
                        }
                    }
                    else
                    {
                        _dicPlugins.Remove(new KeyValuePair <Guid, Version>(f.PluginId, f.Version));
                        PluginInfo newOldPlugin = f.Clone();
                        newOldPlugin.IsOldVersion = true;
                        _newOldPlugins.Add(f);

                        Debug.Assert(!_hasBeenDiscovered.Contains(f));
                        _hasBeenDiscovered.Add(f);

                        _dicPlugins.Add(new KeyValuePair <Guid, Version>(newOldPlugin.PluginId, newOldPlugin.Version), newOldPlugin);
                        _dicPlugins.Add(new KeyValuePair <Guid, Version>(plugin.PluginId, plugin.Version), f);

                        f.Initialize(this, plugin);
                    }
                }
                else
                {
                    Debug.Assert(f != null && (_hasBeenDiscovered.Contains(f) || (f.LastChangedVersion != _discoverer.CurrentVersion)));

                    if (f.LastChangedVersion != _discoverer.CurrentVersion &&
                        !_hasBeenDiscovered.Contains(f))
                    {
                        _hasBeenDiscovered.Add(f);
                        if (f.Merge(this, plugin))
                        {
                            _changedPlugins.Add(f);
                            if (f.IsOldVersion && !_newOldPlugins.Contains(f))
                            {
                                _newOldPlugins.Add(f);
                            }
                        }
                    }
                }
                return(f);
            }
예제 #3
0
        /// <summary>
        /// Read all Type in the assembly.
        /// </summary>
        /// <param name="RegisterServiceInfo">Will be called for each discovered service interface.</param>
        /// <param name="RegisterUseServiceInfo">Will be called for each discovered service reference.</param>
        internal void ReadAllTypes(Func <PluginAssemblyInfo, Type, ServiceInfo> RegisterServiceInfo,
                                   Func <Type, bool, ServiceRefInfo> RegisterUseServiceInfo)
        {
            Debug.Assert(_assembly != null);
            List <PluginInfo>  plug = new List <PluginInfo>();
            List <ServiceInfo> serv = new List <ServiceInfo>();

            // We loop on each type we can find into the assembly.
            foreach (Type t in _assembly.GetExportedTypes())
            {
                // If it implements the IPlugin interface.
                if (t.GetInterface(typeof(IPlugin).FullName) != null)
                {
                    PluginInfo info = null;
                    try
                    {
                        // And if it have the PluginAttribute.
                        foreach (CustomAttributeData attr in CustomAttributeData.GetCustomAttributes(t))
                        {
                            if (attr.Constructor.DeclaringType.FullName == "CK.Plugin.PluginAttribute")
                            {
                                info = new PluginInfo(attr)
                                {
                                    AssemblyInfo = this, PluginFullName = t.FullName
                                };
                                break;
                            }
                        }
                        if (info == null)
                        {
                            info = new PluginInfo("Unable to find Plugin attribute.");
                        }
                    }
                    catch (Exception ex)
                    {
                        info = new PluginInfo(ex.Message);
                    }
                    Debug.Assert(info != null, "At this point, info can not be null.");
                    if (info.ErrorMessage == null)  // If there are no errors
                    {
                        // Discover implemented Services.
                        try
                        {
                            ServiceInfo result = null;
                            foreach (Type i in t.GetInterfaces())
                            {
                                if (i.IsGenericType && i.GetGenericTypeDefinition().AssemblyQualifiedName == typeof(IService <>).AssemblyQualifiedName)
                                {
                                    // Implementing the IService marker interface is an error.
                                    info.AddErrorLine(R.PluginImplementIService);
                                    break;
                                }
                                if (PluginDiscoverer.IsIDynamicService(i))
                                {
                                    if (result != null)
                                    {
                                        // Only one IService can be implemented at a time.
                                        info.AddErrorLine(R.MultipleServiceImplementation);
                                        result = null;
                                        break;
                                    }
                                    else
                                    {
                                        // We are on a IDynamicService, not a IService<>.
                                        ServiceRefInfo r = RegisterUseServiceInfo(i, false);
                                        Debug.Assert(!r.IsIServiceWrapped && !r.IsUnknownGenericInterface, "We tested this above.");
                                        Debug.Assert(r.Reference != null, "Since we are on a IDynamicService (tested above).");
                                        result = r.Reference;
                                    }
                                }
                            }
                            if (result != null)
                            {
                                result.Implementations.Add(info);
                            }
                            info.Service = result;
                        }
                        catch (Exception ex)
                        {
                            info.AddErrorLine(ex.Message);
                        }

                        // Discover referenced Services and edited configuration.
                        try
                        {
                            // Process public properties to discover service references and edited configurations.
                            List <ServiceReferenceInfo> refs = info.ServiceReferences = new List <ServiceReferenceInfo>();
                            foreach (PropertyInfo p in t.GetProperties())
                            {
                                try
                                {
                                    bool serviceRefHandled = false;
                                    bool editedConfHandled = false;
                                    foreach (CustomAttributeData attr in CustomAttributeData.GetCustomAttributes(p))
                                    {
                                        #region The [DynamicServiceAttribute] has the priority.
                                        if (attr.Constructor.DeclaringType.FullName == typeof(DynamicServiceAttribute).FullName)
                                        {
                                            serviceRefHandled = true;
                                            ServiceReferenceInfo dep;
                                            // Since we are in a [DynamicServiceAttribute], we expect a IDynamicService and reject any other generic interface than IService<>,
                                            // but we accept other (not IDynamicService) interfaces in order to capture the reference (hence the registerOnlyIDynamicService = false parameter below).
                                            ServiceRefInfo r = RegisterUseServiceInfo(p.PropertyType, false);
                                            dep = new ServiceReferenceInfo(info, p.Name, r, attr.NamedArguments);
                                            Debug.Assert((r.Reference == null) == (r.IsUnknownGenericInterface));
                                            // Handle errors.
                                            if (!p.CanWrite)
                                            {
                                                dep.AddErrorLine(R.NotWritableServiceType);
                                            }
                                            if (r.IsUnknownGenericInterface)
                                            {
                                                dep.AddErrorLine(R.GenericServiceOtherThanIServiceNotSupported);
                                            }
                                            if (!r.IsIDynamicService)
                                            {
                                                Debug.Assert(!PluginDiscoverer.IsIDynamicService(p.PropertyType));
                                                dep.AddErrorLine(R.DynamicServiceAttributeRequiresIDynamicService);
                                            }
                                            refs.Add(dep);
                                            break;
                                        }
                                        #endregion
                                        #region The [RequiredService] can reference non IDynamicService service.
                                        if (attr.Constructor.DeclaringType.FullName == typeof(RequiredServiceAttribute).FullName)
                                        {
                                            RunningRequirement req = RunningRequirement.MustExistAndRun;
                                            // Since [RequiredServiceAttribute] can have Requires = false parameter.
                                            if (attr.NamedArguments.Count == 1 && (bool)attr.NamedArguments[0].TypedValue.Value == false)
                                            {
                                                // If Requires == false, we consider it to be optional.
                                                req = RunningRequirement.Optional;
                                            }
                                            serviceRefHandled = true;
                                            ServiceRefInfo       r   = RegisterUseServiceInfo(p.PropertyType, false);
                                            ServiceReferenceInfo dep = new ServiceReferenceInfo(info, p.Name, r, req);
                                            if (!p.CanWrite)
                                            {
                                                dep.AddErrorLine(R.NotWritableServiceType);
                                            }
                                            else if (r.IsUnknownGenericInterface)
                                            {
                                                dep.AddErrorLine(R.GenericServiceOtherThanIServiceNotSupported);
                                            }
                                            refs.Add(dep);
                                            break;
                                        }
                                        #endregion
                                        #region The [EditedConfiguration] comes last...
                                        if (attr.Constructor.DeclaringType.FullName == typeof(ConfigurationAccessorAttribute).FullName)
                                        {
                                            editedConfHandled = true;
                                            try
                                            {
                                                info.EditorsInfo.Add(new PluginConfigAccessorInfo(attr, info, false)
                                                {
                                                    ConfigurationPropertyName = p.Name
                                                });
                                            }
                                            catch (Exception ex)
                                            {
                                                info.AddErrorLine(ex.Message);
                                            }
                                        }
                                        #endregion
                                    }
                                    // If the property has not been handled through its attributes, we detect potential services references: any public read/write
                                    // property that expose a IDynamicService or a IService<> is transformed into an optional ServiceReferenceInfo.
                                    if (!serviceRefHandled && !editedConfHandled && p.CanWrite && p.CanRead)
                                    {
                                        if (p.PropertyType.IsInterface)
                                        {
                                            if (p.PropertyType.Name == "IPluginConfigAccessor")
                                            {
                                                info.EditorsInfo.Add(new PluginConfigAccessorInfo(null, info, true)
                                                {
                                                    ConfigurationPropertyName = p.Name
                                                });
                                            }
                                            else
                                            {
                                                // Here we only register services if they are IDynamicService.
                                                ServiceRefInfo r = RegisterUseServiceInfo(p.PropertyType, true);
                                                if (r.Reference != null)
                                                {
                                                    Debug.Assert(r.IsIDynamicService);
                                                    ServiceReferenceInfo dep;
                                                    dep = new ServiceReferenceInfo(info, p.Name, r, RunningRequirement.Optional);
                                                }
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    info.AddErrorLine(ex.Message);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            info.AddErrorLine(ex.Message);
                        }

                        plug.Add(info);
                    }
                }
                // Discover just a service
                else if (t.IsInterface && PluginDiscoverer.IsIDynamicService(t))
                {
                    ServiceInfo service = RegisterServiceInfo(this, t);
                    service.AssemblyQualifiedName = t.AssemblyQualifiedName;

                    // Get the Events that the service exposes
                    foreach (EventInfo e in CK.Reflection.ReflectionHelper.GetFlattenEvents(t))
                    {
                        service.EventsInfoCollection.Add(new SimpleEventInfo(e.Name));
                    }

                    // Get the Properties that the service exposes
                    foreach (PropertyInfo p in CK.Reflection.ReflectionHelper.GetFlattenProperties(t))
                    {
                        service.PropertiesInfoCollection.Add(new SimplePropertyInfo(p.Name, p.PropertyType.ToString()));
                    }

                    // Get the Methods that the service exposes
                    foreach (MethodInfo m in CK.Reflection.ReflectionHelper.GetFlattenMethods(t))
                    {
                        if (!m.IsSpecialName)
                        {
                            Type             tR = m.ReturnType;
                            SimpleMethodInfo s  = new SimpleMethodInfo(m.Name, tR.ToString());
                            foreach (ParameterInfo p in m.GetParameters())
                            {
                                s.Parameters.Add(new SimpleParameterInfo(p.Name, p.ParameterType.ToString()));
                            }
                            service.MethodsInfoCollection.Add(s);
                        }
                    }
                    serv.Add(service);
                }
            }
            // Fills _plugins and _services collections (properties Plugin and Services of this PluginAssemblyInfo)
            // with local collections (Plugin = _plugins = plug & Services = _services = serv).
            _plugins  = plug;
            _services = serv;
        }
예제 #4
0
        internal bool Merge( PluginDiscoverer.Merger merger, Runner.PluginInfo r )
        {
            bool hasChanged = false;

            if( _pluginId != r.PluginId )
            {
                _pluginId = r.PluginId;
                hasChanged = true;
            }
            if( _name != r.PublicName )
            {
                _name = r.PublicName;
                hasChanged = true;
            }
            if( _pluginFullName != r.PluginFullName )
            {
                _pluginFullName = r.PluginFullName;
                hasChanged = true;
            }
            if( _desc != r.Description )
            {
                _desc = r.Description;
                hasChanged = true;
            }
            if( _url != r.RefUrl )
            {
                _url = r.RefUrl;
                hasChanged = true;
            }
            if( _version != r.Version )
            {
                _version = r.Version;
                hasChanged = true;
            }
            if( _iconUri != r.IconUri )
            {
                _iconUri = r.IconUri;
                hasChanged = true;
            }
            if( _isOldVersion != r.IsOldVersion )
            {
                _isOldVersion = r.IsOldVersion;
                hasChanged = true;
            }
            
            Debug.Assert( _categories != null && r.Categories != null, "Already initialized." );
            if( !_categories.SequenceEqual( r.Categories, StringComparer.Ordinal ) )
            {
                _categoriesCollection = r.Categories;
                _categories = new ReadOnlyListOnIList<string>( _categoriesCollection );
                hasChanged = true;
            }
            
            PluginAssemblyInfo newAI = merger.FindOrCreate( r.AssemblyInfo );
            if( _assemblyInfo != newAI )
            {
                _assemblyInfo = newAI;
                hasChanged = true;
            }

            if( PluginDiscoverer.Merger.GenericMergeLists( _servicesReferencesCollection, r.ServiceReferences, ( s ) => { return FindOrCreate( merger, s ); }, null ) )
            {
                hasChanged = true;
            }

            // r.Service can be null, some checks have to be made:
            if( r.Service == null )
            {
                if( _service != null )
                {
                    _service = null;
                    hasChanged = true;
                }
            }
            else
            {
                ServiceInfo s = merger.FindOrCreate( r.Service );
                if( _service != s )
                {
                    _service = s;
                    hasChanged = true;
                }
            }

            if ( PluginDiscoverer.Merger.GenericMergeLists( _editorsCollection, r.EditorsInfo, merger.FindOrCreate, null ) )
            {
                hasChanged = true;
            }

            if( PluginDiscoverer.Merger.GenericMergeLists( _editableByCollection, r.EditableBy, merger.FindOrCreate, null ) )
            {
                hasChanged = true;
            }

            return Merge( r, hasChanged );
        }