You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by do...@apache.org on 2008/05/23 18:43:07 UTC

svn commit: r659590 - in /incubator/shindig/trunk: features/opensocial-current/ java/social-api/src/main/java/org/apache/shindig/social/abdera/ java/social-api/src/main/java/org/apache/shindig/social/abdera/json/ java/social-api/src/main/java/org/apach...

Author: doll
Date: Fri May 23 09:43:06 2008
New Revision: 659590

URL: http://svn.apache.org/viewvc?rev=659590&view=rev
Log:
Converted the old-style DataServiceAdapter to the new DataAdapter class. Deleted the RestServerCollectionAdapter as this was the last old usage. Added tests and fixed the javascript to work with the new data adapter. 

This required some ugliness in JSONFilter as Maps aren't really a supported concept in Abdera. Hopefully we can fix this once Abdera lets us append arbitrary pojos to the response. 

For json, we are now serving up compliant get responses to the three sets of basic urls (ie no st nor pagination yet)



Added:
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/DataAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java
Removed:
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/DataServiceAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RestServerCollectionAdapter.java
Modified:
    incubator/shindig/trunk/features/opensocial-current/restfulcontainer.js
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulJsonDataTest.java

Modified: incubator/shindig/trunk/features/opensocial-current/restfulcontainer.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/opensocial-current/restfulcontainer.js?rev=659590&r1=659589&r2=659590&view=diff
==============================================================================
--- incubator/shindig/trunk/features/opensocial-current/restfulcontainer.js (original)
+++ incubator/shindig/trunk/features/opensocial-current/restfulcontainer.js Fri May 23 09:43:06 2008
@@ -184,7 +184,7 @@
        + "?fields=" + keys.join(',');
   return new RestfulRequestItem(url, "GET", null,
       function (appData) {
-        return gadgets.util.escape(appData[0], true);
+        return gadgets.util.escape(appData['entry'], true);
       });
 };
 

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/DataAdapter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/DataAdapter.java?rev=659590&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/DataAdapter.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/DataAdapter.java Fri May 23 09:43:06 2008
@@ -0,0 +1,163 @@
+package org.apache.shindig.social.abdera;
+
+import org.apache.shindig.social.opensocial.DataService;
+import org.apache.shindig.social.opensocial.model.DataCollection;
+import org.apache.shindig.social.opensocial.model.DataCollection.Data;
+
+import com.google.inject.Inject;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.context.ResponseContextException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * This adapter translates abdera requests into calls to the DataService.
+ * It both fetches and updates Data.
+ * TODO: I'm not sure all of this hoisting is right.
+ */
+public class DataAdapter extends AbstractSocialEntityCollectionAdapter<Data> {
+  private static Logger logger = Logger
+      .getLogger(DataAdapter.class.getName());
+
+  private DataService dataService;
+
+  @Inject
+  public DataAdapter(DataService dataService) {
+    this.dataService = dataService;
+  }
+
+  @Override
+  public Data getEntry(String resourceName,
+      RequestContext request) throws ResponseContextException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public String getId(Data entry) throws ResponseContextException {
+    return entry.getPersonId();
+  }
+
+  @Override
+  public String getName(Data entry)
+      throws ResponseContextException {
+    return entry.getPersonId();
+  }
+
+  @Override
+  public String getTitle(Data entry)
+      throws ResponseContextException {
+    return entry.getPersonId();
+  }
+
+  @Override
+  public Date getUpdated(Data entry)
+      throws ResponseContextException {
+    return new Date();
+  }
+
+  @Override
+  public String getSummary(Data entry)
+      throws ResponseContextException {
+    return entry.getPersonId();
+  }
+
+  /**
+   * Query the underlying model for the list of data objects.
+   *
+   * There is some logic to handle some request dispatching here since this
+   * adapter handles the getFeed method for three Data collections:
+   * APPDATA_OF_APP_OF_USER, APPDATA_OF_FRIENDS_OF_USER
+   *
+   * @param request RequestContext
+   * @return A List Person entities.
+   */
+  @Override
+  public DataCollection getEntries(RequestContext request)
+      throws ResponseContextException {
+    String uid = request.getTarget().getParameter("uid");
+    List<String> ids = new ArrayList<String>();
+    switch (getUrlTemplate(request)) {
+      case APPDATA_OF_APP_OF_USER :
+        ids.add(uid);
+        break;
+      case APPDATA_OF_FRIENDS_OF_USER :
+        ids = getFriendIds(request, uid);
+        break;
+      default:
+        throw new UnsupportedOperationException(
+            "The person adpater was reached with an unsupported url");
+    }
+    return new DataCollection(dataService.getPersonData(ids, getKeys(request),
+        getSecurityToken(request, uid)).getResponse());
+  }
+
+  private List<String> getKeys(RequestContext request) {
+    String fields = request.getTarget().getParameter("fields");
+    if (fields == null) {
+      return new ArrayList<String>();
+    }
+    String[] keyArray = fields.split(",");
+    return Arrays.asList(keyArray);
+  }
+
+  @Override
+  public Data postEntry(String title, IRI id,
+      String summary, Date updated,
+      List<org.apache.abdera.model.Person> authors, Content content,
+      RequestContext request) throws ResponseContextException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void putEntry(Data data,
+      String title, Date updated, List<org.apache.abdera.model.Person> authors,
+      String summary, Content content, RequestContext request)
+      throws ResponseContextException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void deleteEntry(String resourceName, RequestContext request)
+      throws ResponseContextException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * Collection-level hoisting rules
+   */
+
+  /**
+   * The collection-level URL. Calls the getFeedIriForEntry and nulls "pid".
+   *
+   * @param request RequestContext
+   * @return The absolute request URI (includes server name, port, etc) URL
+   */
+  @Override
+  public String getHref(RequestContext request) {
+    return getFeedIriForEntry(request, "pid");
+  }
+
+  @Override
+  public String getId(RequestContext request) {
+    // TODO: what really to return for the feed ID? Better data will help.
+    return getHref(request);
+  }
+
+  public String getTitle(RequestContext request) {
+    return getRoute(request).getName();
+  }
+
+  // hoisting rule: atom:entry/atom:author/atom:uri aliases ?
+  @Override
+  public String getAuthor(RequestContext request)
+      throws ResponseContextException {
+    return request.getTarget().getParameter("uid");
+  }
+
+}

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java?rev=659590&r1=659589&r2=659590&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java Fri May 23 09:43:06 2008
@@ -29,13 +29,13 @@
   private static final String BASE = "/social/rest/";
 
   private PersonAdapter personAdapter;
