Example #1
0
 internal ServiceInfo(PluginAssemblyInfo a, Type t)
 {
     _assembly = a;
     _assemblyQualifiedName = t.AssemblyQualifiedName;
     _serviceFullName       = t.FullName;
     _isDynamicService      = PluginDiscoverer.IsIDynamicService(t);
     _impl = new List <PluginInfo>();
     _eventsInfoCollection     = new List <SimpleEventInfo>();
     _methodsInfoCollection    = new List <SimpleMethodInfo>();
     _propertiesInfoCollection = new List <SimplePropertyInfo>();
 }
        /// <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;
        }