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/07/08 20:41:47 UTC

svn commit: r674909 - in /incubator/shindig/trunk/java: common/src/main/java/org/apache/shindig/common/util/ common/src/test/java/org/apache/shindig/common/util/ social-api/src/main/java/org/apache/shindig/social/canonical/ social-api/src/main/java/org...

Author: doll
Date: Tue Jul  8 11:41:46 2008
New Revision: 674909

URL: http://svn.apache.org/viewvc?rev=674909&view=rev
Log:
SHINDIG-429
Patch from Adam Winer. The new dataservice *service interfaces now use Futures. This allows an implementor to do real batching because all of the futures get executed at once. 

Note: This patch looks large because it touches so many lines but it is really pretty trivial. 


Added:
    incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ImmediateFuture.java
    incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/ImmediateFutureTest.java
Modified:
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JsonDbOpensocialService.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityHandler.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityService.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataHandler.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataService.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataRequestHandler.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataServiceServlet.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonHandler.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonService.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JsonDbOpensocialServiceTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/ActivityHandlerTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/AppDataHandlerTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataRequestHandlerTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataServiceServletTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/PersonHandlerTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/integration/AbstractLargeRestfulTests.java

Added: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ImmediateFuture.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ImmediateFuture.java?rev=674909&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ImmediateFuture.java (added)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ImmediateFuture.java Tue Jul  8 11:41:46 2008
@@ -0,0 +1,57 @@
+/*
+ * 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.common.util;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implements a future that is immediately available.
+ */
+public class ImmediateFuture {
+  private ImmediateFuture() {}
+  
+  /**
+   * Returns a future instance.
+   * @param value the value, which may be null.
+   * @return the future
+   */
+  public static <T> Future<T> newInstance(final T value) {
+    return new Future<T>() {
+      public boolean cancel(boolean mayInterruptIfRunning) {
+        return false;
+      }
+
+      public boolean isCancelled() {
+        return false;
+      }
+
+      public boolean isDone() {
+        return true;
+      }
+
+      public T get() {
+        return value;
+      }
+
+      public T get(long timeout, TimeUnit unit) {
+        return value;
+      }
+    };
+  }
+}

Added: incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/ImmediateFutureTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/ImmediateFutureTest.java?rev=674909&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/ImmediateFutureTest.java (added)
+++ incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/ImmediateFutureTest.java Tue Jul  8 11:41:46 2008
@@ -0,0 +1,51 @@
+/*
+ * 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.common.util;
+
+import junit.framework.TestCase;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests ImmediateFuture.
+ */
+public class ImmediateFutureTest extends TestCase {
+  public void testGet() throws Exception {
+    assertEquals("foo", ImmediateFuture.newInstance("foo").get());
+  }
+
+  public void testGetNull() throws Exception {
+    assertNull(ImmediateFuture.newInstance(null).get());
+  }
+
+  public void testGetWithTimeout() throws Exception {
+    assertEquals("foo", ImmediateFuture.newInstance("foo").get(1L, TimeUnit.MILLISECONDS));
+  }
+
+  public void testCancel() {
+    Future<String> stringFuture = ImmediateFuture.newInstance("foo");
+    assertFalse(stringFuture.cancel(true));
+    assertFalse(stringFuture.cancel(false));
+    assertFalse(stringFuture.isCancelled());
+  }
+
+  public void testIsDone() {
+    assertTrue(ImmediateFuture.newInstance("foo").isDone());
+  }
+}

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JsonDbOpensocialService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JsonDbOpensocialService.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JsonDbOpensocialService.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/canonical/JsonDbOpensocialService.java Tue Jul  8 11:41:46 2008
@@ -18,14 +18,8 @@
  */
 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.common.util.ImmediateFuture;
 import org.apache.shindig.common.util.ResourceLoader;
 import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.ResponseItem;
