using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using System.Xml.Linq; #if BCL using System.Xml; using System.Configuration; #endif using Amazon.Util; using Amazon.Util.Internal; using Amazon.DynamoDBv2; namespace Amazon { /// /// Configurations for accessing DynamoDB /// public static class AWSConfigsDynamoDB { private const string dynamoDBKey = "dynamoDB"; static AWSConfigsDynamoDB() { try { #if BCL var root = new RootConfig(); var section = root.GetServiceSection(dynamoDBKey); if (section == null) return; var rootSection = new DynamoDBSectionRoot(section); if (rootSection.DynamoDB != null) AWSConfigsDynamoDB.Configure(rootSection.DynamoDB); #endif } finally { // If no configuration exist at least // configure the context config to the default. if (Context == null) { Context = new DynamoDBContextConfig(); ConversionSchema = ConversionSchema.V1;; } } } #region DynamoDBContext TableNamePrefix /// /// Key for the DynamoDBContextTableNamePrefix property. /// /// public const string DynamoDBContextTableNamePrefixKey = "AWS.DynamoDBContext.TableNamePrefix"; /// /// Configures the default TableNamePrefix that the DynamoDBContext will use if /// not manually configured. /// Changes to this setting will only take effect in newly-constructed instances of /// DynamoDBContextConfig and DynamoDBContext. /// /// The setting can be configured through App.config, for example: /// /// <appSettings> /// <add key="AWS.DynamoDBContext.TableNamePrefix" value="Test-"/> /// </appSettings> /// /// [Obsolete("This property is obsolete. Use DynamoDBConfig.Context.TableNamePrefix instead.")] public static string DynamoDBContextTableNamePrefix { get { return Context.TableNamePrefix; } set { Context.TableNamePrefix = value; } } #endregion /// /// Conversion schema to use for converting .NET types to DynamoDB types. /// internal static ConversionSchema ConversionSchema { get; set; } /// /// Settings for DynamoDBContext. /// public static DynamoDBContextConfig Context { get; private set; } #if BCL internal static void Configure(DynamoDBSection section) { Context = new DynamoDBContextConfig(); ConversionSchema = ConversionSchema.V1; if (section != null && section.ElementInformation.IsPresent) { ConversionSchema = section.ConversionSchema; if(section.Context != null) Context.Configure(section.Context); } } #endif } } namespace Amazon.Util { #region DynamoDB Config /// /// Settings for DynamoDBContext. /// public partial class DynamoDBContextConfig { /// /// Configures the default TableNamePrefix that the DynamoDBContext will use if /// not manually configured. /// /// TableNamePrefix is used after TableAliases have been applied. /// public string TableNamePrefix { get; set; } /// /// A string-to-string dictionary (From-Table to To-Table) used by DynamoDBContext to /// use a different table from one that is configured for a type. /// /// Remapping is done before applying TableNamePrefix. /// public Dictionary TableAliases { get; private set; } /// /// A Type-to-TypeMapping (type to TypeMapping defining its DynamoDB conversion) used by /// DynamoDBContext to modify or configure a particular type. /// public Dictionary TypeMappings { get; private set; } /// /// Adds a TableAlias to the TableAliases property. /// An exception is thrown if there is already a TableAlias with the same FromTable configured. /// /// public void AddAlias(TableAlias tableAlias) { TableAliases.Add(tableAlias.FromTable, tableAlias.ToTable); } /// /// Adds a TypeMapping to the TypeMappings property. /// An exception is thrown if there is already a TypeMapping with the same Type configured. /// /// public void AddMapping(TypeMapping typeMapping) { TypeMappings.Add(typeMapping.Type, typeMapping); } internal DynamoDBContextConfig() { this.TableNamePrefix = AWSConfigs.GetConfig(AWSConfigsDynamoDB.DynamoDBContextTableNamePrefixKey); TableAliases = new Dictionary(StringComparer.Ordinal); TypeMappings = new Dictionary(); } #if BCL internal void Configure(DynamoDBContextSection section) { if (section != null && section.ElementInformation.IsPresent) { TableNamePrefix = section.TableNamePrefix; InternalSDKUtils.FillDictionary(section.TypeMappings.Items, t => t.Type, t => new TypeMapping(t), TypeMappings); InternalSDKUtils.FillDictionary(section.TableAliases.Items, t => t.FromTable, t => t.ToTable, TableAliases); } } #endif } /// /// Single DynamoDB table alias /// public partial class TableAlias { /// /// Source table /// public string FromTable { get; set; } /// /// Destination table /// public string ToTable { get; set; } /// /// Initializes an empty TableAlias object /// public TableAlias() { } /// /// Initializes a TableAlias object with specific source and /// destination tables /// /// Source table /// Destination table public TableAlias(string fromTable, string toTable) { FromTable = fromTable; ToTable = toTable; } } /// /// Single DynamoDB type mapping config /// public partial class TypeMapping { /// /// Type to which the mapping applies /// public Type Type { get; set; } /// /// Target table for the type /// public string TargetTable { get; set; } /// /// A string-to-PropertyConfig dictionary (property name to PropertyConfig) describing /// how each property on the type should be treated. /// public Dictionary PropertyConfigs { get; private set; } /// /// Adds a PropertyConfig to the PropertyConfigs property. /// An exception is thrown if there is already a PropertyConfig with the same Name configured. /// /// public void AddProperty(PropertyConfig propertyConfig) { PropertyConfigs.Add(propertyConfig.Name, propertyConfig); } /// /// Initializes a TypeMapping object for a specific type and target table. /// /// Target type /// Target table public TypeMapping(Type type, string targetTable) { Type = type; TargetTable = targetTable; PropertyConfigs = new Dictionary(StringComparer.Ordinal); } #if BCL internal TypeMapping(TypeMappingElement mapping) : this(mapping.Type, mapping.TargetTable) { InternalSDKUtils.FillDictionary(mapping.PropertyConfigs.Items, p => p.Name, p => new PropertyConfig(p), PropertyConfigs); } #endif } /// /// Single DynamoDB property mapping config /// public partial class PropertyConfig { /// /// Property name /// public string Name { get; set; } /// /// Attribute name /// public string Attribute { get; set; } /// /// Whether this property should be ignored by DynamoDBContext /// public bool Ignore { get; set; } /// /// Whether this property should be treated as a version property /// public bool Version { get; set; } /// /// The type of converter that should be used on this property /// public Type Converter { get; set; } /// /// Whether this property should be stored as epoch seconds integer. /// public bool StoreAsEpoch { get; set; } /// /// Initializes a PropertyConfig object for a specific property /// /// public PropertyConfig(string propertyName) { Name = propertyName; } #if BCL internal PropertyConfig(PropertyConfigElement prop) : this(prop.Name) { Attribute = prop.Attribute; Ignore = prop.Ignore.GetValueOrDefault(false); Version = prop.Version.GetValueOrDefault(false); Converter = prop.Converter; StoreAsEpoch = prop.StoreAsEpoch.GetValueOrDefault(false); } #endif } #endregion #region DynamoDB sections #if BCL internal class DynamoDBSectionRoot : WritableConfigurationElement { private const string dynamoDBKey = "dynamoDB"; public DynamoDBSectionRoot(XElement section) { if (section != null) { XmlTextReader reader = new XmlTextReader(new StringReader(section.ToString())) { WhitespaceHandling = WhitespaceHandling.None }; this.DeserializeElement(reader, false); } } [ConfigurationProperty(dynamoDBKey)] public DynamoDBSection DynamoDB { get { return (DynamoDBSection)this[dynamoDBKey]; } set { this[dynamoDBKey] = value; } } } /// /// Root DynamoDB section /// internal class DynamoDBSection : WritableConfigurationElement { private const string contextKey = "dynamoDBContext"; private const string conversionKey = "conversionSchema"; public DynamoDBSection() { } [ConfigurationProperty(contextKey)] public DynamoDBContextSection Context { get { return (DynamoDBContextSection)this[contextKey]; } set { this[contextKey] = value; } } [ConfigurationProperty(conversionKey)] public ConversionSchema ConversionSchema { get { return (ConversionSchema)this[conversionKey]; } set { this[conversionKey] = value; } } } /// /// DynamoDBContext section /// internal class DynamoDBContextSection : WritableConfigurationElement { private const string tableNamePrefixKey = "tableNamePrefix"; private const string tableAliasesKey = "tableAliases"; private const string mappingsKey = "mappings"; [ConfigurationProperty(tableNamePrefixKey)] public string TableNamePrefix { get { return (string)this[tableNamePrefixKey]; } set { this[tableNamePrefixKey] = value; } } [ConfigurationProperty(tableAliasesKey)] public TableAliasesCollection TableAliases { get { return (TableAliasesCollection)this[tableAliasesKey]; } set { this[tableAliasesKey] = value; } } [ConfigurationProperty(mappingsKey)] public TypeMappingsCollection TypeMappings { get { return (TypeMappingsCollection)this[mappingsKey]; } set { this[mappingsKey] = value; } } } /// /// Single DDB table alias /// internal class TableAliasElement : SerializableConfigurationElement { private const string fromTableKey = "fromTable"; private const string toTableKey = "toTable"; [ConfigurationProperty(fromTableKey)] public string FromTable { get { return (string)this[fromTableKey]; } set { this[fromTableKey] = value; } } [ConfigurationProperty(toTableKey, IsRequired = true)] public string ToTable { get { return (string)this[toTableKey]; } set { this[toTableKey] = value; } } public TableAliasElement() { } public TableAliasElement(string fromTable, string toTable) { FromTable = fromTable; ToTable = toTable; } } /// /// Collection of DDB table aliases /// [ConfigurationCollection(typeof(TableAliasElement))] internal class TableAliasesCollection : WritableConfigurationElementCollection { protected override string ItemPropertyName { get { return "alias"; } } public TableAliasesCollection() : base() { } public TableAliasesCollection(params TableAliasElement[] remaps) : base() { if (remaps != null) Add(remaps); } } /// /// Single DDB type mapping config /// internal class TypeMappingElement : SerializableConfigurationElement { private const string typeKey = "type"; private const string targetTableKey = "targetTable"; private const string itemKey = ""; [TypeConverter(typeof(TypeNameConverter))] [ConfigurationProperty(typeKey, IsRequired = true)] public Type Type { get { return (Type)this[typeKey]; } set { this[typeKey] = value; } } [ConfigurationProperty(targetTableKey, IsRequired = true)] public string TargetTable { get { return (string)this[targetTableKey]; } set { this[targetTableKey] = value; } } [ConfigurationProperty(itemKey, IsDefaultCollection = true)] public PropertyConfigsCollection PropertyConfigs { get { return (PropertyConfigsCollection)this[itemKey]; } set { this[itemKey] = value; } } } /// /// Collection of DDB type mapping configs /// [ConfigurationCollection(typeof(TypeMappingElement))] internal class TypeMappingsCollection : WritableConfigurationElementCollection { protected override string ItemPropertyName { get { return "map"; } } public TypeMappingsCollection() : base() { } public TypeMappingsCollection(params TypeMappingElement[] mappings) : base() { if (mappings != null) Add(mappings); } } /// /// Single DDB property mapping config /// internal class PropertyConfigElement : SerializableConfigurationElement { private const string nameKey = "name"; private const string attributeKey = "attribute"; private const string ignoreKey = "ignore"; private const string versionKey = "version"; private const string converterKey = "converter"; private const string storeAsEpochKey = "storeAsEpoch"; [ConfigurationProperty(nameKey, IsRequired = true)] public string Name { get { return (string)this[nameKey]; } set { this[nameKey] = value; } } [ConfigurationProperty(attributeKey)] public string Attribute { get { return (string)this[attributeKey]; } set { this[attributeKey] = value; } } [ConfigurationProperty(ignoreKey)] public bool? Ignore { get { return (bool?)this[ignoreKey]; } set { this[ignoreKey] = value; } } [ConfigurationProperty(versionKey)] public bool? Version { get { return (bool?)this[versionKey]; } set { this[versionKey] = value; } } [TypeConverter(typeof(TypeNameConverter))] [ConfigurationProperty(converterKey)] public Type Converter { get { return (Type)this[converterKey]; } set { this[converterKey] = value; } } [ConfigurationProperty(storeAsEpochKey)] public bool? StoreAsEpoch { get { return (bool?)this[storeAsEpochKey]; } set { this[storeAsEpochKey] = value; } } } /// /// Collection of DDB property mapping configs /// [ConfigurationCollection(typeof(PropertyConfigElement))] internal class PropertyConfigsCollection : WritableConfigurationElementCollection { protected override string ItemPropertyName { get { return "property"; } } public PropertyConfigsCollection() : base() { } public PropertyConfigsCollection(params PropertyConfigElement[] configs) : base() { if (configs != null) Add(configs); } } #endif #endregion }