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/05/09 10:02:45 UTC

[2/3] [OLINGO-276] Convert all the DataJS supported functionality from V3 to V4. 1. Remove all the Json verbose logic, make the DataJS accepted and returned javascript object be in Json light format. (Since Json verbose has been completely removed on V4,

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/code/csdlreader.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/csdlreader.cs b/JSLib/tests/code/csdlreader.cs
index 47a331e..253cf10 100644
--- a/JSLib/tests/code/csdlreader.cs
+++ b/JSLib/tests/code/csdlreader.cs
@@ -14,126 +14,90 @@ namespace DataJS.Tests
 
     public static class CsdlReader
     {
-        static readonly string knownNamespace = "http://schemas.microsoft.com";
+        static readonly string knownNamespace = "http://docs.oasis-open.org";
         static readonly string[] repeatingElements = 
             {
-                "End", 
-                "Property", 
-                "PropertyRef", 
-                "EntitySet", 
-                "AssociationSet", 
-                "FunctionImport", 
-                "NavigationProperty", 
-                "Parameter", 
-                "Using", 
-                "EntityContainer", 
-                "EntityType", 
-                "Association", 
-                "ComplexType", 
-                "Function", 
-                "Schema"
+                "Action",
+                "ActionImport",
+                "Annotation",
+                "Annotations",
+                "Apply",
+                "Binary",
+                "Bool",
+                "Cast",
+                "Collection",
+                "ComplexType",
+                "Date",
+                "DateTimeOffset",
+                "Decimal",
+                "Duration",
+                "EntitySet",
+                "EntityType",
+                "EnumMember",
+                "EnumType",
+                "Float",
+                "Function",
+                "FunctionImport",
+                "Guid",
+                "If",
+                "Int",
+                "IsOf",
+                "Key",
+                "LabeledElement",
+                "LabeledElementReference",
+                "Member",
+                "NavigationProperty",
+                "NavigationPropertyBinding",
+                "NavigationPropertyPath",
+                "Null",
+                "OnDelete",
+                "Path",
+                "Parameter",
+                "Property",
+                "PropertyPath",
+                "PropertyRef",
+                "PropertyValue",
+                "Record",
+                "ReferentialConstraint",
+                "String",
+                "Schema",
+                "Singleton",
+                "Term",
+                "TimeOfDay",
+                "TypeDefinition",
+                "UrlRef",
+                "Reference",
+                "Include",
+                "IncludeAnnotations"
             };
 
-        public static JsonObject ReadCsdl(TextReader payload)
+        public static Dictionary<string, object> 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)
+        static Dictionary<string, object> BuildAttributeJsonObject(IEnumerable<XAttribute> xmlAttributes)
         {
-            JsonObject jsonObject = new JsonObject();
-            List<JsonObject> extensions = new List<JsonObject>();
+            Dictionary<string, object> jsonObject = new Dictionary<string, object>();
 
             foreach (XAttribute attribute in xmlAttributes)
             {
                 if (!attribute.IsNamespaceDeclaration)
                 {
                     string attributeNamespace = attribute.Name.Namespace.ToString();
-                    if (string.IsNullOrEmpty(attributeNamespace) || attributeNamespace.StartsWith(knownNamespace, StringComparison.InvariantCultureIgnoreCase))
+                    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;
         }
 
@@ -143,20 +107,19 @@ namespace DataJS.Tests
         /// <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)
+        public static Dictionary<string, object> BuildElementJsonObject(XElement container)
         {
             if (container == null)
             {
                 return null;
             }
 
-            JsonObject jsonObject = new JsonObject();
-            List<JsonObject> extensions = new List<JsonObject>();
+            Dictionary<string, object> jsonObject = new Dictionary<string, object>();
+            string keyName = MakeFirstLetterLowercase(container.Name.LocalName);
 
             if (container.HasAttributes || container.HasElements)
             {
-                Dictionary<string, List<JsonObject>> repeatingObjectArrays = new Dictionary<string, List<JsonObject>>();
-                JsonObject extensionObject = new JsonObject();
+                Dictionary<string, List<Dictionary<string, object>>> repeatingObjectArrays = new Dictionary<string, List<Dictionary<string, object>>>();
 
                 jsonObject = BuildAttributeJsonObject(container.Attributes());
 
@@ -173,8 +136,9 @@ namespace DataJS.Tests
                             // 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.Add(propertyName, new List<Dictionary<string, object>>());
                             }
+
                             repeatingObjectArrays[propertyName].Add(BuildElementJsonObject(propertyElement));
                         }
                         else
@@ -182,15 +146,6 @@ namespace DataJS.Tests
                             jsonObject[propertyName] = BuildElementJsonObject(propertyElement);
                         }
                     }
-                    else
-                    {
-                        extensions.Add(BuildExtensionsElementObject(propertyElement));
-                    }
-                }
-
-                if (extensions.Count > 0)
-                {
-                    jsonObject["extensions"] = extensions.ToArray();
                 }
 
                 foreach (string key in repeatingObjectArrays.Keys)

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/code/jsdate.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/jsdate.cs b/JSLib/tests/code/jsdate.cs
index 40996d0..a02c69f 100644
--- a/JSLib/tests/code/jsdate.cs
+++ b/JSLib/tests/code/jsdate.cs
@@ -16,8 +16,8 @@ namespace DataJS.Tests
     using System.ServiceModel.Web;
     using System.Xml;
     using System.Xml.Linq;