@@ -39,6 +33,13 @@
 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 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.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -47,6 +48,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Future;
 
 /**
  * Implementation of supported services backed by a JSON DB
@@ -91,8 +93,8 @@
     this.converter = converter;
   }
 
-  public ResponseItem<RestfulCollection<Activity>> getActivities(UserId userId, GroupId groupId,
-      String appId, Set<String> fields, SecurityToken token) {
+  public Future<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?
@@ -108,38 +110,42 @@
           }
         }
       }
-      return new ResponseItem<RestfulCollection<Activity>>(new RestfulCollection<Activity>(result));
+      return ImmediateFuture.newInstance(new ResponseItem<RestfulCollection<Activity>>(
+          new RestfulCollection<Activity>(result)));
     } catch (JSONException je) {
-      return new ResponseItem<RestfulCollection<Activity>>(ResponseError.INTERNAL_ERROR,
-          je.getMessage(), null);
+      return ImmediateFuture.newInstance(new ResponseItem<RestfulCollection<Activity>>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 
-  public ResponseItem<Activity> getActivity(UserId userId, GroupId groupId, String appId,
+  public Future<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));
+      String user = userId.getUserId(token);
+      if (db.getJSONObject(ACTIVITIES_TABLE).has(user)) {
+        JSONArray activities = db.getJSONObject(ACTIVITIES_TABLE).getJSONArray(user);
         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)) &&
+          if (activity.get(Activity.Field.USER_ID.toString()).equals(user) &&
               activity.get(Activity.Field.ID.toString()).equals(activityId)) {
-            return new ResponseItem<Activity>(convertToActivity(activity, fields));
+            return ImmediateFuture.newInstance(new ResponseItem<Activity>(
+                convertToActivity(activity, fields)));
           }
         }
       }
-      return null;
+      return ImmediateFuture.newInstance(null);
     } catch (JSONException je) {
-      return new ResponseItem<Activity>(ResponseError.INTERNAL_ERROR, je.getMessage(), null);
+      return ImmediateFuture.newInstance(new ResponseItem<Activity>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 
-  public ResponseItem deleteActivity(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> 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));
+      String user = userId.getUserId(token);
+      if (db.getJSONObject(ACTIVITIES_TABLE).has(user)) {
+        JSONArray activities = db.getJSONObject(ACTIVITIES_TABLE).getJSONArray(user);
         if (activities != null) {
           JSONArray newList = new JSONArray();
           for (int i = 0; i < activities.length(); i++) {
@@ -148,7 +154,7 @@
               newList.put(activity);
             }
           }
-          db.getJSONObject(ACTIVITIES_TABLE).put(userId.getUserId(token), newList);
+          db.getJSONObject(ACTIVITIES_TABLE).put(user, 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) { ??
@@ -156,13 +162,14 @@
         }
       }
       // What is the appropriate response here??
-      return new ResponseItem<Object>(null);
+      return ImmediateFuture.newInstance(new ResponseItem<Object>(null));
     } catch (JSONException je) {
-      return new ResponseItem<Object>(ResponseError.INTERNAL_ERROR, je.getMessage(), null);
+      return ImmediateFuture.newInstance(new ResponseItem<Object>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 
-  public ResponseItem createActivity(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> createActivity(UserId userId, GroupId groupId, String appId,
       Set<String> fields, Activity activity, SecurityToken token) {
     // Are fields really needed here?
     try {
@@ -179,11 +186,12 @@
       // TODO ??
       return null;
     } catch (JSONException je) {
-      return new ResponseItem<Object>(ResponseError.INTERNAL_ERROR, je.getMessage(), null);
+      return ImmediateFuture.newInstance(new ResponseItem<Object>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 
-  public ResponseItem<RestfulCollection<Person>> getPeople(UserId userId, GroupId groupId,
+  public Future<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();
@@ -200,14 +208,15 @@
         // Add group support later
         result.add(convertToPerson(person, fields));
       }
-      return new ResponseItem<RestfulCollection<Person>>(new RestfulCollection<Person>(result));
+      return ImmediateFuture.newInstance(new ResponseItem<RestfulCollection<Person>>(
+          new RestfulCollection<Person>(result)));
     } catch (JSONException je) {
-      return new ResponseItem<RestfulCollection<Person>>(ResponseError.INTERNAL_ERROR,
-          je.getMessage(), null);
+      return ImmediateFuture.newInstance(new ResponseItem<RestfulCollection<Person>>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 
-  public ResponseItem<Person> getPerson(UserId id, Set<String> fields, SecurityToken token) {
+  public Future<ResponseItem<Person>> getPerson(UserId id, Set<String> fields, SecurityToken token) {
     try {
       JSONArray people = db.getJSONArray(PEOPLE_TABLE);
 
@@ -215,17 +224,19 @@
         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));
+          return ImmediateFuture.newInstance(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);
+      return ImmediateFuture.newInstance(new ResponseItem<Person>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 
-  public ResponseItem<DataCollection> getPersonData(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<DataCollection>> getPersonData(UserId userId, GroupId groupId, String appId,
       Set<String> fields, SecurityToken token) {
     // TODO. Does fields==null imply all?
     try {
@@ -253,20 +264,23 @@
         }
         idToData.put(id, data);
       }
-      return new ResponseItem<DataCollection>(new DataCollection(idToData));
+      return ImmediateFuture.newInstance(new ResponseItem<DataCollection>(
+          new DataCollection(idToData)));
     } catch (JSONException je) {
-      return new ResponseItem<DataCollection>(ResponseError.INTERNAL_ERROR, je.getMessage(), null);
+      return ImmediateFuture.newInstance(new ResponseItem<DataCollection>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 
-  public ResponseItem deletePersonData(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> deletePersonData(UserId userId, GroupId groupId, String appId,
       Set<String> fields, SecurityToken token) {
     try {
-      if (!db.getJSONObject(DATA_TABLE).has(userId.getUserId(token))) {
+      String user = userId.getUserId(token);
+      if (!db.getJSONObject(DATA_TABLE).has(user)) {
         return null;
       }
       JSONObject newPersonData = new JSONObject();
-      JSONObject oldPersonData = db.getJSONObject(DATA_TABLE).getJSONObject(userId.getUserId(token));
+      JSONObject oldPersonData = db.getJSONObject(DATA_TABLE).getJSONObject(user);
       Iterator keys = oldPersonData.keys();
       while (keys.hasNext()) {
         String key = (String) keys.next();
@@ -274,15 +288,16 @@
           newPersonData.put(key, oldPersonData.getString(key));
         }
       }
-      db.getJSONObject(DATA_TABLE).put(userId.getUserId(token), newPersonData);
+      db.getJSONObject(DATA_TABLE).put(user, newPersonData);
       // TODO what is the appropriate return value
       return null;
     } catch (JSONException je) {
-      return new ResponseItem<Object>(ResponseError.INTERNAL_ERROR, je.getMessage(), null);
+      return ImmediateFuture.newInstance(new ResponseItem<Object>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 
-  public ResponseItem updatePersonData(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> 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 {
@@ -298,7 +313,8 @@
       // TODO what is the appropriate return value
       return null;
     } catch (JSONException je) {
-      return new ResponseItem<Object>(ResponseError.INTERNAL_ERROR, je.getMessage(), null);
+      return ImmediateFuture.newInstance(new ResponseItem<Object>(
+          ResponseError.INTERNAL_ERROR, je.getMessage(), null));
     }
   }
 

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityHandler.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityHandler.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityHandler.java Tue Jul  8 11:41:46 2008
@@ -22,6 +22,8 @@
 
 import com.google.inject.Inject;
 
+import java.util.concurrent.Future;
+
 public class ActivityHandler extends DataRequestHandler {
   private ActivityService service;
 
@@ -40,7 +42,7 @@
    * examples:
    * /activities/john.doe/@self/1
    */
