internal ServiceRequirement(ServiceRequirementCollection holder, string serviceAssemblyQualifiedName, RunningRequirement requirement) : this( holder ) { Debug.Assert(serviceAssemblyQualifiedName != null); AssemblyQualifiedName = serviceAssemblyQualifiedName; _req = requirement; }
internal ServiceRequirement( ServiceRequirementCollection holder, string serviceAssemblyQualifiedName, RunningRequirement requirement ) : this( holder ) { Debug.Assert( serviceAssemblyQualifiedName != null ); AssemblyQualifiedName = serviceAssemblyQualifiedName; _req = requirement; }
/// <summary> /// Initializes a new <see cref="PluginRequirementCollectionChangingEventArgs"/>. /// </summary> /// <param name="c">The collection that is changing.</param> /// <param name="action">The <see cref="ChangeStatus"/>.</param> /// <param name="pluginId">The plugin identifier concerned.</param> /// <param name="requirement">The <see cref="RunningRequirement"/> of the changed <paramref name="pluginId"/>.</param> public PluginRequirementCollectionChangingEventArgs( IPluginRequirementCollection c, ChangeStatus action, Guid pluginId, RunningRequirement requirement ) { Collection = c; Action = action; PluginId = pluginId; Requirement = requirement; }
internal PluginRequirement( PluginRequirementCollection holder, Guid pluginID, RunningRequirement requirement ) : this( holder ) { Debug.Assert( pluginID != null ); PluginId = pluginID; _req = requirement; }
/// <summary> /// Initializes a new <see cref="PluginRequirementCollectionChangingEventArgs"/>. /// </summary> /// <param name="c">The collection that is changing.</param> /// <param name="action">The <see cref="ChangeStatus"/>.</param> /// <param name="pluginId">The plugin identifier concerned.</param> /// <param name="requirement">The <see cref="RunningRequirement"/> of the changed <paramref name="pluginId"/>.</param> public PluginRequirementCollectionChangingEventArgs(IPluginRequirementCollection c, ChangeStatus action, Guid pluginId, RunningRequirement requirement) { Collection = c; Action = action; PluginId = pluginId; Requirement = requirement; }
/// <summary> /// Initializes a new <see cref="ServiceRequirementCollectionChangedEventArgs"/>. /// </summary> /// <param name="c">The collection that changed.</param> /// <param name="action">The <see cref="ChangeStatus"/>.</param> /// <param name="assemblyQualifiedName">The service identifier concerned.</param> /// <param name="requirement">The <see cref="RunningRequirement"/> of the changed service.</param> public ServiceRequirementCollectionChangedEventArgs( IServiceRequirementCollection c, ChangeStatus action, string assemblyQualifiedName, RunningRequirement requirement ) { Collection = c; Action = action; AssemblyQualifiedName = assemblyQualifiedName; Requirement = requirement; }
internal PluginRequirement(PluginRequirementCollection holder, Guid pluginID, RunningRequirement requirement) : this( holder ) { Debug.Assert(pluginID != null); PluginId = pluginID; _req = requirement; }
internal bool Merge(PluginDiscoverer.Merger merger, Runner.ServiceReferenceInfo r) { bool hasChanged = false; if (_propertyName != r.PropertyName) { _propertyName = r.PropertyName; hasChanged = true; } if (_requirements != r.Requirements) { _requirements = r.Requirements; hasChanged = true; } ServiceInfo newService = merger.FindOrCreate(r.Reference); if (_reference != newService) { _reference = newService; hasChanged = true; } PluginInfo newPlugin = merger.FindOrCreate(r.Owner); if (_owner != newPlugin) { _owner = newPlugin; hasChanged = true; } return(Merge(r, hasChanged)); }
/// <summary> /// Initializes a new <see cref="ServiceRequirementCollectionChangingEventArgs"/>. /// </summary> /// <param name="c">The collection that is changing.</param> /// <param name="action">The <see cref="ChangeStatus"/>.</param> /// <param name="assemblyQualifiedName">The service identifier concerned.</param> /// <param name="requirement">The <see cref="RunningRequirement"/> of the changing service.</param> public ServiceRequirementCollectionChangingEventArgs(IServiceRequirementCollection c, ChangeStatus action, string assemblyQualifiedName, RunningRequirement requirement) { Collection = c; Action = action; AssemblyQualifiedName = assemblyQualifiedName; Requirement = requirement; }
internal void Initialize(PluginDiscoverer.Merger merger, Runner.ServiceReferenceInfo r) { base.Initialize(r); _propertyName = r.PropertyName; _requirements = r.Requirements; _reference = merger.FindOrCreate(r.Reference); _owner = merger.FindOrCreate(r.Owner); }
internal ServiceReferenceInfo(PluginInfo owner, string propertyName, ServiceRefInfo reference, RunningRequirement requires) { Owner = owner; _propertyName = propertyName; _reference = reference.Reference; _isIServiceWrapped = reference.IsIServiceWrapped; _requirements = requires; }
internal void Change(ChangeStatus action, Guid pluginID, RunningRequirement requirement) { if (Changed != null) { PluginRequirementCollectionChangedEventArgs e = new PluginRequirementCollectionChangedEventArgs(this, action, pluginID, requirement); Changed(this, e); } }
internal void Change( ChangeStatus action, Guid pluginID, RunningRequirement requirement ) { if( Changed != null ) { PluginRequirementCollectionChangedEventArgs e = new PluginRequirementCollectionChangedEventArgs( this, action, pluginID, requirement ); Changed( this, e ); } }
internal bool CanChange( ChangeStatus action, Guid pluginID, RunningRequirement requirement ) { if( Changing != null ) { PluginRequirementCollectionChangingEventArgs eCancel = new PluginRequirementCollectionChangingEventArgs( this, action, pluginID, requirement ); Changing( this, eCancel ); return !eCancel.Cancel; } return true; }
internal bool CanChange(ChangeStatus action, Guid pluginID, RunningRequirement requirement) { if (Changing != null) { PluginRequirementCollectionChangingEventArgs eCancel = new PluginRequirementCollectionChangingEventArgs(this, action, pluginID, requirement); Changing(this, eCancel); return(!eCancel.Cancel); } return(true); }
internal ServiceReferenceInfo(PluginInfo owner, string propertyName, ServiceRefInfo reference, IList <CustomAttributeNamedArgument> attrArgs) : this(owner, propertyName, reference, RunningRequirement.Optional) { foreach (CustomAttributeNamedArgument a in attrArgs) { if (a.MemberInfo.Name == "Requires") { _requirements = (RunningRequirement)a.TypedValue.Value; } } }
public PluginRequirement AddOrSet( Guid pluginID, RunningRequirement requirement ) { PluginRequirement req = this.FirstOrDefault( r => r.PluginId == pluginID ); if( req != null ) { if( req.Requirement != requirement && CanChange( ChangeStatus.Update, pluginID, requirement ) ) { req.Requirement = requirement; Change( ChangeStatus.Update, pluginID, requirement ); } } else if( CanChange( ChangeStatus.Add, pluginID, requirement ) ) { req = new PluginRequirement( this, pluginID, requirement ); req.NextElement = _first; _first = req; _count++; Change( ChangeStatus.Add, pluginID, requirement ); } return req; }
public ServiceRequirement AddOrSet(string serviceAssemblyQualifiedName, RunningRequirement requirement) { ServiceRequirement req = this.FirstOrDefault(r => r.AssemblyQualifiedName == serviceAssemblyQualifiedName); if (req != null) { if (req.Requirement != requirement && CanChange(ChangeStatus.Update, serviceAssemblyQualifiedName, requirement)) { req.Requirement = requirement; Change(ChangeStatus.Update, serviceAssemblyQualifiedName, requirement); } } else if (CanChange(ChangeStatus.Add, serviceAssemblyQualifiedName, requirement)) { req = new ServiceRequirement(this, serviceAssemblyQualifiedName, requirement); req.NextElement = _first; _first = req; _count++; Change(ChangeStatus.Add, serviceAssemblyQualifiedName, requirement); } return(req); }
public PluginRequirement AddOrSet(Guid pluginID, RunningRequirement requirement) { PluginRequirement req = this.FirstOrDefault(r => r.PluginId == pluginID); if (req != null) { if (req.Requirement != requirement && CanChange(ChangeStatus.Update, pluginID, requirement)) { req.Requirement = requirement; Change(ChangeStatus.Update, pluginID, requirement); } } else if (CanChange(ChangeStatus.Add, pluginID, requirement)) { req = new PluginRequirement(this, pluginID, requirement); req.NextElement = _first; _first = req; _count++; Change(ChangeStatus.Add, pluginID, requirement); } return(req); }
public void TestPluginRequirementCollectionEvents() { int createdEventFired = 0; int removedEventFired = 0; int updatedEventFired = 0; int clearedEventFired = 0; int creatingEventFired = 0; int removingEventFired = 0; int updatingEventFired = 0; int clearingEventFired = 0; bool cancel = false; Guid changingPluginId = Guid.Empty; RunningRequirement previousRequirement = RunningRequirement.OptionalTryStart; RunningRequirement newRequirement = RunningRequirement.OptionalTryStart; PluginRequirement lastRequirementCreated = null; PluginRequirement lastRequirementRemoved = null; IPluginRequirementCollection reqs = new PluginRequirementCollection(); reqs.Changing += (sender, args) => { switch (args.Action) { case CK.Core.ChangeStatus.Update: updatingEventFired++; if (!cancel) { previousRequirement = args.Collection.Find(args.PluginId).Requirement; } break; case CK.Core.ChangeStatus.Add: creatingEventFired++; break; case CK.Core.ChangeStatus.Delete: removingEventFired++; break; case CK.Core.ChangeStatus.ContainerClear: clearingEventFired++; break; } if (cancel) { args.Cancel = true; } }; reqs.Changed += (sender, args) => { switch (args.Action) { case CK.Core.ChangeStatus.Update: updatedEventFired++; newRequirement = args.Requirement; break; case CK.Core.ChangeStatus.Add: lastRequirementCreated = args.Collection.Find(args.PluginId); createdEventFired++; break; case CK.Core.ChangeStatus.Delete: lastRequirementRemoved = args.Collection.Find(args.PluginId); removedEventFired++; break; case CK.Core.ChangeStatus.ContainerClear: clearedEventFired++; break; } }; PluginRequirement req = reqs.AddOrSet(Guid.NewGuid(), RunningRequirement.MustExistAndRun); Assert.That(lastRequirementCreated == req); Assert.That(createdEventFired == 1); Assert.That(creatingEventFired == 1); PluginRequirement req1 = reqs.AddOrSet(Guid.NewGuid(), RunningRequirement.MustExistAndRun); Assert.That(lastRequirementCreated == req1); Assert.That(createdEventFired == 2); Assert.That(creatingEventFired == 2); PluginRequirement req2 = reqs.AddOrSet(Guid.NewGuid(), RunningRequirement.MustExistAndRun); Assert.That(lastRequirementCreated == req2); Assert.That(createdEventFired == 3); Assert.That(creatingEventFired == 3); reqs.AddOrSet(req2.PluginId, RunningRequirement.MustExist); Assert.That(previousRequirement == RunningRequirement.MustExistAndRun); Assert.That(newRequirement == RunningRequirement.MustExist); Assert.That(updatingEventFired == 1); Assert.That(updatedEventFired == 1); // Now, cancel is true, nothing should be done cancel = true; reqs.AddOrSet(req2.PluginId, RunningRequirement.Optional); Assert.That(previousRequirement == RunningRequirement.MustExistAndRun); Assert.That(newRequirement == RunningRequirement.MustExist); Assert.That(updatingEventFired == 2); Assert.That(updatedEventFired == 1); cancel = false; reqs.Clear(); Assert.That(clearedEventFired, Is.EqualTo(1)); }
/// <summary> /// Reads back an existing <see cref="RequirementLayer"/> or creates a new one /// from xml data previously written by <see cref="WriteInlineToXml"/> method. /// </summary> /// <param name="r">The xml stream to read: the reader must be on an opened element.</param> /// <param name="reqLayer">An existing layer or null to create a new one.</param> public static void ReadInlineFromXml(XmlReader r, ref RequirementLayer reqLayer) { if (reqLayer != null) { reqLayer.LayerName = r.GetAttribute("Name"); } else { reqLayer = new RequirementLayer(r.GetAttribute("Name")); } r.Read(); if (r.IsStartElement("PluginRequirements")) { if (r.IsEmptyElement) { r.Read(); } else { r.Read(); reqLayer.PluginRequirements.Clear(); while (r.IsStartElement("PluginRequirement")) { Guid pluginId = new Guid(r.GetAttribute("PluginId")); RunningRequirement runningReq = (RunningRequirement)Enum.Parse(typeof(RunningRequirement), r.GetAttribute("Requirement")); reqLayer.PluginRequirements.AddOrSet(pluginId, runningReq); if (r.IsEmptyElement) { r.Read(); } else { r.Skip(); } } r.ReadEndElement(); } } if (r.IsStartElement("ServiceRequirements")) { if (r.IsEmptyElement) { r.Read(); } else { r.Read(); reqLayer.ServiceRequirements.Clear(); while (r.IsStartElement("ServiceRequirement")) { string assemblyQualifiedName = r.GetAttribute("AssemblyQualifiedName"); RunningRequirement runningReq = (RunningRequirement)Enum.Parse(typeof(RunningRequirement), r.GetAttribute("Requirement")); reqLayer.ServiceRequirements.AddOrSet(assemblyQualifiedName, runningReq); if (r.IsEmptyElement) { r.Read(); } else { r.Skip(); } } r.ReadEndElement(); } } }
/// <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 CanChange(ChangeStatus action, string serviceAssemblyQualifiedName, RunningRequirement requirement) { if (Changing != null) { ServiceRequirementCollectionChangingEventArgs eCancel = new ServiceRequirementCollectionChangingEventArgs(this, action, serviceAssemblyQualifiedName, requirement); Changing(this, eCancel); return(!eCancel.Cancel); } return(true); }
internal void Change(ChangeStatus action, string serviceAssemblyQualifiedName, RunningRequirement requirement) { if (Changed != null) { ServiceRequirementCollectionChangedEventArgs e = new ServiceRequirementCollectionChangedEventArgs(this, action, serviceAssemblyQualifiedName, requirement); Changed(this, e); } }