-  private DataServiceAdapter dataAdapter;
+  private DataAdapter dataAdapter;
   private ActivityAdapter activityAdapter;
 
   @Inject
   public void setAdapters(
       PersonAdapter personAdapter,
-      DataServiceAdapter dataAdapter,
+      DataAdapter dataAdapter,
       ActivityAdapter activityAdapter) {
     this.personAdapter = personAdapter;
     this.dataAdapter = dataAdapter;
@@ -79,8 +79,9 @@
             TargetType.TYPE_COLLECTION, dataAdapter)
         ;
 
-    addFilter(new JSONFilter());
     addFilter(new ValidRequestFilter());
+    // JsonFilter should always be the last class in the chain of filters
+    addFilter(new JSONFilter());
     targetBuilder = routeManager;
     targetResolver = routeManager;
   }

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java?rev=659590&r1=659589&r2=659590&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java Fri May 23 09:43:06 2008
@@ -17,8 +17,10 @@
 */
 package org.apache.shindig.social.abdera.json;
 
-import org.apache.shindig.social.abdera.util.ValidRequestFilter.Format;
+import org.apache.shindig.social.abdera.AbstractSocialEntityCollectionAdapter;
+import org.apache.shindig.social.abdera.RequestUrlTemplate;
 import org.apache.shindig.social.abdera.util.ValidRequestFilter;
+import org.apache.shindig.social.abdera.util.ValidRequestFilter.Format;
 
 import org.apache.abdera.Abdera;
 import org.apache.abdera.model.Document;
@@ -65,14 +67,17 @@
       return resp;
     }
 
