Author: awiner
Date: Mon Mar 30 23:45:31 2009
New Revision: 760259

URL: http://svn.apache.org/viewvc?rev=760259&view=rev
Log:
SHINDIG-753: Radically simplify the Persistence/AppData API
- Add support for an appData parameter to the fetch-person and fetch-people JS 
APIs
- Add person.getAppData(key) API
- Add JsonDbOpensocialService support for appData and appData.key fields on 
person objects
- Add Person.get/setAppData() API
- Add end-to-end tests of appdata retrieval

New APIs - data pipelining and OS Lite - and the JSON-RPC and REST protocols 
will just use @fields.
No changes have been made to the service APIs (beyond adding the new appData 
key to Person)

Modified:
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-0.8/opensocial8to9.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/container.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/datarequest.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/person.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-rest/restfulcontainer.js
    
incubator/shindig/trunk/java/server/src/test/resources/endtoend/fetchPersonTest.xml
    
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/model/PersonImpl.java
    
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/Person.java
    
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialService.java
    
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialServiceTest.java
    
incubator/shindig/trunk/java/social-api/src/test/resources/org/apache/shindig/social/opensocial/util/opensocial.xsd

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-0.8/opensocial8to9.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-0.8/opensocial8to9.js?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-0.8/opensocial8to9.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-0.8/opensocial8to9.js
 Mon Mar 30 23:45:31 2009
@@ -17,3 +17,30 @@
  * under the License.
  */
 
+opensocial.DataRequest.prototype.newUpdatePersonAppDataRequest_09 =
+    opensocial.DataRequest.prototype.newUpdatePersonAppDataRequest;
+/**
+ * Implementation of 0.8 newUpdatePersonAppDataRequest API
+ */
+opensocial.DataRequest.prototype.newUpdatePersonAppDataRequest = function(id,
+    key, value) {
+  if (id !== opensocial.IdSpec.PersonId.VIEWER) {
+    throw "Cannot update app data for person "  + id;
+  }
+  return this.newUpdatePersonAppDataRequest_09(key, value);
+}
+
+opensocial.DataRequest.prototype.newRemovePersonAppDataRequest_09 =
+    opensocial.DataRequest.prototype.newRemovePersonAppDataRequest;
+/**
+ * Implementation of 0.8 newRemovePersonAppDataRequest API
+ */
+opensocial.DataRequest.prototype.newRemovePersonAppDataRequest = function(id,
+    keys) {
+  if (id !== opensocial.IdSpec.PersonId.VIEWER) {
+    throw "Cannot remove app data for person "  + id;
+  }
+
+  return this.newRemovePersonAppDataRequest_09(keys);
+}
+    

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js
 Mon Mar 30 23:45:31 2009
@@ -23,7 +23,7 @@
 
 var FieldTranslations = {};
 
