PageRenderTime 4185ms CodeModel.GetById 16ms RepoModel.GetById 2ms app.codeStats 0ms

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

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