/// <summary> /// Determines if the dependencies for a PluginDescriptor are created. /// </summary> /// <param name="descriptor">The descriptor to check dependencies for.</param> /// <param name="descriptors">The collection of PluginDescriptor(s) to check against.</param> /// <returns></returns> private static bool AreDependenciesCreated(PluginDescriptor descriptor, PluginDescriptorCollection descriptors) { foreach (Type type in descriptor.PluginDependencies) { if (descriptors[type].PluginInstance == null) { return(false); } } return(true); }
/// <summary> /// Sorts the collection of PluginDescriptors according to their dependency chain. /// </summary> /// <param name="descriptorCollection">The collection of descriptors to sort.</param> /// <param name="leastDependentFirst">A flag that determines how the descriptors are sorted.</param> /// <returns></returns> public static PluginDescriptorCollection Sort(PluginDescriptorCollection descriptorCollection, bool leastDependentFirst) { Log.WriteLine("Sorting PluginDescriptor Collection. LeastDependentFirst: '{0}'.", leastDependentFirst.ToString()); PluginDescriptor[] descriptors = descriptorCollection.ToArray(); PluginDescriptor.Sort(descriptors, leastDependentFirst); descriptorCollection.Clear(); descriptorCollection.Add(descriptors); return(descriptorCollection); }
/// <summary> /// Sorts the collection of PluginDescriptors according to their dependency chain. /// </summary> /// <param name="descriptorCollection">The collection of descriptors to sort.</param> /// <param name="leastDependentFirst">A flag that determines how the descriptors are sorted.</param> /// <returns></returns> public static PluginDescriptorCollection Sort(PluginDescriptorCollection descriptorCollection, bool leastDependentFirst) { Log.WriteLine("Sorting PluginDescriptor Collection. LeastDependentFirst: '{0}'.", leastDependentFirst.ToString()); PluginDescriptor[] descriptors = descriptorCollection.ToArray(); PluginDescriptor.Sort(descriptors, leastDependentFirst); descriptorCollection.Clear(); descriptorCollection.Add(descriptors); return descriptorCollection; }
/// <summary> /// Cleanup any managed resources /// </summary> protected override void DisposeOfManagedResources() { base.DisposeOfManagedResources(); if (_configurationProviders != null) { _configurationProviders.Dispose(); _configurationProviders = null; } //if (_encryptionProviders != null) //{ // _encryptionProviders.Dispose(); // _encryptionProviders = null; //} if (_pluginProviders != null) { _pluginProviders.Dispose(); _pluginProviders = null; } if (_windowProviders != null) { _windowProviders.Dispose(); _windowProviders = null; } if (_pluginDescriptors != null) { _pluginDescriptors.Dispose(); _pluginDescriptors = null; } if (_instanceManager != null) { _instanceManager.Dispose(); _instanceManager = null; } if (_gcTimer != null) { _gcTimer.Dispose(); _gcTimer = null; } _commandLineArgs = null; _progressViewer = null; }
/// <summary> /// Creates instances of the Plugin type defined by each PluginDescriptor. /// </summary> /// <param name="progressViewer">The callback object implementing IProgressViewer that will be used to monitor progress.</param> /// <param name="descriptors">The collection of PluginDescriptors that describe the Plugins to be loaded.</param> public static void CreatePluginInstances(IProgressViewer progressViewer, PluginDescriptorCollection descriptors) { Log.WriteLine("Creating Plugins. # of Plugins: '{0}'.", descriptors.Count.ToString()); foreach (PluginDescriptor descriptor in descriptors) { if (descriptor.IsStartable) { if (AreDependenciesCreated(descriptor, descriptors)) { CreatePluginInstance(progressViewer, descriptor); } } } }
/// <summary> /// Stops the plugins defined in the collection that have been created. /// </summary> /// <param name="progressViewer">The callback object implementing IProgressViewer that will be used to monitor progress.</param> /// <param name="descriptors">The collection of PluginDescriptors that describe the Plugins to be loaded.</param> public static void StopPlugins(IProgressViewer progressViewer, PluginDescriptorCollection descriptors) { Log.WriteLine("Stopping Plugins. # of Plugins: '{0}'.", descriptors.Count.ToString()); // fire the BeforePluginsStopped event of the PluginContext PluginContext.Current.OnBeforePluginsStopped(new PluginContextEventArgs(PluginContext.Current)); // stop all of the plugins foreach (PluginDescriptor descriptor in descriptors) { if (descriptor.PluginInstance != null) { StopPlugin(progressViewer, descriptor); } else { Log.WriteLine(string.Format("Skipped Plugin: '{0}' was not created.", descriptor.PluginName)); } } }
/// <summary> /// Creates PluginDescriptors from each Plugin Type specified. /// </summary> /// <param name="progressViewer">The callback object implementing IProgressViewer that will be used to monitor progress.</param> /// <param name="types">The collection of Plugin Types to create descriptors for.</param> /// <returns></returns> public static PluginDescriptorCollection CreatePluginDescriptors(IProgressViewer progressViewer, TypeCollection types) { PluginDescriptorCollection descriptors = new PluginDescriptorCollection(); foreach (Type type in types) { try { string message = string.Format("Creating PluginDescriptor, Type: '{0}'.", type.FullName); ProgressViewer.SetExtendedDescription(progressViewer, message); Log.WriteLine(message); PluginDescriptor descriptor = new PluginDescriptor(type); descriptors.Add(descriptor); } catch (Exception ex) { Log.WriteLine(ex); } } return(descriptors); }
/// <summary> /// Determines if the dependencies for a PluginDescriptor are created. /// </summary> /// <param name="descriptor">The descriptor to check dependencies for.</param> /// <param name="descriptors">The collection of PluginDescriptor(s) to check against.</param> /// <returns></returns> private static bool AreDependenciesCreated(PluginDescriptor descriptor, PluginDescriptorCollection descriptors) { foreach (Type type in descriptor.PluginDependencies) if (descriptors[type].PluginInstance == null) return false; return true; }
/// <summary> /// Cleanup any managed resources /// </summary> protected override void DisposeOfManagedResources() { base.DisposeOfManagedResources (); if (_configurationProviders != null) { _configurationProviders.Dispose(); _configurationProviders = null; } //if (_encryptionProviders != null) //{ // _encryptionProviders.Dispose(); // _encryptionProviders = null; //} if (_pluginProviders != null) { _pluginProviders.Dispose(); _pluginProviders = null; } if (_windowProviders != null) { _windowProviders.Dispose(); _windowProviders = null; } if (_pluginDescriptors != null) { _pluginDescriptors.Dispose(); _pluginDescriptors = null; } if (_instanceManager != null) { _instanceManager.Dispose(); _instanceManager = null; } if (_gcTimer != null) { _gcTimer.Dispose(); _gcTimer = null; } _commandLineArgs = null; _progressViewer = null; }
// /// <summary> // /// Marks the descriptor if it is missing a dependency // /// </summary> // /// <param name="descriptor">The descriptor to check</param> // /// <param name="descriptors">The collection of PluginDescriptors to check against</param> // private static void MarkDescriptorIfMissingDependency(PluginDescriptor descriptor, PluginDescriptorCollection descriptors) // { // // we may already know that // if (descriptor.IsMissingDependency) // return; // // // check each Type the Plugin depends upon to determine if it is missing // foreach(Type type in descriptor.PluginDependencies) // { // // if the dependency Type is equivalent to Missing, then there is an Assembly reference missing // if ((object)type == Type.Missing) // { // // we know the plugin can't be started now so we're done with this one // descriptor.IsMissingDependency = true; // return; // } // // // check each Type the Plugin depends upon to determine if the Type is listed somewhere in the other descriptors // // it is possible the Type reference could be valid because the correct Assembly is loaded, but the Plugin that is // // required isn't being exported as a Plugin yet. Sometimes the developers forget to export their plugins. // bool found = false; // foreach(PluginDescriptor otherDescriptor in descriptors) // { // // if some other descriptor's PluginType is the Type of this dependency // if (otherDescriptor.PluginType == type) // { // // and we aren't comparing the same descriptor // if (otherDescriptor != descriptor) // { // // then this particular dependency is exported and is in the list of descriptors // found = true; // break; // } // } // } // // // if the Type wasn't found in the list of descriptors then this descriptor's Plugin is missing a dependency // if (!found) // { // // we know the plugin can't be started now so we're done with this one // descriptor.IsMissingDependency = true; // return; // } // } // } /// <summary> /// Marks a descriptor if is is circularly dependent with any other descriptor /// </summary> /// <param name="descriptor">The descriptor to check</param> /// <param name="descriptors">The collection of PluginDescriptors to check against</param> private static void MarkDescriptorIfCircularlyDependent(PluginDescriptor descriptor, PluginDescriptorCollection descriptors) { // check each dependency in that descriptor depends on foreach(Type type in descriptor.PluginDependencies) { // against all the other descriptors foreach(PluginDescriptor otherDescriptor in descriptors) { // when we find a descriptor that describes the Type the first descriptor needs if (otherDescriptor.PluginType == type) { // it better not depend on the first if (otherDescriptor.DependsOn(descriptor)) { // if it does, it's a circular dependency which we cannot have descriptor.IsCircularlyDependent = true; return; } } } } }
/// <summary> /// Marks a descriptor if it has dependencies that themselves are missing dependencies or are circularly dependent /// </summary> /// <param name="descriptor">The descriptor to check</param> /// <param name="descriptors">The collection of PluginDescriptors to check against</param> private static void MarkDescriptorIfDependenciesAreMissingDependencyOrAreCircularlyDependent(PluginDescriptor descriptor, PluginDescriptorCollection descriptors) { // check each dependency in that descriptor depends on foreach(Type type in descriptor.PluginDependencies) { // against all the other descriptors foreach(PluginDescriptor otherDescriptor in descriptors) { // when we find a descriptor that describes the Type the first descriptor needs if (otherDescriptor.PluginType == type) { // the other dependency better not be missing a dependency if (otherDescriptor.IsMissingDependency) { // if it does, the whole chain is jacked descriptor.IsDependentOnTypeThatIsMissingDependency = true; return; } // the other dependency better not be circularly dependent if (otherDescriptor.IsCircularlyDependent) { // if it does, the whole chain is jacked descriptor.IsDependentOnTypeThatIsCircularlyDependent = true; return; } } } } }
/// <summary> /// Creates PluginDescriptors from each Plugin Type specified. /// </summary> /// <param name="progressViewer">The callback object implementing IProgressViewer that will be used to monitor progress.</param> /// <param name="types">The collection of Plugin Types to create descriptors for.</param> /// <returns></returns> public static PluginDescriptorCollection CreatePluginDescriptors(IProgressViewer progressViewer, TypeCollection types) { PluginDescriptorCollection descriptors = new PluginDescriptorCollection(); foreach (Type type in types) { try { string message = string.Format("Creating PluginDescriptor, Type: '{0}'.", type.FullName); ProgressViewer.SetExtendedDescription(progressViewer, message); Log.WriteLine(message); PluginDescriptor descriptor = new PluginDescriptor(type); descriptors.Add(descriptor); } catch(Exception ex) { Log.WriteLine(ex); } } return descriptors; }
/// <summary> /// Validates the dependencies for each of the PluginDescriptors /// </summary> /// <param name="progressViewer">The callback object implementing IProgressViewer that will be used to monitor progress.</param> /// <param name="descriptors">The collection of PluginDescriptors that describe the Plugins to be loaded.</param> public static void ValidatePluginDependencies(IProgressViewer progressViewer, PluginDescriptorCollection descriptors) { /* * Validation Phases * Phase 1: Direct (First level dependencies) * Phase 2: Indirect (Second level dependencies. i.e., dependencies of dependencies. Requires that Phase 1 already executed) * Phase 3: Extended (Provider Validation) * */ // Phase 1: Checks descriptors for missing dependencies and circular references. (direct) foreach (PluginDescriptor descriptor in descriptors) { try { // check for missing dependencies // MarkDescriptorIfMissingDependency(descriptor, descriptors); if (!descriptor.IsMissingDependency) { // check for circular references between plugins (direct, does not check dependency chains) MarkDescriptorIfCircularlyDependent(descriptor, descriptors); } } catch(Exception ex) { Log.WriteLine(ex); } } // Phase 2: Checks depencencies for missing dependencies and circular references. (indirect) foreach (PluginDescriptor descriptor in descriptors) { try { // if (!descriptor.IsMissingDependency && !descriptor.IsCircularlyDependent) { MarkDescriptorIfDependenciesAreMissingDependencyOrAreCircularlyDependent(descriptor, descriptors); } } catch(Exception ex) { Log.WriteLine(ex); } } // Phase 3: Allow for Provider based validation? /* * Here we have an extension point. * If we created another provider who's sole purpose was to validate a PluginDescriptor, * we could move this logic away from the core, and allow for validation to be extended. * Possible reasons for doing this would be to prevent Plugins from being loaded based * on some other criteria. We could provide descriptions of why a particular descriptor failed validation. * */ }
public void Run(Assembly startingAssembly, string[] args) { this.AssertThisIsTheOnlyRunningContext(); // create a new application context _appContext = new PluginApplicationContext(); // save the command line args _commandLineArgs = args; if (CarbonConfig.SingleInstance) { // create a new instance manager, don't dispose of it just yet as we'll need to have our ui plugin // grab it and listen for events until the plugin context is destroyed... _instanceManager = new InstanceManager(CarbonConfig.SingleInstancePort, CarbonConfig.SingleInstanceMutexName); // check to see if this one is the only instance running if (!_instanceManager.IsOnlyInstance) { // if not, forward our command line, and then instruct the _instanceManager.SendCommandLineToPreviousInstance(PluginContext.Current.CommandLineArgs); return; } } // load the Carbon core sub-system providers _windowProviders = CarbonConfig.GetWindowProviders(); _configurationProviders = CarbonConfig.GetConfigurationProviders(); //_encryptionProviders = CarbonConfig.GetEncryptionProviders(); _pluginProviders = CarbonConfig.GetPluginProviders(); // show the splash _splashWindow if the config specifies if (CarbonConfig.ShowSplashWindow) { /* * Not-Threaded * */ using (WindowProvider splashWindowProvider = this.GetSplashWindowProvider()) { _splashWindow = splashWindowProvider.CreateWindow(null); } _splashWindow.Show(); _splashWindow.Refresh(); _progressViewer = _splashWindow as IProgressViewer; } ProgressViewer.SetExtendedDescription(_progressViewer, "Initializing Carbon Framework System Providers."); // start configuration providers ConfigurationProvidersManager.InstructConfigurationProvidersToLoad(_progressViewer, _configurationProviders); // use the plugin manager to load the plugin types that the plugin providers want loaded using (TypeCollection pluginTypes = PluginManager.LoadPluginTypes(_progressViewer, _pluginProviders)) { // use the plugin manager to create descriptors for all of the plugins using (_pluginDescriptors = PluginManager.CreatePluginDescriptors(_progressViewer, pluginTypes)) { // validate the plugin dependencies PluginManager.ValidatePluginDependencies(_progressViewer, _pluginDescriptors); // sort plugins to have the least dependent plugins first // NOTE: Always sort first because the dependencies are taken into account during instance construction! _pluginDescriptors = PluginManager.Sort(_pluginDescriptors, true); // create the plugins PluginManager.CreatePluginInstances(_progressViewer, _pluginDescriptors); // start plugins PluginManager.StartPlugins(_progressViewer, _pluginDescriptors); // if we are supposed to run a message loop, do it now if (CarbonConfig.RunApplicationContext) { this.OnEnteringMainMessageLoop(new PluginContextEventArgs(this)); // run the plugin context's main message loop Application.Run(this.ApplicationContext); this.OnExitingMainMessageLoop(new PluginContextEventArgs(this)); } // sort plugins to have the most dependent plugins first _pluginDescriptors = PluginManager.Sort(_pluginDescriptors, false); // stop plugins PluginManager.StopPlugins(null, _pluginDescriptors); } } // stop configuration providers // start configuration providers ConfigurationProvidersManager.InstructConfigurationProvidersToSave(_configurationProviders); }
/// <summary> /// Validates the dependencies for each of the PluginDescriptors /// </summary> /// <param name="progressViewer">The callback object implementing IProgressViewer that will be used to monitor progress.</param> /// <param name="descriptors">The collection of PluginDescriptors that describe the Plugins to be loaded.</param> public static void ValidatePluginDependencies(IProgressViewer progressViewer, PluginDescriptorCollection descriptors) { /* * Validation Phases * Phase 1: Direct (First level dependencies) * Phase 2: Indirect (Second level dependencies. i.e., dependencies of dependencies. Requires that Phase 1 already executed) * Phase 3: Extended (Provider Validation) * */ // Phase 1: Checks descriptors for missing dependencies and circular references. (direct) foreach (PluginDescriptor descriptor in descriptors) { try { // check for missing dependencies // MarkDescriptorIfMissingDependency(descriptor, descriptors); if (!descriptor.IsMissingDependency) { // check for circular references between plugins (direct, does not check dependency chains) MarkDescriptorIfCircularlyDependent(descriptor, descriptors); } } catch (Exception ex) { Log.WriteLine(ex); } } // Phase 2: Checks depencencies for missing dependencies and circular references. (indirect) foreach (PluginDescriptor descriptor in descriptors) { try { // if (!descriptor.IsMissingDependency && !descriptor.IsCircularlyDependent) { MarkDescriptorIfDependenciesAreMissingDependencyOrAreCircularlyDependent(descriptor, descriptors); } } catch (Exception ex) { Log.WriteLine(ex); } } // Phase 3: Allow for Provider based validation? /* * Here we have an extension point. * If we created another provider who's sole purpose was to validate a PluginDescriptor, * we could move this logic away from the core, and allow for validation to be extended. * Possible reasons for doing this would be to prevent Plugins from being loaded based * on some other criteria. We could provide descriptions of why a particular descriptor failed validation. * */ }
// /// <summary> // /// Marks the descriptor if it is missing a dependency // /// </summary> // /// <param name="descriptor">The descriptor to check</param> // /// <param name="descriptors">The collection of PluginDescriptors to check against</param> // private static void MarkDescriptorIfMissingDependency(PluginDescriptor descriptor, PluginDescriptorCollection descriptors) // { // // we may already know that // if (descriptor.IsMissingDependency) // return; // // // check each Type the Plugin depends upon to determine if it is missing // foreach(Type type in descriptor.PluginDependencies) // { // // if the dependency Type is equivalent to Missing, then there is an Assembly reference missing // if ((object)type == Type.Missing) // { // // we know the plugin can't be started now so we're done with this one // descriptor.IsMissingDependency = true; // return; // } // // // check each Type the Plugin depends upon to determine if the Type is listed somewhere in the other descriptors // // it is possible the Type reference could be valid because the correct Assembly is loaded, but the Plugin that is // // required isn't being exported as a Plugin yet. Sometimes the developers forget to export their plugins. // bool found = false; // foreach(PluginDescriptor otherDescriptor in descriptors) // { // // if some other descriptor's PluginType is the Type of this dependency // if (otherDescriptor.PluginType == type) // { // // and we aren't comparing the same descriptor // if (otherDescriptor != descriptor) // { // // then this particular dependency is exported and is in the list of descriptors // found = true; // break; // } // } // } // // // if the Type wasn't found in the list of descriptors then this descriptor's Plugin is missing a dependency // if (!found) // { // // we know the plugin can't be started now so we're done with this one // descriptor.IsMissingDependency = true; // return; // } // } // } /// <summary> /// Marks a descriptor if is is circularly dependent with any other descriptor /// </summary> /// <param name="descriptor">The descriptor to check</param> /// <param name="descriptors">The collection of PluginDescriptors to check against</param> private static void MarkDescriptorIfCircularlyDependent(PluginDescriptor descriptor, PluginDescriptorCollection descriptors) { // check each dependency in that descriptor depends on foreach (Type type in descriptor.PluginDependencies) { // against all the other descriptors foreach (PluginDescriptor otherDescriptor in descriptors) { // when we find a descriptor that describes the Type the first descriptor needs if (otherDescriptor.PluginType == type) { // it better not depend on the first if (otherDescriptor.DependsOn(descriptor)) { // if it does, it's a circular dependency which we cannot have descriptor.IsCircularlyDependent = true; return; } } } } }
/// <summary> /// Marks a descriptor if it has dependencies that themselves are missing dependencies or are circularly dependent /// </summary> /// <param name="descriptor">The descriptor to check</param> /// <param name="descriptors">The collection of PluginDescriptors to check against</param> private static void MarkDescriptorIfDependenciesAreMissingDependencyOrAreCircularlyDependent(PluginDescriptor descriptor, PluginDescriptorCollection descriptors) { // check each dependency in that descriptor depends on foreach (Type type in descriptor.PluginDependencies) { // against all the other descriptors foreach (PluginDescriptor otherDescriptor in descriptors) { // when we find a descriptor that describes the Type the first descriptor needs if (otherDescriptor.PluginType == type) { // the other dependency better not be missing a dependency if (otherDescriptor.IsMissingDependency) { // if it does, the whole chain is jacked descriptor.IsDependentOnTypeThatIsMissingDependency = true; return; } // the other dependency better not be circularly dependent if (otherDescriptor.IsCircularlyDependent) { // if it does, the whole chain is jacked descriptor.IsDependentOnTypeThatIsCircularlyDependent = true; return; } } } } }