-  protected ResponseItem handleDelete(RequestItem request) {
+  protected Future<? extends ResponseItem> handleDelete(RequestItem request) {
     request.parseUrlWithTemplate(ACTIVITY_ID_PATH);
 
     return service.deleteActivity(request.getUser(), request.getGroup(),
@@ -54,7 +56,7 @@
    * /activities/john.doe/@self
    * - postBody is an activity object
    */
-  protected ResponseItem handlePut(RequestItem request) {
+  protected Future<? extends ResponseItem> handlePut(RequestItem request) {
     return handlePost(request);
   }
 
@@ -65,7 +67,7 @@
    * /activities/john.doe/@self
    * - postBody is an activity object
    */
-  protected ResponseItem handlePost(RequestItem request) {
+  protected Future<? extends ResponseItem> handlePost(RequestItem request) {
     request.parseUrlWithTemplate(GROUP_PATH);
 
     return service.createActivity(request.getUser(), request.getGroup(),
@@ -81,12 +83,12 @@
    * /activities/john.doe/@self
    * /activities/john.doe/@friends
    */
-  protected ResponseItem handleGet(RequestItem request) {
+  protected Future<? extends ResponseItem> handleGet(RequestItem request) {
     request.parseUrlWithTemplate(ACTIVITY_ID_PATH);
     String optionalActivityId = request.getParameters().get("activityId");
 
     if (optionalActivityId != null) {
-      return service.getActivity(request.getUser(), request.getGroup(), request.getAppId(),
+      return service.getActivity(request.getUser(), request.getGroup(),request.getAppId(),
           request.getFields(), optionalActivityId, request.getToken());
     }
 

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityService.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityService.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/ActivityService.java Tue Jul  8 11:41:46 2008
@@ -22,6 +22,7 @@
 import org.apache.shindig.social.opensocial.model.Activity;
 
 import java.util.Set;
+import java.util.concurrent.Future;
 
 public interface ActivityService {
 
@@ -35,7 +36,7 @@
    * @param token A valid SecurityToken
    * @return a response item with the list of activities.
    */
-  public ResponseItem<RestfulCollection<Activity>> getActivities(UserId userId,
+  public Future<ResponseItem<RestfulCollection<Activity>>> getActivities(UserId userId,
       GroupId groupId, String appId, Set<String> fields, SecurityToken token);
 
   /**
@@ -50,7 +51,7 @@
    * @param token A valid SecurityToken
    * @return a response item with the list of activities.
    */
-  public ResponseItem<Activity> getActivity(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Activity>> getActivity(UserId userId, GroupId groupId, String appId,
       Set<String> fields, String activityId, SecurityToken token);
 
   /**
@@ -64,7 +65,7 @@
    * @param token A valid SecurityToken.
    * @return a response item containing any errors
    */
-  public ResponseItem deleteActivity(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> deleteActivity(UserId userId, GroupId groupId, String appId,
       String activityId, SecurityToken token);
 
   /**
@@ -79,6 +80,6 @@
    * @param token A valid SecurityToken
    * @return a response item containing any errors
    */
-  public ResponseItem createActivity(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> createActivity(UserId userId, GroupId groupId, String appId,
       Set<String> fields, Activity activity, SecurityToken token);
 }

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataHandler.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataHandler.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataHandler.java Tue Jul  8 11:41:46 2008
@@ -22,6 +22,7 @@
 import com.google.inject.Inject;
 
 import java.util.HashMap;
+import java.util.concurrent.Future;
 
 public class AppDataHandler extends DataRequestHandler {
   private AppDataService service;
@@ -45,7 +46,7 @@
    * fields vars then all of the data will be overridden.
    * @param request
    */
-  protected ResponseItem handleDelete(RequestItem request) {
+  protected Future<? extends ResponseItem> handleDelete(RequestItem request) {
     request.parseUrlWithTemplate(APP_DATA_PATH);
 
     return service.deletePersonData(request.getUser(), request.getGroup(),
@@ -64,7 +65,7 @@
    * be pulled from the values and set on the person object. If there are no
    * fields vars then all of the data will be overridden.
    */
-  protected ResponseItem handlePut(RequestItem request) {
+  protected Future<? extends ResponseItem> handlePut(RequestItem request) {
     return handlePost(request);
   }
 
@@ -80,7 +81,7 @@
    * be pulled from the values and set. If there are no
    * fields vars then all of the data will be overridden.
    */
-  protected ResponseItem handlePost(RequestItem request) {
+  protected Future<? extends ResponseItem> handlePost(RequestItem request) {
     request.parseUrlWithTemplate(APP_DATA_PATH);
 
     return service.updatePersonData(request.getUser(), request.getGroup(),
@@ -96,7 +97,7 @@
    * /appdata/john.doe/@friends/app?fields=count
    * /appdata/john.doe/@self/app
    */
-  protected ResponseItem handleGet(RequestItem request) {
+  protected Future<? extends ResponseItem> handleGet(RequestItem request) {
     request.parseUrlWithTemplate(APP_DATA_PATH);
 
     return service.getPersonData(request.getUser(), request.getGroup(),

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataService.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataService.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/AppDataService.java Tue Jul  8 11:41:46 2008
@@ -22,6 +22,7 @@
 
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Future;
 
 public interface AppDataService {
 
@@ -34,8 +35,8 @@
    * @param token The security token
    * @return The data fetched
    */
-  public ResponseItem<DataCollection> getPersonData(UserId userId, GroupId groupId, String appId,
-      Set<String> fields, SecurityToken token);
+  public Future<ResponseItem<DataCollection>> getPersonData(UserId userId, GroupId groupId,
+      String appId, Set<String> fields, SecurityToken token);
 
   /**
    * Deletes data for the specified user and group.
@@ -47,7 +48,7 @@
    * @param token The security token
    * @return an error if one occurs
    */
-  public ResponseItem deletePersonData(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> deletePersonData(UserId userId, GroupId groupId, String appId,
       Set<String> fields, SecurityToken token);
 
   /**
@@ -61,7 +62,7 @@
    * @param token The security token
    * @return an error if one occurs
    */
-  public ResponseItem updatePersonData(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> updatePersonData(UserId userId, GroupId groupId, String appId,
       Set<String> fields, Map<String, String> values, SecurityToken token);
 }
 

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataRequestHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataRequestHandler.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataRequestHandler.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataRequestHandler.java Tue Jul  8 11:41:46 2008
@@ -19,24 +19,21 @@
 
 import org.apache.shindig.social.ResponseItem;
 
-import org.apache.commons.lang.StringUtils;
+import java.util.concurrent.Future;
 
 public abstract class DataRequestHandler {
 
-  public ResponseItem handleMethod(RequestItem request) {
+  public Future<? extends ResponseItem> handleItem(RequestItem request) {
     String httpMethod = request.getMethod();
-    if (StringUtils.isBlank(httpMethod)) {
-      throw new IllegalArgumentException("Unserviced Http method type");
-    }
-    ResponseItem responseItem;
+    Future<? extends ResponseItem> responseItem;
 
-    if (httpMethod.equals("GET")) {
+    if ("GET".equals(httpMethod)) {
       responseItem = handleGet(request);
-    } else if (httpMethod.equals("POST")) {
+    } else if ("POST".equals(httpMethod)) {
       responseItem = handlePost(request);
-    } else if (httpMethod.equals("PUT")) {
+    } else if ("PUT".equals(httpMethod)) {
       responseItem = handlePut(request);
-    } else if (httpMethod.equals("DELETE")) {
+    } else if ("DELETE".equals(httpMethod)) {
       responseItem = handleDelete(request);
     } else {
       throw new IllegalArgumentException("Unserviced Http method type");
@@ -44,11 +41,11 @@
     return responseItem;
   }
 
-  protected abstract ResponseItem handleDelete(RequestItem request);
+  protected abstract Future<? extends ResponseItem> handleDelete(RequestItem request);
 
-  protected abstract ResponseItem handlePut(RequestItem request);
+  protected abstract Future<? extends ResponseItem> handlePut(RequestItem request);
 
-  protected abstract ResponseItem handlePost(RequestItem request);
+  protected abstract Future<? extends ResponseItem> handlePost(RequestItem request);
 
-  protected abstract ResponseItem handleGet(RequestItem request);
+  protected abstract Future<? extends ResponseItem> handleGet(RequestItem request);
 }

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataServiceServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataServiceServlet.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataServiceServlet.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/DataServiceServlet.java Tue Jul  8 11:41:46 2008
@@ -23,6 +23,7 @@
 import org.apache.shindig.common.servlet.InjectedServlet;
 import org.apache.shindig.common.servlet.ParameterFetcher;
 import org.apache.shindig.social.ResponseItem;
+import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.opensocial.util.BeanConverter;
 import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
 import org.apache.shindig.social.opensocial.util.BeanXmlConverter;
@@ -43,6 +44,8 @@
 import java.io.PrintWriter;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 import java.util.logging.Logger;
 
 public class DataServiceServlet extends InjectedServlet {
@@ -131,6 +134,7 @@
     }
   }
 
+  /** Handler for non-batch requests */
   private void handleSingleRequest(HttpServletRequest servletRequest,
       HttpServletResponse servletResponse, SecurityToken token,
       BeanConverter converter) throws IOException {
@@ -138,7 +142,7 @@
         servletRequest.getParameter(X_HTTP_METHOD_OVERRIDE));
 
     RequestItem requestItem = new RequestItem(servletRequest, token, method, converter);
-    ResponseItem responseItem = getResponseItem(requestItem);
+    ResponseItem responseItem = getResponseItem(handleRequestItem(requestItem));
 
     if (responseItem.getError() == null) {
       PrintWriter writer = servletResponse.getWriter();
@@ -155,8 +159,12 @@
 
     byte[] postedBytes = IOUtils.toByteArray(servletRequest.getInputStream());
     JSONObject requests = new JSONObject(new String(postedBytes));
-    Map<String, ResponseItem> responses = Maps.newHashMap();
+    Map<String, Future<? extends ResponseItem>> responses = Maps.newHashMap();
 
+    // Gather all Futures.  We do this up front so that
+    // the first call to get() comes after all futures are created,
+    // which allows for implementations that batch multiple Futures
+    // into single requests.
     Iterator keys = requests.keys();
     while (keys.hasNext()) {
       String key = (String) keys.next();
@@ -166,15 +174,41 @@
       requestItem.setToken(token);
       requestItem.setConverter(converter);
 
-      responses.put(key, getResponseItem(requestItem));
+      responses.put(key, handleRequestItem(requestItem));
+    }
+
+    // Resolve each Future into a response.
+    // TODO: should use shared deadline across each request
+    Map<String, ResponseItem> resolvedResponses = Maps.newHashMap();
+    for (Map.Entry<String, Future<? extends ResponseItem>> responseEntry : responses.entrySet()) {
+      ResponseItem response = getResponseItem(responseEntry.getValue());
+      resolvedResponses.put(responseEntry.getKey(), response);
     }
 
     PrintWriter writer = servletResponse.getWriter();
     writer.write(converter.convertToString(
-        Maps.immutableMap("error", false, "responses", responses)));
+        Maps.immutableMap("error", false, "responses", resolvedResponses)));
   }
 
-  ResponseItem getResponseItem(RequestItem requestItem) {
+  private ResponseItem getResponseItem(Future<? extends ResponseItem> future) {
+    ResponseItem response;
+    try {
+      // TODO: use timeout methods?
+      response = future.get();
+    } catch (InterruptedException ie) {
+      response = responseItemFromException(ie);
+    } catch (ExecutionException ee) {
+      response = responseItemFromException(ee.getCause());
+    }
+    return response;
+  }
+
+  /**
+   * Delivers a request item to the appropriate DataRequestHandler.
+   * 
+   * @return the resulting ResponseItem
+   */
+  Future<? extends ResponseItem> handleRequestItem(RequestItem requestItem) {
     String route = getRouteFromParameter(requestItem.getUrl());
     Class<? extends DataRequestHandler> handlerClass = handlers.get(route);
 
@@ -183,7 +217,11 @@
     }
 
     DataRequestHandler handler = injector.getInstance(handlerClass);
-    return handler.handleMethod(requestItem);
+    return handler.handleItem(requestItem);
+  }
+
+  private ResponseItem<?> responseItemFromException(Throwable t) {
+    return new ResponseItem<Void>(ResponseError.INTERNAL_ERROR, t.getMessage(), null);
   }
 
   SecurityToken getSecurityToken(HttpServletRequest servletRequest) {
@@ -198,7 +236,7 @@
 
   BeanConverter getConverterForRequest(HttpServletRequest servletRequest) {
     String formatString = servletRequest.getParameter(FORMAT_PARAM);
-    if (!StringUtils.isBlank(formatString) && formatString.equals(ATOM_FORMAT)) {
+    if (ATOM_FORMAT.equals(formatString)) {
       return xmlConverter;
     }
     return jsonConverter;

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonHandler.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonHandler.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonHandler.java Tue Jul  8 11:41:46 2008
@@ -20,11 +20,13 @@
 import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.opensocial.model.Person;
+import org.apache.shindig.common.util.ImmediateFuture;
 
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
 
 import java.util.Set;
+import java.util.concurrent.Future;
 
 
 public class PersonHandler extends DataRequestHandler {
@@ -41,18 +43,19 @@
     this.personService = personService;
   }
 
-  protected ResponseItem handleDelete(RequestItem request) {
-    return new ResponseItem<Object>(ResponseError.BAD_REQUEST,
-        "You can't delete people. ", null);
+  protected Future<? extends ResponseItem> handleDelete(RequestItem request) {
+    return ImmediateFuture.newInstance(new ResponseItem<Object>(ResponseError.BAD_REQUEST,
+        "You can't delete people. ", null));
   }
 
-  protected ResponseItem handlePut(RequestItem request) {
-    return new ResponseItem<Object>(ResponseError.NOT_IMPLEMENTED,
-        "You can't add people right now. ", null);  }
-
-  protected ResponseItem handlePost(RequestItem request) {
-    return new ResponseItem<Object>(ResponseError.NOT_IMPLEMENTED,
-        "You can't add people right now. ", null);
+  protected Future<? extends ResponseItem> handlePut(RequestItem request) {
+    return ImmediateFuture.newInstance(new ResponseItem<Object>(ResponseError.NOT_IMPLEMENTED,
+        "You can't add people right now. ", null));
+  }
+
+  protected Future<? extends ResponseItem> handlePost(RequestItem request) {
+    return ImmediateFuture.newInstance(new ResponseItem<Object>(ResponseError.NOT_IMPLEMENTED,
+        "You can't add people right now. ", null));
   }
 
   /**
@@ -63,7 +66,7 @@
    * /people/john.doe/@friends
    * /people/john.doe/@self
    */
-  protected ResponseItem handleGet(RequestItem request) {
+  protected Future<? extends ResponseItem> handleGet(RequestItem request) {
     request.parseUrlWithTemplate(PEOPLE_PATH);
 
     UserId userId = request.getUser();

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonService.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonService.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/dataservice/PersonService.java Tue Jul  8 11:41:46 2008
@@ -22,6 +22,7 @@
 import org.apache.shindig.social.opensocial.model.Person;
 
 import java.util.Set;
+import java.util.concurrent.Future;
 
 public interface PersonService {
 
@@ -46,7 +47,7 @@
    * @param token The gadget token
    * @return a list of people.
    */
-  public ResponseItem<RestfulCollection<Person>> getPeople(UserId userId, GroupId groupId,
+  public Future<ResponseItem<RestfulCollection<Person>>> getPeople(UserId userId, GroupId groupId,
       SortOrder sortOrder, FilterType filter, int first, int max,
       Set<String> fields, SecurityToken token);
 
@@ -58,5 +59,5 @@
    * @param token The gadget token
    * @return a list of people.
    */
-  public ResponseItem<Person> getPerson(UserId id, Set<String> fields, SecurityToken token);
+  public Future<ResponseItem<Person>> getPerson(UserId id, Set<String> fields, SecurityToken token);
 }

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java Tue Jul  8 11:41:46 2008
@@ -18,6 +18,7 @@
 package org.apache.shindig.social.samplecontainer;
 
 import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.common.util.ImmediateFuture;
 import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.dataservice.ActivityService;
@@ -35,6 +36,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Future;
 
 public class BasicActivitiesService implements ActivitiesService,
     ActivityService {
@@ -89,8 +91,13 @@
 
   // New interface methods
 
-  public ResponseItem<RestfulCollection<Activity>> getActivities(UserId userId,
+  public Future<ResponseItem<RestfulCollection<Activity>>> getActivities(UserId userId,
       GroupId groupId, String appId, Set<String> fields, SecurityToken token) {
+    return ImmediateFuture.newInstance(getActivitiesInternal(userId, groupId, token));
+  }
+
+  private ResponseItem<RestfulCollection<Activity>> getActivitiesInternal(UserId userId,
+      GroupId groupId, SecurityToken token) {
     List<String> ids = Lists.newArrayList();
     switch (groupId.getType()) {
       case all:
@@ -119,27 +126,27 @@
         new RestfulCollection<Activity>(activities));
   }
 
-  public ResponseItem<Activity> getActivity(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Activity>> getActivity(UserId userId, GroupId groupId, String appId,
       Set<String> fields, String activityId, SecurityToken token) {
 
-    RestfulCollection<Activity> allActivities = getActivities(userId, groupId,
-        appId, fields, token).getResponse();
+    RestfulCollection<Activity> allActivities = getActivitiesInternal(userId, groupId, token)
+        .getResponse();
     for (Activity activity : allActivities.getEntry()) {
       if (activity.getId().equals(activityId)) {
-        return new ResponseItem<Activity>(activity);
+        return ImmediateFuture.newInstance(new ResponseItem<Activity>(activity));
       }
     }
-    return new ResponseItem<Activity>(ResponseError.BAD_REQUEST,
-        "Activity not found", null);
+    return ImmediateFuture.newInstance(new ResponseItem<Activity>(ResponseError.BAD_REQUEST,
+        "Activity not found", null));
   }
 
-  public ResponseItem deleteActivity(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> deleteActivity(UserId userId, GroupId groupId, String appId,
       String activityId, SecurityToken token) {
     fetcher.deleteActivity(userId.getUserId(token), activityId);
-    return new ResponseItem<Object>(new Object());
+    return ImmediateFuture.newInstance(new ResponseItem<Object>(new Object()));
   }
 
-  public ResponseItem createActivity(UserId userId, GroupId groupId, String appId,
+  public Future<ResponseItem<Object>> createActivity(UserId userId, GroupId groupId, String appId,
       Set<String> fields, Activity activity, SecurityToken token) {
 
     // TODO: Validate the activity, respect the fields param, and do any template expanding
@@ -147,7 +154,7 @@
     activity.setPostedTime(new Date().getTime());
 
     fetcher.createActivity(userId.getUserId(token), activity);
-    return new ResponseItem<Object>(new Object());
+    return ImmediateFuture.newInstance(new ResponseItem<Object>(new Object()));
   }
 
 }

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java Tue Jul  8 11:41:46 2008
@@ -18,6 +18,7 @@
 package org.apache.shindig.social.samplecontainer;
 
 import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.common.util.ImmediateFuture;
 import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.dataservice.AppDataService;
@@ -34,6 +35,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Future;
 
 public class BasicDataService implements DataService, AppDataService {
 
@@ -80,7 +82,7 @@
     if (!isValidKey(key)) {
       return new ResponseItem<Object>(ResponseError.BAD_REQUEST,
           "The person data key had invalid characters",
-          new JSONObject());
+          null);
     }
 
     fetcher.setAppData(id, key, value);
@@ -117,7 +119,7 @@
 
   // New interface methods
 
-  public ResponseItem<DataCollection> getPersonData(
+  public Future<ResponseItem<DataCollection>> getPersonData(
       UserId userId, GroupId groupId, String appId, Set<String> fields,
       SecurityToken token) {
     List<String> ids = Lists.newArrayList();
@@ -136,17 +138,17 @@
     // TODO: Respect appId
     Map<String, Map<String, String>> data
         = getPersonData(ids, Lists.newArrayList(fields), token).getResponse();
-    return new ResponseItem<DataCollection>(new DataCollection(data));
+    return ImmediateFuture.newInstance(new ResponseItem<DataCollection>(new DataCollection(data)));
   }
 
-  public ResponseItem updatePersonData(UserId userId,
+  public Future<ResponseItem<Object>> updatePersonData(UserId userId,
       GroupId groupId, String appId, Set<String> fields,
       Map<String, String> values, SecurityToken token) {
     for (String field : fields) {
       if (!isValidKey(field)) {
-        return new ResponseItem<Object>(ResponseError.BAD_REQUEST,
+        return ImmediateFuture.newInstance(new ResponseItem<Object>(ResponseError.BAD_REQUEST,
             "The person data key had invalid characters",
-            new JSONObject());
+            null));
       }
     }
 
@@ -159,14 +161,14 @@
         }
         break;
       default:
-        return new ResponseItem<Object>(ResponseError.NOT_IMPLEMENTED,
-            "We don't support updating data in batches yet", new Object());
+        return ImmediateFuture.newInstance(new ResponseItem<Object>(ResponseError.NOT_IMPLEMENTED,
+            "We don't support updating data in batches yet", null));
     }
 
-    return new ResponseItem<JSONObject>(new JSONObject());
+    return ImmediateFuture.newInstance(new ResponseItem<Object>(new Object()));
   }
 
-  public ResponseItem deletePersonData(UserId userId,
+  public Future<ResponseItem<Object>> deletePersonData(UserId userId,
       GroupId groupId, String appId, Set<String> fields,
       SecurityToken token) {
     switch(groupId.getType()) {
@@ -177,10 +179,10 @@
         }
         break;
       default:
-        return new ResponseItem<Object>(ResponseError.NOT_IMPLEMENTED,
-            "We don't support deleting data in batches yet", new Object());
+        return ImmediateFuture.newInstance(new ResponseItem<Object>(ResponseError.NOT_IMPLEMENTED,
+            "We don't support deleting data in batches yet", null));
     }
 
-    return new ResponseItem<JSONObject>(new JSONObject());
+    return ImmediateFuture.newInstance(new ResponseItem<Object>(new Object()));
   }
 }

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java Tue Jul  8 11:41:46 2008
@@ -18,6 +18,7 @@
 package org.apache.shindig.social.samplecontainer;
 
 import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.common.util.ImmediateFuture;
 import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.dataservice.GroupId;
@@ -39,6 +40,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Future;
 
 public class BasicPeopleService implements PeopleService, PersonService {
   private static final Comparator<Person> NAME_COMPARATOR
@@ -144,7 +146,7 @@
 
   // New interface methods
 
-  public ResponseItem<RestfulCollection<Person>> getPeople(UserId userId,
+  public Future<ResponseItem<RestfulCollection<Person>>> getPeople(UserId userId,
       GroupId groupId, PersonService.SortOrder sortOrder,
       PersonService.FilterType filter, int first, int max,
       Set<String> profileDetails, SecurityToken token) {
@@ -177,16 +179,17 @@
 
     RestfulCollection<Person> collection = new RestfulCollection<Person>(people,
         first, totalSize);
-    return new ResponseItem<RestfulCollection<Person>>(collection);
+    return ImmediateFuture.newInstance(new ResponseItem<RestfulCollection<Person>>(collection));
   }
 
-  public ResponseItem<Person> getPerson(UserId id, Set<String> fields, SecurityToken token) {
+  public Future<ResponseItem<Person>> getPerson(UserId id, Set<String> fields,
+      SecurityToken token) {
     List<Person> people = getPeople(Lists.newArrayList(id.getUserId(token)), token);
     if (people.size() == 1) {
-      return new ResponseItem<Person>(people.get(0));
+      return ImmediateFuture.newInstance(new ResponseItem<Person>(people.get(0)));
     } else {
-      return new ResponseItem<Person>(ResponseError.BAD_REQUEST,
-          "Person " + id.getUserId(token) + " not found", null);
+      return ImmediateFuture.newInstance(new ResponseItem<Person>(ResponseError.BAD_REQUEST,
+          "Person " + id.getUserId(token) + " not found", null));
     }
   }
 

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JsonDbOpensocialServiceTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JsonDbOpensocialServiceTest.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JsonDbOpensocialServiceTest.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/canonical/JsonDbOpensocialServiceTest.java Tue Jul  8 11:41:46 2008
@@ -18,12 +18,6 @@
  */
 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;
@@ -37,6 +31,11 @@
 import org.apache.shindig.social.opensocial.model.Person;
 import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
 
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.inject.Guice;
+import junit.framework.TestCase;
+
 /**
  * Test the JSONOpensocialService
  */
@@ -63,7 +62,7 @@
 
   public void testGetPersonDefaultFields() throws Exception {
     ResponseItem<Person> personResponseItem = db
-        .getPerson(CANON_USER, Person.Field.DEFAULT_FIELDS, token);
+        .getPerson(CANON_USER, Person.Field.DEFAULT_FIELDS, token).get();
 
     assertNotNull("Canonical user not found", personResponseItem.getResponse());
     assertNotNull("Canonical user has no id", personResponseItem.getResponse().getId());
@@ -74,14 +73,14 @@
 
   public void testGetPersonAllFields() throws Exception {
     ResponseItem<Person> personResponseItem = db
-        .getPerson(CANON_USER, Person.Field.ALL_FIELDS, token);
+        .getPerson(CANON_USER, Person.Field.ALL_FIELDS, token).get();
     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);
+        PersonService.FilterType.all, 0, Integer.MAX_VALUE, null, token).get();
     assertNotNull(responseItem.getResponse());
     assertEquals(responseItem.getResponse().getTotalResults(), 4);
     // Test a couple of users
@@ -91,14 +90,14 @@
 
   public void testGetExpectedActivities() throws Exception {
     ResponseItem<RestfulCollection<Activity>> responseItem = db.getActivities(
-        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken());
+        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken()).get();
     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());
+        Sets.newHashSet("appId", "body", "mediaItems"), APP_ID, new FakeGadgetToken()).get();
     assertTrue(responseItem != null);
     assertTrue(responseItem.getResponse() != null);
     // Check that some fields are fetched and others are not
@@ -113,13 +112,13 @@
     // 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());
+        Sets.newHashSet("appId", "body", "mediaItems"), APP_ID, new FakeGadgetToken()).get();
     assertTrue(responseItem == null);
   }
 
   public void testGetExpectedAppData() throws Exception {
     ResponseItem<DataCollection> responseItem = db.getPersonData(
-        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken());
+        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken()).get();
     assertTrue(!responseItem.getResponse().getEntry().isEmpty());
     assertTrue(!responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).isEmpty());
     assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).size() == 2);
@@ -134,7 +133,7 @@
 
     //Fetch the remaining and test
     ResponseItem<DataCollection> responseItem = db.getPersonData(
-        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken());
+        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken()).get();
     assertTrue(!responseItem.getResponse().getEntry().isEmpty());
     assertTrue(!responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).isEmpty());
     assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).size() == 1);
@@ -149,7 +148,7 @@
 
     //Fetch the remaining and test
     ResponseItem<DataCollection> responseItem = db.getPersonData(
-        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken());
+        CANON_USER, SELF_GROUP, APP_ID, null, new FakeGadgetToken()).get();
     assertTrue(!responseItem.getResponse().getEntry().isEmpty());
     assertTrue(!responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).isEmpty());
     assertTrue(responseItem.getResponse().getEntry().get(CANONICAL_USER_ID).size() == 3);

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/ActivityHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/ActivityHandlerTest.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/ActivityHandlerTest.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/ActivityHandlerTest.java Tue Jul  8 11:41:46 2008
@@ -22,6 +22,7 @@
 import org.apache.shindig.social.opensocial.model.Activity;
 import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
 import org.apache.shindig.common.testing.FakeGadgetToken;
+import org.apache.shindig.common.util.ImmediateFuture;
 
 import junit.framework.TestCase;
 import org.easymock.classextension.EasyMock;
@@ -74,16 +75,17 @@
     request.setPostData(postData);
   }
 
-  private void assertHandleGetForGroup(GroupId.Type group) {
+  private void assertHandleGetForGroup(GroupId.Type group) throws Exception {
     setPath("/activities/john.doe/@" + group.toString());
 
     ResponseItem<RestfulCollection<Activity>> data
         = new ResponseItem<RestfulCollection<Activity>>(null);
     EasyMock.expect(activityService.getActivities(new UserId(UserId.Type.userId, "john.doe"),
-        new GroupId(group, null), null, Sets.<String>newHashSet(), token)).andReturn(data);
+        new GroupId(group, null), null, Sets.<String>newHashSet(), token)).andReturn(
+        ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
@@ -105,14 +107,15 @@
     ResponseItem<Activity> data = new ResponseItem<Activity>(null);
     EasyMock.expect(activityService.getActivity(new UserId(UserId.Type.userId, "john.doe"),
         new GroupId(GroupId.Type.friends, null),
-        null, Sets.<String>newHashSet(), "jane.doe", token)).andReturn(data);
+        null, Sets.<String>newHashSet(), "jane.doe", token)).andReturn(
+        ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
-  private ResponseItem setupPostData() {
+  private ResponseItem<Object> setupPostData() {
     String jsonActivity = "{title: hi mom!, etc etc}";
 
     setPathAndPostData("/people/john.doe/@self", jsonActivity);
@@ -120,35 +123,36 @@
     Activity activity = new ActivityImpl();
     EasyMock.expect(converter.convertToObject(jsonActivity, Activity.class)).andReturn(activity);
 
-    ResponseItem data = new ResponseItem<Object>(null);
+    ResponseItem<Object> data = new ResponseItem<Object>(null);
     EasyMock.expect(activityService.createActivity(new UserId(UserId.Type.userId, "john.doe"),
         new GroupId(GroupId.Type.self, null), null, Sets.<String>newHashSet(),
-        activity, token)).andReturn(data);
+        activity, token)).andReturn(ImmediateFuture.newInstance(data));
     replay();
     return data;
   }
 
   public void testHandlePost() throws Exception {
     ResponseItem data = setupPostData();
-    assertEquals(data, handler.handlePost(request));
+    assertEquals(data, handler.handlePost(request).get());
     verify();
   }
 
   public void testHandlePut() throws Exception {
     ResponseItem data = setupPostData();
-    assertEquals(data, handler.handlePut(request));
+    assertEquals(data, handler.handlePut(request).get());
     verify();
   }
 
   public void testHandleDelete() throws Exception {
     setPath("/people/john.doe/@self/1");
 
-    ResponseItem data = new ResponseItem<Object>(null);
+    ResponseItem<Object> data = new ResponseItem<Object>(null);
     EasyMock.expect(activityService.deleteActivity(new UserId(UserId.Type.userId, "john.doe"),
-        new GroupId(GroupId.Type.self, null), null, "1", token)).andReturn(data);
+        new GroupId(GroupId.Type.self, null), null, "1", token)).andReturn(
+        ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleDelete(request));
+    assertEquals(data, handler.handleDelete(request).get());
     verify();
   }
 }
\ No newline at end of file

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/AppDataHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/AppDataHandlerTest.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/AppDataHandlerTest.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/AppDataHandlerTest.java Tue Jul  8 11:41:46 2008
@@ -18,6 +18,7 @@
 package org.apache.shindig.social.dataservice;
 
 import org.apache.shindig.common.testing.FakeGadgetToken;
+import org.apache.shindig.common.util.ImmediateFuture;
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
 
@@ -75,16 +76,16 @@
     request.setPostData(postData);
   }
 
-  private void assertHandleGetForGroup(GroupId.Type group) {
+  private void assertHandleGetForGroup(GroupId.Type group) throws Exception {
     setPath("/activities/john.doe/@" + group.toString() + "/appId");
 
     ResponseItem<DataCollection> data = new ResponseItem<DataCollection>(null);
     EasyMock.expect(appDataService.getPersonData(new UserId(UserId.Type.userId, "john.doe"),
         new GroupId(group, null),
-        "appId", Sets.<String>newHashSet(), token)).andReturn(data);
+        "appId", Sets.<String>newHashSet(), token)).andReturn(ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
@@ -108,14 +109,14 @@
     ResponseItem<DataCollection> data = new ResponseItem<DataCollection>(null);
     EasyMock.expect(appDataService.getPersonData(new UserId(UserId.Type.userId, "john.doe"),
         new GroupId(GroupId.Type.friends, null),
-        "appId", Sets.newHashSet("pandas"), token)).andReturn(data);
+        "appId", Sets.newHashSet("pandas"), token)).andReturn(ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
-  private ResponseItem setupPostData() {
+  private ResponseItem<Object> setupPostData() {
     String jsonAppData = "{pandas: 'are fuzzy'}";
 
     Map<String, String> params = Maps.newHashMap();
@@ -125,23 +126,24 @@
     HashMap<String, String> values = Maps.newHashMap();
     EasyMock.expect(converter.convertToObject(jsonAppData, HashMap.class)).andReturn(values);
 
-    ResponseItem data = new ResponseItem<Object>(null);
+    ResponseItem<Object> data = new ResponseItem<Object>(null);
     EasyMock.expect(appDataService.updatePersonData(new UserId(UserId.Type.userId, "john.doe"),
         new GroupId(GroupId.Type.self, null),
-        "appId", Sets.newHashSet("pandas"), values, token)).andReturn(data);
+        "appId", Sets.newHashSet("pandas"), values, token))
+        .andReturn(ImmediateFuture.newInstance(data));
     replay();
     return data;
   }
 
   public void testHandlePost() throws Exception {
     ResponseItem data = setupPostData();
-    assertEquals(data, handler.handlePost(request));
+    assertEquals(data, handler.handlePost(request).get());
     verify();
   }
 
   public void testHandlePut() throws Exception {
     ResponseItem data = setupPostData();
-    assertEquals(data, handler.handlePut(request));
+    assertEquals(data, handler.handlePut(request).get());
     verify();
   }
 
@@ -150,13 +152,14 @@
     params.put("fields", "pandas");
     setPathAndParams("/appData/john.doe/@self/appId", params);
 
-    ResponseItem data = new ResponseItem<Object>(null);
+    ResponseItem<Object> data = new ResponseItem<Object>(null);
     EasyMock.expect(appDataService.deletePersonData(new UserId(UserId.Type.userId, "john.doe"),
         new GroupId(GroupId.Type.self, null),
-        "appId", Sets.newHashSet("pandas"), token)).andReturn(data);
+        "appId", Sets.newHashSet("pandas"), token))
+        .andReturn(ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleDelete(request));
+    assertEquals(data, handler.handleDelete(request).get());
     verify();
   }
 }
\ No newline at end of file

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataRequestHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataRequestHandlerTest.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataRequestHandlerTest.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataRequestHandlerTest.java Tue Jul  8 11:41:46 2008
@@ -18,9 +18,12 @@
 package org.apache.shindig.social.dataservice;
 
 import org.apache.shindig.social.ResponseItem;
+import org.apache.shindig.common.util.ImmediateFuture;
 
 import junit.framework.TestCase;
 
+import java.util.concurrent.Future;
+
 public class DataRequestHandlerTest extends TestCase {
   private DataRequestHandler drh;
   private RequestItem request;
@@ -28,26 +31,38 @@
   @Override
   protected void setUp() throws Exception {
     drh = new DataRequestHandler() {
-      protected ResponseItem handleDelete(RequestItem request) {
-        return new ResponseItem<String>("DELETE");
+      protected Future<? extends ResponseItem> handleDelete(RequestItem request) {
+        return ImmediateFuture.newInstance(new ResponseItem<String>("DELETE"));
       }
 
-      protected ResponseItem handlePut(RequestItem request) {
-        return new ResponseItem<String>("PUT");
+      protected Future<? extends ResponseItem> handlePut(RequestItem request) {
+        return ImmediateFuture.newInstance(new ResponseItem<String>("PUT"));
       }
 
-      protected ResponseItem handlePost(RequestItem request) {
-        return new ResponseItem<String>("POST");
+      protected Future<? extends ResponseItem> handlePost(RequestItem request) {
+        return ImmediateFuture.newInstance(new ResponseItem<String>("POST"));
       }
 
-      protected ResponseItem handleGet(RequestItem request) {
-        return new ResponseItem<String>("GET");
+      protected Future<? extends ResponseItem> handleGet(RequestItem request) {
+        return ImmediateFuture.newInstance(new ResponseItem<String>("GET"));
       }
     };
 
     request = new RequestItem();
   }
 
+  public void testHandleItemSuccess() throws Exception {
+    verifyItemDispatchMethodCalled("DELETE");
+    verifyItemDispatchMethodCalled("PUT");
+    verifyItemDispatchMethodCalled("POST");
+    verifyItemDispatchMethodCalled("GET");
+  }
+
+  private void verifyItemDispatchMethodCalled(String methodName) throws Exception{
+    request.setMethod(methodName);
+    assertEquals(methodName, drh.handleItem(request).get().getResponse());
+  }
+
   public void testHandleMethodSuccess() throws Exception {
     verifyDispatchMethodCalled("DELETE");
     verifyDispatchMethodCalled("PUT");
@@ -57,7 +72,7 @@
 
   private void verifyDispatchMethodCalled(String methodName) throws Exception {
     request.setMethod(methodName);
-    assertEquals(methodName, drh.handleMethod(request).getResponse());
+    assertEquals(methodName, drh.handleItem(request).get().getResponse());
   }
 
   public void testHandleMethodWithInvalidMethod() throws Exception {
@@ -69,7 +84,7 @@
   private void verifyExceptionThrown(String methodName) throws Exception {
     request.setMethod(methodName);
     try {
-      drh.handleMethod(request);
+      drh.handleItem(request);
       fail("The invalid method " + methodName + " should throw an exception.");
     } catch (IllegalArgumentException e) {
       // Yea! We like exeptions

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataServiceServletTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataServiceServletTest.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataServiceServletTest.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/DataServiceServletTest.java Tue Jul  8 11:41:46 2008
@@ -20,7 +20,7 @@
 import org.apache.shindig.common.BasicSecurityTokenDecoder;
 import org.apache.shindig.common.SecurityTokenDecoder;
 import org.apache.shindig.common.SecurityTokenException;
-import org.apache.shindig.common.servlet.ParameterFetcher;
+import org.apache.shindig.common.util.ImmediateFuture;
 import org.apache.shindig.common.testing.FakeGadgetToken;
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.SocialApiTestsGuiceModule;
@@ -41,6 +41,10 @@
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.StringTokenizer;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 public class DataServiceServletTest extends TestCase {
   private HttpServletRequest req;
@@ -117,6 +121,24 @@
     verifyHandlerWasFoundForPathInfo(route, appDataHandler, "PUT", null, "PUT");
   }
 
+  /** Tests a data handler that returns a failed Future */
+  public void testFailedRequest() throws Exception {
+    String route = "/" + DataServiceServlet.APPDATA_ROUTE;
+    setupRequest(route, "GET", null);
+    EasyMock.expect(injector.getInstance(AppDataHandler.class)).andStubReturn(appDataHandler);    
+    setupInjector();
+
+    EasyMock.expect(appDataHandler.handleItem(EasyMock.isA(RequestItem.class)));
+    EasyMock.expectLastCall().andReturn(new FailingFuture());
+
+    res.sendError(500, "FAILED");
+
+    EasyMock.replay(req, res, appDataHandler, tokenDecoder, injector, jsonConverter);
+    servlet.service(req, res);
+    EasyMock.verify(req, res, appDataHandler, tokenDecoder, injector, jsonConverter);
+    EasyMock.reset(req, res, appDataHandler, tokenDecoder, injector, jsonConverter);
+  }
+
   private void verifyHandlerWasFoundForPathInfo(String peoplePathInfo, DataRequestHandler handler)
       throws Exception {
     String post = "POST";
@@ -125,12 +147,35 @@
 
   private void verifyHandlerWasFoundForPathInfo(String pathInfo, DataRequestHandler handler,
       String actualMethod, String overrideMethod, String expectedMethod) throws Exception {
+    setupRequest(pathInfo, actualMethod, overrideMethod);
+    setupInjector();
+
+    String jsonObject = "my lovely json";
+    ResponseItem<String> response = new ResponseItem<String>(jsonObject);
+    
+    EasyMock.expect(handler.handleItem(EasyMock.isA(RequestItem.class)));
+    EasyMock.expectLastCall().andReturn(ImmediateFuture.newInstance(response));
+
+    EasyMock.expect(jsonConverter.convertToString(jsonObject)).andReturn(jsonObject);
+
+    PrintWriter writerMock = EasyMock.createMock(PrintWriter.class);
+    EasyMock.expect(res.getWriter()).andReturn(writerMock);
+    writerMock.write(jsonObject);
+
+    EasyMock.replay(req, res, handler, tokenDecoder, injector, jsonConverter);
+    servlet.service(req, res);
+    EasyMock.verify(req, res, handler, tokenDecoder, injector, jsonConverter);
+    EasyMock.reset(req, res, handler, tokenDecoder, injector, jsonConverter);
+  }
+
+  private void setupRequest(String pathInfo, String actualMethod, String overrideMethod)
+      throws IOException, SecurityTokenException {
     req.setCharacterEncoding("UTF-8");
 
     EasyMock.expect(req.getInputStream()).andStubReturn(dummyPostData);
     EasyMock.expect(req.getPathInfo()).andStubReturn(pathInfo);
     EasyMock.expect(req.getMethod()).andStubReturn(actualMethod);
-    EasyMock.expect(req.getParameterNames()).andStubReturn((Enumeration) new StringTokenizer(""));
+    EasyMock.expect(req.getParameterNames()).andStubReturn(new StringTokenizer(""));
     EasyMock.expect(req.getParameter(DataServiceServlet.X_HTTP_METHOD_OVERRIDE)).andReturn(
         overrideMethod);
     EasyMock.expect(req.getParameter(DataServiceServlet.FORMAT_PARAM)).andReturn(null);
@@ -141,30 +186,13 @@
 
     FakeGadgetToken token = new FakeGadgetToken();
     EasyMock.expect(tokenDecoder.createToken(Collections.singletonMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, tokenString))).andReturn(token);
-
-    setupInjector();
-
-    String jsonObject = "my lovely json";
-    EasyMock.expect(handler.handleMethod(EasyMock.isA(RequestItem.class)))
-        .andReturn(new ResponseItem<String>(jsonObject));
-
-    EasyMock.expect(jsonConverter.convertToString(jsonObject)).andReturn(jsonObject);
-
-    PrintWriter writerMock = EasyMock.createMock(PrintWriter.class);
-    EasyMock.expect(res.getWriter()).andReturn(writerMock);
-    writerMock.write(jsonObject);
-
-    EasyMock.replay(req, res, handler, tokenDecoder, injector, jsonConverter);
-    servlet.service(req, res);
-    EasyMock.verify(req, res, handler, tokenDecoder, injector, jsonConverter);
-    EasyMock.reset(req, res, handler, tokenDecoder, injector, jsonConverter);
   }
 
   public void testInvalidRoute() throws Exception {
     RequestItem requestItem = new RequestItem();
     requestItem.setUrl("/ahhh!");
     try {
-      servlet.getResponseItem(requestItem);
+      servlet.handleRequestItem(requestItem);
       fail("The route should not have found a valid handler.");
     } catch (RuntimeException e) {
       // Yea!
@@ -176,7 +204,9 @@
     String tokenString = "owner:viewer:app:container.com:foo:bar";
     EasyMock.expect(req.getParameter(DataServiceServlet.SECURITY_TOKEN_PARAM))
         .andReturn(tokenString);
-    EasyMock.expect(tokenDecoder.createToken(Collections.singletonMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, tokenString))).andThrow(new SecurityTokenException(""));
+    EasyMock.expect(tokenDecoder.createToken(
+        Collections.singletonMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, tokenString)))
+        .andThrow(new SecurityTokenException(""));
 
     EasyMock.replay(req, tokenDecoder);
     try {
@@ -240,4 +270,29 @@
     EasyMock.reset(req);
   }
 
+  /**
+   * Future implementation that fails with an exception.
+   */
+  private static class FailingFuture implements Future<ResponseItem> {
+    public boolean cancel(boolean mayInterruptIfRunning) {
+      return false;
+    }
+
+    public boolean isCancelled() {
+      return false;
+    }
+
+    public boolean isDone() {
+      return true;
+    }
+
+    public ResponseItem get() throws InterruptedException, ExecutionException {
+      throw new ExecutionException(new RuntimeException("FAILED"));
+    }
+
+    public ResponseItem get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+      return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+  }
 }

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/PersonHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/PersonHandlerTest.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/PersonHandlerTest.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/PersonHandlerTest.java Tue Jul  8 11:41:46 2008
@@ -18,6 +18,7 @@
 package org.apache.shindig.social.dataservice;
 
 import org.apache.shindig.common.testing.FakeGadgetToken;
+import org.apache.shindig.common.util.ImmediateFuture;
 import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.opensocial.model.Person;
@@ -83,10 +84,11 @@
         PersonService.SortOrder.topFriends,
         PersonService.FilterType.all, 0, 20,
         DEFAULT_FIELDS,
-        token)).andReturn(data);
+        token))
+        .andReturn(ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
@@ -101,10 +103,11 @@
         PersonService.SortOrder.topFriends,
         PersonService.FilterType.all, 0, 20,
         DEFAULT_FIELDS,
-        token)).andReturn(data);
+        token))
+        .andReturn(ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
@@ -126,10 +129,11 @@
     EasyMock.expect(personService.getPeople(
         new UserId(UserId.Type.userId, "john.doe"),
         new GroupId(GroupId.Type.friends, null), order,
-        filter, 5, 10, Sets.newHashSet("money", "fame", "fortune"), token)).andReturn(data);
+        filter, 5, 10, Sets.newHashSet("money", "fame", "fortune"), token))
+        .andReturn(ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
@@ -139,10 +143,10 @@
     ResponseItem<Person> data = new ResponseItem<Person>(null);
     // TODO: We aren't passing john.doe to the service yet.
     EasyMock.expect(personService.getPerson(new UserId(UserId.Type.userId, "jane.doe"),
-        DEFAULT_FIELDS, token)).andReturn(data);
+        DEFAULT_FIELDS, token)).andReturn(ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
@@ -151,28 +155,28 @@
 
     ResponseItem<Person> data = new ResponseItem<Person>(null);
     EasyMock.expect(personService.getPerson(new UserId(UserId.Type.userId, "john.doe"),
-        DEFAULT_FIELDS, token)).andReturn(data);
+        DEFAULT_FIELDS, token)).andReturn(ImmediateFuture.newInstance(data));
 
     replay();
-    assertEquals(data, handler.handleGet(request));
+    assertEquals(data, handler.handleGet(request).get());
     verify();
   }
 
   public void testHandleDelete() throws Exception {
     replay();
-    assertEquals(ResponseError.BAD_REQUEST, handler.handleDelete(request).getError());
+    assertEquals(ResponseError.BAD_REQUEST, handler.handleDelete(request).get().getError());
     verify();
   }
 
   public void testHandlePut() throws Exception {
     replay();
-    assertEquals(ResponseError.NOT_IMPLEMENTED, handler.handlePut(request).getError());
+    assertEquals(ResponseError.NOT_IMPLEMENTED, handler.handlePut(request).get().getError());
     verify();
   }
 
   public void testHandlePost() throws Exception {
     replay();
-    assertEquals(ResponseError.NOT_IMPLEMENTED, handler.handlePost(request).getError());
+    assertEquals(ResponseError.NOT_IMPLEMENTED, handler.handlePost(request).get().getError());
     verify();
   }
 }
\ No newline at end of file

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/integration/AbstractLargeRestfulTests.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/integration/AbstractLargeRestfulTests.java?rev=674909&r1=674908&r2=674909&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/integration/AbstractLargeRestfulTests.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/integration/AbstractLargeRestfulTests.java Tue Jul  8 11:41:46 2008
@@ -18,7 +18,6 @@
 package org.apache.shindig.social.dataservice.integration;
 
 import org.apache.shindig.common.BasicSecurityTokenDecoder;
-import org.apache.shindig.social.GadgetDataServletFetcher;
 import org.apache.shindig.social.SocialApiTestsGuiceModule;
 import org.apache.shindig.social.dataservice.ActivityHandler;
 import org.apache.shindig.social.dataservice.AppDataHandler;