-FieldTranslations.translateServerPersonToJsPerson = function(serverJson) {
+FieldTranslations.translateServerPersonToJsPerson = function(serverJson, 
opt_params) {
   if (serverJson.emails) {
     for (var i = 0; i < serverJson.emails.length; i++) {
       serverJson.emails[i].address = serverJson.emails[i].value;
@@ -88,6 +88,11 @@
   if (serverJson.name) {
     serverJson.name.unstructured = serverJson.name.formatted;
   }
+  
+  if (serverJson.appData) {
+    serverJson.appData = opensocial.Container.escape(
+        serverJson.appData, opt_params, true);
+  }
 
 };
 
@@ -148,3 +153,32 @@
   
   return new Date(Number(time));
 }
+
+/**
+ * AppData is provided by the REST and JSON-RPC protocols using
+ * an "appData" or "appData.key" field, but is described by
+ * the JS fetchPerson() API in terms of an appData param.  Translate
+ * between the two.
+ */
+FieldTranslations.addAppDataAsProfileFields = function(opt_params) {
+  if (opt_params) {
+    // Push the appData keys in as profileDetails
+    if (opt_params['appData']) {
+      var appDataKeys = opt_params['appData'];
+      if (typeof appDataKeys === 'string') {
+        appDataKeys = [appDataKeys];
+      }
+      
+      var profileDetail = opt_params['profileDetail'] || [];
+      for (var i = 0; i < appDataKeys.length; i++) {
+        if (appDataKeys[i] === '*') {
+          profileDetail.push('appData');
+        } else {
+          profileDetail.push('appData.' + appDataKeys[i]);
+        }
+      }
+      
+      opt_params['appData'] = appDataKeys;
+    }
+  }    
+}
\ No newline at end of file

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js
 Mon Mar 30 23:45:31 2009
@@ -99,3 +99,8 @@
 JsonPerson.prototype.getDisplayName = function() {
   return this.getField("displayName");
 };
+
+JsonPerson.prototype.getAppData = function(key) {
+  var appData = this.getField("appData");
+  return appData && appData[key];
+};

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js
 Mon Mar 30 23:45:31 2009
@@ -273,7 +273,7 @@
     var me = this;
     return new JsonRpcRequestItem(peopleRequest.rpc,
             function(rawJson) {
-              return me.createPersonFromJson(rawJson);
+              return me.createPersonFromJson(rawJson, opt_params);
             });
   };
 
@@ -281,6 +281,9 @@
       opt_params) {
     var rpc = { method : "people.get" };
     rpc.params = this.translateIdSpec(idSpec);
+
+    FieldTranslations.addAppDataAsProfileFields(opt_params);
+
     if (opt_params['profileDetail']) {
       
FieldTranslations.translateJsPersonFieldsToServerFields(opt_params['profileDetail']);
       rpc.params.fields = opt_params['profileDetail'];
@@ -315,15 +318,15 @@
 
           var people = [];
           for (var i = 0; i < jsonPeople.length; i++) {
-            people.push(me.createPersonFromJson(jsonPeople[i]));
+            people.push(me.createPersonFromJson(jsonPeople[i], opt_params));
           }
           return new opensocial.Collection(people,
               rawJson['startIndex'], rawJson['totalResults']);
         });
   };
 
-  JsonRpcContainer.prototype.createPersonFromJson = function(serverJson) {
-    FieldTranslations.translateServerPersonToJsPerson(serverJson);
+  JsonRpcContainer.prototype.createPersonFromJson = function(serverJson, 
opt_params) {
+    FieldTranslations.translateServerPersonToJsPerson(serverJson, opt_params);
     return new JsonPerson(serverJson);
   };
 
@@ -362,10 +365,10 @@
         });
   };
 
