You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by bi...@apache.org on 2014/03/26 05:23:22 UTC

[05/15] This change set contains the odata javascript library V3. The version number is 1.1.2

http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/tests/code/ReflectionDataContext.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/ReflectionDataContext.cs b/JSLib/tests/code/ReflectionDataContext.cs
new file mode 100644
index 0000000..762b56f
--- /dev/null
+++ b/JSLib/tests/code/ReflectionDataContext.cs
@@ -0,0 +1,742 @@
+// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 
+// files (the "Software"), to deal  in the Software without restriction, including without limitation the rights  to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+namespace DataJS.Tests
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Collections.ObjectModel;
+    using System.Data.Services;
+    using System.Data.Services.Common;
+    using System.Globalization;
+    using System.Linq;
+    using System.Reflection;
+
+    /// <summary>
+    /// Provides a reflection-based, updatable data context.
+    /// </summary>
+    public abstract class ReflectionDataContext
+    {
+        // Fields
+        private List<object> deletedObjects = new List<object>();
+        private List<Action> pendingChanges;
+        private static Dictionary<Type, Dictionary<string, IList>> resourceSetsByContextTypeStorage = new Dictionary<Type, Dictionary<string, IList>>();
+
+        // Methods
+        protected ReflectionDataContext()
+        {
+            this.MetadataHelper = new ReflectionMetadataHelper(this);
+            this.pendingChanges = new List<Action>();
+            if (!resourceSetsByContextTypeStorage.ContainsKey(base.GetType()))
+            {
+                resourceSetsByContextTypeStorage.Add(base.GetType(), new Dictionary<string, IList>());
+                foreach (string resourceSetName in this.MetadataHelper.GetResourceSetNames())
+                {
+                    Type resourceType = this.MetadataHelper.GetResourceTypeOfSet(resourceSetName);
+                    IList listOfTInstance = Activator.CreateInstance(typeof(List<>).MakeGenericType(new Type[] { resourceType })) as IList;
+                    this.ResourceSetsStorage.Add(resourceSetName, listOfTInstance);
+                }
+            }
+            this.EnsureDataIsInitialized();
+        }
+
+        public virtual void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
+            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
+            ExceptionUtilities.CheckArgumentNotNull(resourceToBeAdded, "resourceToBeAdded");
+            UpdatableToken targetToken = UpdatableToken.AssertIsToken(targetResource, "targetResource");
+            targetResource = targetToken.Resource;
+            resourceToBeAdded = UpdatableToken.AssertIsTokenAndResolve(resourceToBeAdded, "resourceToBeAdded");
+            IList list = this.GetValue(targetToken, propertyName) as IList;
+            ExceptionUtilities.CheckObjectNotNull(list, "Property '{0}' on type '{1}' was not a list", new object[] { propertyName, targetResource.GetType().Name });
+            this.pendingChanges.Add(delegate {
+                list.Add(resourceToBeAdded);
+            });
+        }
+
+        public virtual void ClearChanges()
+        {
+            this.pendingChanges.Clear();
+        }
+
+        public void ClearData()
+        {
+            this.ResourceSetsStorage.Clear();
+        }
+
+        private static bool CompareETagValues(Dictionary<string, object> resourceCookieValues, IEnumerable<KeyValuePair<string, object>> concurrencyValues)
+        {
+            if (concurrencyValues.Count<KeyValuePair<string, object>>() != resourceCookieValues.Count)
+            {
+                return false;
+            }
+            foreach (KeyValuePair<string, object> keyValuePair in concurrencyValues)
+            {
+                if (!resourceCookieValues.ContainsKey(keyValuePair.Key))
+                {
+                    return false;
+                }
+                if (keyValuePair.Value == null)
+                {
+                    return (resourceCookieValues[keyValuePair.Key] == null);
+                }
+                if (!keyValuePair.Value.Equals(resourceCookieValues[keyValuePair.Key]))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public virtual object CreateResource(string containerName, string fullTypeName)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(fullTypeName, "fullTypeName");
+            UpdatableToken token = this.InstantiateResourceType(fullTypeName);
+            if (containerName != null)
+            {
+                this.pendingChanges.Add(delegate {
+                    this.GetResourceSetEntities(containerName).Add(token.Resource);
+                });
+            }
+            return token;
+        }
+
+        private void DeleteAllReferences(object targetResource)
+        {
+            foreach (string currentSetName in this.MetadataHelper.GetResourceSetNames())
+            {
+                Type currentEntityType = this.MetadataHelper.GetResourceTypeOfSet(currentSetName);
+                IList entitySetList = this.GetResourceSetEntities(currentSetName);
+                foreach (NavigationPropertyInfo navigationProperty in this.MetadataHelper.GetNavigationProperties(GetResourceTypeFullName(currentEntityType)))
+                {
+                    if (navigationProperty.CollectionElementType != null)
+                    {
+                        foreach (object currentEntityInstance in entitySetList)
+                        {
+                            this.RemoveResourceFromCollectionOnTargetResourceMatch(targetResource, navigationProperty, currentEntityInstance);
+                        }
+                    }
+                    else
+                    {
+                        ExceptionUtilities.CheckObjectNotNull(navigationProperty.PropertyInfo, "Invalid navigation property info", new object[0]);
+                        foreach (object currentEntityInstance in entitySetList)
+                        {
+                            this.SetEntityReferenceToNullOnTargetResourceMatch(targetResource, navigationProperty, currentEntityInstance);
+                        }
+                    }
+                }
+            }
+        }
+
+        public virtual void DeleteResource(object targetResource)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
+            targetResource = UpdatableToken.AssertIsTokenAndResolve(targetResource, "targetResource");
+            string resourceSetName = this.GetResourceSetOfTargetResource(targetResource);
+            ExceptionUtilities.CheckObjectNotNull(resourceSetName, "Unable to find set of the resource to delete", new object[0]);
+            this.deletedObjects.Add(targetResource);
+            IList resourceSetList = this.GetResourceSetEntities(resourceSetName);
+            this.DeleteAllReferences(targetResource);
+            this.pendingChanges.Add(delegate {
+                resourceSetList.Remove(targetResource);
+            });
+        }
+
+        protected abstract void EnsureDataIsInitialized();
+
+        protected virtual Type GetCollectionPropertyType(string fullTypeName, string propertyName)
+        {
+            Type type = this.MetadataHelper.FindClrTypeByFullName(fullTypeName);
+            Type collectionType = null;
+            if (type != null)
+            {
+                PropertyInfo property = type.GetProperty(propertyName);
+                if (property != null)
+                {
+                    collectionType = property.PropertyType;
+                }
+            }
+            return collectionType;
+        }
+
+        private Dictionary<string, object> GetConcurrencyValues(object targetResource)
+        {
+            Dictionary<string, object> etagValues = new Dictionary<string, object>();
+            foreach (string etagProperty in this.MetadataHelper.GetETagPropertiesOfType(GetResourceTypeFullName(targetResource.GetType())))
+            {
+                etagValues.Add(etagProperty, targetResource.GetType().GetProperty(etagProperty).GetValue(targetResource, null));
+            }
+            return etagValues;
+        }
+
+        public virtual object GetResource(IQueryable query, string fullTypeName)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(query, "query");
+            object resource = null;
+            foreach (object r in query)
+            {
+                ExceptionUtilities.Assert(resource == null, "Invalid Uri specified. The query '{0}' must refer to a single resource", new object[] { query.ToString() });
+                resource = r;
+            }
+            if (resource == null)
+            {
+                return null;
+            }
+            if (fullTypeName != null)
+            {
+                this.ValidateResourceType(resource, fullTypeName);
+            }
+            return new UpdatableToken(resource);
+        }
+
+        public IList<T> GetResourceSetEntities<T>(string resourceSetName)
+        {
+            return (IList<T>) this.GetResourceSetEntities(resourceSetName);
+        }
+
+        internal IList GetResourceSetEntities(string resourceSetName)
+        {
+            IList entities;
+            if (!this.ResourceSetsStorage.TryGetValue(resourceSetName, out entities))
+            {
+                Type elementType = this.MetadataHelper.GetResourceTypeOfSet(resourceSetName);
+                entities = (IList) Activator.CreateInstance(typeof(List<>).MakeGenericType(new Type[] { elementType }));
+                this.ResourceSetsStorage[resourceSetName] = entities;
+            }
+            return entities;
+        }
+
+        private string GetResourceSetOfTargetResource(object targetResource)
+        {
+            foreach (string currentResourceSetName in this.MetadataHelper.GetResourceSetNames())
+            {
+                if (this.GetResourceSetEntities(currentResourceSetName).Contains(targetResource))
+                {
+                    return currentResourceSetName;
+                }
+            }
+            return null;
+        }
+
+        public static string GetResourceTypeFullName(Type type)
+        {
+            return type.FullName.Replace('+', '_');
+        }
+
+        public virtual object GetValue(object targetResource, string propertyName)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
+            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
+            UpdatableToken token = UpdatableToken.AssertIsToken(targetResource, "targetResource");
+            if (token.PendingPropertyUpdates.ContainsKey(propertyName))
+            {
+                return token.PendingPropertyUpdates[propertyName];
+            }
+            targetResource = token.Resource;
+            PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);
+            ExceptionUtilities.CheckObjectNotNull(pi, "Cannot find the property '{0}' on type '{1}'", new object[] { propertyName, targetResource.GetType().Name });
+            object value = pi.GetValue(targetResource, null);
+            if ((value != null) && (pi.PropertyType.Assembly == base.GetType().Assembly))
+            {
+                ExceptionUtilities.Assert(!this.MetadataHelper.IsTypeAnEntityType(pi.PropertyType), "GetValue should never be called for reference properties. Type was '{0}', property was '{1}'", new object[] { pi.PropertyType.FullName, propertyName });
+                value = new UpdatableToken(value);
+            }
+            return value;
+        }
+
+        private UpdatableToken InstantiateResourceType(string fullTypeName)
+        {
+            Type t = this.MetadataHelper.FindClrTypeByFullName(fullTypeName);
+            object instance = Activator.CreateInstance(t);
+            UpdatableToken token = new UpdatableToken(instance);
+            foreach (PropertyInfo p in t.GetProperties())
+            {
+                object generatedValue;
+                PropertyInfo property = p;
+                if (this.IsCollectionProperty(property))
+                {
+                    Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(t), property.Name);
+                    if (collectionType != null)
+                    {
+                        object newCollection = Activator.CreateInstance(collectionType);
+                        token.PendingPropertyUpdates[property.Name] = newCollection;
+                        this.pendingChanges.Add(delegate {
+                            property.SetValue(instance, newCollection, null);
+                        });
+                    }
+                }
+                if (this.TryGetStoreGeneratedValue(fullTypeName, property.Name, out generatedValue))
+                {
+                    token.PendingPropertyUpdates[property.Name] = generatedValue;
+                    this.pendingChanges.Add(delegate {
+                        property.SetValue(instance, generatedValue, null);
+                    });
+                }
+            }
+            return token;
+        }
+
+        protected virtual bool IsCollectionProperty(PropertyInfo propertyInfo)
+        {
+            return ((typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType) && (propertyInfo.PropertyType != typeof(string))) && (propertyInfo.PropertyType != typeof(byte[])));
+        }
+
+        public virtual void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
+            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
+            ExceptionUtilities.CheckArgumentNotNull(resourceToBeRemoved, "resourceToBeRemoved");
+            UpdatableToken.AssertIsToken(targetResource, "targetResource");
+            resourceToBeRemoved = UpdatableToken.AssertIsTokenAndResolve(resourceToBeRemoved, "resourceToBeRemoved");
+            IList list = this.GetValue(targetResource, propertyName) as IList;
+            ExceptionUtilities.CheckObjectNotNull(list, "Property '{0}' on type '{1}' was not a list", new object[] { propertyName, targetResource.GetType().Name });
+            this.pendingChanges.Add(delegate {
+                list.Remove(resourceToBeRemoved);
+            });
+        }
+
+        private void RemoveResourceFromCollectionOnTargetResourceMatch(object targetResource, NavigationPropertyInfo navigationPropertyInfo, object currentEntityInstance)
+        {
+            IEnumerable childCollectionObject = navigationPropertyInfo.PropertyInfo.GetValue(currentEntityInstance, null) as IEnumerable;
+            if (childCollectionObject.Cast<object>().Any<object>(delegate (object o) {
+                return o == targetResource;
+            }))
+            {
+                MethodInfo removeMethod = navigationPropertyInfo.PropertyInfo.PropertyType.GetMethod("Remove");
+                this.pendingChanges.Add(delegate {
+                    removeMethod.Invoke(childCollectionObject, new object[] { targetResource });
+                });
+            }
+        }
+
+        public virtual object ResetResource(object resource)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
+            UpdatableToken token = UpdatableToken.AssertIsToken(resource, "resource");
+            resource = token.Resource;
+            token = new UpdatableToken(resource);
+            object newInstance = Activator.CreateInstance(resource.GetType());
+            ExceptionUtilities.CheckObjectNotNull(newInstance, "Cannot reset resource because unable to creating new instance of type '{0}' returns null", new object[] { resource.GetType().Name });
+            foreach (string propertyToReset in this.MetadataHelper.GetPropertiesToReset(GetResourceTypeFullName(resource.GetType())))
+            {
+                PropertyInfo pi = newInstance.GetType().GetProperty(propertyToReset);
+                ExceptionUtilities.CheckObjectNotNull(pi, "Cannot reset resource because unable to find property '{0}'", new object[] { propertyToReset });
+                object newValue = pi.GetValue(newInstance, null);
+                this.pendingChanges.Add(delegate {
+                    pi.SetValue(resource, newValue, null);
+                });
+                token.PendingPropertyUpdates[propertyToReset] = newValue;
+            }
+            return token;
+        }
+
+        public virtual object ResolveResource(object resource)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
+            return UpdatableToken.AssertIsTokenAndResolve(resource, "resource");
+        }
+
+        public virtual void SaveChanges()
+        {
+            foreach (Action pendingChange in this.pendingChanges)
+            {
+                pendingChange();
+            }
+            this.pendingChanges.Clear();
+            foreach (object deleted in this.deletedObjects)
+            {
+                foreach (object entity in this.ResourceSetsStorage.SelectMany<KeyValuePair<string, IList>, object>(delegate (KeyValuePair<string, IList> p) {
+                    return p.Value.Cast<object>();
+                }))
+                {
+                    ExceptionUtilities.Assert(!object.ReferenceEquals(deleted, entity), "Found deleted entity!", new object[0]);
+                    foreach (PropertyInfo propertyInfo in entity.GetType().GetProperties())
+                    {
+                        object value = propertyInfo.GetValue(entity, null);
+                        ExceptionUtilities.Assert(!object.ReferenceEquals(deleted, value), "Found deleted entity!", new object[0]);
+                        IEnumerable enumerable = value as IEnumerable;
+                        if (enumerable != null)
+                        {
+                            foreach (object valueElement in enumerable.Cast<object>())
+                            {
+                                ExceptionUtilities.Assert(!object.ReferenceEquals(deleted, valueElement), "Found deleted entity!", new object[0]);
+                            }
+                        }
+                    }
+                }
+            }
+            this.deletedObjects.Clear();
+        }
+
+        protected virtual void SetCollectionPropertyValue(object targetResource, PropertyInfo propertyInfo, IEnumerable propertyValue)
+        {
+            object collection;
+            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
+            ExceptionUtilities.CheckArgumentNotNull(propertyInfo, "propertyInfo");
+            ExceptionUtilities.CheckArgumentNotNull(propertyValue, "propertyValue");
+            Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(propertyInfo.ReflectedType), propertyInfo.Name);
+            ExceptionUtilities.CheckObjectNotNull(collectionType, "Could not infer collection type for property", new object[0]);
+            propertyValue = propertyValue.Cast<object>().Select<object, object>(delegate (object o) {
+                return UpdatableToken.ResolveIfToken(o);
+            });
+            ConstructorInfo enumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable) });
+            if (enumerableConstructor != null)
+            {
+                collection = enumerableConstructor.Invoke(new object[] { propertyValue });
+            }
+            else if (collectionType.IsGenericType && (collectionType.GetGenericArguments().Count<Type>() == 1))
+            {
+                Type typeArgument = collectionType.GetGenericArguments().Single<Type>();
+                ConstructorInfo typedEnumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable<>).MakeGenericType(new Type[] { typeArgument }) });
+                if (typedEnumerableConstructor != null)
+                {
+                    object typedEnumerable = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(new Type[] { typeArgument }).Invoke(null, new object[] { propertyValue });
+                    collection = typedEnumerableConstructor.Invoke(new object[] { typedEnumerable });
+                }
+                else
+                {
+                    MethodInfo typedAddMethod = collectionType.GetMethod("Add", new Type[] { typeArgument });
+                    ExceptionUtilities.CheckObjectNotNull(typedAddMethod, "Could not find constructor or add method for type: " + collectionType.FullName, new object[0]);
+                    collection = Activator.CreateInstance(collectionType);
+                    foreach (object element in propertyValue)
+                    {
+                        typedAddMethod.Invoke(collection, new object[] { element });
+                    }
+                }
+            }
+            else
+            {
+                MethodInfo addMethod = collectionType.GetMethod("Add");
+                ExceptionUtilities.CheckObjectNotNull(addMethod, "Could not find constructor or add method for type: " + collectionType.FullName, new object[0]);
+                collection = Activator.CreateInstance(collectionType);
+                foreach (object element in propertyValue)
+                {
+                    addMethod.Invoke(collection, new object[] { element });
+                }
+            }
+            propertyInfo.SetValue(targetResource, collection, null);
+        }
+
+        public virtual void SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(resourceCookie, "resourceCookie");
+            ExceptionUtilities.ThrowDataServiceExceptionIfFalse(checkForEquality.HasValue, 0x1a1, "Missing concurrency token for update operation", new object[0]);
+            ExceptionUtilities.Assert(checkForEquality.Value, "Should not be called with check for equality parameter equal to false", new object[0]);
+            ExceptionUtilities.CheckArgumentNotNull(concurrencyValues, "concurrencyValues");
+            if (concurrencyValues.Any<KeyValuePair<string, object>>())
+            {
+                resourceCookie = UpdatableToken.AssertIsTokenAndResolve(resourceCookie, "resourceCookie");
+                ExceptionUtilities.ThrowDataServiceExceptionIfFalse(CompareETagValues(this.GetConcurrencyValues(resourceCookie), concurrencyValues), 0x19c, "Concurrency tokens do not match", new object[0]);
+            }
+        }
+
+        private void SetEntityReferenceToNullOnTargetResourceMatch(object targetResource, NavigationPropertyInfo navigationPropertyInfo, object currentEntityInstance)
+        {
+            if (navigationPropertyInfo.PropertyInfo.GetValue(currentEntityInstance, null) == targetResource)
+            {
+                this.pendingChanges.Add(delegate {
+                    navigationPropertyInfo.PropertyInfo.SetValue(currentEntityInstance, null, null);
+                });
+            }
+        }
+
+        public virtual void SetReference(object targetResource, string propertyName, object propertyValue)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
+            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
+            if (propertyValue != null)
+            {
+                UpdatableToken.AssertIsToken(propertyValue, "propertyValue");
+            }
+            this.SetValue(targetResource, propertyName, propertyValue);
+        }
+
+        public virtual void SetValue(object targetResource, string propertyName, object propertyValue)
+        {
+            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
+            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
+            UpdatableToken token = UpdatableToken.AssertIsToken(targetResource, "targetResource");
+            targetResource = token.Resource;
+            token.PendingPropertyUpdates[propertyName] = propertyValue;
+            this.pendingChanges.Add(delegate {
+                object generatedValue;
+                Type t = targetResource.GetType();
+                PropertyInfo pi = t.GetProperty(propertyName);
+                ExceptionUtilities.CheckObjectNotNull(pi, "Unable to find property '{0}' on type '{1}'", new object[] { propertyName, targetResource.GetType().Name });
+                if (this.TryGetStoreGeneratedValue(GetResourceTypeFullName(t), propertyName, out generatedValue))
+                {
+                    propertyValue = generatedValue;
+                }
+                if (this.IsCollectionProperty(pi))
+                {
+                    ExceptionUtilities.CheckObjectNotNull(propertyValue, "Collection property value was null", new object[0]);
+                    IEnumerable enumerable = propertyValue as IEnumerable;
+                    ExceptionUtilities.CheckObjectNotNull(enumerable, "Collection property value was not an enumerable", new object[0]);
+                    this.SetCollectionPropertyValue(targetResource, pi, enumerable);
+                }
+                else
+                {
+                    propertyValue = UpdatableToken.ResolveIfToken(propertyValue);
+                    pi.SetValue(targetResource, propertyValue, null);
+                }
+            });
+        }
+
+        protected virtual bool TryGetStoreGeneratedValue(string fullTypeName, string propertyName, out object propertyValue)
+        {
+            propertyValue = null;
+            return false;
+        }
+
+        private void ValidateResourceType(object targetResource, string fullTypeName)
+        {
+            ExceptionUtilities.Assert(this.MetadataHelper.FindClrTypeByFullName(fullTypeName).IsAssignableFrom(targetResource.GetType()), "Invalid uri specified. expected type: '{0}', actual type: '{1}'", new object[] { fullTypeName, targetResource.GetType().FullName });
+        }
+
+        // Properties
+        internal ReflectionMetadataHelper MetadataHelper { get; set; }
+
+        internal Dictionary<string, IList> ResourceSetsStorage
+        {
+            get
+            {
+                Dictionary<string, IList> resourceSetsLookup = null;
+                Type currentContextType = base.GetType();
+                ExceptionUtilities.Assert(resourceSetsByContextTypeStorage.TryGetValue(currentContextType, out resourceSetsLookup), "Cannot find resource sets by the context type '{0}'", new object[] { currentContextType });
+                return resourceSetsLookup;
+            }
+        }
+
+        #region Inner types.
+    
+        internal class ReflectionMetadataHelper
+        {
+            // Fields
+            private ReflectionDataContext reflectionDataContext;
+
+            // Methods
+            public ReflectionMetadataHelper(ReflectionDataContext reflectionDataContext)
+            {
+                this.reflectionDataContext = reflectionDataContext;
+            }
+
+            public Type FindClrTypeByFullName(string resourceTypeFullName)
+            {
+                Type type = this.reflectionDataContext.GetType().Assembly.GetTypes().Where<Type>(delegate (Type t) {
+                    return (ReflectionDataContext.GetResourceTypeFullName(t) == resourceTypeFullName);
+                }).FirstOrDefault<Type>();
+                ExceptionUtilities.CheckObjectNotNull(type, "Unable to find type '{0}'", new object[] { resourceTypeFullName });
+                return type;
+            }
+
+            public string[] GetETagPropertiesOfType(string fullTypeName)
+            {
+                Type type = this.FindClrTypeByFullName(fullTypeName);
+                List<string> etags = new List<string>();
+                foreach (ETagAttribute customAttribute in type.GetCustomAttributes(typeof(ETagAttribute), true))
+                {
+                    etags.AddRange(customAttribute.PropertyNames);
+                }
+                
+                return etags.ToArray();
+            }
+
+            public string[] GetKeyProperties(string fullTypeName)
+            {
+                Type type = this.FindClrTypeByFullName(fullTypeName);
+                List<string> keyPropertyList = new List<string>();
+                foreach (PropertyInfo keyProperty in type.GetProperties().Where(pi => pi.Name.Contains("ID")))
+                {
+                    keyPropertyList.Add(keyProperty.Name);
+                }
+
+                foreach (DataServiceKeyAttribute customAttribute in type.GetCustomAttributes(typeof(DataServiceKeyAttribute), true))
+                {
+                    keyPropertyList.AddRange(customAttribute.KeyNames);
+                }
+                
+                return keyPropertyList.ToArray();
+            }
+
+            public NavigationPropertyInfo[] GetNavigationProperties(string fullTypeName)
+            {
+                Type type = this.FindClrTypeByFullName(fullTypeName);
+                var navigationProperties = new List<NavigationPropertyInfo>();
+                var keyProperties = new List<string>(this.GetKeyProperties(fullTypeName));
+                foreach (PropertyInfo pi in type.GetProperties())
+                {
+                    if (!keyProperties.Contains(pi.Name))
+                    {
+                        if (this.IsTypeAnEntityType(pi.PropertyType))
+                        {
+                            navigationProperties.Add(new NavigationPropertyInfo(pi, null));
+                        }
+
+                        if (pi.PropertyType.IsGenericType && ((pi.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) || (pi.PropertyType.GetGenericTypeDefinition() == typeof(Collection<>))))
+                        {
+                            Type elementType = pi.PropertyType.GetGenericArguments()[0];
+                            if (this.IsTypeAnEntityType(elementType))
+                            {
+                                navigationProperties.Add(new NavigationPropertyInfo(pi, elementType));
+                            }
+                        }
+                    }
+                }
+
+                return navigationProperties.ToArray();
+            }
+
+            public string[] GetPropertiesToReset(string fullTypeName)
+            {
+                Type type = this.FindClrTypeByFullName(fullTypeName);
+                var keyProperties = new List<string>(this.GetKeyProperties(fullTypeName));
+                var navigationProperties = new List<string>(this.GetNavigationProperties(fullTypeName).Select(ni =>ni.PropertyInfo.Name));
+                return type.GetProperties().Where(
+                    pi => !keyProperties.Contains(pi.Name) && !navigationProperties.Contains(pi.Name)
+                ).Select(pi => pi.Name).ToArray();
+            }
+
+            public string[] GetResourceSetNames()
+            {
+                return this.reflectionDataContext.GetType().GetProperties().Where(
+                    pi => pi.PropertyType.IsGenericType && (pi.PropertyType.GetGenericTypeDefinition() == typeof(IQueryable<>))
+                ).Select(pi => pi.Name).ToArray();
+            }
+
+            public Type GetResourceTypeOfSet(string resourceSetName)
+            {
+                PropertyInfo resourceSetPropertyInfo = this.reflectionDataContext.GetType().GetProperties().Where(pi => pi.Name == resourceSetName).FirstOrDefault();
+                ExceptionUtilities.CheckObjectNotNull(resourceSetPropertyInfo, "Error finding type of set '{0}'", new object[] { resourceSetName });
+                return resourceSetPropertyInfo.PropertyType.GetGenericArguments()[0];
+            }
+
+            public bool IsTypeAnEntityType(Type t)
+            {
+                foreach (string setName in this.GetResourceSetNames())
+                {
+                    if (this.GetResourceTypeOfSet(setName).IsAssignableFrom(t))
+                    {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+        }
+
+        internal static class ExceptionUtilities
+        {
+            // Methods
+            public static void Assert(bool condition, string errorMessage, params object[] messageArguments)
+            {
+                if (!condition)
+                {
+                    throw new InvalidOperationException("Assertion failed: " + string.Format(CultureInfo.InvariantCulture, errorMessage, messageArguments));
+                }
+            }
+
+            public static void CheckArgumentNotNull(object argument, string argumentName)
+            {
+                if (argument == null)
+                {
+                    throw new ArgumentNullException(argumentName);
+                }
+            }
+
+            public static void CheckCollectionNotEmpty<TElement>(IEnumerable<TElement> argument, string argumentName)
+            {
+                CheckArgumentNotNull(argument, argumentName);
+                if (!argument.Any<TElement>())
+                {
+                    throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Collection argument '{0}' must have at least one element.", new object[] { argumentName }));
+                }
+            }
+
+            public static void CheckObjectNotNull(object value, string exceptionMessageFormatText, params object[] messageArguments)
+            {
+                Assert(exceptionMessageFormatText != null, "message cannnot be null", new object[0]);
+                Assert(messageArguments != null, "messageArguments cannnot be null", new object[0]);
+                if (value == null)
+                {
+                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, exceptionMessageFormatText, messageArguments));
+                }
+            }
+
+            public static void ThrowDataServiceExceptionIfFalse(bool condition, int statusCode, string errorMessage, params object[] messageArguments)
+            {
+                if (!condition)
+                {
+                    throw new DataServiceException(statusCode, string.Format(CultureInfo.InvariantCulture, errorMessage, messageArguments));
+                }
+            }
+        }
+
+        public class UpdatableToken
+        {
+            // Methods
+            public UpdatableToken(object resource)
+            {
+                ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
+                this.Resource = resource;
+                this.PendingPropertyUpdates = new Dictionary<string, object>();
+            }
+
+            public static UpdatableToken AssertIsToken(object resource, string name)
+            {
+                ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
+                UpdatableToken token = resource as UpdatableToken;
+                ExceptionUtilities.CheckObjectNotNull(token, "{0} was not a token. Type was: '{1}'", new object[] { name, resource.GetType() });
+                return token;
+            }
+
+            public static object AssertIsTokenAndResolve(object resource, string name)
+            {
+                return AssertIsToken(resource, name).Resource;
+            }
+
+            public static object ResolveIfToken(object resource)
+            {
+                UpdatableToken token = resource as UpdatableToken;
+                if (token != null)
+                {
+                    resource = token.Resource;
+                }
+                return resource;
+            }
+
+            // Properties
+            public IDictionary<string, object> PendingPropertyUpdates { get; set; }
+
+            public object Resource { get; set; }
+        }
+
+        internal class NavigationPropertyInfo
+        {
+            // Methods
+            internal NavigationPropertyInfo(PropertyInfo pi, Type collectionElementType)
+            {
+                this.PropertyInfo = pi;
+                this.CollectionElementType = collectionElementType;
+            }
+
+            // Properties
+            public Type CollectionElementType { get; set; }
+
+            public PropertyInfo PropertyInfo { get; set; }
+        }
+
+        #endregion Inner types.
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/tests/code/atomreader.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/atomreader.cs b/JSLib/tests/code/atomreader.cs
new file mode 100644
index 0000000..6391d87
--- /dev/null
+++ b/JSLib/tests/code/atomreader.cs
@@ -0,0 +1,796 @@
+/// <summary>
+/// Class used to parse the Content section of the feed to return the properties data and metadata
+/// </summary>
+
+namespace DataJS.Tests
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Linq;
+    using System.ServiceModel.Syndication;
+    using System.Spatial;
+    using System.Xml;
+    using System.Xml.Linq;
+
+    public static class AtomReader
+    {
+        const string atomXmlNs = "http://www.w3.org/2005/Atom";
+        const string gmlXmlNs = "http://www.opengis.net/gml";
+        const string odataRelatedPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/related";
+        const string odataRelatedLinksPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks";
+        const string odataXmlNs = "http://schemas.microsoft.com/ado/2007/08/dataservices";
+        const string odataMetaXmlNs = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
+        const string odataEditMediaPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/edit-media";
+        const string odataMediaResourcePrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/mediaresource";
+
+        const string hrefAttribute = "href";
+        const string titleElement = "title";
+        const string workspaceElement = "workspace";
+        const string workspacesProperty = "workspaces";
+        const string collectionElement = "collection";
+        const string collectionsProperty = "collections";
+        const string extensionsProperty = "extensions";
+        static string baseUri = string.Empty;
+
+        /// <summary>
+        /// Creates a service document object
+        /// </summary>
+        /// <param name="container">The XML container</param>
+        /// <param name="uri">Uri to append to the href value</param>
+        /// <returns>The service document JsonObject</returns>
+        public static JsonObject ReadServiceDocument(TextReader payload, string baseUri)
+        {
+            JsonObject jsonObject = new JsonObject();
+            XElement container = XElement.Load(payload);
+
+            if (container != null && container.HasElements)
+            {
+                jsonObject["workspaces"] =
+                    container
+                        .Elements()
+                            .Where(element => element.Name.LocalName.Equals(workspaceElement))
+                            .Select(element => ReadWorkspaceObject(element, baseUri))
+                            .ToArray();
+
+                jsonObject["extensions"] =
+                    container
+                        .Elements()
+                            .Where(element => !element.Name.LocalName.Equals(workspaceElement))
+                            .Select(element => ReadExtensionElement(element))
+                            .ToArray();
+            }
+
+            return jsonObject;
+        }
+
+        public static JsonObject ReadEntry(TextReader payload)
+        {
+            SyndicationItem item = SyndicationItem.Load(XmlReader.Create(payload));
+            return ReadEntry(item);
+        }
+
+        public static JsonObject ReadFeed(TextReader payload)
+        {
+            SyndicationFeed feed = SyndicationFeed.Load(XmlReader.Create(payload));
+            JsonObject feedData = new JsonObject();
+            JsonObject feedMetadata = new JsonObject();
+
+            feedData["results"] = feed.Items.Select(item => ReadEntry(item)).ToArray();
+            feedData["__metadata"] = feedMetadata;
+
+            feedMetadata["feed_extensions"] = feed.AttributeExtensions.Select(pair => ReadExtension(pair)).ToArray();
+
+            if (feed.Id != null)
+            {
+                feedMetadata["uri"] = feed.Id;
+                feedMetadata["uri_extensions"] = new JsonObject[] { };
+            }
+
+            if (feed.Title != null)
+            {
+                feedMetadata["title"] = feed.Title.Text;
+                feedMetadata["title_extensions"] = GetTitleExtensions(feed.Title);
+            }
+
+            SyndicationLink feedSelfLink = GetLink("self", feed.Links);
+            if (feedSelfLink != null)
+            {
+                feedMetadata["self"] = feedSelfLink.GetAbsoluteUri().AbsoluteUri;
+                feedMetadata["self_extensions"] = GetLinkExtensions(feedSelfLink);
+            }
+
+            long? count = GetInlineCount(feed);
+            if (count.HasValue)
+            {
+                feedData["__count"] = count.Value;
+            }
+
+            SyndicationLink feedNextLink = GetLink("next", feed.Links);
+            if (feedNextLink != null)
+            {
+                feedData["__next"] = feedNextLink.GetAbsoluteUri().AbsoluteUri;
+                feedMetadata["next_extensions"] = GetLinkExtensions(feedNextLink);
+            }
+
+            return feedData;
+        }
+
+        private static JsonObject ReadEntry(SyndicationItem item)
+        {
+            SyndicationLink entryEditLink = GetLink("edit", item.Links);
+            SyndicationCategory entryCategory = item.Categories.FirstOrDefault();
+
+            XElement propertiesElement = GetPropertiesElement(item);
+            JsonObject entryData = ReadObject(propertiesElement);
+            entryData = JsonObject.Merge(entryData, ReadNavigationProperties(item));
+            entryData = JsonObject.Merge(entryData, ReadNamedStreams(item));
+
+            JsonObject propertiesMetadata = ReadPropertiesMetadata(propertiesElement);
+            propertiesMetadata = JsonObject.Merge(propertiesMetadata, ReadNavigationPropertiesMetadata(item));
+            propertiesMetadata = JsonObject.Merge(propertiesMetadata, ReadNamedStreamMetadata(item));
+
+            JsonObject entryMetadata = new JsonObject();
+            entryData["__metadata"] = entryMetadata;
+            entryMetadata["properties"] = propertiesMetadata;
+
+            if (item.Id != null)
+            {
+                entryMetadata["uri"] = item.Id;
+                entryMetadata["uri_extensions"] = new JsonObject[] { };
+            }
+
+            if (entryCategory != null)
+            {
+                entryMetadata["type"] = entryCategory.Name;
+                entryMetadata["type_extensions"] = new JsonObject[] { };
+            }
+
+            if (entryEditLink != null)
+            {
+                entryMetadata["edit"] = entryEditLink.GetAbsoluteUri().AbsoluteUri;
+                entryMetadata["edit_link_extensions"] = GetLinkExtensions(entryEditLink);
+            }
+
+            return entryData;
+        }
+
+        private static JsonObject ReadExtension(KeyValuePair<XmlQualifiedName, string> pair)
+        {
+            return ReaderUtils.CreateExtension(pair.Key.Name, pair.Key.Namespace, pair.Value);
+        }
+
+        private static string GetCollectionType(string type)
+        {
+            if (type != null && type.StartsWith("Collection("))
+            {
+                int start = 11;
+                int end = type.IndexOf(")") - 11;
+                return type.Substring(start, end);
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Find the m:properties element within a feed entry
+        /// </summary>
+        /// <param name="item">The feed entry</param>
+        /// <returns>The m:properties element</returns>
+        private static XElement GetPropertiesElement(SyndicationItem item)
+        {
+            // Check if the m:properties element is within the content element
+            XmlSyndicationContent xmlContent = item.Content as XmlSyndicationContent;
+            if (xmlContent != null)
+            {
+                XElement contentElement = XElement.Load(xmlContent.GetReaderAtContent());
+                return contentElement.Elements().FirstOrDefault(e => e.Name == XName.Get("properties", odataMetaXmlNs));
+            }
+            // If we're here, then we are dealing with a feed that has an MLE
+            // i.e. the m:properties element is a peer of the content element, and shows up
+            // in the elementExtensions instead
+            SyndicationElementExtension propertiesElementExtension = item.ElementExtensions.FirstOrDefault(e => e.OuterName.Equals("properties"));
+            if (propertiesElementExtension != null)
+            {
+                XNode propertiesElement = XNode.ReadFrom(propertiesElementExtension.GetReader());
+                return (XElement)propertiesElement;
+            }
+
+            throw new NotSupportedException("Unsupported feed entry format");
+        }
+
+        /// <summary>
+        /// Gets the inline count within a feed
+        /// </summary>
+        /// <param name="feed">The feed</param>
+        /// <returns>The inline count, or null if none exists</returns>
+        private static long? GetInlineCount(SyndicationFeed feed)
+        {
+            SyndicationElementExtension countElementExtension = feed.ElementExtensions.SingleOrDefault(extension =>
+                extension.OuterName.Equals("count", StringComparison.OrdinalIgnoreCase) &&
+                extension.OuterNamespace.Equals(odataMetaXmlNs));
+
+            if (countElementExtension != null)
+            {
+                XElement countElement = (XElement)XNode.ReadFrom(countElementExtension.GetReader());
+                return XmlConvert.ToInt64(countElement.Value);
+            }
+            else
+            {
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Gets the link with the specified relationship type
+        /// </summary>
+        /// <param name="rel">Relationship type</param>
+        /// <param name="links">The set of links to search from</param>
+        /// <returns>The link with the specified relationship type, or null if none exists</returns>
+        private static SyndicationLink GetLink(string rel, IEnumerable<SyndicationLink> links)
+        {
+            return links.SingleOrDefault(link => link.RelationshipType.Equals(rel, StringComparison.InvariantCultureIgnoreCase));
+        }
+
+        private static IEnumerable<SyndicationLink> GetLinks(string rel, IEnumerable<SyndicationLink> links)
+        {
+            return links.Where(link => link.RelationshipType.StartsWith(rel, StringComparison.Ordinal));
+        }
+
+        //TODO refactor the extraction of extensions into extension elements and extension attribute methods.
+        private static JsonObject[] GetLinkExtensions(SyndicationLink link)
+        {
+            List<JsonObject> extensions = new List<JsonObject>();
+            //TODO: fix the inclusion of title as extension.  Title attribute is not required in the link element and its
+            //inclusion as an extension should be tested for the precesence of the attribute in the xml element.  Unfortunately,
+            //SyndicationLink doesn't allow for accessing the underlying XML document.. perhaps using an AtomFormatter10?? 
+            extensions.Add(ReaderUtils.CreateExtension("title", null, link.Title));
+            extensions.AddRange(link.AttributeExtensions.Select(pair => ReadExtension(pair)));
+
+            return extensions.ToArray();
+        }
+
+        private static JsonObject[] GetTitleExtensions(TextSyndicationContent title)
+        {
+            List<JsonObject> extensions = new List<JsonObject>();
+            extensions.Add(ReaderUtils.CreateExtension("type", null, title.Type));
+            extensions.AddRange(title.AttributeExtensions.Select(pair => ReadExtension(pair)));
+
+            return extensions.ToArray();
+        }
+
+        /// <summary>
+        /// Gets the "type" value from a property element
+        /// </summary>
+        /// <param name="propertyElement">The property element</param>
+        /// <returns>The "type" value, or default (Edm.String) if none specified</returns>
+        private static string GetTypeAttribute(XElement propertyElement)
+        {
+            XAttribute typeAttribute = propertyElement.Attribute(XName.Get("type", odataMetaXmlNs));
+            if (typeAttribute == null)
+            {
+                if (propertyElement.HasElements)
+                {
+                    return null;
+                }
+                return "Edm.String";
+            }
+            return typeAttribute.Value;
+        }
+
+        private static bool HasTypeAttribute(XElement propertyElement)
+        {
+            return propertyElement.Attribute(XName.Get("type", odataMetaXmlNs)) != null;
+        }
+
+        private static bool IsCollectionProperty(XElement propertyElement)
+        {
+            string type = GetTypeAttribute(propertyElement);
+            if (type != null && type.StartsWith("Collection("))
+            {
+                return true;
+
+            }
+            return propertyElement.Elements().Count(pe => pe.Name == XName.Get("element", odataXmlNs)) > 1;
+        }
+
+        private static JsonObject ReadWorkspaceObject(XElement container, string baseUri)
+        {
+            JsonObject jsonObject = new JsonObject();
+
+            jsonObject["collections"] =
+                container
+                    .Elements()
+                        .Where(element => element.Name.LocalName.Equals("collection"))
+                        .Select(element => ReadWorkspaceCollections(element, baseUri))
+                        .ToArray();
+
+            jsonObject["extensions"] =
+                container
+                    .Elements()
+                        .Where(element =>
+                            !(element.Name.LocalName.Equals("collection") ||
+                              element.Name.LocalName.Equals("title")))
+                        .Select(element => ReadExtensionElement(element))
+                        .ToArray();
+
+            jsonObject["title"] =
+                container
+                    .Elements()
+                    .Where(element => element.Name.LocalName.Equals("title"))
+                    .First()
+                    .Value;
+
+            return jsonObject;
+        }
+
+        private static JsonObject ReadWorkspaceCollections(XElement container, string baseUri)
+        {
+            JsonObject jsonObject = new JsonObject();
+            string title = string.Empty;
+
+            jsonObject["extensions"] =
+                container
+                    .Elements()
+                        .Where(element =>
+                            !(element.Name.LocalName.Equals(collectionElement) ||
+                              element.Name.LocalName.Equals(titleElement)))
+                        .Select(element => ReadExtensionElement(element))
+                        .ToArray();
+
+            jsonObject["title"] =
+                container
+                    .Elements()
+                        .Where(element => element.Name.LocalName.Equals("title"))
+                        .First()
+                        .Value;
+
+            IEnumerable<XAttribute> hrefAttributes =
+                container
+                    .Attributes()
+                        .Where(element => element.Name.LocalName.Equals("href"));
+
+            jsonObject["href"] = baseUri + hrefAttributes.First().Value;
+
+            return jsonObject;
+        }
+
+        private static JsonObject ReadExtensionElement(XElement element)
+        {
+            JsonObject jsonObject = ReaderUtils.CreateExtension(element.Name.LocalName, element.BaseUri, null);
+            jsonObject.Remove("value");
+            jsonObject["attributes"] = ReadExtensionAttributes(element);
+            jsonObject["children"] = element.Elements().Select(child => ReadExtensionElement(element)).ToArray();
+
+            return jsonObject;
+        }
+
+        private static JsonObject ReadExtensionAttribute(XAttribute attribute)
+        {
+            return ReaderUtils.CreateExtension(attribute.Name.LocalName, attribute.BaseUri, attribute.Value);
+        }
+
+        private static JsonObject[] ReadExtensionAttributes(XElement container)
+        {
+            List<JsonObject> attributes = new List<JsonObject>();
+            foreach (XAttribute attribute in container.Attributes())
+            {
+                attributes.Add(ReadExtensionAttribute(attribute));
+            }
+            return attributes.ToArray();
+        }
+
+        private static JsonObject ReadNamedStreamMetadata(SyndicationItem item)
+        {
+            JsonObject propertiesMetadata = new JsonObject();
+            JsonObject streamMetadata;
+            string propertyName;
+
+            foreach (SyndicationLink link in GetLinks(odataEditMediaPrefix, item.Links))
+            {
+                streamMetadata = new JsonObject();
+                streamMetadata["edit_media_extensions"] = GetLinkExtensions(link);
+                streamMetadata["media_src_extensions"] = new JsonObject[0];
+
+                propertyName = link.RelationshipType.Substring(odataEditMediaPrefix.Length + 1);
+                propertiesMetadata[propertyName] = streamMetadata;
+            }
+
+            foreach (SyndicationLink link in GetLinks(odataMediaResourcePrefix, item.Links))
+            {
+                streamMetadata = new JsonObject();
+                streamMetadata["media_src_extensions"] = GetLinkExtensions(link);
+
+                propertyName = link.RelationshipType.Substring(odataMediaResourcePrefix.Length + 1);
+                if (propertiesMetadata.ContainsKey(propertyName))
+                {
+                    streamMetadata = JsonObject.Merge((JsonObject)propertiesMetadata[propertyName], streamMetadata);
+                }
+                propertiesMetadata[propertyName] = streamMetadata;
+            }
+            return propertiesMetadata;
+        }
+
+        private static JsonObject ReadNamedStreams(SyndicationItem item)
+        {
+            // Not very elegant, but quick and easy, do it in two passes.
+            JsonObject streams = new JsonObject();
+            JsonObject streamValue;
+            JsonObject mediaResource;
+            string propertyName;
+
+            foreach (SyndicationLink link in GetLinks(odataEditMediaPrefix, item.Links))
+            {
+                propertyName = link.RelationshipType.Substring(odataEditMediaPrefix.Length + 1);
+                streamValue = new JsonObject();
+                mediaResource = new JsonObject();
+
+                streams[propertyName] = streamValue;
+
+                streamValue["__mediaresource"] = mediaResource;
+
+                mediaResource["edit_media"] = link.GetAbsoluteUri().AbsoluteUri;
+                mediaResource["content_type"] = link.MediaType;
+                mediaResource["media_src"] = link.GetAbsoluteUri().AbsoluteUri;
+
+                var etagAttributeName = new XmlQualifiedName("etag", odataMetaXmlNs);
+                if (link.AttributeExtensions.ContainsKey(etagAttributeName))
+                {
+                    mediaResource["media_etag"] = link.AttributeExtensions[etagAttributeName];
+                    link.AttributeExtensions.Remove(etagAttributeName);
+                }
+            }
+
+            foreach (SyndicationLink link in GetLinks(odataMediaResourcePrefix, item.Links))
+            {
+                propertyName = link.RelationshipType.Substring(odataMediaResourcePrefix.Length + 1);
+                mediaResource = new JsonObject();
+                mediaResource["content_type"] = link.MediaType;
+                mediaResource["media_src"] = link.GetAbsoluteUri().AbsoluteUri;
+
+                if (streams.ContainsKey(propertyName))
+                {
+                    streamValue = streams[propertyName] as JsonObject;
+                    mediaResource = JsonObject.Merge(streamValue["__mediaresource"] as JsonObject, mediaResource);
+                }
+                else
+                {
+                    streamValue = new JsonObject();
+                }
+                streamValue["__mediaresource"] = mediaResource;
+                streams[propertyName] = streamValue;
+            }
+            return streams;
+        }
+
+        private static JsonObject ReadNavigationProperties(SyndicationItem item)
+        {
+            JsonObject navProperties = new JsonObject();
+            SyndicationElementExtension inline;
+
+            string propertyName;
+            JsonObject propertyValue = null;
+
+            foreach (SyndicationLink link in GetLinks(odataRelatedPrefix, item.Links))
+            {
+                propertyName = link.RelationshipType.Substring(odataRelatedPrefix.Length + 1);
+                inline = link.ElementExtensions.SingleOrDefault(e =>
+                    odataMetaXmlNs.Equals(e.OuterNamespace, StringComparison.Ordinal) &&
+                    e.OuterName.Equals("inline", StringComparison.Ordinal));
+
+                if (inline != null)
+                {
+                    XElement inlineElement = (XElement)XNode.ReadFrom(inline.GetReader());
+                    XElement innerElement = inlineElement.Elements().FirstOrDefault();
+
+                    if (innerElement != null)
+                    {
+                        // By default the inner feed/entry does not have the xml:base attribute, so we need to
+                        // add it so that the parsed SyndicationFeed or SyndicationItem retains the baseUri
+                        if (link.BaseUri != null)
+                        {
+                            innerElement.SetAttributeValue(XNamespace.Xml + "base", link.BaseUri.OriginalString);
+                        }
+
+                        // We are converting to a string before creating the reader to strip out extra indenting,
+                        // otherwise the reader creates extra XmlText nodes that SyndicationFeed/SyndicationItem cannot handle
+                        try
+                        {
+                            propertyValue = ReadFeed(new StringReader(innerElement.ToString()));
+                        }
+                        catch (XmlException)
+                        {
+                            // Try with entry instead .. 
+
+                            propertyValue = ReadEntry(new StringReader(innerElement.ToString()));
+                        }
+                    }
+                }
+                else
+                {
+                    JsonObject deferred = new JsonObject();
+                    deferred["uri"] = link.GetAbsoluteUri().AbsoluteUri;
+
+                    propertyValue = new JsonObject();
+                    propertyValue["__deferred"] = deferred;
+                }
+                navProperties[propertyName] = propertyValue;
+            }
+            return navProperties;
+        }
+
+        private static JsonObject ReadNavigationPropertiesMetadata(SyndicationItem item)
+        {
+            JsonObject propertiesMetadata = new JsonObject();
+            JsonObject navMetadata;
+            string propertyName;
+
+            foreach (SyndicationLink link in GetLinks(odataRelatedPrefix, item.Links))
+            {
+                navMetadata = new JsonObject();
+                navMetadata["extensions"] = GetLinkExtensions(link).Where(e =>
+                    !(string.Equals(e["name"] as string, "inline", StringComparison.Ordinal) &&
+                        string.Equals(e["namespaceURI"] as string, odataMetaXmlNs, StringComparison.Ordinal))
+                ).ToArray();
+
+                propertyName = link.RelationshipType.Substring(odataRelatedPrefix.Length + 1);
+                propertiesMetadata[propertyName] = navMetadata;
+            }
+
+            foreach (SyndicationLink link in GetLinks(odataRelatedLinksPrefix, item.Links))
+            {
+                navMetadata = new JsonObject();
+                navMetadata["associationuri"] = link.GetAbsoluteUri().AbsoluteUri;
+                navMetadata["associationuri_extensions"] = link.GetAbsoluteUri().AbsoluteUri;
+
+                propertyName = link.RelationshipType.Substring(odataRelatedLinksPrefix.Length + 1);
+                if (propertiesMetadata.ContainsKey(propertyName))
+                {
+                    navMetadata = JsonObject.Merge(propertiesMetadata[propertyName] as JsonObject, navMetadata);
+                }
+                propertiesMetadata[propertyName] = navMetadata;
+            }
+
+            return propertiesMetadata;
+        }
+
+        private static JsonObject ReadPropertiesMetadata(XElement container)
+        {
+            JsonObject json = null;
+            if (container != null && container.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
+            {
+                json = new JsonObject();
+                foreach (XElement propertyElement in container.Elements())
+                {
+                    json[propertyElement.Name.LocalName] = ReadPropertyMetadata(propertyElement);
+                }
+            }
+            return json;
+        }
+
+        private static JsonObject ReadPropertyMetadata(XElement property)
+        {
+            var metadata = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(property));
+
+            if (IsCollectionProperty(property))
+            {
+                string collectionType = GetCollectionType(GetTypeAttribute(property));
+                if (collectionType == null)
+                {
+                    metadata["type"] = "Collection()";
+                }
+
+                List<JsonObject> elements = new List<JsonObject>();
+                foreach (XElement item in property.Elements(XName.Get("element", odataXmlNs)))
+                {
+                    string itemType =
+                        HasTypeAttribute(item) ? GetTypeAttribute(item) :
+                        IsCollectionProperty(item) ? "Collection()" : collectionType;
+
+                    var itemMetadata = ReaderUtils.CreateEntryPropertyMetadata(itemType);
+                    if (item.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
+                    {
+                        itemMetadata["properties"] = ReadPropertiesMetadata(item);
+                    }
+                    elements.Add(itemMetadata);
+                }
+                metadata["elements"] = elements.ToArray();
+            }
+            else if (property != null && property.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
+            {
+                metadata["properties"] = ReadPropertiesMetadata(property);
+            }
+
+            return metadata;
+        }
+
+        /// <summary>
+        /// Creates a JsonObject from an XML container element (e.g. the m:properties element) of an OData ATOM feed entry. 
+        /// </summary>
+        /// <param name="container">The XML container</param>
+        /// <param name="buildValue">Function that builds a value from a property element</param>
+        /// <returns>The JsonObject containing the name-value pairs</returns>
+        private static JsonObject ReadObject(XElement container)
+        {
+            if (container == null)
+            {
+                return null;
+            }
+
+            var json = new JsonObject();
+            foreach (XElement propertyElement in container.Elements())
+            {
+                json[propertyElement.Name.LocalName] = ReadDataItem(propertyElement);
+            }
+            return json;
+        }
+
+        private static JsonObject ReadCollectionProperty(XElement property, string typeName)
+        {
+            var collectionType = GetCollectionType(typeName);
+
+            var json = new JsonObject();
+            var results = new List<object>();
+
+            foreach (XElement item in property.Elements())
+            {
+                object resultItem = ReadDataItem(item);
+                results.Add(resultItem);
+
+                JsonObject complexValue = resultItem as JsonObject;
+                if (complexValue != null)
+                {
+                    var metadata = complexValue["__metadata"] as JsonObject;
+                    if (!string.IsNullOrEmpty(collectionType) && metadata["type"] == null)
+                    {
+                        metadata["type"] = collectionType;
+                    }
+                }
+            }
+
+            json["results"] = results;
+            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(typeName, false);
+
+            return json;
+        }
+
+        private static JsonObject ReadComplexProperty(XElement container, string typeName)
+        {
+            JsonObject json = ReadObject(container);
+            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(container), false);
+            return json;
+        }
+
+        private static JsonObject ReadJsonSpatialProperty(XElement container, XElement gmlValue, bool isGeography)
+        {
+            GmlFormatter gmlFormatter = GmlFormatter.Create();
+            GeoJsonObjectFormatter jsonformatter = GeoJsonObjectFormatter.Create();
+
+            bool ignoreCrc = !gmlValue.Attributes().Any(a => a.Name.LocalName == "srsName");
+
+            ISpatial spatialValue;
+            if (isGeography)
+            {
+                spatialValue = gmlFormatter.Read<Geography>(gmlValue.CreateReader());
+            }
+            else
+            {
+                spatialValue = gmlFormatter.Read<Geometry>(gmlValue.CreateReader());
+            }
+
+            IDictionary<string, object> geoJsonData = jsonformatter.Write(spatialValue);
+            JsonObject json = new JsonObject();
+
+            Queue<object> geoJsonScopes = new Queue<object>();
+            Queue<object> jsonScopes = new Queue<object>();
+
+            geoJsonScopes.Enqueue(geoJsonData);
+            jsonScopes.Enqueue(json);
+
+            Func<object, object> convertScope = (scope) =>
+            {
+                object newScope =
+                        scope is List<object> || scope is object[] ? (object)new List<Object>() :
+                        scope is IDictionary<string, object> ? (object)new JsonObject() :
+                        null;
+
+                if (newScope != null)
+                {
+                    geoJsonScopes.Enqueue(scope);
+                    jsonScopes.Enqueue(newScope);
+                }
+
+                return newScope ?? scope;
+            };
+
+            while (jsonScopes.Count > 0)
+            {
+                if (jsonScopes.Peek() is JsonObject)
+                {
+                    var currentGeoJson = (IDictionary<string, object>)geoJsonScopes.Dequeue();
+                    var currentJson = (JsonObject)jsonScopes.Dequeue();
+
+                    foreach (var item in currentGeoJson)
+                    {
+                        if (!ignoreCrc || item.Key != "crs")
+                        {
+                            currentJson[item.Key] = convertScope(item.Value);
+                        }
+                    }
+                }
+                else
+                {
+                    var currentGeoJson = (IEnumerable<object>)geoJsonScopes.Dequeue();
+                    var currentJson = (List<object>)jsonScopes.Dequeue();
+
+                    foreach (var item in currentGeoJson)
+                    {
+                        currentJson.Add(convertScope(item));
+                    }
+                }
+            }
+            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(container), false);
+            return json;
+        }
+
+        public static object ReadDataItem(XElement item)
+        {
+            string typeName = GetTypeAttribute(item);
+            XElement gmlRoot = item.Elements().SingleOrDefault(e => e.Name.NamespaceName == gmlXmlNs);
+
+            if (gmlRoot != null)
+            {
+                bool isGeography = typeName.StartsWith("Edm.Geography");
+                return ReadJsonSpatialProperty(item, gmlRoot, isGeography);
+            }
+
+            bool isCollection = IsCollectionProperty(item);
+            if (item.HasElements || isCollection)
+            {
+                // Complex type, Collection Type: parse recursively
+                return isCollection ? ReadCollectionProperty(item, typeName) : ReadComplexProperty(item, typeName);
+            }
+
+            // Primitive type: null value
+            XNamespace mNamespace = item.GetNamespaceOfPrefix("m");
+            XAttribute nullAttribute = mNamespace == null ? null : item.Attribute(mNamespace.GetName("null"));
+            if (nullAttribute != null && nullAttribute.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase))
+            {
+                return null;
+            }
+
+            // Primitive type: check type and parse value accordingly
+            string value = item.Value;
+            switch (typeName)
+            {
+                case "Edm.Byte":
+                    return XmlConvert.ToByte(value);
+                case "Edm.Int16":
+                    return XmlConvert.ToInt16(value);
+                case "Edm.Int32":
+                    return XmlConvert.ToInt32(value);
+                case "Edm.SByte":
+                    return XmlConvert.ToSByte(value);
+                case "Edm.Boolean":
+                    return XmlConvert.ToBoolean(value);
+                case "Edm.Double":
+                    return XmlConvert.ToDouble(value);
+                case "Edm.Single":
+                    return XmlConvert.ToSingle(value);
+                case "Edm.Guid":
+                    return XmlConvert.ToGuid(value);
+                case "Edm.DateTime":
+                    return new JsDate(XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc));
+                case "Edm.DateTimeOffset":
+                    return new JsDate(XmlConvert.ToDateTimeOffset(value));
+                case "Edm.Time":
+                    throw new NotSupportedException(typeName + " is not supported");
+                // Decimal and Int64 values are sent as strings over the wire.  This is the same behavior as WCF Data Services JSON serializer.
+                case "Edm.Decimal":
+                case "Edm.Int64":
+                case "":
+                default:
+                    return value;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/tests/code/csdlreader.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/csdlreader.cs b/JSLib/tests/code/csdlreader.cs
new file mode 100644
index 0000000..47a331e
--- /dev/null
+++ b/JSLib/tests/code/csdlreader.cs
@@ -0,0 +1,231 @@
+/// <summary>
+/// Class used to parse csdl to create the metatdata object
+/// </summary>
+/// 
+
+namespace DataJS.Tests
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Linq;
+    using System.Xml.Linq;
+
+
+    public static class CsdlReader
+    {
+        static readonly string knownNamespace = "http://schemas.microsoft.com";
+        static readonly string[] repeatingElements = 
+            {
+                "End", 
+                "Property", 
+                "PropertyRef", 
+                "EntitySet", 
+                "AssociationSet", 
+                "FunctionImport", 
+                "NavigationProperty", 
+                "Parameter", 
+                "Using", 
+                "EntityContainer", 
+                "EntityType", 
+                "Association", 
+                "ComplexType", 
+                "Function", 
+                "Schema"
+            };
+
+        public static JsonObject ReadCsdl(TextReader payload)
+        {
+            return BuildElementJsonObject(XElement.Load(payload));
+        }
+
+        /// <summary>
+        /// Builds the extensions element object
+        /// extensions = {
+        /// name: string, // local name of the custom XML element
+        /// namespace: string, // namespace URI of the custom XML element
+        /// value: string, // value of the custom XML element
+        /// attributes: array, // array of attribute extension objects of the custom XML element
+        /// children: array // array of element extension objects of the custom XML element };
+        /// </summary>
+        /// <param name="customElement">The custom element to be made into an extension object</param>
+        /// <returns>the custom element json object</returns>
+        static JsonObject BuildExtensionsElementObject(XElement customElement)
+        {
+            string value;
+            // customElement.Value contains the value of the element's children, but these are already
+            // captured in the children propterty.
+            if (customElement.HasElements)
+            {
+                value = null;
+            }
+            else
+            {
+                if (customElement.Value == "")
+                {
+                    value = null;
+                }
+                else
+                {
+                    value = customElement.Value;
+                }
+            }
+
+            JsonObject jsonObject = BuildBaseExtensionsObject(customElement.Name.LocalName, customElement.Name.Namespace.ToString(), value);
+
+            jsonObject["attributes"] = customElement.Attributes().Select(
+                attribute => BuildBaseExtensionsObject(attribute.Name.LocalName, attribute.Name.Namespace.ToString(), attribute.Value)
+                ).ToArray();
+            jsonObject["children"] = customElement.Elements().Select(element => BuildExtensionsElementObject(element)).ToArray();
+
+            return jsonObject;
+        }
+
+        /// <summary>
+        /// Creates a generic extension object
+        /// extensions = {
+        /// name: string, // local name of the custom XML element or attribute
+        /// namespace: string, // namespace URI of the custom XML element or attribute
+        /// value: string, // value of the custom XML element or attribute }
+        /// </summary>
+        /// <param name="name">name of the object</param>
+        /// <param name="objectNamespace">namespace of the obect</param>
+        /// <param name="value">value of the object</param>
+        /// <returns></returns>
+        static JsonObject BuildBaseExtensionsObject(string name, string objectNamespace, string value)
+        {
+            JsonObject jsonObject = new JsonObject();
+
+            jsonObject["name"] = name;
+            jsonObject["namespace"] = objectNamespace;
+            jsonObject["value"] = value;
+
+            return jsonObject;
+        }
+
+        /// <summary>
+        /// Build the attribute object 
+        /// </summary>
+        /// <param name="xmlAttributes">IEnumberable of XAttributes to build the attribute object</param>
+        /// <returns>The JsonObject containing the name-value pairs for an element's attributes</returns>
+        static JsonObject BuildAttributeJsonObject(IEnumerable<XAttribute> xmlAttributes)
+        {
+            JsonObject jsonObject = new JsonObject();
+            List<JsonObject> extensions = new List<JsonObject>();
+
+            foreach (XAttribute attribute in xmlAttributes)
+            {
+                if (!attribute.IsNamespaceDeclaration)
+                {
+                    string attributeNamespace = attribute.Name.Namespace.ToString();
+                    if (string.IsNullOrEmpty(attributeNamespace) || attributeNamespace.StartsWith(knownNamespace, StringComparison.InvariantCultureIgnoreCase))
+                    {
+                        jsonObject[MakeFirstLetterLowercase(attribute.Name.LocalName)] = attribute.Value;
+                    }
+                    else
+                    {
+                        extensions.Add(BuildBaseExtensionsObject(attribute.Name.LocalName, attribute.Name.Namespace.ToString(), attribute.Value));
+                    }
+                }
+            }
+
+            if (extensions.Count > 0)
+            {
+                jsonObject["extensions"] = extensions.ToArray();
+            }
+
+            return jsonObject;
+        }
+
+        /// <summary>
+        /// Creates a JsonObject from an XML container element with each attribute or subelement as a property
+        /// </summary>
+        /// <param name="container">The XML container</param>
+        /// <param name="buildValue">Function that builds a value from a property element</param>
+        /// <returns>The JsonObject containing the name-value pairs</returns>
+        public static JsonObject BuildElementJsonObject(XElement container)
+        {
+            if (container == null)
+            {
+                return null;
+            }
+
+            JsonObject jsonObject = new JsonObject();
+            List<JsonObject> extensions = new List<JsonObject>();
+
+            if (container.HasAttributes || container.HasElements)
+            {
+                Dictionary<string, List<JsonObject>> repeatingObjectArrays = new Dictionary<string, List<JsonObject>>();
+                JsonObject extensionObject = new JsonObject();
+
+                jsonObject = BuildAttributeJsonObject(container.Attributes());
+
+                foreach (XElement propertyElement in container.Elements())
+                {
+                    string propertyName = MakeFirstLetterLowercase(propertyElement.Name.LocalName);
+                    string properyNamespace = propertyElement.Name.Namespace.ToString();
+
+                    if (string.IsNullOrEmpty(properyNamespace) || properyNamespace.StartsWith(knownNamespace, StringComparison.InvariantCultureIgnoreCase))
+                    {
+                        // Check to see if the element is repeating and needs to be an array
+                        if (repeatingElements.Contains(propertyElement.Name.LocalName))
+                        {
+                            // See if property was already created as an array, if not then create it
+                            if (!repeatingObjectArrays.ContainsKey(propertyName))
+                            {
+                                repeatingObjectArrays.Add(propertyName, new List<JsonObject>());
+                            }
+                            repeatingObjectArrays[propertyName].Add(BuildElementJsonObject(propertyElement));
+                        }
+                        else
+                        {
+                            jsonObject[propertyName] = BuildElementJsonObject(propertyElement);
+                        }
+                    }
+                    else
+                    {
+                        extensions.Add(BuildExtensionsElementObject(propertyElement));
+                    }
+                }
+
+                if (extensions.Count > 0)
+                {
+                    jsonObject["extensions"] = extensions.ToArray();
+                }
+
+                foreach (string key in repeatingObjectArrays.Keys)
+                {
+                    jsonObject[key] = repeatingObjectArrays[key].ToArray();
+                }
+            }
+            else
+            {
+                jsonObject[MakeFirstLetterLowercase(container.Name.LocalName)] = container.Value;
+            }
+
+            return jsonObject;
+        }
+
+        /// <summary>
+        /// Makes the first letter of a string lowercase
+        /// </summary>
+        /// <param name="name">The string to be modified</param>
+        /// <returns>Modified string</returns>
+        private static string MakeFirstLetterLowercase(string str)
+        {
+            if (!string.IsNullOrWhiteSpace(str))
+            {
+                if (str.Length > 1 && !(str[1].ToString() == str[1].ToString().ToUpper()))
+                {
+                    return str[0].ToString().ToLower() + str.Substring(1);
+                }
+                else
+                {
+                    return str;
+                }
+            }
+
+            return str;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/tests/code/jsdate.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/jsdate.cs b/JSLib/tests/code/jsdate.cs
new file mode 100644
index 0000000..40996d0
--- /dev/null
+++ b/JSLib/tests/code/jsdate.cs
@@ -0,0 +1,40 @@
+/// <summary>
+/// The oracle's representation of a Javascript date object as deserialized by the library
+/// </summary>
+
+namespace DataJS.Tests
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Linq;
+    using System.Net;
+    using System.Runtime.Serialization;
+    using System.ServiceModel;
+    using System.ServiceModel.Activation;
+    using System.ServiceModel.Syndication;
+    using System.ServiceModel.Web;
+    using System.Xml;
+    using System.Xml.Linq;
+    using System.Spatial;
+    using Microsoft.Data.OData;
+
+    [Serializable]
+    public class JsDate : JsonObject
+    {
+        private static readonly DateTime JsEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+        public JsDate(DateTime dateTime)
+            : base()
+        {
+            this["milliseconds"] = dateTime.Subtract(JsEpoch).TotalMilliseconds;
+        }
+
+        public JsDate(DateTimeOffset dateTimeOffset)
+            : this(dateTimeOffset.UtcDateTime)
+        {
+            this["__edmType"] = "Edm.DateTimeOffset";
+            this["__offset"] = (dateTimeOffset.Offset < TimeSpan.Zero ? "-" : "+") + dateTimeOffset.Offset.ToString("hh':'mm");
+        }
+    }
+}
\ No newline at end of file