From b6c07f5be2dcc958afd601dd103da89a456dcdf7 Mon Sep 17 00:00:00 2001 From: Gabriel Kliot Date: Wed, 18 Mar 2015 12:57:07 -0700 Subject: [PATCH] 1) More programmatic support to provider configuration: TryGetProviderConfiguration and GetAllProviderConfigurations 2) Added constructor to ProviderConfiguration class. 3) Added more functions to IProviderConfiguration: Type, SetProperty, RemoveProperty, ReadOnlyDictionary Properties. 4) Updated examples in AzureWebSample. --- .../OrleansAzureSilos/WorkerRole.cs | 111 ++++++++---------- .../Configuration/ClientConfiguration.cs | 33 +++++- .../Configuration/GlobalConfiguration.cs | 32 ++++- .../Configuration/ProviderConfiguration.cs | 84 ++++++++++--- src/Orleans/Providers/IOrleansProvider.cs | 28 ++++- 5 files changed, 196 insertions(+), 92 deletions(-) diff --git a/Samples/AzureWebSample/OrleansAzureSilos/WorkerRole.cs b/Samples/AzureWebSample/OrleansAzureSilos/WorkerRole.cs index 3fbe870c51..90281c4fe0 100644 --- a/Samples/AzureWebSample/OrleansAzureSilos/WorkerRole.cs +++ b/Samples/AzureWebSample/OrleansAzureSilos/WorkerRole.cs @@ -70,9 +70,9 @@ public override void Run() config.StandardLoad(); // First example of how to configure an existing provider - ConfigureExistingStorageProvider(config); - ConfigureNewStorageProvider(config); - ConfigureNewBootstrapProvider(config); + //ConfigureExistingStorageProvider(config); + //ConfigureNewStorageProvider(config); + //ConfigureNewBootstrapProvider(config); // It is IMPORTANT to start the silo not in OnStart but in Run. // Azure may not have the firewalls open yet (on the remote silos) at the OnStart phase. @@ -150,90 +150,81 @@ private static void SetupEnvironmentChangeHandlers() // Below is an example of how to set the storage key in the ProviderConfiguration and how to add a new custom configuration property. private void ConfigureExistingStorageProvider(ClusterConfiguration config) { - ProviderCategoryConfiguration storageConfiguration; - if (config.Globals.ProviderConfigurations.TryGetValue(STORAGE_KEY, out storageConfiguration)) + IProviderConfiguration storageProvider = null; + + const string myProviderFullTypeName = "Orleans.Storage.AzureTableStorage"; // Alternatively, can be something like typeof(AzureTableStorage).FullName + const string myProviderName = "AzureStore"; // what ever arbitrary name you want to give to your provider + if (config.Globals.TryGetProviderConfiguration(myProviderFullTypeName, myProviderName, out storageProvider)) { - // Modify the specific "AzureStore" provider - IProviderConfiguration iProviderConfig = null; - if (storageConfiguration.Providers.TryGetValue("AzureStore", out iProviderConfig)) - { - ProviderConfiguration storageProvider = iProviderConfig as ProviderConfiguration; - storageProvider.SetProperty("MyCustomProperty1", "MyCustomPropertyValue1"); - } + // provider configuration already exists, modify it. + string connectionString = RoleEnvironment.GetConfigurationSettingValue(DATA_CONNECTION_STRING_KEY); + storageProvider.SetProperty(DATA_CONNECTION_STRING_KEY, connectionString); + storageProvider.SetProperty("MyCustomProperty1", "MyCustomPropertyValue1"); + } + else + { + // provider configuration does not exists, add a new one. + var properties = new Dictionary(); + string connectionString = RoleEnvironment.GetConfigurationSettingValue(DATA_CONNECTION_STRING_KEY); + properties.Add(DATA_CONNECTION_STRING_KEY, connectionString); + properties.Add("MyCustomProperty2", "MyCustomPropertyValue2"); + + config.Globals.RegisterStorageProvider(myProviderFullTypeName, myProviderName, properties); + } - // Alternatively, find all storage providers and modify them as necessary - foreach (ProviderConfiguration providerConfig in storageConfiguration.Providers.Values.Where(provider => provider is ProviderConfiguration).Cast()) + // Alternatively, find all storage providers and modify them as necessary + foreach (IProviderConfiguration providerConfig in config.Globals.GetAllProviderConfigurations())//storageConfiguration.Providers.Values.Where(provider => provider is ProviderConfiguration).Cast()) + { + if (providerConfig.Type.Equals(myProviderFullTypeName)) { string connectionString = RoleEnvironment.GetConfigurationSettingValue(DATA_CONNECTION_STRING_KEY); providerConfig.SetProperty(DATA_CONNECTION_STRING_KEY, connectionString); - providerConfig.SetProperty("MyCustomProperty2", "MyCustomPropertyValue2"); - + providerConfig.SetProperty("MyCustomProperty3", "MyCustomPropertyValue3"); } - - // Once silo starts you can see that it prints in the log: - // Providers: - // StorageProviders: - // Name=AzureStore, Type=Orleans.Storage.AzureTableStorage, Properties=[DataConnectionString, MyCustomProperty, MyCustomProperty2] } + + // Once silo starts you can see that it prints in the log: + // Providers: + // StorageProviders: + // Name=AzureStore, Type=Orleans.Storage.AzureTableStorage, Properties=[DataConnectionString, MyCustomProperty, MyCustomProperty1, MyCustomProperty3] } // Below is an example of how to define a full configuration for a new storage provider that is not already specified in the config file. private void ConfigureNewStorageProvider(ClusterConfiguration config) { - ProviderCategoryConfiguration categoryConfiguration; - if (!config.Globals.ProviderConfigurations.TryGetValue(STORAGE_KEY, out categoryConfiguration)) - { - categoryConfiguration = new ProviderCategoryConfiguration() - { - Name = STORAGE_KEY, - Providers = new Dictionary() - }; - config.Globals.ProviderConfigurations.Add(STORAGE_KEY, categoryConfiguration); - } - - string myProviderName = "MyNewAzureStoreProvider"; // what ever arbitrary name you want to give to your provider - // Alternatively, the 2nd argument, type, can be something like typeof(EventStoreInitBootstrapProvider).FullName - ProviderConfiguration providerConfig = new ProviderConfiguration(new Dictionary(), "Orleans.Storage.AzureTableStorage", myProviderName); - categoryConfiguration.Providers.Add(myProviderName, providerConfig); + const string myProviderFullTypeName = "Orleans.Storage.AzureTableStorage"; // Alternatively, can be something like typeof(AzureTableStorage).FullName + const string myProviderName = "MyNewAzureStoreProvider"; // what ever arbitrary name you want to give to your provider + var properties = new Dictionary(); string connectionString = RoleEnvironment.GetConfigurationSettingValue(DATA_CONNECTION_STRING_KEY); - providerConfig.SetProperty(DATA_CONNECTION_STRING_KEY, connectionString); - providerConfig.SetProperty("MyCustomProperty3", "MyCustomPropertyValue3"); + properties.Add(DATA_CONNECTION_STRING_KEY, connectionString); + properties.Add("MyCustomProperty3", "MyCustomPropertyValue3"); + + config.Globals.RegisterStorageProvider(myProviderFullTypeName, myProviderName, properties); // Once silo starts you can see that it prints in the log: - // Providers: - // StorageProviders: - // Name=MyNewAzureStoreProvider, Type=Orleans.Storage.AzureTableStorage, Properties=[DataConnectionString, MyCustomProperty3] + // Providers: + // StorageProviders: + // Name=MyNewAzureStoreProvider, Type=Orleans.Storage.AzureTableStorage, Properties=[DataConnectionString, MyCustomProperty3] } // Below is an example of how to define a full configuration for a new Bootstrap provider that is not already specified in the config file. private void ConfigureNewBootstrapProvider(ClusterConfiguration config) { - ProviderCategoryConfiguration categoryConfiguration; - if (!config.Globals.ProviderConfigurations.TryGetValue(BOOTSTRAP_KEY, out categoryConfiguration)) - { - categoryConfiguration = new ProviderCategoryConfiguration() - { - Name = BOOTSTRAP_KEY, - Providers = new Dictionary() - }; - config.Globals.ProviderConfigurations.Add(BOOTSTRAP_KEY, categoryConfiguration); - } - - string myProviderName = "MyNewBootstrapProvider"; // what ever arbitrary name you want to give to your provider - // Alternatively, the 2nd argument, type, can be something like typeof(EventStoreInitBootstrapProvider).FullName - ProviderConfiguration providerConfig = new ProviderConfiguration(new Dictionary(), "FullNameSpace.NewBootstrapProviderType", myProviderName); - //categoryConfiguration.Providers.Add(myProviderName, providerConfig); + const string myProviderFullTypeName = "FullNameSpace.NewBootstrapProviderType"; // Alternatively, can be something like typeof(EventStoreInitBootstrapProvider).FullName + const string myProviderName = "MyNewBootstrapProvider"; // what ever arbitrary name you want to give to your provider + var properties = new Dictionary(); + config.Globals.RegisterBootstrapProvider(myProviderFullTypeName, myProviderName, properties); - // The last line, categoryConfiguration.Providers.Add, is commented out because the assembly with "FullNameSpace.NewBootstrapProviderType" is not added to the project, + // The last line, config.Globals.RegisterBootstrapProvider, is commented out because the assembly with "FullNameSpace.NewBootstrapProviderType" is not added to the project, // this the silo will fail to load the new bootstrap provider upon startup. // !!!!!!!!!! Provider of type FullNameSpace.NewBootstrapProviderType name MyNewBootstrapProvider was not loaded. // Once you add your new provider to the project, uncommnet this line. // Once silo starts you can see that it prints in the log: - // Providers: - // BootstrapProviders: - // Name=MyNewBootstrapProvider, Type=FullNameSpace.NewBootstrapProviderType, Properties=[] + // Providers: + // BootstrapProviders: + // Name=MyNewBootstrapProvider, Type=FullNameSpace.NewBootstrapProviderType, Properties=[] } } } diff --git a/src/Orleans/Configuration/ClientConfiguration.cs b/src/Orleans/Configuration/ClientConfiguration.cs index ca46bfe74e..614814b1cc 100644 --- a/src/Orleans/Configuration/ClientConfiguration.cs +++ b/src/Orleans/Configuration/ClientConfiguration.cs @@ -28,6 +28,7 @@ The above copyright notice and this permission notice shall be included in all c using System.Net.Sockets; using System.Text; using System.Xml; +using Orleans.Providers; namespace Orleans.Runtime.Configuration { @@ -308,17 +309,16 @@ internal void LoadFromXml(XmlElement root) default: if (child.LocalName.EndsWith("Providers", StringComparison.Ordinal)) { - var providerConfig = new ProviderCategoryConfiguration(); - providerConfig.Load(child); + var providerCategory = ProviderCategoryConfiguration.Load(child); - if (ProviderConfigurations.ContainsKey(providerConfig.Name)) + if (ProviderConfigurations.ContainsKey(providerCategory.Name)) { - var existingProviderConfig = ProviderConfigurations[providerConfig.Name]; - existingProviderConfig.Merge(providerConfig); + var existingCategory = ProviderConfigurations[providerCategory.Name]; + existingCategory.Merge(providerCategory); } else { - ProviderConfigurations.Add(providerConfig.Name, providerConfig); + ProviderConfigurations.Add(providerCategory.Name, providerCategory); } } break; @@ -376,6 +376,27 @@ public void RegisterStreamProvider(string providerTypeFullName, string providerN ProviderConfigurationUtility.RegisterProvider(ProviderConfigurations, ProviderCategoryConfiguration.STREAM_PROVIDER_CATEGORY_NAME, providerTypeFullName, providerName, properties); } + /// + /// Retrieves an existing provider configuration + /// + /// Full name of the stream provider type + /// Name of the stream provider + /// The provider configuration, if exists + /// True if a configuration for this provider already exists, false otherwise. + public bool TryGetProviderConfiguration(string providerTypeFullName, string providerName, out IProviderConfiguration config) + { + return ProviderConfigurationUtility.TryGetProviderConfiguration(ProviderConfigurations, providerTypeFullName, providerName, out config); + } + + /// + /// Retrieves an enumeration of all currently configured provider configurations. + /// + /// An enumeration of all currently configured provider configurations. + public IEnumerable GetAllProviderConfigurations() + { + return ProviderConfigurationUtility.GetAllProviderConfigurations(ProviderConfigurations); + } + /// /// This method may be called by the client host or test host to tweak a provider configuration after it has been already loaded. /// Its is optional and should NOT be automaticaly called by the runtime. diff --git a/src/Orleans/Configuration/GlobalConfiguration.cs b/src/Orleans/Configuration/GlobalConfiguration.cs index f7514b00fa..225c49f622 100644 --- a/src/Orleans/Configuration/GlobalConfiguration.cs +++ b/src/Orleans/Configuration/GlobalConfiguration.cs @@ -671,17 +671,16 @@ internal override void Load(XmlElement root) default: if (child.LocalName.EndsWith("Providers", StringComparison.Ordinal)) { - var providerConfig = new ProviderCategoryConfiguration(); - providerConfig.Load(child); + var providerCategory = ProviderCategoryConfiguration.Load(child); - if (ProviderConfigurations.ContainsKey(providerConfig.Name)) + if (ProviderConfigurations.ContainsKey(providerCategory.Name)) { - var existingProviderConfig = ProviderConfigurations[providerConfig.Name]; - existingProviderConfig.Merge(providerConfig); + var existingCategory = ProviderConfigurations[providerCategory.Name]; + existingCategory.Merge(providerCategory); } else { - ProviderConfigurations.Add(providerConfig.Name, providerConfig); + ProviderConfigurations.Add(providerCategory.Name, providerCategory); } } break; @@ -772,5 +771,26 @@ public void RegisterStorageProvider(string providerTypeFullName, string provider { ProviderConfigurationUtility.RegisterProvider(ProviderConfigurations, ProviderCategoryConfiguration.STORAGE_PROVIDER_CATEGORY_NAME, providerTypeFullName, providerName, properties); } + + /// + /// Retrieves an existing provider configuration + /// + /// Full name of the stream provider type + /// Name of the stream provider + /// The provider configuration, if exists + /// True if a configuration for this provider already exists, false otherwise. + public bool TryGetProviderConfiguration(string providerTypeFullName, string providerName, out IProviderConfiguration config) + { + return ProviderConfigurationUtility.TryGetProviderConfiguration(ProviderConfigurations, providerTypeFullName, providerName, out config); + } + + /// + /// Retrieves an enumeration of all currently configured provider configurations. + /// + /// An enumeration of all currently configured provider configurations. + public IEnumerable GetAllProviderConfigurations() + { + return ProviderConfigurationUtility.GetAllProviderConfigurations(ProviderConfigurations); + } } } diff --git a/src/Orleans/Configuration/ProviderConfiguration.cs b/src/Orleans/Configuration/ProviderConfiguration.cs index 320cd70914..428ac0e464 100644 --- a/src/Orleans/Configuration/ProviderConfiguration.cs +++ b/src/Orleans/Configuration/ProviderConfiguration.cs @@ -23,8 +23,9 @@ The above copyright notice and this permission notice shall be included in all c using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; using System.Xml; using Orleans.Providers; @@ -42,23 +43,34 @@ public class ProviderConfiguration : IProviderConfiguration [NonSerialized] private IProviderManager providerManager; - internal string Type { get; private set; } + public string Type { get; private set; } public string Name { get; private set; } + private ReadOnlyDictionary readonlyCopyOfProperties; /// /// Properties of this provider. /// - public IDictionary Properties { get { return new Dictionary(properties); } } + public ReadOnlyDictionary Properties + { + get + { + if (readonlyCopyOfProperties == null) + { + readonlyCopyOfProperties = new ReadOnlyDictionary(properties); + } + return readonlyCopyOfProperties; + } + } internal ProviderConfiguration() { properties = new Dictionary(); } - public ProviderConfiguration(IDictionary properties, string type, string name) + public ProviderConfiguration(IDictionary properties, string providerType, string name) { this.properties = properties; - Type = type; + Type = providerType; Name = name; } @@ -72,6 +84,7 @@ internal ProviderConfiguration(IDictionary properties, IList... internal void Load(XmlElement child, IDictionary alreadyLoaded, XmlNamespaceManager nsManager) { + readonlyCopyOfProperties = null; // cause later refresh of readonlyCopyOfProperties if (nsManager == null) { nsManager = new XmlNamespaceManager(new NameTable()); @@ -145,6 +158,7 @@ internal void SetProviderManager(IProviderManager manager) public void SetProperty(string key, string val) { + readonlyCopyOfProperties = null; // cause later refresh of readonlyCopyOfProperties if (!properties.ContainsKey(key)) { properties.Add(key, val); @@ -157,6 +171,12 @@ public void SetProperty(string key, string val) } } + public bool RemoveProperty(string key) + { + readonlyCopyOfProperties = null; // cause later refresh of readonlyCopyOfProperties + return properties.Remove(key); + } + public override string ToString() { // print only _properties keys, not values, to not leak application sensitive data. @@ -201,19 +221,27 @@ public class ProviderCategoryConfiguration public string Name { get; set; } public IDictionary Providers { get; set; } + public ProviderCategoryConfiguration(string name) + { + Name = name; + Providers = new Dictionary(); + } + // Load from an element with the format ... // that contains a sequence of Provider elements (see the ProviderConfiguration type) - internal void Load(XmlElement child) + internal static ProviderCategoryConfiguration Load(XmlElement child) { - Name = child.LocalName.Substring(0, child.LocalName.Length - 9); - Providers = new Dictionary(); + string name = child.LocalName.Substring(0, child.LocalName.Length - 9); + + var category = new ProviderCategoryConfiguration(name); var nsManager = new XmlNamespaceManager(new NameTable()); nsManager.AddNamespace("orleans", "urn:orleans"); ProviderConfiguration.LoadProviderConfigurations( - child, nsManager, Providers, - c => Providers.Add(c.Name, c)); + child, nsManager, category.Providers, + c => category.Providers.Add(c.Name, c)); + return category; } internal void Merge(ProviderCategoryConfiguration other) @@ -232,7 +260,6 @@ internal void SetConfiguration(string key, string val) } } - internal static string ProviderConfigsToXmlString(IDictionary providerConfig) { var sb = new StringBuilder(); @@ -285,11 +312,7 @@ internal static void RegisterProvider(IDictionary() - }; + category = new ProviderCategoryConfiguration(providerCategory); providerConfigurations.Add(category.Name, category); } @@ -304,13 +327,36 @@ internal static void RegisterProvider(IDictionary providerConfigurations, + string providerTypeFullName, string providerName, out IProviderConfiguration config) + { + foreach (ProviderCategoryConfiguration category in providerConfigurations.Values) + { + foreach (IProviderConfiguration providerConfig in category.Providers.Values) + { + if (providerConfig.Type.Equals(providerTypeFullName) && providerConfig.Name.Equals(providerName)) + { + config = providerConfig; + return true; + } + } + } + config = null; + return false; + } + + internal static IEnumerable GetAllProviderConfigurations(IDictionary providerConfigurations) + { + return providerConfigurations.Values.SelectMany(category => category.Providers.Values); + } + internal static void AdjustConfiguration(IDictionary providerConfigurations, string deploymentId) { if (String.IsNullOrEmpty(deploymentId)) return; - foreach (ProviderCategoryConfiguration providerConfig in providerConfigurations.Where(kv => kv.Key.Equals(ProviderCategoryConfiguration.STREAM_PROVIDER_CATEGORY_NAME)).Select(kv => kv.Value)) + foreach (ProviderCategoryConfiguration providerCategoryConfig in providerConfigurations.Where(kv => kv.Key.Equals(ProviderCategoryConfiguration.STREAM_PROVIDER_CATEGORY_NAME)).Select(kv => kv.Value)) { - providerConfig.SetConfiguration("DeploymentId", deploymentId); + providerCategoryConfig.SetConfiguration("DeploymentId", deploymentId); } } diff --git a/src/Orleans/Providers/IOrleansProvider.cs b/src/Orleans/Providers/IOrleansProvider.cs index 8d0c70cef7..632f74904c 100644 --- a/src/Orleans/Providers/IOrleansProvider.cs +++ b/src/Orleans/Providers/IOrleansProvider.cs @@ -22,6 +22,7 @@ The above copyright notice and this permission notice shall be included in all c */ using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Threading.Tasks; @@ -74,16 +75,41 @@ internal interface IProviderManager /// public interface IProviderConfiguration { + /// + /// Full type name of this provider. + /// + string Type { get; } + + /// + /// Name of this provider. + /// string Name { get; } /// /// Configuration properties for this provider instance, as name-value pairs. /// - IDictionary Properties { get; } + ReadOnlyDictionary Properties { get; } /// /// Nested providers in case of a hierarchical tree of dependencies /// IList Children { get; } + + /// + /// Set a property in this provider configuration. + /// If the property with this key already exists, it is been overwritten with the new value, otherwise it is just added. + /// + /// The key of the property + /// The value of the property + /// Provider instance with the given name + void SetProperty(string key, string val); + + /// + /// Removes a property in this provider configuration. + /// + /// The key of the property. + /// True if the property was found and removed, false otherwise. + bool RemoveProperty(string key); + } } \ No newline at end of file