-    return new JsonResponseContext(resp, request.getAbdera());
+    return new JsonResponseContext(resp, request.getAbdera(), request);
   }
 
   private class JsonResponseContext extends ResponseContextWrapper {
     private final Abdera abdera;
+    private final RequestContext request;
 
-    public JsonResponseContext(ResponseContext response, Abdera abdera) {
+    public JsonResponseContext(ResponseContext response, Abdera abdera,
+        RequestContext request) {
       super(response);
+      this.request = request;
       setContentType("application/json");
       this.abdera = abdera;
     }
@@ -121,18 +126,20 @@
         JSONObject json = new JSONObject();
 
         try {
-          // TODO: Add the top level items for real
-          json.put("startIndex", 0);
-          json.put("totalResults", entries.size());
-
-          JSONArray jsonArray = new JSONArray();
-          for (Entry entry : feed.getEntries()) {
-            String contentValue = entry.getContentElement().getValue();
-            JSONObject jsonItem = new JSONObject(contentValue);
-            jsonArray.put(jsonItem);
-          }
-          json.put("entry", jsonArray);
+          RequestUrlTemplate url = AbstractSocialEntityCollectionAdapter
+              .getUrlTemplate(request);
 
+          // If the type of object is Data, then we want to create a JSONObject
+          // instead of a JSONArray
+          // TODO: This is another messy thing to clean up...
+          switch (url) {
+            case APPDATA_OF_APP_OF_USER :
+            case APPDATA_OF_FRIENDS_OF_USER :
+              createDataMapping(json, feed.getEntries());
+              break;
+            default :
+              createJsonArray(json, entries);
+          }
         } catch (JSONException e) {
           throw new RuntimeException(
               "The atom Document could not be converted to JSON", e);
@@ -144,5 +151,33 @@
       throw new UnsupportedOperationException("Converting a non-Entry "
           + "non-Feed abdera Document to JSON is not supported");
     }
+
+    private void createDataMapping(JSONObject json, List<Entry> entries)
+        throws JSONException {
+      JSONObject jsonObject = new JSONObject();
+      for (Entry entry : entries) {
+        String contentValue = entry.getContentElement().getValue();
+        JSONObject jsonItem = new JSONObject(contentValue);
+
+        jsonObject.put(jsonItem.getString("personId"),
+            jsonItem.getJSONObject("appdata"));
+      }
+      json.put("entry", jsonObject);
+    }
+
+    private void createJsonArray(JSONObject json, List<Entry> entries)
+        throws JSONException {
+      // TODO: Add the top level items for real
+      json.put("startIndex", 0);
+      json.put("totalResults", entries.size());
+
+      JSONArray jsonArray = new JSONArray();
+      for (Entry entry : entries) {
+        String contentValue = entry.getContentElement().getValue();
+        JSONObject jsonItem = new JSONObject(contentValue);
+        jsonArray.put(jsonItem);
+      }
+      json.put("entry", jsonArray);
+    }
   }
 }

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java?rev=659590&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java Fri May 23 09:43:06 2008
@@ -0,0 +1,58 @@
+package org.apache.shindig.social.opensocial.model;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.HashSet;
+
+public class DataCollection implements Iterable<DataCollection.Data> {
+  Set<Data> data;
+
+  // Legacy constructor. Remove once we fix the DataService api
+  public DataCollection(Map<String, Map<String, String>> data) {
+    this.data = new HashSet<Data>();
+    for (Map.Entry<String, Map<String, String>> entry : data.entrySet()) {
+      this.data.add(new Data(entry.getKey(), entry.getValue()));
+    }
+  }
+
+  public DataCollection(Set<Data> data) {
+    this.data = data;
+  }
+
+  public Set<Data> getData() {
+    return data;
+  }
+
+  public Iterator<Data> iterator() {
+    return data.iterator();
+  }
+
+  public Map<String, Map<String, String>> dataMap() {
+    Map<String, Map<String, String>> dataMap = new HashMap<String,
+        Map<String, String>>();
+    for (Data entry : data) {
+      dataMap.put(entry.getPersonId(), entry.getAppdata());
+    }
+    return dataMap;
+  }
+
+  public static class Data {
+    String personId;
+    Map<String, String> appdata;
+
+    public Data(String personId, Map<String, String> appdata) {
+      this.personId = personId;
+      this.appdata = appdata;
+    }
+
+    public String getPersonId() {
+      return personId;
+    }
+
+    public Map<String, String> getAppdata() {
+      return appdata;
+    }
+  }
+}

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulJsonDataTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulJsonDataTest.java?rev=659590&r1=659589&r2=659590&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulJsonDataTest.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulJsonDataTest.java Fri May 23 09:43:06 2008
@@ -17,6 +17,10 @@
  */
 package org.apache.shindig.social.abdera;
 