-    using System.Spatial;
-    using Microsoft.Data.OData;
+    using Microsoft.Spatial;
+    using Microsoft.OData.Core;
 
     [Serializable]
     public class JsDate : JsonObject

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/code/readerutils.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/readerutils.cs b/JSLib/tests/code/readerutils.cs
index 35b98ba..284ce04 100644
--- a/JSLib/tests/code/readerutils.cs
+++ b/JSLib/tests/code/readerutils.cs
@@ -1,4 +1,8 @@
-using System.Net;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Web.Script.Serialization;
+
 namespace DataJS.Tests
 {
     public static class ReaderUtils
@@ -44,5 +48,21 @@ namespace DataJS.Tests
             return request;
         }
 
+        public static Stream ConvertDictionarytoJsonlightStream(Dictionary<string, object> dict)
+        {
+            MemoryStream stream = new MemoryStream();
+            if (dict == null)
+            {
+                return stream;
+            }
+
+            string jsonString = new JavaScriptSerializer().Serialize(dict);
+            StreamWriter writer = new StreamWriter(stream);
+            writer.Write(jsonString);
+            writer.Flush();
+            stream.Position = 0;
+            return stream;
+        }
+
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/common/ODataReadOracle.js
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/ODataReadOracle.js b/JSLib/tests/common/ODataReadOracle.js
index a0c0bbc..4114745 100644
--- a/JSLib/tests/common/ODataReadOracle.js
+++ b/JSLib/tests/common/ODataReadOracle.js
@@ -14,7 +14,7 @@
 // Client for the odata.read oracle service
 
 (function (window, undefined) {
-    var jsonMime = "application/json;odata=verbose";
+    var jsonMime = "application/json";
     var universalMime = "*/*";
     var atomMime = "application/atom+xml";
 
@@ -25,9 +25,6 @@
         /// <param name="mimeType" type="String">The MIME media type in the Accept header</param>
         var readMethod = getReadMethod(mimeType, "ReadFeed");
         oracleRequest("GET", readMethod, typeof url === "string" ? { url: url} : url, mimeType, recognizeDates, function (data) {
-            if (!data.results) {
-                data = { results: data };
-            }
             success(data);
         });
     };
@@ -72,9 +69,6 @@
         readJson(
             url,
             function (data) {
-                if (!data.results) {
-                    data = { results: data };
-                }
                 success(data);
             }
         );
@@ -84,13 +78,7 @@
         /// <summary>Calls the ReadMetadata endpoint with the specified URL</summary>
         /// <param name="url" type="String">The URL to read the metadata from</param>
         /// <param name="success" type="Function">The success callback function</param>
-        $.getJSON(
-            "./common/ODataReadOracle.svc/ReadMetadata?url=" + escape(url),
-            function (data) {
-                removeProperty(data.d, "__type");
-                success(data.d);
-            }
-        );
+        oracleRequest("GET", "ReadMetadata", typeof url === "string" ? { url: url} : url, null, null, success);
     };
 
     var readServiceDocument = function (url, success, mimeType) {
@@ -98,20 +86,8 @@
         /// <param name="url" type="String">The URL to the service</param>
         /// <param name="success" type="Function">The success callback function</param>
         /// <param name="mimeType" type="String">The MIME type being tested</param>
-
-        $.getJSON(
-            "./common/ODataReadOracle.svc/ReadServiceDocument?url=" + escape(url) + "&mimeType=" + mimeType,
-            function (data) {
-                removeProperty(data.d, "__type");
-                if (mimeType == jsonMime) {
-                    removeProperty(data.d, "extensions");
-                    $.each(data.d["workspaces"], function (_, workspace) {
-                        delete workspace["title"];
-                    });
-                }
-                success(data.d);
-            }
-        );
+        var readMethod = getReadMethod(mimeType, "ReadServiceDocument");
+        oracleRequest("GET", readMethod, typeof url === "string" ? { url: url} : url, mimeType, null, success);
     };
 
     var readJson = function (url, success) {
@@ -121,43 +97,59 @@
             dataType: "json",
             beforeSend: function (xhr) {
                 xhr.setRequestHeader("Accept", jsonMime);
-                xhr.setRequestHeader("MaxDataServiceVersion", "3.0");
+                xhr.setRequestHeader("OData-MaxVersion", "4.0");
             },
             success: function (data) {
-                success(data.d);
+                success(data);
             }
         });
     };
 
     var readJsonAcrossServerPages = function (url, success) {
-        var data = [];
+        var data = {};
         var readPage = function (url) {
             readJson(url, function (feedData) {
-                var results = feedData.results || feedData;
-                var next = feedData.__next;
+                var nextLink = feedData["@odata.nextLink"];
+                if (nextLink) {
+                    var index = url.indexOf(".svc/", 0);
+                    if (index != -1) {
+                        nextLink = url.substring(0, index + 5) + nextLink;
+                    }
+                }
+
+                if (data.value && feedData.value) {
+                    data.value = data.value.concat(feedData.value);
+                }
+                else {
+                    for (var property in feedData) {
+                        if (property != "@odata.nextLink") {
+                            data[property] = feedData[property];
+                        }
+                    }
+                }
 
-                data = data.concat(results);
-                if (next) {
-                    readPage(next);
-                } else {
+                if (nextLink) {
+                    readPage(nextLink);
+                }
+                else {
                     success(data);
                 }
             });
         };
 
         readPage(url);
-    }
+    };
 
     var getReadMethod = function (mimeType, defaultEndpoint) {
         switch (mimeType) {
-            case universalMime:
             case atomMime:
                 return defaultEndpoint;
             case jsonMime:
+            case universalMime:
             default:
                 return "ReadJson";
         }
-    }
+    };
 
     var oracleRequest = function (method, endpoint, data, mimeType, recognizeDates, success) {
         /// <summary>Requests a JSON object from the oracle service, removing WCF-specific artifacts</summary>
@@ -166,17 +158,19 @@
         /// <param name="data" type="Object">The data to send with the request</param>
         /// <param name="reviver" type="Function">The reviver function to run on each deserialized object</param>
         /// <param name="success" type="Function">Success callback</param>
-        var reviver = mimeType === jsonMime || mimeType === undefined ? (recognizeDates ? odataDateReviver : undefined) : oracleDateReviver;
         var url = "./common/ODataReadOracle.svc/" + endpoint;
+        if (mimeType) {
+            data.mimeType = mimeType;
+        }
+
         $.ajax({
             type: method,
             url: url,
             data: data,
             dataType: "text",
             success: function (data) {
-                var json = JSON.parse(data, reviver);
-                removeProperty(json.d, "__type");
-                success(json.d);
+                var json = JSON.parse(data);
+                success(json);
             }
         });
     };