-  JsonRpcContainer.prototype.newUpdatePersonAppDataRequest = function(id, key,
+  JsonRpcContainer.prototype.newUpdatePersonAppDataRequest = function(key,
       value) {
     var rpc = { method : "appdata.update" };
-    rpc.params = this.translateIdSpec(this.makeIdSpec(id));
+    rpc.params = {userId: ["@viewer"], groupId: "@self"};
     rpc.params.appId = "@app";
     rpc.params.data = {};
     rpc.params.data[key] = value;
@@ -373,9 +376,9 @@
     return new JsonRpcRequestItem(rpc);
   };
 
-  JsonRpcContainer.prototype.newRemovePersonAppDataRequest = function(id, 
keys) {
+  JsonRpcContainer.prototype.newRemovePersonAppDataRequest = function(keys) {
     var rpc = { method : "appdata.delete" };
-    rpc.params = this.translateIdSpec(this.makeIdSpec(id));
+    rpc.params = {userId: ["@viewer"], groupId: "@self"};
     rpc.params.appId = "@app";
     rpc.params.fields = this.getFieldsList(keys);
 

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/container.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/container.js?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/container.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/container.js
 Mon Mar 30 23:45:31 2009
@@ -271,33 +271,32 @@
 
 
 /**
- * Used to request an update of an app field for the given person.
+ * Creates an item to request an update of an app field for the current VIEWER
  * When processed, does not return any data.
+ * App Data is stored as a series of key value pairs of strings, scoped per
+ * person, per application. Containers supporting this request SHOULD provide
+ * at least 10KB of space per user per application for this data.
  *
- * @param {String} id The id of the person to update. (Right now only the
- *    special VIEWER id is allowed.)
  * @param {String} key The name of the key
  * @param {String} value The value
  * @return {Object} a request object
  * @private
  */
-opensocial.Container.prototype.newUpdatePersonAppDataRequest = function(id,
+opensocial.Container.prototype.newUpdatePersonAppDataRequest = function(
     key, value) {};
 
 
 /**
- * Deletes the given keys from the datastore for the given person.
+ * Deletes the given keys from the datastore for the current VIEWER.
  * When processed, does not return any data.
  *
- * @param {String} id The ID of the person to update; only the
- *     special <code>VIEWER</code> ID is currently allowed.
  * @param {Array.&lt;String&gt; | String} keys The keys you want to delete from
  *     the datastore; this can be an array of key names, a single key name,
  *     or "*" to mean "all keys"
  * @return {Object} A request object
  * @private
  */
-opensocial.Container.prototype.newRemovePersonAppDataRequest = function(id,
+opensocial.Container.prototype.newRemovePersonAppDataRequest = function(
     keys) {};
 
 

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/datarequest.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/datarequest.js?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/datarequest.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/datarequest.js
 Mon Mar 30 23:45:31 2009
@@ -251,7 +251,24 @@
    *
    * @member opensocial.DataRequest.PeopleRequestFields
    */
-  MAX : 'max'
+  MAX : 'max',
+
+  /**
+   * A string or array of strings, specifying the app data keys to fetch for
+   * each of the Person objects. This field may be used interchangeably with
+   * the string 'appData'.  Pass the string '*' to fetch all app data keys.
+   * @member opensocial.DataRequest.PeopleRequestFields
+   */
+  APP_DATA : 'appData',
+
+  /**
+   * How to escape app data returned from the server;
+   * defaults to HTML_ESCAPE. Possible values are defined by
+   * <a href="opensocial.EscapeType.html">EscapeType</a>.
+   * This field may be used interchangeably with the string 'escapeType'.
+   * @member opensocial.DataRequest.PeopleRequestFields
+   */
+   ESCAPE_TYPE : 'escapeType' 
 };
 
 
@@ -368,7 +385,11 @@
    * How to escape person data returned from the server; defaults to 
HTML_ESCAPE.
    * Possible values are defined by
    * <a href="opensocial.EscapeType.html">EscapeType</a>.
+   * Use of this function is deprecated in favor of using the
+   * <a href="#opensocial.DataRequest.PeopleRequestFields.ESCAPE_TYPE">
+   * ESCAPE_TYPE</a> request field.
    *
+   * @deprecated
    * @member opensocial.DataRequest.DataRequestFields
    */
   ESCAPE_TYPE : 'escapeType'
@@ -381,7 +402,11 @@
  * <a href="opensocial.DataRequest.PersonId.html">PersonId</a>,
  * Map&lt;String, String&gt;&gt; object.
  * All of the data values returned will be valid json.
+ * Use of this function is deprecated in favor of using the
+ * <a href="#opensocial.DataRequest.PeopleRequestFields.APP_DATA">APP_DATA</a>
+ * request field.
  *
+ * @deprecated
  * @param {opensocial.IdSpec} idSpec An IdSpec used to specify which people to
  *     fetch. See also <a href="opensocial.IdSpec.html">IdSpec</a>.
  * @param {Array.&lt;String&gt; | String} keys The keys you want data for; this
@@ -401,37 +426,34 @@
 
 
 /**
- * Creates an item to request an update of an app field for the given person.
+ * Creates an item to request an update of an app field for the current VIEWER
  * When processed, does not return any data.
- *
- * @param {String} id The ID of the person to update; only the
- *     special <code>VIEWER</code> ID is currently allowed.
+ * App Data is stored as a series of key value pairs of strings, scoped per
+ * person, per application. Containers supporting this request SHOULD provide
+ * at least 10KB of space per user per application for this data.
  * @param {String} key The name of the key. This may only contain alphanumeric
  *     (A-Za-z0-9) characters, underscore(_), dot(.) or dash(-).
  * @param {String} value The value, must be valid json
  * @return {Object} A request object
  */
-opensocial.DataRequest.prototype.newUpdatePersonAppDataRequest = function(id,
+opensocial.DataRequest.prototype.newUpdatePersonAppDataRequest = function(
     key, value) {
-  return opensocial.Container.get().newUpdatePersonAppDataRequest(id, key,
+  return opensocial.Container.get().newUpdatePersonAppDataRequest(key,
       value);
 };
 
 
 /**
- * Deletes the given keys from the datastore for the given person.
+ * Deletes the given keys from the datastore for the current VIEWER.
  * When processed, does not return any data.
  *
- * @param {String} id The ID of the person to update; only the
- *     special <code>VIEWER</code> ID is currently allowed.
  * @param {Array.&lt;String&gt; | String} keys The keys you want to delete from
  *     the datastore; this can be an array of key names, a single key name,
  *     or "*" to mean "all keys"
  * @return {Object} A request object
  */
-opensocial.DataRequest.prototype.newRemovePersonAppDataRequest = function(id,
-    keys) {
-  return opensocial.Container.get().newRemovePersonAppDataRequest(id, keys);
+opensocial.DataRequest.prototype.newRemovePersonAppDataRequest = 
function(keys) {
+  return opensocial.Container.get().newRemovePersonAppDataRequest(keys);
 };
 
 

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/person.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/person.js?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/person.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-reference/person.js
 Mon Mar 30 23:45:31 2009
@@ -554,6 +554,17 @@
 
 
 /**
+ * Gets the app data for this person that is associated with the specified
+ * key.
+ *
+ * @param {String} key The key to get app data for.
+ * @return {String} The corresponding app data.
+ */
+opensocial.Person.prototype.getAppData = function(key) {
+};
+
+
+/**
  * Returns true if this person object represents the currently logged in user.
  *
  * @return {Boolean} True if this is the currently logged in user;

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-rest/restfulcontainer.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-rest/restfulcontainer.js?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-rest/restfulcontainer.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-rest/restfulcontainer.js
 Mon Mar 30 23:45:31 2009
@@ -209,7 +209,7 @@
   var me = this;
   return new RestfulRequestItem(peopleRequest.url, peopleRequest.method, null,
       function(rawJson) {
-        return me.createPersonFromJson(rawJson['entry']);
+        return me.createPersonFromJson(rawJson['entry'], opt_params);
       });
 };
 
@@ -217,7 +217,9 @@
     opt_params) {
   var url = "/people/" + this.translateIdSpec(idSpec);
 
+  FieldTranslations.addAppDataAsProfileFields(opt_params);
   
FieldTranslations.translateJsPersonFieldsToServerFields(opt_params['profileDetail']);
+  
   url += "?fields=" + (opt_params['profileDetail'].join(','));
   url += "&startIndex=" + (opt_params['first'] || 0);
   url += "&count=" + (opt_params['max'] || 20);
@@ -240,15 +242,15 @@
 
         var people = [];
         for (var i = 0; i < jsonPeople.length; i++) {
-          people.push(me.createPersonFromJson(jsonPeople[i]));
+          people.push(me.createPersonFromJson(jsonPeople[i], opt_params));
         }
         return new opensocial.Collection(people,
             rawJson['startIndex'], rawJson['totalResults']);
       });
 };
 
-RestfulContainer.prototype.createPersonFromJson = function(serverJson) {
-  FieldTranslations.translateServerPersonToJsPerson(serverJson);
+RestfulContainer.prototype.createPersonFromJson = function(serverJson, 
opt_params) {
+  FieldTranslations.translateServerPersonToJsPerson(serverJson, opt_params);
   return new JsonPerson(serverJson);
 };
 
@@ -281,17 +283,17 @@
       });
 };
 
-RestfulContainer.prototype.newUpdatePersonAppDataRequest = function(id, key,
+RestfulContainer.prototype.newUpdatePersonAppDataRequest = function(key,
     value) {
-  var url = "/appdata/" + this.translateIdSpec(this.makeIdSpec(id))
+  var url = "/appdata/@viewer/@self"
       + "/@app?fields=" + key;
   var data = {};
   data[key] = value;
   return new RestfulRequestItem(url, "POST", data);
 };
 
-RestfulContainer.prototype.newRemovePersonAppDataRequest = function(id, keys) {
-  var url = "/appdata/" + this.translateIdSpec(this.makeIdSpec(id))
+RestfulContainer.prototype.newRemovePersonAppDataRequest = function(keys) {
+  var url = "/appdata/@viewer/@self"
       + "/@app?" + this.getFieldsList(keys);
   return new RestfulRequestItem(url, "DELETE");
 };

Modified: 
incubator/shindig/trunk/java/server/src/test/resources/endtoend/fetchPersonTest.xml
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/server/src/test/resources/endtoend/fetchPersonTest.xml?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/server/src/test/resources/endtoend/fetchPersonTest.xml
 (original)
+++ 
incubator/shindig/trunk/java/server/src/test/resources/endtoend/fetchPersonTest.xml
 Mon Mar 30 23:45:31 2009
@@ -125,9 +125,51 @@
 
             // Send the request
             req.send(receivedData);
-          }
-        };
+          },
+          
+          /** Test fetching app data */
+          fetchAppData: function() {
+            var req = opensocial.newDataRequest();
+
+            // Request the "canonical" viewer
+            req.add(req.newFetchPersonRequest("canonical",
+                {appData: '*'}), "canonical");
+
+            var receivedData = function(response) {
+              var user = getAndCheckError(response, "canonical");
+              assertEquals("Names don't match",
+                "Shin Digg", user.getDisplayName());
+              assertEquals("Wrong app data returned", "2", 
user.getAppData("count"));
+              assertEquals("Wrong app data returned", "100", 
user.getAppData("size"));
+              finished();
+            }
+
+            // Send the request
+            req.send(receivedData);
+          },
 
+          /** Test fetching app data via the array */
+          fetchTwoProperties: function() {
+            var req = opensocial.newDataRequest();
+
+            // Request the "canonical" viewer
+            req.add(req.newFetchPersonRequest("canonical",
+                {appData: ['count', 'notThere']}), "canonical");
+
+            var receivedData = function(response) {
+              var user = getAndCheckError(response, "canonical");
+              assertEquals("Names don't match",
+                "Shin Digg", user.getDisplayName());
+              assertEquals("Wrong app data returned", "2", 
user.getAppData("count"));
+              assertEquals("Too much app data returned", undefined, 
user.getAppData("size"));
+              assertEquals("App data that shouldn't exist returned", 
undefined, user.getAppData("notThere"));
+              finished();
+            }
+
+            // Send the request
+            req.send(receivedData);
+          },
+        };
 
         function getAndCheckError(response, key) {
           assertFalse("Data error", response.hadError());

Modified: 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/model/PersonImpl.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/model/PersonImpl.java?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/model/PersonImpl.java
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/model/PersonImpl.java
 Mon Mar 30 23:45:31 2009
@@ -35,6 +35,7 @@
 
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Default Implementation of the Person object in the model.
@@ -45,6 +46,7 @@
   private List<String> activities;
   private List<Address> addresses;
   private Integer age;
+  private Map<String, ? extends Object> appData;
   private Date birthday;
   private BodyType bodyType;
   private List<String> books;
@@ -158,6 +160,14 @@
     this.age = age;
   }
 
+  public Map<String, ? extends Object> getAppData() {
+    return this.appData;
+  }
+  
+  public void setAppData(Map<String, ? extends Object> appData) {
+    this.appData = appData;
+  }
+
   public BodyType getBodyType() {
     return bodyType;
   }
@@ -611,8 +621,7 @@
   public void setIsViewer(boolean isViewer) {
     this.isViewer = isViewer;
   }
-
-
+  
   // Proxied fields
 
   public String getProfileUrl() {

Modified: 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/Person.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/Person.java?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/Person.java
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/Person.java
 Mon Mar 30 23:45:31 2009
@@ -79,7 +79,7 @@
   }
 
   /**
-   * The fields that represent the person object ion json form.
+   * The fields that represent the person object in json form.
    */
   public static enum Field {
     /** the json field for aboutMe. */
@@ -92,6 +92,8 @@
     ADDRESSES("addresses"),
     /** the json field for age. */
     AGE("age"),
+    /** the json field for appData. */
+    APP_DATA("appData"),
     /** the json field for bodyType. */
     BODY_TYPE("bodyType"),
     /** the json field for books. */
@@ -336,6 +338,20 @@
   void setAge(Integer age);
 
   /**
+   * Get app data for the person.
+   * 
+   * @return the app data, possibly a subset.
+   */
+  Map<String, ? extends Object> getAppData();
+  
+  /**
+   * Sets app data for the person.
+   * 
+   * @param appData the app data, possibly a subset 
+   */
+  void setAppData(Map<String, ? extends Object> appData);
+
+  /**
    * Get the person's date of birth, specified as a {...@link Date} object. 
Container support for this
    * field is OPTIONAL.
    *
@@ -1201,5 +1217,4 @@
    * @param thumbnailUrl the person's photo thumbnail URL
    */
   void setThumbnailUrl(String thumbnailUrl);
-
 }

Modified: 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialService.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialService.java?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialService.java
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialService.java
 Mon Mar 30 23:45:31 2009
@@ -262,8 +262,14 @@
         if (!idSet.contains(person.get(Person.Field.ID.toString()))) {
           continue;
         }
+
         // Add group support later
-        result.add(filterFields(person, fields, Person.class));
+        Person personObj = filterFields(person, fields, Person.class);
+        Map<String, Object> appData = getPersonAppData(
+            person.getString(Person.Field.ID.toString()), fields);
+        personObj.setAppData(appData);
+
+        result.add(personObj);
       }
 
       if (GroupId.Type.self == groupId.getType() && result.isEmpty()) {
@@ -302,7 +308,12 @@
         JSONObject person = people.getJSONObject(i);
         if (id != null && person.get(Person.Field.ID.toString())
             .equals(id.getUserId(token))) {
-          return ImmediateFuture.newInstance(filterFields(person, fields, 
Person.class));
+          Person personObj = filterFields(person, fields, Person.class);
+          Map<String, Object> appData = getPersonAppData(
+              person.getString(Person.Field.ID.toString()), fields);
+          personObj.setAppData(appData);
+          
+          return ImmediateFuture.newInstance(personObj);
         }
       }
       throw new SocialSpiException(ResponseError.BAD_REQUEST, "Person not 
found");
@@ -311,6 +322,42 @@
     }
   }
 
+  private Map<String, Object> getPersonAppData(String id, Set<String> fields) {
+    try {
+      Map<String, Object> appData = null;
+      JSONObject personData = db.getJSONObject(DATA_TABLE).optJSONObject(id);
+      if (personData != null) {
+        if (fields.contains(Person.Field.APP_DATA.toString())) {
+            appData = Maps.newHashMap();
+            @SuppressWarnings("unchecked")
+            Iterator<String> keys = personData.keys();
+            while (keys.hasNext()) {
+              String key = keys.next();
+              appData.put(key, personData.get(key));
+            }
+        } else {
+          String appDataPrefix = Person.Field.APP_DATA.toString() + ".";
+          for (String field : fields) {
+            if (field.startsWith(appDataPrefix)) {
+              if (appData == null) {
+                appData = Maps.newHashMap();
+              }
+              
+              String appDataField = field.substring(appDataPrefix.length());
+              if (personData.has(appDataField)) {
+                appData.put(appDataField, personData.get(appDataField));
+              }
+            }
+          }
+        }
+      }
+    
+      return appData;
+    } catch (JSONException je) {
+      throw new SocialSpiException(ResponseError.INTERNAL_ERROR, 
je.getMessage(), je);
+    }
+  }
+
   public Future<DataCollection> getPersonData(Set<UserId> userIds, GroupId 
groupId,
       String appId, Set<String> fields, SecurityToken token) throws 
SocialSpiException {
     try {

Modified: 
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialServiceTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialServiceTest.java?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialServiceTest.java
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/sample/spi/JsonDbOpensocialServiceTest.java
 Mon Mar 30 23:45:31 2009
@@ -83,6 +83,38 @@
     assertNotNull("Canonical user not found", person);
   }
 
+  public void testGetPersonAllAppData() throws Exception {
+    Person person = db
+        .getPerson(CANON_USER, ImmutableSet.of("id", "appData"), token).get();
+
+    assertNotNull("Canonical user not found", person);
+    assertEquals("Canonical user has wrong id", "canonical", person.getId());
+    assertEquals("Canonical user has wrong app data",
+        ImmutableMap.of("count", "2", "size", "100"), person.getAppData());
+  }
+
+  public void testGetPersonOneAppDataField() throws Exception {
+    Person person = db
+        .getPerson(CANON_USER, ImmutableSet.of("id", "appData.size"), 
token).get();
+
+    assertNotNull("Canonical user not found", person);
+    assertEquals("Canonical user has wrong id", "canonical", person.getId());
+    assertEquals("Canonical user has wrong app data",
+        ImmutableMap.of("size", "100"), person.getAppData());
+  }
+
+  public void testGetPersonMultipleAppDataFields() throws Exception {
+    Person person = db
+        .getPerson(CANON_USER,
+            ImmutableSet.of("id", "appData.size", "appData.count", 
"appData.bogus"),
+            token).get();
+
+    assertNotNull("Canonical user not found", person);
+    assertEquals("Canonical user has wrong id", "canonical", person.getId());
+    assertEquals("Canonical user has wrong app data",
+        ImmutableMap.of("count", "2", "size", "100"), person.getAppData());
+  }
+
   public void testGetExpectedFriends() throws Exception {
     CollectionOptions options = new CollectionOptions();
     options.setSortBy(PersonService.TOP_FRIENDS_SORT);

Modified: 
incubator/shindig/trunk/java/social-api/src/test/resources/org/apache/shindig/social/opensocial/util/opensocial.xsd
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/resources/org/apache/shindig/social/opensocial/util/opensocial.xsd?rev=760259&r1=760258&r2=760259&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/test/resources/org/apache/shindig/social/opensocial/util/opensocial.xsd
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/test/resources/org/apache/shindig/social/opensocial/util/opensocial.xsd
 Mon Mar 30 23:45:31 2009
@@ -82,6 +82,7 @@
       <xs:element minOccurs="0" maxOccurs="unbounded" name="addresses" 
type="tns:Address" />
       <xs:element minOccurs="0" name="age" type="xs:string"/>
       <xs:element minOccurs="0" name="anniversary" type="xs:dateTime" />
+      <xs:element minOccurs="0" name="appData" type="tns:Appdata"/>
       <xs:element minOccurs="0" name="birthday" type="xs:dateTime" />
       <xs:element minOccurs="0" name="bodyType" type="tns:BodyType" />
       <xs:element minOccurs="0" maxOccurs="unbounded" name="books" 
type="xs:string" />


Reply via email to