internal ServiceInfo FindOrCreate(Runner.ServiceInfo service) { ServiceInfo f = null; if (!_dicServices.TryGetValue(service.AssemblyQualifiedName, out f)) { f = new ServiceInfo(_discoverer); _dicServices.Add(service.AssemblyQualifiedName, f); _newServices.Add(f); _hasBeenDiscovered.Add(f); f.Initialize(this, service); if (!service.HasError) { _discoverer._services.Add(f); } _discoverer._servicesByAssemblyQualifiedName[f.AssemblyQualifiedName] = f; } 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, service)) { _changedServices.Add(f); } } } return(f); }
internal void Initialize(PluginDiscoverer.Merger merger, Runner.ServiceInfo r) { _assemblyQualifiedName = r.AssemblyQualifiedName; _serviceFullName = r.ServiceFullName; _isDynamicService = r.IsDynamicService; Debug.Assert(!_isDynamicService || (r.HasError || r.AssemblyInfo != null), "If we are a DynamicService, we must have an assembly or be in error."); if (r.AssemblyInfo != null) { _assembly = merger.FindOrCreate(r.AssemblyInfo); } base.Initialize(r); _implCollection = new List <PluginInfo>(); foreach (Runner.PluginInfo plugin in r.Implementations) { _implCollection.Add(merger.FindOrCreate(plugin)); } _impl = new ReadOnlyListOnIList <PluginInfo>(_implCollection); _propertiesInfoCollection = new List <SimplePropertyInfo>(); foreach (Runner.SimplePropertyInfo rP in r.PropertiesInfoCollection) { SimplePropertyInfo p = new SimplePropertyInfo(); p.Initialize(rP); _propertiesInfoCollection.Add(p); } _propertiesInfoCollectionEx = new ReadOnlyListOnIList <SimplePropertyInfo>(_propertiesInfoCollection); _methodsInfoCollection = new List <SimpleMethodInfo>(); foreach (Runner.SimpleMethodInfo rM in r.MethodsInfoCollection) { SimpleMethodInfo m = new SimpleMethodInfo(); m.Initialize(rM); _methodsInfoCollection.Add(m); } _methodsInfoCollectionEx = new ReadOnlyListOnIList <SimpleMethodInfo>(_methodsInfoCollection); _eventsInfoCollection = new List <SimpleEventInfo>(); foreach (Runner.SimpleEventInfo rE in r.EventsInfoCollection) { SimpleEventInfo e = new SimpleEventInfo(); e.Initialize(rE); _eventsInfoCollection.Add(e); } _eventsInfoCollectionEx = new ReadOnlyListOnIList <SimpleEventInfo>(_eventsInfoCollection); }
internal bool Merge(PluginDiscoverer.Merger merger, Runner.ServiceInfo r) { bool hasChanged = false; if (_assemblyQualifiedName != r.AssemblyQualifiedName) { _assemblyQualifiedName = r.AssemblyQualifiedName; hasChanged = true; } if (_serviceFullName != r.ServiceFullName) { _serviceFullName = r.ServiceFullName; hasChanged = true; } if (_isDynamicService != r.IsDynamicService) { _isDynamicService = r.IsDynamicService; hasChanged = true; } PluginAssemblyInfo newAI = r.AssemblyInfo != null?merger.FindOrCreate(r.AssemblyInfo) : null; if (_assembly != newAI) { _assembly = newAI; hasChanged = true; } if (PluginDiscoverer.Merger.GenericMergeLists(_implCollection, r.Implementations, merger.FindOrCreate, null)) { hasChanged = true; } if (PluginDiscoverer.Merger.GenericMergeLists(_methodsInfoCollection, r.MethodsInfoCollection, FindOrCreate, null)) { hasChanged = true; } if (PluginDiscoverer.Merger.GenericMergeLists(_eventsInfoCollection, r.EventsInfoCollection, FindOrCreate, null)) { hasChanged = true; } if (PluginDiscoverer.Merger.GenericMergeLists(_propertiesInfoCollection, r.PropertiesInfoCollection, FindOrCreate, null)) { hasChanged = true; } return(Merge(r, hasChanged)); }
/// <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; }