PageRenderTime 41ms CodeModel.GetById 28ms app.highlight 10ms RepoModel.GetById 0ms app.codeStats 0ms

/sdk/src/Services/DynamoDBv2/Custom/DataModel/Utils.cs

https://gitlab.com/CORP-RESELLER/aws-sdk-net
C# | 354 lines | 297 code | 40 blank | 17 comment | 61 complexity | fc333c5369e06ea008a69deca73e2618 MD5 | raw file
  1/*
  2 * Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3 * 
  4 * Licensed under the Apache License, Version 2.0 (the "License").
  5 * You may not use this file except in compliance with the License.
  6 * A copy of the License is located at
  7 * 
  8 *  http://aws.amazon.com/apache2.0
  9 * 
 10 * or in the "license" file accompanying this file. This file is distributed
 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 12 * express or implied. See the License for the specific language governing
 13 * permissions and limitations under the License.
 14 */
 15
 16using System;
 17using System.Collections.Generic;
 18using System.IO;
 19using System.Linq;
 20using System.Reflection;
 21using System.Text;
 22
 23using Amazon.Util.Internal;
 24using System.Globalization;
 25using System.Collections;
 26using Amazon.DynamoDBv2.DocumentModel;
 27
 28namespace Amazon.DynamoDBv2.DataModel
 29{
 30    internal static class Utils
 31    {
 32        #region Type methods
 33
 34        private static readonly Type[] primitiveTypesArray = new Type[]
 35        {
 36            typeof(Boolean),
 37            typeof(Byte),
 38            typeof(Char),
 39            typeof(DateTime),
 40            typeof(Decimal),
 41            typeof(Double),
 42            typeof(int),
 43            typeof(long),
 44            typeof(SByte),
 45            typeof(short),
 46            typeof(Single),
 47            typeof(String),
 48            typeof(uint),
 49            typeof(ulong),
 50            typeof(ushort),
 51            typeof(Guid),
 52            typeof(byte[]),
 53            typeof(MemoryStream),
 54            typeof(Primitive)
 55        };
 56
 57        public static readonly IEnumerable<Type> PrimitiveTypes = new HashSet<Type>(primitiveTypesArray);
 58        private static readonly HashSet<ITypeInfo> PrimitiveTypeInfos = new HashSet<ITypeInfo>(primitiveTypesArray
 59            .Select(p => TypeFactory.GetTypeInfo(p)));
 60
 61        public static bool IsPrimitive(Type type)
 62        {
 63            var typeWrapper = TypeFactory.GetTypeInfo(type);
 64            return PrimitiveTypeInfos.Any(ti => typeWrapper.IsAssignableFrom(ti));
 65        }
 66        public static bool IsPrimitive<T>()
 67        {
 68            return IsPrimitive(typeof(T));
 69        }
 70        public static void ValidatePrimitiveType(Type type)
 71        {
 72            if (!Utils.IsPrimitive(type))
 73                throw new InvalidCastException(string.Format(CultureInfo.InvariantCulture,
 74                    "{0} is not a supported Primitive type", type.FullName));
 75        }
 76        public static void ValidatePrimitiveType<T>()
 77        {
 78            ValidatePrimitiveType(typeof(T));
 79        }
 80
 81        public static void ValidateVersionType(Type memberType)
 82        {
 83            var memberTypeWrapper = TypeFactory.GetTypeInfo(memberType);
 84            if (memberTypeWrapper.IsGenericType && memberTypeWrapper.GetGenericTypeDefinition() == typeof(Nullable<>) &&
 85                (memberTypeWrapper.IsAssignableFrom(TypeFactory.GetTypeInfo(typeof(Byte))) ||
 86                memberTypeWrapper.IsAssignableFrom(TypeFactory.GetTypeInfo(typeof(SByte))) ||
 87                memberTypeWrapper.IsAssignableFrom(TypeFactory.GetTypeInfo(typeof(int))) ||
 88                memberTypeWrapper.IsAssignableFrom(TypeFactory.GetTypeInfo(typeof(uint))) ||
 89                memberTypeWrapper.IsAssignableFrom(TypeFactory.GetTypeInfo(typeof(long))) ||
 90                memberTypeWrapper.IsAssignableFrom(TypeFactory.GetTypeInfo(typeof(ulong))) ||
 91                memberTypeWrapper.IsAssignableFrom(TypeFactory.GetTypeInfo(typeof(short))) ||
 92                memberTypeWrapper.IsAssignableFrom(TypeFactory.GetTypeInfo(typeof(ushort)))))
 93            {
 94                return;
 95            }
 96            throw new InvalidOperationException("Version property must be of primitive, numeric, integer, nullable type (e.g. int?, long?, byte?)");
 97        }
 98
 99        public static Type GetPrimitiveElementType(Type collectionType)
100        {
101            var elementType = Utils.GetElementType(collectionType);
102
103            if (elementType != null)
104            {
105                Utils.ValidatePrimitiveType(elementType);
106                return elementType;
107            }
108
109            throw new InvalidOperationException("Unable to determine element type");
110        }
111        public static Type GetElementType(Type collectionType)
112        {
113            var elementType = collectionType.GetElementType();
114
115            if (elementType == null)
116            {
117                var collectionTypeInfo = TypeFactory.GetTypeInfo(collectionType);
118                var genericArguments = collectionTypeInfo.GetGenericArguments();
119                if (genericArguments != null && genericArguments.Length == 1)
120                    elementType = genericArguments[0];
121            }
122
123            // elementType may be null at this point, meaning that the collectionType isn't a collectionType
124            return elementType;
125        }
126
127        public static bool ItemsToCollection(Type targetType, IEnumerable<object> items, out object result)
128        {
129            result = Utils.Instantiate(targetType);
130
131            var ilist = result as IList;
132            if (ilist != null)
133            {
134                foreach (var item in items)
135                    ilist.Add(item);
136                return true;
137            }
138
139            var targetTypeInfo = TypeFactory.GetTypeInfo(targetType);
140            var addMethod = targetTypeInfo.GetMethod("Add");
141            if (addMethod != null)
142            {
143                foreach (var item in items)
144                    addMethod.Invoke(result, new object[] { item });
145                return true;
146            }
147
148            result = null;
149            return false;
150        }
151
152        #endregion
153
154        #region Attribute methods
155
156        public static DynamoDBTableAttribute GetTableAttribute(ITypeInfo targetTypeInfo)
157        {
158            DynamoDBTableAttribute tableAttribute = GetAttribute(targetTypeInfo) as DynamoDBTableAttribute;
159            if (tableAttribute == null)
160                return null;
161            return tableAttribute;
162        }
163
164        public static DynamoDBAttribute GetAttribute(ITypeInfo targetTypeInfo)
165        {
166            if (targetTypeInfo == null) throw new ArgumentNullException("targetTypeInfo");
167            object[] attributes = targetTypeInfo.GetCustomAttributes(TypeFactory.GetTypeInfo(typeof(DynamoDBAttribute)), true);
168            return GetSingleDDBAttribute(attributes);
169        }
170        public static DynamoDBAttribute GetAttribute(MemberInfo targetMemberInfo)
171        {
172            object[] attributes = GetAttributeObjects(targetMemberInfo);
173            return GetSingleDDBAttribute(attributes);
174        }
175        public static List<DynamoDBAttribute> GetAttributes(MemberInfo targetMemberInfo)
176        {
177            object[] attObjects = GetAttributeObjects(targetMemberInfo) ?? new object[0];
178            var attributes = new List<DynamoDBAttribute>();
179            foreach (var attObj in attObjects)
180            {
181                var attribute = attObj as DynamoDBAttribute;
182                if (attribute != null)
183                    attributes.Add(attribute);
184            }
185            return attributes;
186        }
187
188        private static DynamoDBAttribute GetSingleDDBAttribute(object[] attributes)
189        {
190            if (attributes.Length == 0)
191                return null;
192            if (attributes.Length == 1)
193                return (attributes[0] as DynamoDBAttribute);
194            throw new InvalidOperationException("Cannot have multiple DynamoDBAttributes on a single member");
195        }
196
197        private static object[] GetAttributeObjects(MemberInfo targetMemberInfo)
198        {
199            if (targetMemberInfo == null) throw new ArgumentNullException("targetMemberInfo");
200#if PCL
201            object[] attributes = targetMemberInfo.GetCustomAttributes(typeof(DynamoDBAttribute), true).ToArray();
202#else
203            object[] attributes = targetMemberInfo.GetCustomAttributes(typeof(DynamoDBAttribute), true);
204#endif
205            return attributes;
206        }
207
208        #endregion
209
210        #region Non-DynamoDB utilities
211
212        public static string ToLowerCamelCase(string value)
213        {
214            if (string.IsNullOrEmpty(value) || char.IsLower(value[0])) return value;
215            StringBuilder sb = new StringBuilder(value);
216            sb[0] = char.ToLowerInvariant(sb[0]);
217            return sb.ToString();
218        }
219
220        private static ITypeInfo[][] validConstructorInputs = new ITypeInfo[][]
221        {
222            TypeFactory.EmptyTypes,
223        };
224        private static ITypeInfo[][] validConverterConstructorInputs = new ITypeInfo[][]
225        {
226            TypeFactory.EmptyTypes,
227            new ITypeInfo[] { TypeFactory.GetTypeInfo(typeof(DynamoDBContext)) }
228        };
229
230        public static object InstantiateConverter(Type objectType, IDynamoDBContext context)
231        {
232            return InstantiateHelper(objectType, validConverterConstructorInputs, new object[] { context });
233        }
234        public static object Instantiate(Type objectType)
235        {
236            return InstantiateHelper(objectType, validConstructorInputs, null);
237        }
238        private static object InstantiateHelper(Type objectType, ITypeInfo[][] validConstructorInputs, object[] optionalInput = null)
239        {
240            if (objectType == null)
241                throw new ArgumentNullException("objectType");
242            if (!CanInstantiateHelper(objectType, validConstructorInputs))
243                throw new InvalidOperationException("Cannot instantiate type " + objectType.FullName);
244
245            var objectTypeWrapper = TypeFactory.GetTypeInfo(objectType);
246            var constructors = GetConstructors(objectTypeWrapper, validConverterConstructorInputs).ToList();
247
248            if (constructors != null && constructors.Count > 0)
249            {
250                foreach (var constructor in constructors)
251                {
252                    var inputs = constructor.GetParameters();
253                    object[] constructorParameters = inputs.Length == 0 ?
254                        null : optionalInput;
255                    object instance = constructor.Invoke(constructorParameters);
256                    return instance;
257                }
258            }
259
260            throw new InvalidOperationException("Unable to find valid constructor for type " + objectType.FullName);
261        }
262        private static IEnumerable<ConstructorInfo> GetConstructors(ITypeInfo typeInfo, ITypeInfo[][] validConstructorInputs)
263        {
264            foreach(var inputTypes in validConstructorInputs)
265            {
266                var constructor = typeInfo.GetConstructor(inputTypes);
267                if (constructor != null)
268                    yield return constructor;
269            }
270        }
271
272        public static bool CanInstantiate(Type objectType)
273        {
274            return CanInstantiateHelper(objectType, validConstructorInputs);
275        }
276        public static bool CanInstantiateConverter(Type objectType)
277        {
278            return CanInstantiateHelper(objectType, validConverterConstructorInputs);
279        }
280        private static bool CanInstantiateHelper(Type objectType, ITypeInfo[][] validConstructorInputs)
281        {
282            var objectTypeWrapper = TypeFactory.GetTypeInfo(objectType);
283
284            bool candidate =
285                //objectType.IsPublic &&
286                objectTypeWrapper.IsClass &&
287                !objectTypeWrapper.IsInterface &&
288                !objectTypeWrapper.IsAbstract &&
289                !objectTypeWrapper.IsGenericTypeDefinition &&
290                !objectTypeWrapper.ContainsGenericParameters;
291
292            if (!candidate)
293                return false;
294
295            // check valid constructor inputs
296            var constructors = GetConstructors(objectTypeWrapper, validConstructorInputs).ToList();
297            if (constructors.Count == 0)
298                return false;
299
300            return true;
301        }
302        public static Type GetType(MemberInfo member)
303        {
304            var pi = member as PropertyInfo;
305            var fi = member as FieldInfo;
306            if (pi == null && fi == null)
307                throw new ArgumentOutOfRangeException("member", "member must be of type PropertyInfo or FieldInfo");
308
309            return (pi != null ? pi.PropertyType : fi.FieldType);
310        }
311        public static bool IsReadWrite(MemberInfo member)
312        {
313            PropertyInfo property = member as PropertyInfo;
314            FieldInfo field = member as FieldInfo;
315
316            if (property != null)
317            {
318                return (property.CanRead && property.CanWrite);
319            }
320            else if (field != null)
321            {
322                return (field.IsPublic && !field.IsLiteral && !field.IsInitOnly);
323            }
324            else
325            {
326                throw new ArgumentOutOfRangeException("member", "Member must be FieldInfo or PropertyInfo");
327            }
328        }
329        public static bool ImplementsInterface(Type targetType, Type interfaceType)
330        {
331            var targetTypeWrapper = TypeFactory.GetTypeInfo(targetType);
332            var interfaceTypeWrapper = TypeFactory.GetTypeInfo(interfaceType);
333            if (!interfaceTypeWrapper.IsInterface)
334                throw new ArgumentOutOfRangeException("interfaceType", "Type is not an interface");
335
336            foreach (var inter in targetTypeWrapper.GetInterfaces())
337            {
338                var interWrapper = TypeFactory.GetTypeInfo(inter);
339                if (object.Equals(interWrapper, interfaceTypeWrapper))
340                    return true;
341                if (interfaceTypeWrapper.IsGenericTypeDefinition && interWrapper.IsGenericType)
342                {
343                    var generic = interWrapper.GetGenericTypeDefinition();
344                    if (generic == interfaceType)
345                        return true;
346                }
347            }
348            return false;
349        }
350
351#endregion
352
353    }
354}