/mcs/class/System.Data.Services.Client/Client/System/Data/Services/Client/Binding/BindingEntityInfo.cs
C# | 360 lines | 292 code | 58 blank | 10 comment | 41 complexity | dfc20d4bda1c39e8a1b754975cdfc888 MD5 | raw file
- //Copyright 2010 Microsoft Corporation
- //
- //Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
- //You may obtain a copy of the License at
- //
- //http://www.apache.org/licenses/LICENSE-2.0
- //
- //Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
- //"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- //See the License for the specific language governing permissions and limitations under the License.
-
-
- namespace System.Data.Services.Client
- {
- #region Namespaces
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data.Services.Common;
- using System.Diagnostics;
- using System.Linq;
- using System.Reflection;
- using System.Threading;
- #endregion
-
- internal enum BindingPropertyKind
- {
- BindingPropertyKindComplex,
-
- BindingPropertyKindEntity,
-
- BindingPropertyKindCollection
- }
-
- internal class BindingEntityInfo
- {
- private static readonly object FalseObject = new object();
-
- private static readonly object TrueObject = new object();
-
- private static readonly ReaderWriterLockSlim metadataCacheLock = new ReaderWriterLockSlim();
-
- private static readonly HashSet<Type> knownNonEntityTypes = new HashSet<Type>(EqualityComparer<Type>.Default);
-
- private static readonly Dictionary<Type, object> knownObservableCollectionTypes = new Dictionary<Type, object>(EqualityComparer<Type>.Default);
-
- private static readonly Dictionary<Type, BindingEntityInfoPerType> bindingEntityInfos = new Dictionary<Type, BindingEntityInfoPerType>(EqualityComparer<Type>.Default);
-
- internal static IList<BindingPropertyInfo> GetObservableProperties(Type entityType)
- {
- return GetBindingEntityInfoFor(entityType).ObservableProperties;
- }
-
- internal static ClientType GetClientType(Type entityType)
- {
- return GetBindingEntityInfoFor(entityType).ClientType;
- }
-
- internal static string GetEntitySet(
- object target,
- string targetEntitySet)
- {
- Debug.Assert(target != null, "Argument 'target' cannot be null.");
- Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "Argument 'target' must be an entity type.");
-
- if (!String.IsNullOrEmpty(targetEntitySet))
- {
- return targetEntitySet;
- }
- else
- {
- return BindingEntityInfo.GetEntitySetAttribute(target.GetType());
- }
- }
-
- internal static bool IsDataServiceCollection(Type collectionType)
- {
- Debug.Assert(collectionType != null, "Argument 'collectionType' cannot be null.");
-
- metadataCacheLock.EnterReadLock();
- try
- {
- object resultAsObject;
- if (knownObservableCollectionTypes.TryGetValue(collectionType, out resultAsObject))
- {
- return resultAsObject == TrueObject;
- }
- }
- finally
- {
- metadataCacheLock.ExitReadLock();
- }
-
- Type type = collectionType;
- bool result = false;
-
- while (type != null)
- {
- if (type.IsGenericType)
- {
- Type[] parms = type.GetGenericArguments();
-
- if (parms != null && parms.Length == 1 && IsEntityType(parms[0]))
- {
- Type dataServiceCollection = WebUtil.GetDataServiceCollectionOfT(parms);
- if (dataServiceCollection != null && dataServiceCollection.IsAssignableFrom(type))
- {
- result = true;
- break;
- }
- }
- }
-
- type = type.BaseType;
- }
-
- metadataCacheLock.EnterWriteLock();
- try
- {
- if (!knownObservableCollectionTypes.ContainsKey(collectionType))
- {
- knownObservableCollectionTypes[collectionType] = result ? TrueObject : FalseObject;
- }
- }
- finally
- {
- metadataCacheLock.ExitWriteLock();
- }
-
- return result;
- }
-
- internal static bool IsEntityType(Type type)
- {
- Debug.Assert(type != null, "Argument 'type' cannot be null.");
-
- metadataCacheLock.EnterReadLock();
- try
- {
- if (knownNonEntityTypes.Contains(type))
- {
- return false;
- }
- }
- finally
- {
- metadataCacheLock.ExitReadLock();
- }
-
- try
- {
- if (BindingEntityInfo.IsDataServiceCollection(type))
- {
- return false;
- }
-
- return ClientType.Create(type).IsEntityType;
- }
- catch (InvalidOperationException)
- {
- metadataCacheLock.EnterWriteLock();
- try
- {
- if (!knownNonEntityTypes.Contains(type))
- {
- knownNonEntityTypes.Add(type);
- }
- }
- finally
- {
- metadataCacheLock.ExitWriteLock();
- }
-
- return false;
- }
- }
-
- internal static object GetPropertyValue(object source, string sourceProperty, out BindingPropertyInfo bindingPropertyInfo)
- {
- Type sourceType = source.GetType();
-
- bindingPropertyInfo = BindingEntityInfo.GetObservableProperties(sourceType)
- .SingleOrDefault(x => x.PropertyInfo.PropertyName == sourceProperty);
-
- if (bindingPropertyInfo == null)
- {
- return BindingEntityInfo.GetClientType(sourceType)
- .GetProperty(sourceProperty, false)
- .GetValue(source);
- }
- else
- {
- return bindingPropertyInfo.PropertyInfo.GetValue(source);
- }
- }
-
- private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType)
- {
- BindingEntityInfoPerType bindingEntityInfo;
-
- metadataCacheLock.EnterReadLock();
- try
- {
- if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
- {
- return bindingEntityInfo;
- }
- }
- finally
- {
- metadataCacheLock.ExitReadLock();
- }
-
- bindingEntityInfo = new BindingEntityInfoPerType();
-
- object[] attributes = entityType.GetCustomAttributes(typeof(EntitySetAttribute), true);
-
- bindingEntityInfo.EntitySet = (attributes != null && attributes.Length == 1) ? ((EntitySetAttribute)attributes[0]).EntitySet : null;
- bindingEntityInfo.ClientType = ClientType.Create(entityType);
-
- foreach (ClientType.ClientProperty p in bindingEntityInfo.ClientType.Properties)
- {
- BindingPropertyInfo bpi = null;
-
- Type propertyType = p.PropertyType;
-
- if (p.CollectionType != null)
- {
- if (BindingEntityInfo.IsDataServiceCollection(propertyType))
- {
- bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindCollection };
- }
- }
- else
- if (BindingEntityInfo.IsEntityType(propertyType))
- {
- bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindEntity };
- }
- else
- if (BindingEntityInfo.CanBeComplexProperty(p))
- {
- bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindComplex };
- }
-
- if (bpi != null)
- {
- bpi.PropertyInfo = p;
-
- if (bindingEntityInfo.ClientType.IsEntityType || bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex)
- {
- bindingEntityInfo.ObservableProperties.Add(bpi);
- }
- }
- }
-
- metadataCacheLock.EnterWriteLock();
- try
- {
- if (!bindingEntityInfos.ContainsKey(entityType))
- {
- bindingEntityInfos[entityType] = bindingEntityInfo;
- }
- }
- finally
- {
- metadataCacheLock.ExitWriteLock();
- }
-
- return bindingEntityInfo;
- }
-
- private static bool CanBeComplexProperty(ClientType.ClientProperty property)
- {
- Debug.Assert(property != null, "property != null");
- if (typeof(INotifyPropertyChanged).IsAssignableFrom(property.PropertyType))
- {
- Debug.Assert(!property.IsKnownType, "Known types do not implement INotifyPropertyChanged.");
- return true;
- }
-
- return false;
- }
-
- private static string GetEntitySetAttribute(Type entityType)
- {
- return GetBindingEntityInfoFor(entityType).EntitySet;
- }
-
- internal class BindingPropertyInfo
- {
- public ClientType.ClientProperty PropertyInfo
- {
- get;
- set;
- }
-
- public BindingPropertyKind PropertyKind
- {
- get;
- set;
- }
- }
-
- private sealed class BindingEntityInfoPerType
- {
- private List<BindingPropertyInfo> observableProperties;
-
- public BindingEntityInfoPerType()
- {
- this.observableProperties = new List<BindingPropertyInfo>();
- }
-
- public String EntitySet
- {
- get;
- set;
- }
-
- public ClientType ClientType
- {
- get;
- set;
- }
-
- public List<BindingPropertyInfo> ObservableProperties
- {
- get
- {
- return this.observableProperties;
- }
- }
- }
-
- #if ASTORIA_LIGHT
- private sealed class ReaderWriterLockSlim
- {
- private object _lock = new object();
-
- internal void EnterReadLock()
- {
- Monitor.Enter(_lock);
- }
-
- internal void EnterWriteLock()
- {
- Monitor.Enter(_lock);
- }
-
- internal void ExitReadLock()
- {
- Monitor.Exit(_lock);
- }
-
- internal void ExitWriteLock()
- {
- Monitor.Exit(_lock);
- }
- }
- #endif
- }
- }