@@ -194,70 +188,6 @@
                 removeProperty(data[prop], property);
             }
         }
-    }
-
-    var oracleDateReviver = function (key, value) {
-        /// <summary>Revives date objects received from the oracle service</summary>
-        if (value && value["__type"] && value["__type"].search("JsDate") > -1) {
-            var data = new Date(value.milliseconds);
-            if (value["__edmType"]) {
-                data["__edmType"] = value["__edmType"];
-            }
-
-            if (value["__offset"]) {
-                data["__offset"] = value["__offset"];
-            }
-
-            return data;
-        }
-
-        return value;
-    }
-
-    var odataDateReviver = function (key, value) {
-        /// <summary>Revives date objects received from OData JSON payloads</summary>
-        var regexp = /^\/Date\((-?\d+)(\+|-)?(\d+)?\)\/$/;
-        var matches = regexp.exec(value);
-        if (matches) {
-            var milliseconds = parseInt(matches[1], 10);
-            if (!isNaN(milliseconds)) {
-                var result = new Date(milliseconds);
-                if (matches[2]) {
-                    var sign = matches[2];
-                    var offsetMinutes = parseInt(matches[3], 10);
-                    if (sign === "-") {
-                        offsetMinutes = -offsetMinutes;
-                    }
-
-                    result.setUTCMinutes(result.getUTCMinutes() - offsetMinutes);
-                    result["__edmType"] = "Edm.DateTimeOffset";
-                    result["__offset"] = minutesToOffset(offsetMinutes);
-                }
-                return result;
-            }
-        }
-
-        return value;
-    }
-
-    var minutesToOffset = function (minutes) {
-        var padIfNeeded = function (value) {
-            var result = value.toString(10);
-            return result.length < 2 ? "0" + result : result;
-        };
-
-        var sign;
-        if (minutes < 0) {
-            sign = "-";
-            minutes = -minutes;
-        } else {
-            sign = "+";
-        }
-
-        var hours = Math.floor(minutes / 60);
-        minutes = minutes - (60 * hours);
-
-        return sign + padIfNeeded(hours) + ":" + padIfNeeded(minutes);
     };
 
     window.ODataReadOracle = {

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/common/ODataReadOracle.svc
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/ODataReadOracle.svc b/JSLib/tests/common/ODataReadOracle.svc
index 32b4d50..51ccd62 100644
--- a/JSLib/tests/common/ODataReadOracle.svc
+++ b/JSLib/tests/common/ODataReadOracle.svc
@@ -31,8 +31,9 @@ namespace DataJS.Tests
     using System.ServiceModel.Web;
     using System.Xml;
     using System.Xml.Linq;
-    using System.Spatial;
-    using Microsoft.Data.OData;
+    using Microsoft.Spatial;
+    using Microsoft.OData.Core;
+    using System.Web.Script.Serialization;
 
     /// <summary>
     /// Oracle for the OData.read library function
@@ -42,7 +43,7 @@ namespace DataJS.Tests
     [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
     public class ODataReadOracle
     {
-        const string jsonVerboseMediaType = "application/json;odata=verbose";
+        const string jsonlightMediaType = "application/json";
 
         /// <summary>
         /// Reads a URI that will return an OData ATOM feed
@@ -78,13 +79,14 @@ namespace DataJS.Tests
         /// Reads a URI that will return a metadata object
         /// </summary>
         /// <param name="url">The URL to send the request to</param>
-        /// <returns>JSON object expected to be returned by OData.read (plus type metadata markers that will need to be removed)</returns>
+        /// <returns>Stream of metadata in json light format</returns>
         [OperationContract]
-        [WebGet(ResponseFormat = WebMessageFormat.Json)]
-        public JsonObject ReadMetadata(string url)
+        [WebGet]
+        public Stream ReadMetadata(string url)
         {
             WebResponse response = WebRequest.Create(ResolveUri(url, UriKind.Absolute)).GetResponse();
-            return CsdlReader.ReadCsdl(new StreamReader(response.GetResponseStream()));
+            Dictionary<string, object> jsonObject = CsdlReader.ReadCsdl(new StreamReader(response.GetResponseStream()));
+            return ReaderUtils.ConvertDictionarytoJsonlightStream(jsonObject);
         }
 
         /// <summary>
@@ -101,7 +103,7 @@ namespace DataJS.Tests
             string baseUri = string.Empty;
 
             // With JSON responses only relative path passed to the library is available
-            if (mimeType.Equals(jsonVerboseMediaType))
+            if (mimeType.Equals(jsonlightMediaType))
             {
                 baseUri = ResolveUri(url, UriKind.Relative).ToString();
             }
@@ -122,10 +124,15 @@ namespace DataJS.Tests
         /// <returns>Stream of the Json response expected to be returned by OData.read</returns>
         [OperationContract]
         [WebGet(ResponseFormat = WebMessageFormat.Json)]
-        public Stream ReadJson(string url, string user, string password)
+        public Stream ReadJson(string url, string mimeType, string user, string password)
         {
+            if (mimeType == null)
+            {
+                mimeType = jsonlightMediaType + ";odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8";
+            }
+            
             HttpWebRequest request = (HttpWebRequest)ReaderUtils.CreateRequest(ResolveUri(url, UriKind.Absolute), user, password);
-            request.Accept = jsonVerboseMediaType + "; charset=utf-8";
+            request.Accept = mimeType;
             WebResponse response = request.GetResponse();
 
             return response.GetResponseStream();

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/common/djstest.js
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/djstest.js b/JSLib/tests/common/djstest.js
index c7b2de5..b9df624 100644
--- a/JSLib/tests/common/djstest.js
+++ b/JSLib/tests/common/djstest.js
@@ -223,6 +223,15 @@
         }
     };
 
+    djstest.addFullTest = function (disable, fn, name, arg, timeout) {
+        /// <summary>Add the unit test cases</summary>
+        /// <param name="disable">Indicate whether this test case should be disabled</param>
+        if (disable != true) {
+            djstest.addTest(fn, name, arg, timeout);
+        }
+    };
+
+
     djstest.addTest = function (fn, name, arg, timeout) {
         if (!name) {
             name = extractFunctionName(fn.toString());
@@ -237,7 +246,7 @@
             QUnit.stop();
             fn.call(this, arg);
         });
-    }
+    };
 
     djstest.assert = function (test, message) {
         /// <summary>Asserts that a condition is true.</summary>

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/endpoints/FoodStoreDataService.svc
----------------------------------------------------------------------
diff --git a/JSLib/tests/endpoints/FoodStoreDataService.svc b/JSLib/tests/endpoints/FoodStoreDataService.svc
index 9e7e332..b080e47 100644
--- a/JSLib/tests/endpoints/FoodStoreDataService.svc
+++ b/JSLib/tests/endpoints/FoodStoreDataService.svc
@@ -1,7 +1,7 @@
 <%@ ServiceHost Language="C#" Factory="System.Data.Services.DataServiceHostFactory, Microsoft.Data.Services, Version=5.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
     Service="DataJS.Tests.V1.FoodStoreDataService" %>
 
-// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// Copyright (c) Microsoft.  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 

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/endpoints/FoodStoreDataServiceV2.svc
----------------------------------------------------------------------
diff --git a/JSLib/tests/endpoints/FoodStoreDataServiceV2.svc b/JSLib/tests/endpoints/FoodStoreDataServiceV2.svc
index 40ddaa7..bcf00fb 100644
--- a/JSLib/tests/endpoints/FoodStoreDataServiceV2.svc
+++ b/JSLib/tests/endpoints/FoodStoreDataServiceV2.svc
@@ -1,7 +1,7 @@
 <%@ ServiceHost Language="C#" Factory="System.Data.Services.DataServiceHostFactory, Microsoft.Data.Services, Version=5.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
     Service="DataJS.Tests.V2.FoodStoreDataService" %>
 
-// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// Copyright (c) Microsoft.  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 

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/endpoints/FoodStoreDataServiceV3.svc
----------------------------------------------------------------------
diff --git a/JSLib/tests/endpoints/FoodStoreDataServiceV3.svc b/JSLib/tests/endpoints/FoodStoreDataServiceV3.svc
index 6ad9671..144c8bd 100644
--- a/JSLib/tests/endpoints/FoodStoreDataServiceV3.svc
+++ b/JSLib/tests/endpoints/FoodStoreDataServiceV3.svc
@@ -1,7 +1,7 @@
 <%@ ServiceHost Language="C#" Factory="System.Data.Services.DataServiceHostFactory, Microsoft.Data.Services, Version=5.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
     Service="DataJS.Tests.V3.FoodStoreDataService" %>
 
-// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// Copyright (c) Microsoft.  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 

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/endpoints/FoodStoreDataServiceV4.svc
----------------------------------------------------------------------
diff --git a/JSLib/tests/endpoints/FoodStoreDataServiceV4.svc b/JSLib/tests/endpoints/FoodStoreDataServiceV4.svc
new file mode 100644
index 0000000..21f09cf
--- /dev/null
+++ b/JSLib/tests/endpoints/FoodStoreDataServiceV4.svc
@@ -0,0 +1,589 @@
+<%@ ServiceHost Language="C#" Factory="Microsoft.OData.Service.DataServiceHostFactory, Microsoft.OData.Service, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
+    Service="DataJS.Tests.V4.FoodStoreDataService" %>
+
+// 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.V4
+{
+    using System;
+    using System.Collections.Generic;
+    using Microsoft.OData.Service;
+    using Microsoft.OData.Service.Common;
+    using Microsoft.OData.Service.Providers;
+    using System.Linq;
+    using System.ServiceModel.Web;
+    using System.Web;
+    using System.IO;
+    using Microsoft.Spatial;
+    
+    /// <summary>
+    /// Provides a service similar to FoodStoreDataService, but uses V4 and WCF Data Services 6.0.0-beta1
+    /// features.
+    /// </summary>
+    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
+    public class FoodStoreDataService : DataService<FoodContainer>
+    {
+        // This method is called only once to initialize service-wide policies.
+        public static void InitializeService(DataServiceConfiguration config)
+        {
+            config.SetEntitySetAccessRule("*", EntitySetRights.All);
+            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
+            config.UseVerboseErrors = true;
+            // Set Foods page size to 5 for cache testing
+            config.SetEntitySetPageSize("Foods", 5);
+            // Make the Categories set paged to have a paged feed
+            config.SetEntitySetPageSize("Categories", 1);
+        }
+        
+        [WebInvoke]
+        public string ResetData()
+        {
+            this.CurrentDataSource.ResetData();
+            return "Data Reset";
+        }
+
+        [WebGet]
+        public IQueryable<string> FoodsAvailable()
+        {
+            return this.CurrentDataSource.Foods.Select(food => food.Name);
+        }
+
+        [WebGet]
+        public IQueryable<Package> PackagingTypes()
+        {
+            return this.CurrentDataSource.Foods.Select(food => food.Packaging);
+        }
+
+        [WebGet]
+        public string UserNameAndPassword()
+        {
+            var request = WebOperationContext.Current.IncomingRequest;
+            string authorization = request.Headers["Authorization"];
+            if (String.IsNullOrEmpty(authorization))
+            {
+                WebOperationContext.Current.OutgoingResponse.Headers["WWW-Authenticate"] = "Basic realm=\"localhost\"";
+                throw new DataServiceException(401, "Access denied in UserNameAndPassword");
+            }
+
+            return authorization;
+        }
+    }
+
+    public class FoodContainer : ReflectionDataContext, IUpdatable, IDataServiceStreamProvider2
+    {
+        private static bool dataInitialized;
+
+        public IQueryable<Category> Categories
+        {
+            get { return this.GetResourceSetEntities<Category>("Categories").AsQueryable(); }
+        }
+        
+        public IQueryable<Food> Foods
+        {
+            get { return this.GetResourceSetEntities<Food>("Foods").AsQueryable(); }
+        }
+
+        public void ResetData()
+        {
+            this.ClearData();
+
+            var builder = SpatialImplementation.CurrentImplementation.CreateBuilder();
+            builder.GeometryPipeline.SetCoordinateSystem(CoordinateSystem.DefaultGeography);
+            builder.GeometryPipeline.BeginGeometry(SpatialType.Collection);
+            builder.GeometryPipeline.BeginFigure(new GeometryPosition(5.0, 5.0));
+            builder.GeometryPipeline.EndFigure();
+            builder.GeometryPipeline.EndGeometry();
+            
+            int i = 0;
+            Category[] categories = new Category[]
+            {
+                new Category { CategoryID = i++, Name = "Baking Supplies" },
+                new Category { CategoryID = i++, Name = "Condiments" },
+                new Category { CategoryID = i++, Name = "Empty Category" }
+            };
+            Array.ForEach(categories, (category) => this.GetResourceSetEntities<Category>("Categories").Add(category));
+            
+            i = 0;
+            Food[] foods = new Food[]
+            {            
+                new Food()
+                {
+                    FoodID = i++,
+                    Name = "flour",
+                    UnitPrice = .19999,
+                    ServingSize = 1,
+                    MeasurementUnit = "Cup",
+                    ProteinGrams = 3,
+                    FatGrams = 1,
+                    CarbohydrateGrams = 20,
+                    CaloriesPerServing = 140,
+                    IsAvailable = true,
+                    ExpirationDate = new DateTime(2010, 12, 25, 12, 0, 0),
+                    ItemGUID = new Guid("27272727272727272727272727272727"),
+                    Weight = 10f,
+                    AvailableUnits = 1,
+                    
+                    Packaging = new Package(){
+                        Type = null, 
+                        Color = String.Empty, 
+                        NumberPerPackage = int.MaxValue, 
+                        RequiresRefridgeration = false, 
+                        PackageDimensions = new Dimensions()
+                        {
+                            Length = Decimal.MaxValue, 
+                            Height = Int16.MaxValue, 
+                            Width = Int64.MaxValue, 
+                            Volume = double.MaxValue,   
+                        },
+                        ShipDate = new DateTime(2000, 12, 29)
+                    },
+                    
+                    CookedSize = new CookedDimensions()
+                    {
+                        Height = 1,
+                        Length = 2,
+                        Width = 3,
+                        Volume = 1 * 2 * 3
+                    },
+                    
+                    Category = categories[0],
+                    
+                    AlternativeNames = new List<string>() {"ground cereal", "ground grain"},
+                    
+                    Providers = new List<Provider> {
+                        new Provider() { 
+                             Name= "Flour Provider", 
+                             Aliases = new List<string>() {"fp1", "flour provider1"},
+                             Details = new ProviderDetails() {
+                                 Telephone= "555-555-555",
+                                 PreferredCode = 1001
+                             }
+                        },
+                        new Provider() { 
+                             Name= "Ground Grains", 
+                             Aliases = new List<string>()
+                        }
+                    },
+                    
+                    SpatialData = (GeometryCollection)builder.ConstructedGeometry 
+                },
+                
+                new Food()
+                {
+                    FoodID = i++,
+                    Name = "sugar",
+                    UnitPrice = .2,
+                    ServingSize = 1,
+                    MeasurementUnit = "tsp",
+                    ProteinGrams = 0,
+                    FatGrams = 0,
+                    CarbohydrateGrams = 4,
+                    CaloriesPerServing = 16,
+                    IsAvailable = false,
+                    ExpirationDate = new DateTime(2011, 12, 28),
+                    ItemGUID = new Guid("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
+                    Weight = 0.1f,
+                    AvailableUnits = 0,
+
+                    Packaging = new Package(){
+                        Type = " ",
+                        Color = "BLUE",
+                        NumberPerPackage = int.MinValue,
+                        RequiresRefridgeration = true,
+                        PackageDimensions = new Dimensions(){
+                            Length = Decimal.MinValue,
+                            Height = Int16.MinValue,
+                            Width = Int64.MinValue,
+                            Volume = double.MinValue,
+                        },
+                        ShipDate = new DateTime(2000, 12, 29),
+                    },
+                    
+                    Category = categories[1],
+                },
+
+                new Food()
+                {
+                    FoodID = i++,
+                    Name = "1 Chicken Egg",
+                    UnitPrice = 0.55,
+                    MeasurementUnit = null,
+                    ServingSize = 1,
+                    ProteinGrams = 6,
+                    FatGrams = 1,
+                    CarbohydrateGrams = 1,
+                    CaloriesPerServing = 70,
+                    IsAvailable = true,
+                    ExpirationDate = new DateTime(2000, 12, 29),
+                    ItemGUID = new Guid("00000000000000000000000000000000"),
+                    Weight = 0,
+                    AvailableUnits = -128,
+                    
+                    Packaging = new Package(){
+                        Type = "18     - Carton",
+                        Color = " brown ",
+                        NumberPerPackage = 0,
+                        RequiresRefridgeration = true,
+                        PackageDimensions = null,
+                        ShipDate = new DateTime(2000, 12, 29),
+                    },
+                    
+                    Category = null,
+                },
+
+                new Food()
+                {
+                    FoodID = i++,
+                    Name = "Brown Sugar",
+                    UnitPrice = 1.6,
+                    ServingSize = 1,
+                    MeasurementUnit = "TSP.",
+                    ProteinGrams = 0,
+                    FatGrams = 0,
+                    CarbohydrateGrams = 5, 
+                    CaloriesPerServing = 16,
+                    IsAvailable = true,
+                    ExpirationDate = new DateTime(2011, 12, 28),
+                    ItemGUID = new Guid("0123456789abcdef0123456789abcdef"),
+                    Weight = 4.5f,
+                    AvailableUnits = 127,
+                    Packaging = null,
+                    Category = categories[1],
+                },
+                
+                new PreparedFood()
+                {
+                    FoodID = i++,
+                    Name = "Cobb Salad",
+                    UnitPrice = 1.99,
+                    ServingSize = -1,
+                    MeasurementUnit = "cups",
+                    ProteinGrams = 6,
+                    FatGrams = 1,
+                    CarbohydrateGrams = 3, 
+                    CaloriesPerServing = 5,
+                    IsAvailable = true,
+                    ExpirationDate = new DateTime(2000, 12, 29),
+                    ItemGUID = new Guid("0123456789abcdef0123456789abcdef"),
+                    Weight = 5.674f,
+                    AvailableUnits = 127,
+                    Packaging = null,
+                    Category = categories[1],
+                    Instructions = "1.) Open 2.) Eat",
+                    NumberOfIngredients = 4,
+                },
+                
+                new PreparedFood()
+                {
+                    FoodID = i++,
+                    Name = "Lasagna",
+                    UnitPrice = 0,
+                    ServingSize = 8,
+                    MeasurementUnit = " servings",
+                    ProteinGrams = 100,
+                    FatGrams = 4,
+                    CarbohydrateGrams = 27, 
+                    CaloriesPerServing = 389,
+                    IsAvailable = true,
+                    ExpirationDate = new DateTime(1904, 2, 29),
+                    ItemGUID = new Guid("0123456789abcdef0123456789abcdef"),
+                    Weight = 0,
+                    AvailableUnits = 4,
+                    Packaging = new Package(){
+                        Type = "box",
+                        Color = " 1 ",
+                        NumberPerPackage = 1,
+                        RequiresRefridgeration = true,
+                        PackageDimensions = new Dimensions(){
+                            Length = 3,
+                            Height = 1,
+                            Width = 5,
+                            Volume = 1.5,
+                        },
+                        ShipDate = new DateTime(2000, 12, 29),
+                    },
+                    Category = categories[0],
+                    Instructions = "Bake in oven",
+                    NumberOfIngredients = 15,
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Chocolate"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Pizza"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Avocados"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Quinoa"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Oatmeal"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Peanut Butter"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Banana"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Yam"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Clam"
+                },
+                
+                new Food()
+                {                    
+                    FoodID = i++,
+                    Name = "Spam"
+                }
+            };
+            Array.ForEach(foods, (food) => this.GetResourceSetEntities<Food>("Foods").Add(food));
+
+            categories[0].Foods.Add(foods[0]);
+            categories[1].Foods.Add(foods[2]);
+            categories[1].Foods.Add(foods[3]);
+        }
+
+        protected override void EnsureDataIsInitialized()
+        {
+            if (!dataInitialized)
+            {
+                this.ResetData();
+                dataInitialized = true;
+            }
+        }
+
+        public Stream GetReadStream(object entity, ResourceProperty streamProperty, string etag, bool? checkETagForEquality, DataServiceOperationContext operationContext)
+        {
+            return new MemoryStream();
+        }
+
+        public Uri GetReadStreamUri(object entity, ResourceProperty streamProperty, DataServiceOperationContext operationContext)
+        {
+            if (streamProperty.Name == "Icon")
+            {
+                return null;
+            }
+            return new Uri(operationContext.AbsoluteServiceUri, streamProperty.Name);
+        }
+
+        public string GetStreamContentType(object entity, ResourceProperty streamProperty, DataServiceOperationContext operationContext)
+        {
+            if (streamProperty.Name == "Icon")
+            {
+                return "image/gif";
+            }
+            return "image/png";
+        }
+
+        public string GetStreamETag(object entity, ResourceProperty streamProperty, DataServiceOperationContext operationContext)
+        {
+            return "W/\"123456789\"";
+        }
+
+        public Stream GetWriteStream(object entity, ResourceProperty streamProperty, string etag, bool? checkETagForEquality, DataServiceOperationContext operationContext)
+        {
+            return new MemoryStream();
+        }
+
+        public void DeleteStream(object entity, DataServiceOperationContext operationContext)
+        {
+            // do nothing.
+        }
+
+        public Stream GetReadStream(object entity, string etag, bool? checkETagForEquality, DataServiceOperationContext operationContext)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Uri GetReadStreamUri(object entity, DataServiceOperationContext operationContext)
+        {
+            throw new NotImplementedException();
+        }
+
+        public string GetStreamContentType(object entity, DataServiceOperationContext operationContext)
+        {
+            throw new NotImplementedException();
+        }
+
+        public string GetStreamETag(object entity, DataServiceOperationContext operationContext)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Stream GetWriteStream(object entity, string etag, bool? checkETagForEquality, DataServiceOperationContext operationContext)
+        {
+            throw new NotImplementedException();
+        }
+
+        public string ResolveType(string entitySetName, DataServiceOperationContext operationContext)
+        {
+            throw new NotImplementedException();
+        }
+
+        public int StreamBufferSize
+        {
+            get { return 1024; }
+        }
+    }
+
+    /// <summary>
+    /// The Category class is a simple class with V1-compatible feed customizations.
+    /// </summary>
+    [DataServiceKey("CategoryID")]
+    [EntitySet("Categories")]
+    [NamedStream("Icon")]
+    public class Category
+    {
+        public Category()
+        {
+            this.Foods = new List<Food>();
+        }
+        
+        public int CategoryID { get; set; }
+        public string Name { get; set; }
+        public List<Food> Foods { get; set; }
+    }
+    
+    /// <summary>
+    /// The Food class has a mixture of V1-compatible and incompatible feed
+    /// customizations (thus it's V2), and custom mappings.
+    /// </summary>
+    [DataServiceKey("FoodID")]
+    [EntitySet("Foods")]
+    [NamedStream("Picture")]
+    public class Food
+    {
+        private List<string> alternativeNames = new List<string>();
+        private List<Provider> providers = new List<Provider>();
+        
+        // Primitive types
+        public int FoodID { get; set; }
+        public string Name { get; set; }
+        public double UnitPrice { get; set; }
+        public Decimal ServingSize { get; set; }
+        public string MeasurementUnit { get; set; }
+        public Byte ProteinGrams { get; set; }
+        public Int16 FatGrams { get; set; }
+        public Int32 CarbohydrateGrams { get; set; }
+        public Int64 CaloriesPerServing { get; set; }
+        public Boolean IsAvailable { get; set; }
+        public DateTime ExpirationDate { get; set; }
+        public Guid ItemGUID { get; set; }
+        public Single Weight { get; set; }
+        public sbyte AvailableUnits { get; set; }
+
+        // Complex types
+        public Package Packaging { get; set; }
+        public CookedDimensions CookedSize { get; set; }
+
+        // Navigation properties
+        public Category Category { get; set; }
+
+        // Collection properties
+        public List<string> AlternativeNames
+        {
+            get { return alternativeNames; }
+            set { alternativeNames = value; }
+        }
+
+        public List<Provider> Providers
+        {
+            get { return providers; }
+            set { providers = value; }
+        }
+
+        public GeometryCollection SpatialData
+        {
+            get;
+            set;
+        }
+        
+    }
+
+    public class Provider
+    {
+        public string Name { get; set; }
+        public List<string> Aliases { get; set; }
+        public ProviderDetails Details { get; set; }
+    }
+
+    public class ProviderDetails
+    {
+        public string Telephone { get; set; }
+        public int PreferredCode { get; set; }
+    }
+    
+    public class Package
+    {
+        public string Type { get; set; }
+        public string Color { get; set; }
+        public int NumberPerPackage { get; set; }
+        public Boolean RequiresRefridgeration { get; set; }
+        public DateTime ShipDate { get; set; }
+        public Dimensions PackageDimensions { get; set; }
+    }
+
+    public class Dimensions
+    {
+        public Decimal Length { get; set; }
+        public Int16 Height { get; set; }
+        public Int64 Width { get; set; }
+        public double Volume { get; set; }
+    }
+
+    public class CookedDimensions
+    {
+        public Decimal Length { get; set; }
+        public Int16 Height { get; set; }
+        public Int64 Width { get; set; }
+        public double Volume { get; set; }
+    }
+
+    public class PreparedFood : Food
+    {
+        public string Instructions { get; set; }
+        public float NumberOfIngredients { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/9d81e7e3/JSLib/tests/endpoints/web.config
----------------------------------------------------------------------
diff --git a/JSLib/tests/endpoints/web.config b/JSLib/tests/endpoints/web.config
index 4875aa4..5836287 100644
--- a/JSLib/tests/endpoints/web.config
+++ b/JSLib/tests/endpoints/web.config
@@ -10,10 +10,9 @@
         <add assembly='System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089'/>
         <add assembly='System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089'/>
         <add assembly='System.ServiceModel.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35'/>
-
-        <add assembly='Microsoft.Data.OData, Version=5.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35'/>
-        <add assembly='Microsoft.Data.Services, Version=5.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35'/>
-        <add assembly='Microsoft.Data.Services.Client, Version=5.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35'/>
+        <add assembly="Microsoft.OData.Core, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
+        <add assembly="Microsoft.OData.Service, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
+        <add assembly="Microsoft.OData.Client, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
       </assemblies>
     </compilation>
   </system.web>