You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by Cassie <do...@google.com> on 2008/07/08 02:38:49 UTC

Re: svn commit: r674686 - in /incubator/shindig/trunk: java/social-api/src/main/java/org/apache/shindig/social/canonical/ java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/ java/social-api/src/test/java/org/apache/shindig/socia

On Mon, Jul 7, 2008 at 5:22 PM, <lr...@apache.org> wrote:

> Author: lryan
> Date: Mon Jul  7 17:22:19 2008
> New Revision: 674686
>
> URL: http://svn.apache.org/viewvc?rev=674686&view=rev
> Log:
> Dataservice implementation backed by the canonical JSON file.
>
> Added:
>
>  incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JSONOpensocialService.java
>
>  incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JSONOpensocialServiceTest.java


Can we change the casing here to be "JsonOpenSocialService"?


>
> Modified:
>
>  incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/Person.java
>    incubator/shindig/trunk/javascript/sampledata/canonicaldb.json
>
> Added:
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JSONOpensocialService.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JSONOpensocialService.java?rev=674686&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JSONOpensocialService.java
> (added)
> +++
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JSONOpensocialService.java
> Mon Jul  7 17:22:19 2008
> @@ -0,0 +1,355 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License.  You may obtain a copy of the License at
> + *
> + *   http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied.  See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + */
> +package org.apache.shindig.social.canonical;
> +
> +import com.google.common.collect.Lists;
> +import com.google.common.collect.Maps;
> +import com.google.common.collect.Sets;
> +import com.google.inject.Inject;
> +import com.google.inject.name.Named;
> +
> +import org.apache.commons.io.IOUtils;
> +import org.apache.shindig.common.SecurityToken;
> +import org.apache.shindig.social.ResponseError;
> +import org.apache.shindig.social.ResponseItem;
> +import org.apache.shindig.social.dataservice.ActivityService;
> +import org.apache.shindig.social.dataservice.AppDataService;
> +import org.apache.shindig.social.dataservice.DataCollection;
> +import org.apache.shindig.social.dataservice.GroupId;
> +import org.apache.shindig.social.dataservice.PersonService;
> +import org.apache.shindig.social.dataservice.RestfulCollection;
> +import org.apache.shindig.social.dataservice.UserId;
> +import org.apache.shindig.social.opensocial.model.Activity;
> +import org.apache.shindig.social.opensocial.model.Person;
> +import org.apache.shindig.social.opensocial.util.BeanConverter;
> +import org.json.JSONArray;
> +import org.json.JSONException;
> +import org.json.JSONObject;
> +
> +import java.util.Iterator;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.Set;
> +
> +/**
> + * Implementation of supported services backed by a JSON DB
> + */
> +public class JSONOpensocialService implements ActivityService,
> PersonService, AppDataService {
> +
> +  /**
> +   * The DB
> +   */
> +  private JSONObject db;
> +
> +  /**
> +   * The JSON<->Bean converter
> +   */
> +  private BeanConverter converter;
> +
> +  /**
> +   * db["activities"] -> Array<Person>
> +   */
> +  private static final String PEOPLE_TABLE = "people";
> +
> +  /**
> +   * db["people"] -> Map<Person.Id, Array<Activity>>
> +   */
> +  private static final String ACTIVITIES_TABLE = "activities";
> +
> +  /**
> +   * db["data"] -> Map<Person.Id, Map<String, String>>
> +   */
> +  private static final String DATA_TABLE = "data";
> +
> +  /**
> +   * db["friendLinks"] -> Map<Person.Id, Array<Person.Id>>
> +   */
> +  private static final String FRIEND_LINK_TABLE = "friendLinks";
> +
> +  @Inject
> +  public JSONOpensocialService(@Named("canonical.json.db")String
> jsonLocation,
> +      BeanConverter converter) throws Exception {
> +    String content = IOUtils.toString(new
> java.net.URL(jsonLocation).openStream(), "UTF-8");
> +    this.db = new JSONObject(content);
> +    this.converter = converter;
> +  }
> +
> +  public ResponseItem<RestfulCollection<Activity>> getActivities(UserId
> userId, GroupId groupId,
> +      String appId, Set<String> fields, SecurityToken token) {
> +    List<Activity> result = Lists.newArrayList();
> +    try {
> +      // TODO Is it really valid to read activities across multiple users
> in one rpc?
> +      Set<String> idSet = getIdSet(userId, groupId, token);
> +      for (String id : idSet) {
> +        if (db.getJSONObject(ACTIVITIES_TABLE).has(id)) {
> +          JSONArray activities =
> db.getJSONObject(ACTIVITIES_TABLE).getJSONArray(id);
> +          for (int i = 0; i < activities.length(); i++) {
> +            JSONObject activity = activities.getJSONObject(i);
> +            if (appId != null &&
> activity.get(Activity.Field.APP_ID.toString()).equals(appId)) {
> +              result.add(convertToActivity(activity, fields));
> +            }
> +          }
> +        }
> +      }
> +      return new ResponseItem<RestfulCollection<Activity>>(new
> RestfulCollection<Activity>(result));
> +    } catch (JSONException je) {
> +      return new
> ResponseItem<RestfulCollection<Activity>>(ResponseError.INTERNAL_ERROR,
> +          je.getMessage(), null);
> +    }
> +  }
> +
> +  public ResponseItem<Activity> getActivity(UserId userId, GroupId
> groupId, String appId,
> +      Set<String> fields, String activityId, SecurityToken token) {
> +    try {
> +      if (db.getJSONObject(ACTIVITIES_TABLE).has(userId.getUserId(token)))
> {
> +        JSONArray activities =
> db.getJSONObject(ACTIVITIES_TABLE).getJSONArray(userId.getUserId(token));
> +        for (int i = 0; i < activities.length(); i++) {
> +          JSONObject activity = activities.getJSONObject(i);
> +          if (userId != null &&
> activity.get(Activity.Field.USER_ID.toString())
> +              .equals(userId.getUserId(token)) &&
> +
>  activity.get(Activity.Field.ID.toString()).equals(activityId)) {
> +            return new ResponseItem<Activity>(convertToActivity(activity,
> fields));
> +          }
> +        }
> +      }
> +      return null;
> +    } catch (JSONException je) {
> +      return new ResponseItem<Activity>(ResponseError.INTERNAL_ERROR,
> je.getMessage(), null);
> +    }
> +  }
> +
> +  public ResponseItem deleteActivity(UserId userId, GroupId groupId,
> String appId,
> +      String activityId, SecurityToken token) {
> +    try {
> +      if (db.getJSONObject(ACTIVITIES_TABLE).has(userId.getUserId(token)))
> {
> +        JSONArray activities =
> db.getJSONObject(ACTIVITIES_TABLE).getJSONArray(userId.getUserId(token));
> +        if (activities != null) {
> +          JSONArray newList = new JSONArray();
> +          for (int i = 0; i < activities.length(); i++) {
> +            JSONObject activity = activities.getJSONObject(i);
> +            if
> (!activity.get(Activity.Field.ID.toString()).equals(activityId)) {
> +              newList.put(activity);
> +            }
> +          }
> +          db.getJSONObject(ACTIVITIES_TABLE).put(userId.getUserId(token),
> newList);
> +          // TODO. This seems very odd that we return no useful response
> in this case
> +          // There is no way to represent not-found
> +          // if (found) { ??
> +          //}
> +        }
> +      }
> +      // What is the appropriate response here??
> +      return new ResponseItem<Object>(null);
> +    } catch (JSONException je) {
> +      return new ResponseItem<Object>(ResponseError.INTERNAL_ERROR,
> je.getMessage(), null);
> +    }
> +  }
> +
> +  public ResponseItem createActivity(UserId userId, GroupId groupId,
> String appId,
> +      Set<String> fields, Activity activity, SecurityToken token) {
> +    // Are fields really needed here?
> +    try {
> +      JSONObject jsonObject = convertFromActivity(activity, fields);
> +      if (!jsonObject.has(Activity.Field.ID.toString())) {
> +        jsonObject.put(Activity.Field.ID.toString(),
> System.currentTimeMillis());
> +      }
> +      JSONArray jsonArray =
> db.getJSONObject(ACTIVITIES_TABLE).getJSONArray(userId.getUserId(token));
> +      if (jsonArray == null) {
> +        jsonArray = new JSONArray();
> +        db.getJSONObject(ACTIVITIES_TABLE).put(userId.getUserId(token),
> jsonArray);
> +      }
> +      jsonArray.put(jsonObject);
> +      // TODO ??
> +      return null;
> +    } catch (JSONException je) {
> +      return new ResponseItem<Object>(ResponseError.INTERNAL_ERROR,
> je.getMessage(), null);
> +    }
> +  }
> +
> +  public ResponseItem<RestfulCollection<Person>> getPeople(UserId userId,
> GroupId groupId,
> +      SortOrder sortOrder, FilterType filter, int first, int max,
> +      Set<String> fields, SecurityToken token) {
> +    List<Person> result = Lists.newArrayList();
> +    try {
> +      JSONArray people = db.getJSONArray(PEOPLE_TABLE);
> +
> +      Set<String> idSet = getIdSet(userId, groupId, token);
> +
> +      for (int i = 0; i < people.length(); i++) {
> +        JSONObject person = people.getJSONObject(i);
> +        if (!idSet.contains(person.get(Person.Field.ID.toString()))) {
> +          continue;
> +        }
> +        // Add group support later
> +        result.add(convertToPerson(person, fields));
> +      }
> +      return new ResponseItem<RestfulCollection<Person>>(new
> RestfulCollection<Person>(result));
> +    } catch (JSONException je) {
> +      return new
> ResponseItem<RestfulCollection<Person>>(ResponseError.INTERNAL_ERROR,
> +          je.getMessage(), null);
> +    }
> +  }
> +
> +  public ResponseItem<Person> getPerson(UserId id, Set<String> fields,
> SecurityToken token) {
> +    try {
> +      JSONArray people = db.getJSONArray(PEOPLE_TABLE);
> +
> +      for (int i = 0; i < people.length(); i++) {
> +        JSONObject person = people.getJSONObject(i);
> +        if (id != null && person.get(Person.Field.ID.toString())
> +            .equals(id.getUserId(token))) {
> +          return new ResponseItem<Person>(convertToPerson(person,
> fields));
> +        }
> +      }
> +      // TODO What does this mean?
> +      return null;
> +    } catch (JSONException je) {
> +      return new ResponseItem<Person>(ResponseError.INTERNAL_ERROR,
> je.getMessage(), null);
> +    }
> +  }
> +
> +  public ResponseItem<DataCollection> getPersonData(UserId userId, GroupId
> groupId, String appId,
> +      Set<String> fields, SecurityToken token) {
> +    // TODO. Does fields==null imply all?
> +    try {
> +      Map<String, Map<String, String>> idToData = Maps.newHashMap();
> +      Set<String> idSet = getIdSet(userId, groupId, token);
> +      for (String id : idSet) {
> +        JSONObject personData;
> +        if (!db.getJSONObject(DATA_TABLE).has(id)) {
> +          personData = new JSONObject();
> +        } else {
> +          if (fields != null) {
> +            personData = new JSONObject(
> +                db.getJSONObject(DATA_TABLE).getJSONObject(id),
> +                fields.toArray(new String[fields.size()]));
> +          } else {
> +            personData = db.getJSONObject(DATA_TABLE).getJSONObject(id);
> +          }
> +        }
> +
> +        Iterator keys = personData.keys();
> +        Map<String, String> data = Maps.newHashMap();
> +        while (keys.hasNext()) {
> +          String key = (String) keys.next();
> +          data.put(key, personData.getString(key));
> +        }
> +        idToData.put(id, data);
> +      }
> +      return new ResponseItem<DataCollection>(new
> DataCollection(idToData));
> +    } catch (JSONException je) {
> +      return new
> ResponseItem<DataCollection>(ResponseError.INTERNAL_ERROR, je.getMessage(),
> null);
> +    }
> +  }
> +
> +  public ResponseItem deletePersonData(UserId userId, GroupId groupId,
> String appId,
> +      Set<String> fields, SecurityToken token) {
> +    try {
> +      if (!db.getJSONObject(DATA_TABLE).has(userId.getUserId(token))) {
> +        return null;
> +      }
> +      JSONObject newPersonData = new JSONObject();
> +      JSONObject oldPersonData =
> db.getJSONObject(DATA_TABLE).getJSONObject(userId.getUserId(token));
> +      Iterator keys = oldPersonData.keys();
> +      while (keys.hasNext()) {
> +        String key = (String) keys.next();
> +        if (fields != null && !fields.contains(key)) {
> +          newPersonData.put(key, oldPersonData.getString(key));
> +        }
> +      }
> +      db.getJSONObject(DATA_TABLE).put(userId.getUserId(token),
> newPersonData);
> +      // TODO what is the appropriate return value
> +      return null;
> +    } catch (JSONException je) {
> +      return new ResponseItem<Object>(ResponseError.INTERNAL_ERROR,
> je.getMessage(), null);
> +    }
> +  }
> +
> +  public ResponseItem updatePersonData(UserId userId, GroupId groupId,
> String appId,
> +      Set<String> fields, Map<String, String> values, SecurityToken token)
> {
> +    // TODO this seems redundant. No need to pass both fields and a map of
> field->value
> +    try {
> +      JSONObject personData =
> db.getJSONObject(DATA_TABLE).getJSONObject(userId.getUserId(token));
> +      if (personData == null) {
> +        personData = new JSONObject();
> +        db.getJSONObject(DATA_TABLE).put(userId.getUserId(token),
> personData);
> +      }
> +
> +      for (Map.Entry<String, String> entry : values.entrySet()) {
> +        personData.put(entry.getKey(), entry.getValue());
> +      }
> +      // TODO what is the appropriate return value
> +      return null;
> +    } catch (JSONException je) {
> +      return new ResponseItem<Object>(ResponseError.INTERNAL_ERROR,
> je.getMessage(), null);
> +    }
> +  }
> +
> +  /**
> +   * Get the set of user id's from a user and group
> +   */
> +  private Set<String> getIdSet(UserId user, GroupId group, SecurityToken
> token)
> +      throws JSONException {
> +    String userId = user.getUserId(token);
> +
> +    if (group == null) {
> +      return Sets.newLinkedHashSet(userId);
> +    }
> +
> +    Set<String> returnVal = Sets.newLinkedHashSet();
> +    switch (group.getType()) {
> +      case all:
> +      case friends:
> +      case groupId:
> +        if (db.getJSONObject(FRIEND_LINK_TABLE).has(userId)) {
> +          JSONArray friends =
> db.getJSONObject(FRIEND_LINK_TABLE).getJSONArray(userId);
> +          for (int i = 0; i < friends.length(); i++) {
> +            returnVal.add(friends.getString(i));
> +          }
> +        }
> +        break;
> +      case self:
> +        returnVal.add(userId);
> +        break;
> +    }
> +    return returnVal;
> +  }
> +
> +  private Activity convertToActivity(JSONObject object, Set<String>
> fields) throws JSONException {
> +    if (fields != null && !fields.isEmpty()) {
> +      // Create a copy with just the specified fields
> +      object = new JSONObject(object, fields.toArray(new
> String[fields.size()]));
> +    }
> +    return converter.convertToObject(object.toString(), Activity.class);
> +  }
> +
> +  private JSONObject convertFromActivity(Activity activity, Set<String>
> fields)
> +      throws JSONException {
> +    // TODO Not using fields yet
> +    return new JSONObject(converter.convertToString(activity));
> +  }
> +
> +  private Person convertToPerson(JSONObject object, Set<String> fields)
> throws JSONException {
> +    if (fields != null && !fields.isEmpty()) {
> +      // Create a copy with just the specified fields
> +      object = new JSONObject(object, fields.toArray(new
> String[fields.size()]));
> +    }
> +    return converter.convertToObject(object.toString(), Person.class);
> +  }
> +}
>
> 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=674686&r1=674685&r2=674686&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 Jul  7 17:22:19 2008
> @@ -17,8 +17,11 @@
>  */
>  package org.apache.shindig.social.opensocial.model;
>
> -import java.util.List;
> +import org.apache.shindig.social.opensocial.util.EnumUtil;
> +
>  import java.util.Date;
> +import java.util.List;
> +import java.util.Set;
>
>  /**
>  * see
> @@ -87,6 +90,12 @@
>
>     private final String jsonString;
>
> +    public static final Set<String> DEFAULT_FIELDS =
> +        EnumUtil.getEnumStrings(ID, NAME, THUMBNAIL_URL);
> +
> +    public static final Set<String> ALL_FIELDS =
> +        EnumUtil.getEnumStrings(Field.values());
> +
>     private Field(String jsonString) {
>       this.jsonString = jsonString;
>     }
>
> Added:
> incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JSONOpensocialServiceTest.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JSONOpensocialServiceTest.java?rev=674686&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JSONOpensocialServiceTest.java
> (added)
> +++
> incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JSONOpensocialServiceTest.java
> Mon Jul  7 17:22:19 2008
> @@ -0,0 +1,164 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License.  You may obtain a copy of the License at
> + *
> + *   http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied.  See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + */
> +package org.apache.shindig.social.canonical;
> +
> +import com.google.common.collect.Maps;
> +import com.google.common.collect.Sets;
> +import com.google.inject.Guice;
> +
> +import junit.framework.TestCase;
> +
> +import org.apache.shindig.common.SecurityToken;
> +import org.apache.shindig.common.testing.FakeGadgetToken;
> +import org.apache.shindig.social.ResponseItem;
> +import org.apache.shindig.social.SocialApiTestsGuiceModule;
> +import org.apache.shindig.social.dataservice.DataCollection;
> +import org.apache.shindig.social.dataservice.GroupId;
> +import org.apache.shindig.social.dataservice.PersonService;
> +import org.apache.shindig.social.dataservice.RestfulCollection;
> +import org.apache.shindig.social.dataservice.UserId;
> +import org.apache.shindig.social.opensocial.model.Activity;
> +import org.apache.shindig.social.opensocial.model.Person;
> +import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
> +
> +/**
> + * Test the JSONOpensocialService
> + */
> +public class JSONOpensocialServiceTest extends TestCase {
> +
> +  private JSONOpensocialService db;
> +
> +  private static final UserId CANON_USER = new UserId(UserId.Type.userId,
> "canonical");
> +  private static final GroupId SELF_GROUP = new GroupId(GroupId.Type.self,
> null);
> +  private static final String APP_ID = "1";
> +
> +  private static final String CANONICAL_USER_ID = "canonical";
> +  private SecurityToken token = new FakeGadgetToken();
> +
> +
> +  @Override
> +  protected void setUp() throws Exception {
> +    BeanJsonConverter beanJsonConverter = new BeanJsonConverter(
> +        Guice.createInjector(new SocialApiTestsGuiceModule()));
> +    db = new JSONOpensocialService(
> +
>  "file:///home/lryan/shindig/trunk/javascript/sampledata/canonicaldb.json",
> +        beanJsonConverter);
> +  }
> +
> +  public void testGetPersonDefaultFields() throws Exception {
> +    ResponseItem<Person> personResponseItem = db
> +        .getPerson(CANON_USER, Person.Field.DEFAULT_FIELDS, token);
> +
> +    assertNotNull("Canonical user not found",
> personResponseItem.getResponse());
> +    assertNotNull("Canonical user has no id",
> personResponseItem.getResponse().getId());
> +    assertNotNull("Canonical user has no name",
> personResponseItem.getResponse().getName());
> +    assertNotNull("Canonical user has no thumbnail",
> +        personResponseItem.getResponse().getThumbnailUrl());
> +  }
> +
> +  public void testGetPersonAllFields() throws Exception {
> +    ResponseItem<Person> personResponseItem = db
> +        .getPerson(CANON_USER, Person.Field.ALL_FIELDS, token);
> +    assertNotNull("Canonical user not found",
> personResponseItem.getResponse());
> +  }
> +
> +  public void testGetExpectedFriends() throws Exception {
> +    ResponseItem<RestfulCollection<Person>> responseItem = db.getPeople(
> +        CANON_USER, new GroupId(GroupId.Type.friends, null),
> PersonService.SortOrder.topFriends,
> +        PersonService.FilterType.all, 0, Integer.MAX_VALUE, null, token);
> +    assertNotNull(responseItem.getResponse());
> +    assertEquals(responseItem.getResponse().getTotalResults(), 4);
> +    // Test a couple of users
> +    assertEquals(responseItem.getResponse().getEntry().get(0).getId(),
> "john.doe");
> +    assertEquals(responseItem.getResponse().getEntry().get(1).getId(),
> "jane.doe");
> +  }
> +
> +  public void testGetExpectedActivities() throws Exception {
> +    ResponseItem<RestfulCollection<Activity>> responseItem =
> db.getActivities(
> +        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken());
> +    assertTrue(responseItem.getResponse().getTotalResults() == 2);
> +  }
> +
> +  public void testGetExpectedActivity() throws Exception {
> +    ResponseItem<Activity> responseItem = db.getActivity(
> +        CANON_USER, SELF_GROUP, APP_ID,
> +        Sets.newHashSet("appId", "body", "mediaItems"), APP_ID, new
> FakeGadgetToken());
> +    assertTrue(responseItem != null);
> +    assertTrue(responseItem.getResponse() != null);
> +    // Check that some fields are fetched and others are not
> +    assertTrue(responseItem.getResponse().getBody() != null);
> +    assertTrue(responseItem.getResponse().getBodyId() == null);
> +  }
> +
> +  public void testDeleteExpectedActivity() throws Exception {
> +    db.deleteActivity(CANON_USER, SELF_GROUP, APP_ID, APP_ID,
> +        new FakeGadgetToken());
> +
> +    // Try to fetch the activity
> +    ResponseItem<Activity> responseItem = db.getActivity(
> +        CANON_USER, SELF_GROUP, APP_ID,
> +        Sets.newHashSet("appId", "body", "mediaItems"), APP_ID, new
> FakeGadgetToken());
> +    assertTrue(responseItem == null);
> +  }
> +
> +  public void testGetExpectedAppData() throws Exception {
> +    ResponseItem<DataCollection> responseItem = db.getPersonData(
> +        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken());
> +    assertTrue(!responseItem.getResponse().getEntry().isEmpty());
> +
>  assertTrue(!responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).isEmpty());
> +
>  assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).size()
> == 2);
> +
>  assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).containsKey("count"));
> +
>  assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).containsKey("size"));
> +  }
> +
> +  public void testDeleteExpectedAppData() throws Exception {
> +    // Delete the data
> +    db.deletePersonData(CANON_USER, SELF_GROUP, APP_ID,
> +        Sets.newHashSet("count"), new FakeGadgetToken());
> +
> +    //Fetch the remaining and test
> +    ResponseItem<DataCollection> responseItem = db.getPersonData(
> +        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken());
> +    assertTrue(!responseItem.getResponse().getEntry().isEmpty());
> +
>  assertTrue(!responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).isEmpty());
> +
>  assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).size()
> == 1);
> +
>  assertTrue(!responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).containsKey("count"));
> +
>  assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).containsKey("size"));
> +  }
> +
> +  public void testUpdateExpectedAppData() throws Exception {
> +    // Delete the data
> +    db.updatePersonData(CANON_USER, SELF_GROUP, APP_ID,
> +        null, Maps.immutableMap("count", "10", "newvalue", "20"), new
> FakeGadgetToken());
> +
> +    //Fetch the remaining and test
> +    ResponseItem<DataCollection> responseItem = db.getPersonData(
> +        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken());
> +    assertTrue(!responseItem.getResponse().getEntry().isEmpty());
> +
>  assertTrue(!responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).isEmpty());
> +
>  assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).size()
> == 3);
> +
>  assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).containsKey("count"));
> +    assertTrue(
> +
>  responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).get("count").equals("10"));
> +    assertTrue(
> +
>  responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).containsKey("newvalue"));
> +    assertTrue(
> +
>  responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).get("newvalue").equals("20"));
> +  }
> +}
>
> Modified: incubator/shindig/trunk/javascript/sampledata/canonicaldb.json
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/javascript/sampledata/canonicaldb.json?rev=674686&r1=674685&r2=674686&view=diff
>
> ==============================================================================
> --- incubator/shindig/trunk/javascript/sampledata/canonicaldb.json
> (original)
> +++ incubator/shindig/trunk/javascript/sampledata/canonicaldb.json Mon Jul
>  7 17:22:19 2008
> @@ -10,8 +10,8 @@
>  //
>  //  Notes:
>  //   - The structure of Person, Activity MUST! match those in the RESTful
> spec
> -//   - Data for "canonical" user should exercise every field in the spec.
> And is relied on for unit-testing
> -//     so change at your peril
> +//   - Data for "canonical" user should exercise every field in the spec.
> And is relied on
> +//     for unit-testing so change at your peril
>  //   - Consider adding a structure for Map<Person.Id, Array<appId>> to
> represent installed gadgets
>  //
>  //  TODO:
> @@ -175,7 +175,10 @@
>   },
>   {
>     "id" : "john.doe",
> -    "gender" : "M",
> +    "gender" : {
> +      "key" : "MALE",
> +      "displayvalue" : "Male"
> +    },
>     "hasApp" : true,
>     "name" : {
>       "familyName" : "Doe",
> @@ -185,7 +188,10 @@
>   },
>   {
>     "id" : "jane.doe",
> -    "gender" : "F",
> +    "gender" : {
> +      "key" : "FEMALE",
> +      "displayvalue" : "Female"
> +    },
>     "hasApp" : true,
>     "name" : {
>       "familyName" : "Doe",
> @@ -195,7 +201,10 @@
>   },
>   {
>     "id" : "george.doe",
> -    "gender" : "M",
> +    "gender" : {
> +      "key" : "MALE",
> +      "displayvalue" : "Female"
> +    },
>     "hasApp" : true,
>     "name" : {
>       "familyName" : "Doe",
> @@ -205,7 +214,10 @@
>   },
>   {
>     "id" : "mario.rossi",
> -    "gender" : "M",
> +    "gender" : {
> +      "key" : "MALE",
> +      "displayvalue" : "Male"
> +    },
>     "hasApp" : true,
>     "name" : {
>       "familyName" : "Rossi",
> @@ -215,7 +227,10 @@
>   },
>   {
>     "id" : "maija.m",
> -    "gender" : "F",
> +    "gender" : {
> +      "key" : "FEMALE",
> +      "displayvalue" : "Female"
> +    },
>     "hasApp" : true,
>     "name" : {
>       "familyName" : "Meikäläinen",
> @@ -324,6 +339,7 @@
>   // ----------------------------- Data
> ---------------------------------------
>   //
>   "friendLinks" : {
> +    "canonical" : ["john.doe", "jane.doe", "george.doe", "maija.m"],
>     "john.doe" : ["jane.doe", "george.doe", "maija.m"],
>     "jane.doe" : ["john.doe"],
>     "george.doe" : ["john.doe"],
>
>
>