+import org.apache.shindig.social.SocialApiTestsGuiceModule.MockPeopleService;
+
+import static junit.framework.Assert.assertEquals;
+import org.json.JSONObject;
 import org.junit.Test;
 
 
@@ -38,8 +42,20 @@
   public void testGetFriendsAppDataJson() throws Exception {
     // app id is mocked out
     resp = client.get(BASEURL + "/appdata/john.doe/@friends/app?fields=count");
-    // checkForGoodJsonResponse(resp);
-    // JSONObject result = getJson(resp);
+    checkForGoodJsonResponse(resp);
+
+    JSONObject data = getJson(resp).getJSONObject("entry");
+    assertEquals(2, data.length());
+
+    JSONObject janesEntries = data.getJSONObject(
+        MockPeopleService.janeDoe.getId());
+    assertEquals(1, janesEntries.length());
+    assertEquals("5", janesEntries.getString("count"));
+
+    JSONObject simplesEntries = data.getJSONObject(
+        MockPeopleService.simpleDoe.getId());
+    assertEquals(1, simplesEntries.length());
+    assertEquals("7", simplesEntries.getString("count"));
   }
 
   /**
@@ -53,13 +69,18 @@
    *
    * @throws Exception if test encounters an error
    */
-   // TODO: Shindig currently throws an exception when no keys are specified
-   // @Test
+  @Test
   public void testGetSelfAppDataJson() throws Exception {
     // app id is mocked out
     resp = client.get(BASEURL + "/appdata/john.doe/@self/app");
-    // checkForGoodJsonResponse(resp);
-    // JSONObject result = getJson(resp);
+    checkForGoodJsonResponse(resp);
+    JSONObject data = getJson(resp).getJSONObject("entry");
+    assertEquals(1, data.length());
+
+    JSONObject johnsEntries = data.getJSONObject(
+        MockPeopleService.johnDoe.getId());
+    assertEquals(1, johnsEntries.length());
+    assertEquals("0", johnsEntries.getString("count"));
   }
 
   /**
@@ -77,8 +98,15 @@
   public void testGetSelfAppDataJsonWithKey() throws Exception {
     // app id is mocked out
     resp = client.get(BASEURL + "/appdata/john.doe/@self/app?fields=count");
-    // checkForGoodJsonResponse(resp);
-    // JSONObject result = getJson(resp);
+    checkForGoodJsonResponse(resp);
+
+    JSONObject data = getJson(resp).getJSONObject("entry");
+    assertEquals(1, data.length());
+
+    JSONObject johnsEntries = data.getJSONObject(
+        MockPeopleService.johnDoe.getId());
+    assertEquals(1, johnsEntries.length());
+    assertEquals("0", johnsEntries.getString("count"));
   }
 
   /**
@@ -94,11 +122,17 @@
    * @throws Exception if test encounters an error
    */
   @Test
-  public void testGetSelfAppDataJsonWithoutKeys() throws Exception {
+  public void testGetSelfAppDataJsonWithInvalidKeys() throws Exception {
     // app id is mocked out
     resp = client.get(BASEURL + "/appdata/john.doe/@self/app?fields=peabody");
-    // checkForGoodJsonResponse(resp);
-    // JSONObject result = getJson(resp);
+    checkForGoodJsonResponse(resp);
+
+    JSONObject data = getJson(resp).getJSONObject("entry");
+    assertEquals(1, data.length());
+
+    JSONObject johnsEntries = data.getJSONObject(
+        MockPeopleService.johnDoe.getId());
+    assertEquals(0, johnsEntries.length());
   }
 
   // TODO: support for indexBy??