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 ); }
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); }
/// <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; }
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 ); }