PageRenderTime 58ms CodeModel.GetById 42ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/skolima/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
 12
 13namespace System.Data.Services.Client
 14{
 15#region Namespaces
 16    using System.Collections.Generic;
 17    using System.ComponentModel;
 18    using System.Data.Services.Common;
 19    using System.Diagnostics;
 20    using System.Linq;
 21    using System.Reflection;
 22    using System.Threading;
 23#endregion
 24
 25    internal enum BindingPropertyKind
 26    {
 27        BindingPropertyKindComplex,
 28
 29        BindingPropertyKindEntity,
 30
 31        BindingPropertyKindCollection
 32    }
 33
 34    internal class BindingEntityInfo
 35    {
 36        private static readonly object FalseObject = new object();
 37
 38        private static readonly object TrueObject = new object();
 39
 40        private static readonly ReaderWriterLockSlim metadataCacheLock = new ReaderWriterLockSlim();
 41
 42        private static readonly HashSet<Type> knownNonEntityTypes = new HashSet<Type>(EqualityComparer<Type>.Default);
 43
 44        private static readonly Dictionary<Type, object> knownObservableCollectionTypes = new Dictionary<Type, object>(EqualityComparer<Type>.Default);
 45
 46        private static readonly Dictionary<Type, BindingEntityInfoPerType> bindingEntityInfos = new Dictionary<Type, BindingEntityInfoPerType>(EqualityComparer<Type>.Default);
 47
 48        internal static IList<BindingPropertyInfo> GetObservableProperties(Type entityType)
 49        {
 50            return GetBindingEntityInfoFor(entityType).ObservableProperties;
 51        }
 52
 53        internal static ClientType GetClientType(Type entityType)
 54        {
 55            return GetBindingEntityInfoFor(entityType).ClientType;
 56        }
 57
 58        internal static string GetEntitySet(
 59            object target,
 60            string targetEntitySet)
 61        {
 62            Debug.Assert(target != null, "Argument 'target' cannot be null.");
 63            Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "Argument 'target' must be an entity type.");
 64
 65            if (!String.IsNullOrEmpty(targetEntitySet))
 66            {
 67                return targetEntitySet;
 68            }
 69            else
 70            {
 71                return BindingEntityInfo.GetEntitySetAttribute(target.GetType());
 72            }
 73        }
 74
 75        internal static bool IsDataServiceCollection(Type collectionType)
 76        {
 77            Debug.Assert(collectionType != null, "Argument 'collectionType' cannot be null.");
 78
 79            metadataCacheLock.EnterReadLock();
 80            try
 81            {
 82                object resultAsObject;
 83                if (knownObservableCollectionTypes.TryGetValue(collectionType, out resultAsObject))
 84                {
 85                    return resultAsObject == TrueObject;
 86                }
 87            }
 88            finally
 89            {
 90                metadataCacheLock.ExitReadLock();
 91            }
 92
 93            Type type = collectionType;
 94            bool result = false;
 95
 96            while (type != null)
 97            {
 98                if (type.IsGenericType)
 99                {
100                    Type[] parms = type.GetGenericArguments();
101
102                    if (parms != null && parms.Length == 1 && IsEntityType(parms[0]))
103                    {
104                        Type dataServiceCollection = WebUtil.GetDataServiceCollectionOfT(parms);
105                        if (dataServiceCollection != null && dataServiceCollection.IsAssignableFrom(type))
106                        {
107                            result = true;
108                            break;
109                        }
110                    }
111                }
112
113                type = type.BaseType;
114            }
115
116            metadataCacheLock.EnterWriteLock();
117            try
118            {
119                if (!knownObservableCollectionTypes.ContainsKey(collectionType))
120                {
121                    knownObservableCollectionTypes[collectionType] = result ? TrueObject : FalseObject;
122                }
123            }
124            finally
125            {
126                metadataCacheLock.ExitWriteLock();
127            }
128
129            return result;
130        }
131
132        internal static bool IsEntityType(Type type)
133        {
134            Debug.Assert(type != null, "Argument 'type' cannot be null.");
135
136            metadataCacheLock.EnterReadLock();
137            try
138            {
139                if (knownNonEntityTypes.Contains(type))
140                {
141                    return false;
142                }
143            }
144            finally
145            {
146                metadataCacheLock.ExitReadLock();
147            }
148
149            try
150            {
151                if (BindingEntityInfo.IsDataServiceCollection(type))
152                {
153                    return false;
154                }
155
156                return ClientType.Create(type).IsEntityType;
157            }
158            catch (InvalidOperationException)
159            {
160                metadataCacheLock.EnterWriteLock();
161                try
162                {
163                    if (!knownNonEntityTypes.Contains(type))
164                    {
165                        knownNonEntityTypes.Add(type);
166                    }
167                }
168                finally
169                {
170                    metadataCacheLock.ExitWriteLock();
171                }
172
173                return false;
174            }
175        }
176
177        internal static object GetPropertyValue(object source, string sourceProperty, out BindingPropertyInfo bindingPropertyInfo)
178        {
179            Type sourceType = source.GetType();
180
181            bindingPropertyInfo = BindingEntityInfo.GetObservableProperties(sourceType)
182                                                   .SingleOrDefault(x => x.PropertyInfo.PropertyName == sourceProperty);
183
184            if (bindingPropertyInfo == null)
185            {
186                return BindingEntityInfo.GetClientType(sourceType)
187                                        .GetProperty(sourceProperty, false)
188                                        .GetValue(source);
189            }
190            else
191            {
192                return bindingPropertyInfo.PropertyInfo.GetValue(source);
193            }
194        }
195
196        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType)
197        {
198            BindingEntityInfoPerType bindingEntityInfo;
199
200            metadataCacheLock.EnterReadLock();
201            try
202            {
203                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
204                {
205                    return bindingEntityInfo;
206                }
207            }
208            finally
209            {
210                metadataCacheLock.ExitReadLock();
211            }
212
213            bindingEntityInfo = new BindingEntityInfoPerType();
214
215            object[] attributes = entityType.GetCustomAttributes(typeof(EntitySetAttribute), true);
216
217            bindingEntityInfo.EntitySet = (attributes != null && attributes.Length == 1) ? ((EntitySetAttribute)attributes[0]).EntitySet : null;
218            bindingEntityInfo.ClientType = ClientType.Create(entityType);
219            
220            foreach (ClientType.ClientProperty p in bindingEntityInfo.ClientType.Properties)
221            {
222                BindingPropertyInfo bpi = null;
223            
224                Type propertyType = p.PropertyType;
225                
226                if (p.CollectionType != null)
227                {
228                    if (BindingEntityInfo.IsDataServiceCollection(propertyType))
229                    {
230                        bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindCollection };
231                    }
232                }
233                else
234                if (BindingEntityInfo.IsEntityType(propertyType))
235                {
236                    bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindEntity };
237                }
238                else
239                if (BindingEntityInfo.CanBeComplexProperty(p))
240                {
241                    bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindComplex };
242                }
243                
244                if (bpi != null)
245                {
246                    bpi.PropertyInfo = p;
247                    
248                    if (bindingEntityInfo.ClientType.IsEntityType || bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex)
249                    {
250                        bindingEntityInfo.ObservableProperties.Add(bpi);
251                    }
252                }
253            }
254
255            metadataCacheLock.EnterWriteLock();
256            try
257            {
258                if (!bindingEntityInfos.ContainsKey(entityType))
259                {
260                    bindingEntityInfos[entityType] = bindingEntityInfo;
261                }
262            }
263            finally
264            {
265                metadataCacheLock.ExitWriteLock();
266            }
267
268            return bindingEntityInfo;
269        }
270
271        private static bool CanBeComplexProperty(ClientType.ClientProperty property)
272        {
273            Debug.Assert(property != null, "property != null");
274            if (typeof(INotifyPropertyChanged).IsAssignableFrom(property.PropertyType))
275            {
276                Debug.Assert(!property.IsKnownType, "Known types do not implement INotifyPropertyChanged.");
277                return true;
278            }
279
280            return false;
281        }
282
283        private static string GetEntitySetAttribute(Type entityType)
284        {
285            return GetBindingEntityInfoFor(entityType).EntitySet;
286        }
287
288        internal class BindingPropertyInfo
289        {
290            public ClientType.ClientProperty PropertyInfo
291            {
292                get;
293                set;
294            }
295
296            public BindingPropertyKind PropertyKind
297            {
298                get;
299                set;
300            }
301        }
302
303        private sealed class BindingEntityInfoPerType
304        {
305            private List<BindingPropertyInfo> observableProperties;
306
307            public BindingEntityInfoPerType()
308            {
309                this.observableProperties = new List<BindingPropertyInfo>();
310            }
311
312            public String EntitySet
313            {
314                get;
315                set;
316            }
317
318            public ClientType ClientType
319            {
320                get;
321                set;
322            }
323
324            public List<BindingPropertyInfo> ObservableProperties
325            {
326                get
327                {
328                    return this.observableProperties;
329                }
330            }
331        }
332
333#if ASTORIA_LIGHT
334        private sealed class ReaderWriterLockSlim
335        {
336            private object _lock = new object();
337
338            internal void EnterReadLock()
339            {
340                Monitor.Enter(_lock);
341            }
342
343            internal void EnterWriteLock()
344            {
345                Monitor.Enter(_lock);
346            }
347
348            internal void ExitReadLock()
349            {
350                Monitor.Exit(_lock);
351            }
352
353            internal void ExitWriteLock()
354            {
355                Monitor.Exit(_lock);
356            }
357        }
358#endif
359    }
360}