PageRenderTime 29ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Data.Services.Client/Client/System/Data/Services/Client/Binding/BindingEntityInfo.cs

https://github.com/iainlane/mono
C# | 360 lines | 292 code | 58 blank | 10 comment | 41 complexity | dfc20d4bda1c39e8a1b754975cdfc888 MD5 | raw file
  1. //Copyright 2010 Microsoft Corporation
  2. //
  3. //Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  4. //You may obtain a copy of the License at
  5. //
  6. //http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. //Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
  9. //"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. //See the License for the specific language governing permissions and limitations under the License.
  11. namespace System.Data.Services.Client
  12. {
  13. #region Namespaces
  14. using System.Collections.Generic;
  15. using System.ComponentModel;
  16. using System.Data.Services.Common;
  17. using System.Diagnostics;
  18. using System.Linq;
  19. using System.Reflection;
  20. using System.Threading;
  21. #endregion
  22. internal enum BindingPropertyKind
  23. {
  24. BindingPropertyKindComplex,
  25. BindingPropertyKindEntity,
  26. BindingPropertyKindCollection
  27. }
  28. internal class BindingEntityInfo
  29. {
  30. private static readonly object FalseObject = new object();
  31. private static readonly object TrueObject = new object();
  32. private static readonly ReaderWriterLockSlim metadataCacheLock = new ReaderWriterLockSlim();
  33. private static readonly HashSet<Type> knownNonEntityTypes = new HashSet<Type>(EqualityComparer<Type>.Default);
  34. private static readonly Dictionary<Type, object> knownObservableCollectionTypes = new Dictionary<Type, object>(EqualityComparer<Type>.Default);
  35. private static readonly Dictionary<Type, BindingEntityInfoPerType> bindingEntityInfos = new Dictionary<Type, BindingEntityInfoPerType>(EqualityComparer<Type>.Default);
  36. internal static IList<BindingPropertyInfo> GetObservableProperties(Type entityType)
  37. {
  38. return GetBindingEntityInfoFor(entityType).ObservableProperties;
  39. }
  40. internal static ClientType GetClientType(Type entityType)
  41. {
  42. return GetBindingEntityInfoFor(entityType).ClientType;
  43. }
  44. internal static string GetEntitySet(
  45. object target,
  46. string targetEntitySet)
  47. {
  48. Debug.Assert(target != null, "Argument 'target' cannot be null.");
  49. Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "Argument 'target' must be an entity type.");
  50. if (!String.IsNullOrEmpty(targetEntitySet))
  51. {
  52. return targetEntitySet;
  53. }
  54. else
  55. {
  56. return BindingEntityInfo.GetEntitySetAttribute(target.GetType());
  57. }
  58. }
  59. internal static bool IsDataServiceCollection(Type collectionType)
  60. {
  61. Debug.Assert(collectionType != null, "Argument 'collectionType' cannot be null.");
  62. metadataCacheLock.EnterReadLock();
  63. try
  64. {
  65. object resultAsObject;
  66. if (knownObservableCollectionTypes.TryGetValue(collectionType, out resultAsObject))
  67. {
  68. return resultAsObject == TrueObject;
  69. }
  70. }
  71. finally
  72. {
  73. metadataCacheLock.ExitReadLock();
  74. }
  75. Type type = collectionType;
  76. bool result = false;
  77. while (type != null)
  78. {
  79. if (type.IsGenericType)
  80. {
  81. Type[] parms = type.GetGenericArguments();
  82. if (parms != null && parms.Length == 1 && IsEntityType(parms[0]))
  83. {
  84. Type dataServiceCollection = WebUtil.GetDataServiceCollectionOfT(parms);
  85. if (dataServiceCollection != null && dataServiceCollection.IsAssignableFrom(type))
  86. {
  87. result = true;
  88. break;
  89. }
  90. }
  91. }
  92. type = type.BaseType;
  93. }
  94. metadataCacheLock.EnterWriteLock();
  95. try
  96. {
  97. if (!knownObservableCollectionTypes.ContainsKey(collectionType))
  98. {
  99. knownObservableCollectionTypes[collectionType] = result ? TrueObject : FalseObject;
  100. }
  101. }
  102. finally
  103. {
  104. metadataCacheLock.ExitWriteLock();
  105. }
  106. return result;
  107. }
  108. internal static bool IsEntityType(Type type)
  109. {
  110. Debug.Assert(type != null, "Argument 'type' cannot be null.");
  111. metadataCacheLock.EnterReadLock();
  112. try
  113. {
  114. if (knownNonEntityTypes.Contains(type))
  115. {
  116. return false;
  117. }
  118. }
  119. finally
  120. {
  121. metadataCacheLock.ExitReadLock();
  122. }
  123. try
  124. {
  125. if (BindingEntityInfo.IsDataServiceCollection(type))
  126. {
  127. return false;
  128. }
  129. return ClientType.Create(type).IsEntityType;
  130. }
  131. catch (InvalidOperationException)
  132. {
  133. metadataCacheLock.EnterWriteLock();
  134. try
  135. {
  136. if (!knownNonEntityTypes.Contains(type))
  137. {
  138. knownNonEntityTypes.Add(type);
  139. }
  140. }
  141. finally
  142. {
  143. metadataCacheLock.ExitWriteLock();
  144. }
  145. return false;
  146. }
  147. }
  148. internal static object GetPropertyValue(object source, string sourceProperty, out BindingPropertyInfo bindingPropertyInfo)
  149. {
  150. Type sourceType = source.GetType();
  151. bindingPropertyInfo = BindingEntityInfo.GetObservableProperties(sourceType)
  152. .SingleOrDefault(x => x.PropertyInfo.PropertyName == sourceProperty);
  153. if (bindingPropertyInfo == null)
  154. {
  155. return BindingEntityInfo.GetClientType(sourceType)
  156. .GetProperty(sourceProperty, false)
  157. .GetValue(source);
  158. }
  159. else
  160. {
  161. return bindingPropertyInfo.PropertyInfo.GetValue(source);
  162. }
  163. }
  164. private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType)
  165. {
  166. BindingEntityInfoPerType bindingEntityInfo;
  167. metadataCacheLock.EnterReadLock();
  168. try
  169. {
  170. if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
  171. {
  172. return bindingEntityInfo;
  173. }
  174. }
  175. finally
  176. {
  177. metadataCacheLock.ExitReadLock();
  178. }
  179. bindingEntityInfo = new BindingEntityInfoPerType();
  180. object[] attributes = entityType.GetCustomAttributes(typeof(EntitySetAttribute), true);
  181. bindingEntityInfo.EntitySet = (attributes != null && attributes.Length == 1) ? ((EntitySetAttribute)attributes[0]).EntitySet : null;
  182. bindingEntityInfo.ClientType = ClientType.Create(entityType);
  183. foreach (ClientType.ClientProperty p in bindingEntityInfo.ClientType.Properties)
  184. {
  185. BindingPropertyInfo bpi = null;
  186. Type propertyType = p.PropertyType;
  187. if (p.CollectionType != null)
  188. {
  189. if (BindingEntityInfo.IsDataServiceCollection(propertyType))
  190. {
  191. bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindCollection };
  192. }
  193. }
  194. else
  195. if (BindingEntityInfo.IsEntityType(propertyType))
  196. {
  197. bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindEntity };
  198. }
  199. else
  200. if (BindingEntityInfo.CanBeComplexProperty(p))
  201. {
  202. bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindComplex };
  203. }
  204. if (bpi != null)
  205. {
  206. bpi.PropertyInfo = p;
  207. if (bindingEntityInfo.ClientType.IsEntityType || bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex)
  208. {
  209. bindingEntityInfo.ObservableProperties.Add(bpi);
  210. }
  211. }
  212. }
  213. metadataCacheLock.EnterWriteLock();
  214. try
  215. {
  216. if (!bindingEntityInfos.ContainsKey(entityType))
  217. {
  218. bindingEntityInfos[entityType] = bindingEntityInfo;
  219. }
  220. }
  221. finally
  222. {
  223. metadataCacheLock.ExitWriteLock();
  224. }
  225. return bindingEntityInfo;
  226. }
  227. private static bool CanBeComplexProperty(ClientType.ClientProperty property)
  228. {
  229. Debug.Assert(property != null, "property != null");
  230. if (typeof(INotifyPropertyChanged).IsAssignableFrom(property.PropertyType))
  231. {
  232. Debug.Assert(!property.IsKnownType, "Known types do not implement INotifyPropertyChanged.");
  233. return true;
  234. }
  235. return false;
  236. }
  237. private static string GetEntitySetAttribute(Type entityType)
  238. {
  239. return GetBindingEntityInfoFor(entityType).EntitySet;
  240. }
  241. internal class BindingPropertyInfo
  242. {
  243. public ClientType.ClientProperty PropertyInfo
  244. {
  245. get;
  246. set;
  247. }
  248. public BindingPropertyKind PropertyKind
  249. {
  250. get;
  251. set;
  252. }
  253. }
  254. private sealed class BindingEntityInfoPerType
  255. {
  256. private List<BindingPropertyInfo> observableProperties;
  257. public BindingEntityInfoPerType()
  258. {
  259. this.observableProperties = new List<BindingPropertyInfo>();
  260. }
  261. public String EntitySet
  262. {
  263. get;
  264. set;
  265. }
  266. public ClientType ClientType
  267. {
  268. get;
  269. set;
  270. }
  271. public List<BindingPropertyInfo> ObservableProperties
  272. {
  273. get
  274. {
  275. return this.observableProperties;
  276. }
  277. }
  278. }
  279. #if ASTORIA_LIGHT
  280. private sealed class ReaderWriterLockSlim
  281. {
  282. private object _lock = new object();
  283. internal void EnterReadLock()
  284. {
  285. Monitor.Enter(_lock);
  286. }
  287. internal void EnterWriteLock()
  288. {
  289. Monitor.Enter(_lock);
  290. }
  291. internal void ExitReadLock()
  292. {
  293. Monitor.Exit(_lock);
  294. }
  295. internal void ExitWriteLock()
  296. {
  297. Monitor.Exit(_lock);
  298. }
  299. }
  300. #endif
  301. }
  302. }