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

svn commit: r674954 [1/3] - in /incubator/shindig/trunk: ./ config/ java/social-api/src/main/java/org/apache/shindig/social/abdera/ java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/ java/social-api/src/main/java/org/apache/shindig/so...

Author: lryan
Date: Tue Jul  8 14:00:54 2008
New Revision: 674954

URL: http://svn.apache.org/viewvc?rev=674954&view=rev
Log:
Apply https://issues.apache.org/jira/browse/SHINDIG-422

Added:
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RawResponseContext.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRequestContext.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/AbstractSocialEntityCollectionAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/ActivityAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/DataAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/PersonAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/PersonJsonAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/SimpleJsonAdapter.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/SocialRequestContextTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/atom/
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/atom/RestfulAtomActivityTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/atom/RestfulAtomDataTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/atom/RestfulAtomPeopleTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/json/
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/json/PersonJsonAdapterTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/json/RestfulJsonActivityTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/json/RestfulJsonDataTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/json/RestfulJsonPeopleTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanUtil.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/model/
    incubator/shindig/trunk/javascript/sampledata/canonicaldb.bak.json
    incubator/shindig/trunk/javascript/sampledata/examplebatchrequest.json
Removed:
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/AbstractSocialEntityCollectionAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/ActivityAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/DataAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/PersonAdapter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SimpleJsonAdapter.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulAtomActivityTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulAtomDataTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulAtomPeopleTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulJsonActivityTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulJsonDataTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/RestfulJsonPeopleTest.java
Modified:
    incubator/shindig/trunk/config/container.js
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RequestUrlTemplate.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRouteManager.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/util/ValidRequestFilter.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/PeopleService.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/SampleContainerRouteManager.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/SocialApiProviderTestFixture.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/ValidRequestTest.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/dataservice/integration/AbstractLargeRestfulTests.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/samplecontainer/SampleContainerRoutesTest.java
    incubator/shindig/trunk/pom.xml

Modified: incubator/shindig/trunk/config/container.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/config/container.js?rev=674954&r1=674953&r2=674954&view=diff
==============================================================================
--- incubator/shindig/trunk/config/container.js (original)
+++ incubator/shindig/trunk/config/container.js Tue Jul  8 14:00:54 2008
@@ -109,7 +109,7 @@
     // Otherwise, uses the json wire format.
     // If you are using the default Shindig setup and want to use rest, don't
     // forget to change the "path" config to /social/rest
-    "useRestful" : false
+    "useRestful" : true
   }
 
 }}

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RawResponseContext.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RawResponseContext.java?rev=674954&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RawResponseContext.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RawResponseContext.java Tue Jul  8 14:00:54 2008
@@ -0,0 +1,93 @@
+package org.apache.shindig.social.abdera;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+import org.apache.abdera.protocol.server.context.SimpleResponseContext;
+import org.apache.abdera.util.EntityTag;
+import org.apache.commons.io.IOUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.Date;
+
+
+/**
+ * A ResponseContext implementation that use a generic writer.
+ */
+public class RawResponseContext 
+  extends SimpleResponseContext {
+  
+  private InputStream in;
+
+  public RawResponseContext(
+    InputStream in, 
+    EntityTag etag, 
+    int status) {
+      this.in = in;
+      this.status = status;
+      setEntityTag(etag);
+  }
+  
+  public RawResponseContext(
+    InputStream in,  
+    int status) {
+      this.in = in;
+      this.status = status;
+  }
+  
+  public RawResponseContext(
+    InputStream in, 
+    Date lastmodified, 
+    int status) {
+      this.in = in;
+      this.status = status;
+      setLastModified(lastmodified);
+  }
+
+  public RawResponseContext(String content, int status) throws UnsupportedEncodingException {
+    this.in = new ByteArrayInputStream(content.getBytes("UTF-8"));
+    this.status = status;
+  }
+
+  public boolean hasEntity() {
+    return in != null;
+  }
+
+  public void writeTo(
+    OutputStream out) 
+      throws IOException {
+    if (hasEntity()) {
+      if (in != null) {
+        IOUtils.copy(in, out);
+      }
+    }
+  } 
+
+  protected void writeEntity(
+    Writer out) 
+      throws IOException {
+    if (in != null) {
+      IOUtils.copy(in, out);
+    }
+  }
+}

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RequestUrlTemplate.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RequestUrlTemplate.java?rev=674954&r1=674953&r2=674954&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RequestUrlTemplate.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/RequestUrlTemplate.java Tue Jul  8 14:00:54 2008
@@ -17,6 +17,12 @@
  */
 package org.apache.shindig.social.abdera;
 
+import org.apache.shindig.social.abdera.util.ValidRequestFilter;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * The RequestUrlTemplate enum standardizes the names and descriptions of the
  * URL templates as defined in the RESTful API spec.
@@ -31,46 +37,68 @@
 
 public enum RequestUrlTemplate {
   // People
-  PROFILES_OF_CONNECTIONS_OF_USER("Profiles of Connections of User",
-      "people/:uid/@all", "/people/{guid}/@all"),
-  PROFILES_OF_FRIENDS_OF_USER("Profiles of Friends of User",
-      "people/:uid/@friends", "/people/{guid}/@friends"),
-  PROFILES_IN_GROUP_OF_USER("Profiles in Group of User",
-      "people/:uid/:gid", "/people/{guid}/{groupid}"),
-  PROFILE_OF_CONNECTION_OF_USER("Profile of Connection of User",
-      "people/:uid/@all/:pid", "/people/{guid}/@all/{pid}"),
-  PROFILE_OF_USER("Profile of User",
-      "people/:uid/@self", "/people/{guid}/@self"),
-  PROFILE_OF_REQUESTER("Profile of Requester",
-          "people/@me/@self", "/people/@me/@self"),
+  JSON_PROFILES_OF_CONNECTIONS_OF_USER("Profiles of Connections of User in JSON format",
+      "people/:uid/@all", ValidRequestFilter.Format.JSON),
+  ATOM_PROFILES_OF_CONNECTIONS_OF_USER("Profiles of Connections of User in ATOM format",
+      "people/:uid/@all", ValidRequestFilter.Format.ATOM),
+
+  JSON_PROFILES_OF_FRIENDS_OF_USER("Profiles of Friends of User in JSON format",
+      "people/:uid/@friends", ValidRequestFilter.Format.JSON),
+  ATOM_PROFILES_OF_FRIENDS_OF_USER("Profiles of Friends of User in ATOM format",
+      "people/:uid/@friends", ValidRequestFilter.Format.ATOM),
+
+  JSON_PROFILES_IN_GROUP_OF_USER("Profiles in Group of User in JSON format",
+      "people/:uid/:gid", ValidRequestFilter.Format.JSON),
+  ATOM_PROFILES_IN_GROUP_OF_USER("Profiles in Group of User in ATOM format",
+      "people/:uid/:gid", ValidRequestFilter.Format.ATOM),
+
+  JSON_PROFILE_OF_CONNECTION_OF_USER("Profile of Connection of User in the JSON format",
+      "people/:uid/@all/:pid", ValidRequestFilter.Format.JSON),
+  ATOM_PROFILE_OF_CONNECTION_OF_USER("Profile of Connection of User in the ATOM format",
+      "people/:uid/@all/:pid", ValidRequestFilter.Format.ATOM),
+
+  JSON_PROFILE_OF_USER("Profile of User in JSON format",
+      "people/:uid/@self", ValidRequestFilter.Format.JSON),
+  ATOM_PROFILE_OF_USER("Profile of User in ATOM format",
+      "people/:uid/@self", ValidRequestFilter.Format.ATOM),
+
+  JSON_PROFILE_OF_REQUESTER("Profile of Requester in JSON format",
+      "people/@me/@self", ValidRequestFilter.Format.JSON),
+  ATOM_PROFILE_OF_REQUESTER("Profile of Requester in ATOM format",
+      "people/@me/@self", ValidRequestFilter.Format.ATOM),
+
   // Activities
   ACTIVITIES_OF_USER("Activities of User",
-      "activities/:uid/@self", "/activities/{uid}/@self"),
+      "activities/:uid/@self", null),
   ACTIVITIES_OF_FRIENDS_OF_USER("Activities of Friends of User",
-      "activities/:uid/@friends", "/activities/{uid}/@friends"),
+      "activities/:uid/@friends", null),
   ACTIVITIES_OF_GROUP_OF_USER("Activities of Group of User",
-      "activities/:uid/:gid", "/activities/{uid}/{gid}"),
+      "activities/:uid/:gid", null),
   ACTIVITY_OF_USER("Activity of User",
-      "activities/:uid/@self/:aid", "/activities/{uid}/@self/{aid}"),
+      "activities/:uid/@self/:aid", null),
   // AppData
   APPDATA_OF_APP_OF_USER("AppData of App of User",
-      "appdata/:uid/@self/:aid", "/appdata/{uid}/@self/{aid}"),
+      "appdata/:uid/@self/:aid", null),
   APPDATA_OF_FRIENDS_OF_USER("AppData of Friends of User",
-      "appdata/:uid/@friends/:aid", "/appdata/{uid}/@friends/{aid}");
+      "appdata/:uid/@friends/:aid", null);
 
-  private String description;
-  private String routePattern;
-  private String urlTemplate;
+  private final String description;
+  private final String routePattern;
+  private final ValidRequestFilter.Format formatRestriction;
 
   private RequestUrlTemplate(String description, String routePattern,
-      String urlTemplate) {
+      ValidRequestFilter.Format format) {
     this.description = description;
     this.routePattern = routePattern;
-    this.urlTemplate = urlTemplate;
+    this.formatRestriction = format;
   }
 
   @Override
   public String toString() {
+    return getDescription();
+  }
+  
+  public String getDescription() {
     return description;
   }
 
@@ -78,11 +106,35 @@
     return routePattern;
   }
 
-  public String getUrlTemplate() {
-    return urlTemplate;
+  public ValidRequestFilter.Format getFormatRestriction() {
+    return formatRestriction;
+  }
+
+  //Reverse Lookup for the description Field
+  private static final Map<String, RequestUrlTemplate> lookupByDescription = 
+    new HashMap<String, RequestUrlTemplate>();
+
+  static {
+    for (RequestUrlTemplate t : EnumSet.allOf(RequestUrlTemplate.class)) {
+      lookupByDescription.put(t.getDescription(), t);
+    }
   }
 
-  public static RequestUrlTemplate getValue(String value) {
-    return valueOf(value.replaceAll(" ", "_").toUpperCase());
+  public static RequestUrlTemplate getByDescription(String description) {
+    return lookupByDescription.get(description);
   }
+
+  //Reverse Lookup for the routePattern Field
+  private static final Map<String, RequestUrlTemplate> lookupByRoutePattern = 
+    new HashMap<String, RequestUrlTemplate>();
+
+  static {
+    for (RequestUrlTemplate t : EnumSet.allOf(RequestUrlTemplate.class))
+      lookupByRoutePattern.put(t.getRoutePattern(), t);
+  }
+
+  public static RequestUrlTemplate getByRoutePattern(String pattern) {
+    return lookupByRoutePattern.get(pattern);
+  }
+
 }

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRequestContext.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRequestContext.java?rev=674954&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRequestContext.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRequestContext.java Tue Jul  8 14:00:54 2008
@@ -0,0 +1,67 @@
+package org.apache.shindig.social.abdera;
+
+import com.google.common.collect.Sets;
+
+import org.apache.shindig.social.dataservice.PersonService;
+import org.apache.shindig.social.opensocial.model.Person;
+
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.context.RequestContextWrapper;
+
+import java.util.Set;
+
+public class SocialRequestContext extends RequestContextWrapper {
+
+  // Common OpenSocial RESTful parameters
+  public static final String START_INDEX = "startIndex";
+  public static final String COUNT = "count";
+  public static final String ORDER_BY = "orderBy";
+  public static final String FILTER_BY = "filterBy";
+  public static final String FIELDS = "fields";
+  public static final String SECURITY_TOKEN_PARAM = "st";
+
+  // OpenSocial parameter defaults
+  public static final int DEFAULT_START_INDEX = 0;
+  public static final int DEFAULT_COUNT = 20;
+  public static final Set<String> DEFAULT_PERSON_FIELDS = Sets.newHashSet(
+      Person.Field.ID.toString(),
+      Person.Field.NAME.toString(),
+      Person.Field.THUMBNAIL_URL.toString());
+  
+  public SocialRequestContext(RequestContext request) {
+    super(request);
+  }
+
+ //these parameter handling methods are from social/dataservice/RequestItem.java
+  public int getStartIndex() {
+    String startIndex = request.getParameter(START_INDEX);
+    return startIndex == null ? DEFAULT_START_INDEX : Integer.valueOf(startIndex);
+  }
+
+  public int getCount() {
+    String count = request.getParameter(COUNT);
+    return count == null ? DEFAULT_COUNT : Integer.valueOf(count);
+  }
+
+  public PersonService.SortOrder getOrderBy() {
+    String orderBy = request.getParameter(ORDER_BY);
+    return orderBy == null
+        ? PersonService.SortOrder.topFriends
+        : PersonService.SortOrder.valueOf(orderBy);
+  }
+
+  public PersonService.FilterType getFilterBy() {
+    String filterBy = request.getParameter(FILTER_BY);
+    return filterBy == null
+        ? PersonService.FilterType.all
+        : PersonService.FilterType.valueOf(filterBy);
+  }
+ 
+  public Set<String> getFields() {
+    String paramValue = request.getParameter(FIELDS);
+    return paramValue == null
+        ? DEFAULT_PERSON_FIELDS
+        : Sets.newHashSet(paramValue.split(","));
+  }
+  
+}

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRouteManager.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRouteManager.java?rev=674954&r1=674953&r2=674954&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRouteManager.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialRouteManager.java Tue Jul  8 14:00:54 2008
@@ -17,70 +17,206 @@
  */
 package org.apache.shindig.social.abdera;
 
+import org.apache.shindig.social.abdera.atom.ActivityAdapter;
+import org.apache.shindig.social.abdera.atom.DataAdapter;
+import org.apache.shindig.social.abdera.atom.PersonAdapter;
+import org.apache.shindig.social.abdera.json.PersonJsonAdapter;
+import org.apache.shindig.social.abdera.util.ValidRequestFilter;
+import org.apache.shindig.social.abdera.util.ValidRequestFilter.Format;
+
+import org.apache.abdera.i18n.templates.Route;
+import org.apache.abdera.protocol.Request;
 import org.apache.abdera.protocol.server.CollectionAdapter;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.Target;
 import org.apache.abdera.protocol.server.TargetType;
+import org.apache.abdera.protocol.server.impl.DefaultWorkspaceManager;
 import org.apache.abdera.protocol.server.impl.RouteManager;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class SocialRouteManager extends RouteManager {
-  private PersonAdapter personAdapter;
-  private DataAdapter dataAdapter;
-  private ActivityAdapter activityAdapter;
+  private final PersonJsonAdapter personJsonAdapter;
+  private final PersonAdapter personAtomAdapter;
+  private final DataAdapter dataAtomAdapter;
+  private final ActivityAdapter activityAtomAdapter;
   private static final String BASE = "/social/rest/";
-  protected String base;
+  protected final String base;
 
-  public SocialRouteManager(PersonAdapter personAdapter, DataAdapter dataAdapter,
-      ActivityAdapter activityAdapter) {
+  public SocialRouteManager(PersonJsonAdapter personJsonAdapter, PersonAdapter personAtomAdapter,
+      DataAdapter dataAtomAdapter, ActivityAdapter activityAtomAdapter) {
     this.base = BASE;
-    this.personAdapter = personAdapter;
-    this.dataAdapter = dataAdapter;
-    this.activityAdapter = activityAdapter;
+    this.personJsonAdapter = personJsonAdapter;
+    this.personAtomAdapter = personAtomAdapter;
+    this.dataAtomAdapter = dataAtomAdapter;
+    this.activityAtomAdapter = activityAtomAdapter;
   }
 
   public void setRoutes() {
         // People
-    this.addRoute(RequestUrlTemplate.PROFILES_OF_CONNECTIONS_OF_USER,
-            TargetType.TYPE_COLLECTION, personAdapter)
-        .addRoute(RequestUrlTemplate.PROFILES_OF_FRIENDS_OF_USER,
-            TargetType.TYPE_COLLECTION, personAdapter)
-        .addRoute(RequestUrlTemplate.PROFILES_IN_GROUP_OF_USER,
-            TargetType.TYPE_COLLECTION, personAdapter)
-        .addRoute(RequestUrlTemplate.PROFILE_OF_CONNECTION_OF_USER,
-            TargetType.TYPE_ENTRY, personAdapter)
-        .addRoute(RequestUrlTemplate.PROFILE_OF_USER,
-            TargetType.TYPE_ENTRY, personAdapter)
+    this.addRoute(RequestUrlTemplate.JSON_PROFILES_OF_CONNECTIONS_OF_USER,
+            TargetType.TYPE_COLLECTION, personJsonAdapter)
+        .addRoute(RequestUrlTemplate.ATOM_PROFILES_OF_CONNECTIONS_OF_USER,
+            TargetType.TYPE_COLLECTION, personAtomAdapter)
+        .addRoute(RequestUrlTemplate.JSON_PROFILES_OF_FRIENDS_OF_USER,
+            TargetType.TYPE_COLLECTION, personJsonAdapter)
+        .addRoute(RequestUrlTemplate.ATOM_PROFILES_OF_FRIENDS_OF_USER,
+            TargetType.TYPE_COLLECTION, personAtomAdapter)
+        .addRoute(RequestUrlTemplate.JSON_PROFILES_IN_GROUP_OF_USER,
+            TargetType.TYPE_COLLECTION, personJsonAdapter)
+        .addRoute(RequestUrlTemplate.ATOM_PROFILES_IN_GROUP_OF_USER,
+            TargetType.TYPE_COLLECTION, personAtomAdapter)
+        .addRoute(RequestUrlTemplate.JSON_PROFILE_OF_CONNECTION_OF_USER,
+            TargetType.TYPE_ENTRY, personJsonAdapter)
+        .addRoute(RequestUrlTemplate.ATOM_PROFILE_OF_CONNECTION_OF_USER,
+            TargetType.TYPE_ENTRY, personAtomAdapter)
+        .addRoute(RequestUrlTemplate.JSON_PROFILE_OF_USER,
+            TargetType.TYPE_ENTRY, personJsonAdapter)
+        .addRoute(RequestUrlTemplate.ATOM_PROFILE_OF_USER,
+            TargetType.TYPE_ENTRY, personAtomAdapter)
 
         // Activities
         .addRoute(RequestUrlTemplate.ACTIVITIES_OF_USER,
-            TargetType.TYPE_COLLECTION, activityAdapter)
+            TargetType.TYPE_COLLECTION, activityAtomAdapter)
         .addRoute(RequestUrlTemplate.ACTIVITIES_OF_FRIENDS_OF_USER,
-            TargetType.TYPE_COLLECTION, activityAdapter)
+            TargetType.TYPE_COLLECTION, activityAtomAdapter)
         .addRoute(RequestUrlTemplate.ACTIVITIES_OF_GROUP_OF_USER,
             TargetType.TYPE_COLLECTION, null)
         .addRoute(RequestUrlTemplate.ACTIVITY_OF_USER,
-            TargetType.TYPE_ENTRY, activityAdapter)
+            TargetType.TYPE_ENTRY, activityAtomAdapter)
 
         // AppData
         .addRoute(RequestUrlTemplate.APPDATA_OF_APP_OF_USER,
-            TargetType.TYPE_COLLECTION, dataAdapter)
+            TargetType.TYPE_COLLECTION, dataAtomAdapter)
         .addRoute(RequestUrlTemplate.APPDATA_OF_FRIENDS_OF_USER,
-            TargetType.TYPE_COLLECTION, dataAdapter)
+            TargetType.TYPE_COLLECTION, dataAtomAdapter)
         ;
   }
 
   /**
-   * This extension of the addRoute from the parent allows a RequestUrlTemplate
-   * to be passed in instead of a name and pattern. This is just a convenience
-   * method to clean up the code. The parent method maps routes to types and
-   * adapters.
-   *
+   * Adds an additional addRoute constructor that allows a RequestUrlTemplate to be passed in
+   * instead of a name and pattern. This is just a convenience method to clean up the code.
+   * 
    * @param template RequestUrlTemplate enum should contain names and patterns.
    * @param type TargetType
    * @param collectionAdapter CollectionAdapter
    * @return addRoute from the parent RouteManager
    */
-  public SocialRouteManager addRoute(RequestUrlTemplate template,
-      TargetType type, CollectionAdapter collectionAdapter) {
-    return (SocialRouteManager) addRoute(template.toString(),
-        base + template.getRoutePattern(), type, collectionAdapter);
+  public SocialRouteManager addRoute(RequestUrlTemplate template, TargetType type,
+      CollectionAdapter collectionAdapter) {
+    return addRoute(template.name(), base + template.getRoutePattern(), type, template
+        .getFormatRestriction(), collectionAdapter);
+  }
+
+  /**
+   * Adds an additional addRoute constructor beyond abdera.protocol.server.impl.RouteManager#resolve
+   * so that a requirement can be added to each Route that includes the format that the Route
+   * accepts
+   * 
+   * @param name The name of the Route
+   * @param pattern The pattern to match and generate urls for requests
+   * @param type The TargetType for the Route
+   * @param format A Format enum of ATOM or JSON
+   * @param collectionAdapter The CollectionAdapter to associate with the Route
+   */
+  public SocialRouteManager addRoute(
+    String name, 
+    String pattern, 
+    TargetType type,
+    ValidRequestFilter.Format format,
+    CollectionAdapter collectionAdapter) {
+    Map<String, String> requirements = new HashMap<String, String>();
+    if (format !=null){
+      requirements.put(ValidRequestFilter.FORMAT_FIELD, format.toString()); 
+    }
+    Route route = new Route(name, pattern, null, requirements);
+    route2CA.put(route, collectionAdapter);
+    return (SocialRouteManager) addRoute(route, type);
+  }
+
+  /**
+   * Overrides abdera.protocol.server.impl.RouteManager#resolve to add a format restriction for
+   * routes
+   */
+  public Target resolve(Request request) {
+    RequestContext context = (RequestContext) request;
+    String uri = context.getTargetPath();
+    int idx = uri.indexOf('?');
+    if (idx != -1) {
+      uri = uri.substring(0, idx);
+    }
+
+    for(RouteTargetType routeTarget : targets) {
+      // check if the formatRestriction requirement is in the route and if it is satisfied.
+      if (matchRequestFormat(context, routeTarget.getRoute())) {
+        // match the path portion of the url
+        if (routeTarget.getRoute().match(uri)) {
+          CollectionAdapter ca = route2CA.get(routeTarget.getRoute());
+          if (ca != null) {
+            context.setAttribute(DefaultWorkspaceManager.COLLECTION_ADAPTER_ATTRIBUTE, ca);
+          }
+          return getTarget(context, routeTarget.getRoute(), uri, routeTarget.getTargetType());
+        }
+      }
+    }
+    return null;
+  }
+
+
+  /**
+   * The ValidRequestFilter runs after the initial resolving of the target so it cannot ensure that
+   * a request will be stopped if the url does not have a proper format parameter. This method
+   * returns false if there is no valid format parameter.
+   * 
+   * However, if the format requirement field in the route is null, we call it a match, since that
+   * means the route does not have a format restriction
+   * 
+   * @param request Abdera's RequestContext
+   * @param route Abdera's Route object
+   */
+  private boolean matchRequestFormat(RequestContext request, Route route) {
+    Format requestFormat = ValidRequestFilter.getFormatTypeFromRequest(request);
+    String routeFormatRestriction = route.getRequirement(ValidRequestFilter.FORMAT_FIELD);
+    if (requestFormat == null) {
+      return false;
+    } else {
+      if (routeFormatRestriction != null) {
+        return routeFormatRestriction.toUpperCase().equals(
+            requestFormat.getDisplayValue().toUpperCase());
+      }
+      return true;
+    }
+  }
+  
+  private Target getTarget(
+    RequestContext context,
+    Route route, 
+    String uri, 
+    TargetType type) {
+      return new RouteTarget(type, context, route, uri);
+    }
+  
+  // TODO: We should probably move the static methods here into a helper class
+  public static RequestUrlTemplate getUrlTemplate(RequestContext request) {
+    String routeName = getRoute(request).getName();
+    return RequestUrlTemplate.valueOf(routeName);
+  }
+
+  /**
+   * This assumes the target resolver was a RouteManager and returns a Route
+   * object. If it does not, it throws a NPE for now. It could also deal with a
+   * Regex resolver
+   *
+   * @param request Abdera's RequestContext
+   * @return The Route object that matched the request.
+   */
+  public static Route getRoute(RequestContext request) {
+    Object matcher = request.getTarget().getMatcher();
+    if (matcher instanceof Route) {
+      return (Route) matcher;
+    } else {
+      throw new NullPointerException();
+    }
   }
 }

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/AbstractSocialEntityCollectionAdapter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/AbstractSocialEntityCollectionAdapter.java?rev=674954&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/AbstractSocialEntityCollectionAdapter.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/AbstractSocialEntityCollectionAdapter.java Tue Jul  8 14:00:54 2008
@@ -0,0 +1,389 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.shindig.social.abdera.atom;
+
+import org.apache.shindig.common.BasicSecurityToken;
+import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.common.SecurityTokenDecoder;
+import org.apache.shindig.common.SecurityTokenException;
+import org.apache.shindig.common.crypto.BlobCrypterException;
+import org.apache.shindig.social.abdera.RequestUrlTemplate;
+import org.apache.shindig.social.abdera.util.ValidRequestFilter;
+import org.apache.shindig.social.abdera.util.ValidRequestFilter.Format;
+import org.apache.shindig.social.opensocial.PeopleService;
+import org.apache.shindig.social.opensocial.model.IdSpec;
+import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
+import org.apache.shindig.social.opensocial.util.BeanXmlConverter;
+
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.i18n.templates.Route;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Link;
+import org.apache.abdera.model.Person;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.ResponseContext;
+import org.apache.abdera.protocol.server.context.ResponseContextException;
+import org.apache.abdera.protocol.server.impl.AbstractEntityCollectionAdapter;
+import org.json.JSONException;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * By extending this class it becomes easy to build Collections which are backed
+ * by a set of Social entities - such as a person or activity.
+ *
+ * This base class also has the data connection to the People service and some
+ * helper methods for getting social graph information.
+ *
+ * @param <T> The entity that this is backed by.
+ */
+
+public abstract class AbstractSocialEntityCollectionAdapter<T> extends
+    AbstractEntityCollectionAdapter<T> {
+  private static final Logger logger = Logger
+      .getLogger(AbstractEntityCollectionAdapter.class.getName());
+
+  // the name of the URI query parameter that is the gadget security token
+  protected static final String SECURITY_TOKEN_PARAM = "st";
+  
+  protected PeopleService peopleService;
+  protected final String ID_PREFIX;
+  protected final Factory factory;
+  private BeanXmlConverter beanXmlConverter;
+  private BeanJsonConverter beanJsonConverter;
+  protected SecurityTokenDecoder securityTokenDecoder;
+
+  public AbstractSocialEntityCollectionAdapter() {
+    ID_PREFIX = "urn:guid:";
+    factory = new Abdera().getFactory();
+  }
+
+  /**
+   * All the adapters need access to the PeopleService, which has the basic
+   * social graph information. Each service adapter will also add an instance
+   * of their respective data service.
+   * TODO: Also include groups service in base?
+   * @param peopleService The people service
+   */
+  @Inject
+  public void setPeopleService(PeopleService peopleService) {
+    this.peopleService = peopleService;
+  }
+
+  @Inject
+  public void setConverters(BeanXmlConverter beanXmlConverter,
+      BeanJsonConverter beanJsonConverter) {
+    this.beanXmlConverter = beanXmlConverter;
+    this.beanJsonConverter = beanJsonConverter;
+  }
+
+  @Inject
+  public void setSecurityTokenDecoder(SecurityTokenDecoder
+      securityTokenDecoder) {
+    this.securityTokenDecoder = securityTokenDecoder;
+  }
+
+  /**
+   * Get the token from the "st" url parameter or throw an exception.
+   * @param request Abdera's RequestContext
+   * @return SecurityToken
+   * @throws SecurityTokenException If the token is invalid
+   */
+  /**
+   * Reads the gadget security token out of an {@link HttpServletRequest},
+   * making sure to return null if there are problems.
+   */
+  protected SecurityToken getSecurityToken(RequestContext request) {
+    String token = request.getParameter(SECURITY_TOKEN_PARAM);
+
+    if (token == null || token.trim().length() == 0) {
+      return null;
+    }
+
+    try {
+      Map<String, String> params = 
+          Collections.singletonMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, 
+              token);
+      return securityTokenDecoder.createToken(params);
+    } catch (SecurityTokenException e) {
+      String message = new StringBuilder()
+          .append("found security token, but couldn't decode it ")
+          .append("(treating it as not present). token is: ")
+          .append(token)
+          .toString();
+      logger.warning(message);
+      return null;
+    }
+  }
+
+  /**
+   * This alternate version of getSecurityToken adds the ability to generate a
+   * new security token based on some viewerid supplied.
+   *
+   * @param request Abdera's RequestContext
+   * @param viewerId The viewer ID to fake.
+   * @return A call to the parent getSecurityToken which returns a SecurityToken
+   */
+  protected SecurityToken getSecurityToken(RequestContext request,
+      final String viewerId) {
+    SecurityToken token = getSecurityToken(request); 
+
+    if (token == null) {
+      try {
+        return new BasicSecurityToken("o", viewerId, "a", "d", "u", "m");
+      } catch (BlobCrypterException be) {
+        be.printStackTrace();
+        return null;
+      }
+    } 
+     return token;
+  }
+
+  /**
+   * @param request RequestContext
+   * @param resourceRouteVariable The route variable for the entry. So, for a
+   *     route pattern of /:collection/:id, with "id" resourceRouteVariable this
+   *     would remove "id" in the generated URL.
+   * @return The absolute request URI (includes server name, port, etc) URL for
+   *     the collection of the entry.
+   */
+  public String getFeedIriForEntry(RequestContext request,
+      String resourceRouteVariable) {
+    Map<String, Object> params = Maps.newHashMap();
+    Route theRoute = getRoute(request);
+    for (String var: theRoute.getVariables()){
+      Object value = request.getTarget().getParameter(var);
+      if (!params.containsKey(var) && !var.equals(resourceRouteVariable)) {
+        params.put(var, value);
+      }
+    }
+    String uri = request.urlFor(theRoute.getName(), params);
+    return request.getResolvedUri().resolve(uri).toString();
+  }
+
+  /**
+   * This assumes the target resolver was a RouteManager and returns a Route
+   * object. If it does not, it throws a NPE for now. It could also deal with a
+   * Regex resolver
+   *
+   * @param request Abdera's RequestContext
+   * @return The Route object that matched the request.
+   */
+  public static Route getRoute(RequestContext request) {
+    Object matcher = request.getTarget().getMatcher();
+    if (matcher instanceof Route) {
+      return (Route) matcher;
+    } else {
+      throw new NullPointerException();
+    }
+  }
+
+  // TODO: We should probably move the static methods here into a helper class
+  public static RequestUrlTemplate getUrlTemplate(RequestContext request) {
+    String routeName = getRoute(request).getName();
+    return RequestUrlTemplate.valueOf(routeName);
+  }
+
+  @Override
+  public Object getContent(T entity, RequestContext request)
+      throws ResponseContextException {
+    Format format = ValidRequestFilter.getFormatTypeFromRequest(request);
+    Content content = factory.newContent();
+
+    switch (format) {
+      case ATOM:
+        content.setContentType(Content.Type.XML);
+        content.setValue(beanXmlConverter.convertToXml(entity));
+        break;
+      case JSON:
+        content.setContentType(Content.Type.TEXT);
+        content.setValue(beanJsonConverter.convertToJson(entity).toString());
+        break;
+    }
+    return content;
+  }
+
+  public abstract String getSummary(T entity) throws ResponseContextException;
+
+  /**
+   * Add the details to an entry.
+   *
+   * @param request Abdera's RequestContext.
+   * @param entry The entry FOM object.
+   * @param feedIri The feed IRI that the entry came from.
+   * @param entity The object that the entry is based on.
+   */
+  @Override
+  protected String addEntryDetails(RequestContext request, Entry entry,
+      IRI feedIri, T entity) throws ResponseContextException {
+    addRequiredEntryDetails(request, entry, feedIri, entity);
+    addOptionalEntryDetails(request, entry, feedIri, entity);
+    return getLink(entity, feedIri, request);
+  }
+
+  /**
+   * This very similar to the superclass's addEntryDetails but modified to do a
+   * minimum of required fields.
+   *
+   * @param request Abdera's RequestContext.
+   * @param entry The entry FOM object.
+   * @param feedIri The feed IRI that the entry came from.
+   * @param entity The object that the entry is based on.
+   * @throws ResponseContextException If the authors can not be fetched
+   */
+  protected void addRequiredEntryDetails(RequestContext request, Entry entry,
+      IRI feedIri, T entity) throws ResponseContextException {
+    entry.setId(getId(entity));
+    entry.setTitle(getTitle(entity));
+    entry.setUpdated(getUpdated(entity));
+    entry.setSummary(getSummary(entity));
+    List<Person> authors = getAuthors(entity, request);
+    if (authors != null) {
+      for (Person a : authors) {
+        entry.addAuthor(a);
+      }
+    }
+  }
+
+  /**
+   * This is a good place for the subclass to do any special processing of the
+   * entry element to customize it beyond the basic atom fields like title and
+   * author.
+   *
+   * @param request Abdera's RequestContext.
+   * @param entry The entry FOM object.
+   * @param feedIri The feed IRI that the entry came from.
+   * @param entity The object that the entry is based on.
+   * @throws ResponseContextException If some entry data can not be fetched
+   */
+  protected void addOptionalEntryDetails(RequestContext request, Entry entry,
+      IRI feedIri, T entity) throws ResponseContextException {
+  }
+
+  /**
+   * Create the base feed for the requested collection.
+   *
+   * TODO: This method needs to be refactored to deal with hoisting and json.
+   *
+   * @param request Abdera's RequestContext
+   */
+  @Override
+  protected Feed createFeedBase(RequestContext request)
+      throws ResponseContextException {
+    Factory factory = request.getAbdera().getFactory();
+    Feed feed = factory.newFeed();
+    String link = getHref(request);
+    // TODO: this should create links that are aware of the request format.
+    feed.addLink(link, "self", "application/atom+xml", null, null, 0);
+    feed.setId(getId(request));
+    feed.setTitle(getTitle(request));
+    feed.addAuthor(getAuthor(request));
+    feed.setUpdated(new Date());
+    return feed;
+  }
+
+  protected void addEditLinkToEntry(Entry entry) throws Exception {
+    if (getEditUriFromEntry(entry) == null) {
+      entry.addLink(entry.getId().toString(), "edit");
+    }
+  }
+
+  protected String getEditUriFromEntry(Entry entry) throws Exception {
+    String editUri = null;
+    List<Link> editLinks = entry.getLinks("edit");
+    if (editLinks != null) {
+      for (Link link : editLinks) {
+        // if there is more than one edit link, we should not automatically
+        // assume that it's always going to point to an Atom document
+        // representation.
+        if (link.getMimeType() != null) {
+          if (link.getMimeType().match("application/atom+xml")) {
+            editUri = link.getResolvedHref().toString();
+            break;
+          }
+        } else {
+          // edit link with no type attribute is the right one to use
+          editUri = link.getResolvedHref().toString();
+          break;
+        }
+      }
+    }
+   return editUri;
+  }
+   
+  /**
+   * Unimplemented HTTP methods
+   */
+
+  @Override
+  public ResponseContext deleteEntry(RequestContext request) {
+    return null;
+  }
+
+  @Override
+  public ResponseContext putEntry(RequestContext request) {
+    return null;
+  }
+  
+  /**
+   * Gets the IDs of friends for the given user.
+   * 
+   * @param request Abdera's RequestContext
+   * @param uid The User ID to get friends for.
+   * @return A list of ID strings.
+   */
+  public List<String> getFriendIds(RequestContext request, String uid) {
+    SecurityToken token = getSecurityToken(request, uid);
+    IdSpec idSpec = new IdSpec(null, IdSpec.Type.VIEWER_FRIENDS);
+    try {
+      return peopleService.getIds(idSpec, token);
+    } catch (JSONException e) {
+      // TODO: Ignoring this for now. Eventually we can make the service apis
+      // fit the restful model better. For now, it is worth some hackiness to
+      // keep the interfaces stable.
+      return null;
+    }
+  }
+
+  /**
+   * Gets the IDs of connections of the given user.
+   * 
+   * @param request Abdera's RequestContext
+   * @param uid The User ID to get connections for.
+   * @return A list of ID strings.
+   */
+  public List<String> getConnectionIds(RequestContext request, String uid,
+      SecurityTokenDecoder securityTokenDecoder, PeopleService peopleService) {
+    // TODO: Implement connections. For now, just return friends
+    return getFriendIds(request, uid);
+  }
+  
+
+}

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/ActivityAdapter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/ActivityAdapter.java?rev=674954&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/ActivityAdapter.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/ActivityAdapter.java Tue Jul  8 14:00:54 2008
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.shindig.social.abdera.atom;
+
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.social.abdera.RequestUrlTemplate;
+import org.apache.shindig.social.abdera.SocialRouteManager;
+import org.apache.shindig.social.opensocial.ActivitiesService;
+import org.apache.shindig.social.opensocial.model.Activity;
+
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Person;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.context.ResponseContextException;
+
+import org.apache.commons.betwixt.io.BeanReader;
+import org.xml.sax.SAXException;
+
+import java.beans.IntrospectionException;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * This Collection is backed by a set of Activity entities
+ */
+public class ActivityAdapter extends
+    AbstractSocialEntityCollectionAdapter<Activity> {
+
+  private final ActivitiesService activitiesService;
+
+  /**
+   * The Adapter needs Activities, People and Groups.
+   * The PeopleService comes from the base class. Groups is unimplemented.
+   * @param activitiesService The activities service
+   */
+  @Inject
+  public ActivityAdapter(ActivitiesService activitiesService) {
+    this.activitiesService = activitiesService;
+  }
+
+  /**
+   * Query the underlying model for an Activity object.
+   *
+   * @param request RequestContext
+   * @return An Activity entity.
+   */
+  @Override
+  public Activity getEntry(String resourceName, RequestContext request)
+      throws ResponseContextException {
+    String aid = resourceName;
+    String uid = request.getTarget().getParameter("uid");
+    SecurityToken authToken = getSecurityToken(request, uid);
+    return activitiesService.getActivity(uid, aid, authToken).getResponse();
+  }
+
+  /**
+   * atom:entry/atom:id aliases the "id" field. In the Atom format, it is
+   * translated into the required URI data type by prepending "urn:guid:" to the
+   * OpenSocial ID string.
+   */
+  @Override
+  public String getId(Activity activityObj) throws ResponseContextException {
+    return ID_PREFIX + activityObj.getId();
+  }
+
+  // hoisting rule: atom:entry/atom:author/atom:uri aliases "user_id"
+  @Override
+  public List<Person> getAuthors(Activity activityObj, RequestContext request)
+      throws ResponseContextException {
+    Person author = factory.newAuthor();
+    author.setUri(ID_PREFIX + activityObj.getUserId());
+    return Arrays.asList(author);
+  }
+
+  /**
+   * Get the name of the entry resource (used to construct links)
+   */
+  @Override
+  public String getName(Activity activityObj) throws ResponseContextException {
+    return activityObj.getId();
+  }
+
+  // hoisting rule: atom:entry/atom:title aliases "title"
+  @Override
+  public String getTitle(Activity activityObj) throws ResponseContextException {
+    return activityObj.getTitle();
+  }
+
+  // hoisting rule: atom:entry/atom:updated aliases POSTED_TIME for Activity
+  // or the generation time if no better information is available.
+  @Override
+  public Date getUpdated(Activity activityObj) throws ResponseContextException {
+    return activityObj.getUpdated();
+  }
+
+  // hoisting rule: atom:entry/atom:summary aliases "body"
+  @Override
+  public String getSummary(Activity activityObj)
+      throws ResponseContextException {
+    return activityObj.getBody();
+  }
+
+  // hoisting rule: atom:entry/atom:published aliases POSTED_TIME
+  public Long getPublished(Activity activityObj)
+      throws ResponseContextException {
+    // TODO: Add published element to the entry object.
+    // TODO: Switch based on output format from RFC date to epoch-based.
+    // POSTED_TIME is seconds since the epoch.
+    return activityObj.getPostedTime();
+  }
+
+  /**
+   * This is where some activity entry format customization happens.
+   *
+   * @param request Abdera's RequestContext.
+   * @param entry The entry FOM object.
+   * @param feedIri The feed IRI that the entry came from.
+   * @param activityObj The object that the entry is based on.
+   * @throws ResponseContextException
+   */
+  @Override
+  protected void addOptionalEntryDetails(RequestContext request, Entry entry,
+      IRI feedIri, Activity activityObj) throws ResponseContextException {
+    String link = getLink(activityObj, feedIri, request);
+    // TODO: this should create links that are aware of the request format.
+    entry.addLink(link, "self", "application/atom+xml", null, null, 0);
+
+    // TODO:
+    // atom:entry/atom:generator/atom:uri aliases "app_id"
+    // atom:entry/atom:published aliases POSTED_TIME
+  }
+
+  /**
+   * Unimplemented Data methods
+   */
+  @Override
+  public void deleteEntry(String resourceName, RequestContext request)
+      throws ResponseContextException {
+    // TODO: Auto-generated method stub
+  }
+
+  /**
+   * Query the underlying model for the list activity objects.
+   *
+   * There is some logic to handle some request dispatching here since this
+   * adapter handles the getFeed method for three Activity collections:
+   * ACTIVITIES_OF_USER, ACTIVITIES_OF_FRIENDS_OF_USER and
+   * ACTIVITIES_OF_GROUP_OF_USER
+   *
+   * @param request RequestContext
+   * @return A List Activity entities.
+   */
+  @Override
+  public Iterable<Activity> getEntries(RequestContext request)
+      throws ResponseContextException {
+    String uid = request.getTarget().getParameter("uid");
+    List<String> ids = Lists.newArrayList();
+    switch (SocialRouteManager.getUrlTemplate(request)) {
+      case ACTIVITIES_OF_USER :
+        ids.add(uid);
+        break;
+      case ACTIVITIES_OF_FRIENDS_OF_USER :
+        // TODO: Change activities service to handle the friend lookup itself
+        ids = getFriendIds(request, uid);
+        break;
+      case ACTIVITIES_OF_GROUP_OF_USER :
+        // TODO: add something like ids = getGroupIds(request, gid);
+        String gid = request.getTarget().getParameter("gid");
+        break;
+      default:
+        // TODO: Clean this code up so we don't need this check
+        throw new UnsupportedOperationException(
+            "The activity adpater was reached with an unsupported url");
+    }
+
+    SecurityToken authToken = getSecurityToken(request, uid);
+    return activitiesService.getActivities(ids, authToken).getResponse();
+  }
+
+  /**
+   * When an entry is POSTed to a collection, purpose is to add that entry
+   * to the collection.
+   * 
+   * Currently, the following method only handles POST to the following
+   * collection
+   *           /activities/:uid/@self
+   */
+  @Override
+  public Activity postEntry(String title, IRI id, String summary, Date updated,
+      List<Person> authors, Content content, RequestContext request)
+      throws ResponseContextException {
+
+    // handle Atom/XML. TODO handle Json
+
+    /* 
+     * To extract Activity obj from the posted Entry, content element is 
+     * used. To make this work, content element should contain everything
+     * we need to create the Activity object correctly. If there are 
+     * some fields in other atom: elements, copy them into the content element.
+     * i.e., implement "reverse hoisting" logic here
+     */ 
+    // TODO is userId field in content element (correspodns to Activity.userId)
+    // supposed to be filled in by the caller
+    // OR is it to be picked up from the ":uid" param on URL
+    // assuming that it is already filled by the caller.
+    
+    String contentXml = content.getValue();
+    BeanReader reader = new BeanReader();
+    Activity postedActivity = null;
+    try {
+      reader.registerBeanClass("activity", Activity.class);
+      StringReader rd = new StringReader(contentXml);
+      postedActivity = (Activity)reader.parse(rd);
+    } catch (IntrospectionException e) {
+      throw new ResponseContextException(null, e);
+    } catch (IOException e) {
+      throw new ResponseContextException(null, e);
+    } catch (SAXException e) {
+      throw new ResponseContextException(null, e);
+    }
+
+    /*
+     * in Atom/Xml, the posted entry is returned to the original caller
+     * with the following fields being "potentially" different from
+     * what the caller sent:
+     *   1. atom:id  server can optionally assign a new id to the entry
+     *               and return it to the caller. This may not be reqd
+     *   2. editUri link should be added to the entry if required.
+     *           refer to atom spec on all you need to know about this field.
+     *      included the following methods in baseclass to help with this
+     *       . addEditLinkToEntry(Entry entry)
+     *       . getEditUriFromEntry(Entry entry)
+     *       
+     *    TODO figure out WHERE the postedEntry doc is being constructed in
+     *    Abdera. thats where the logic to add editUri should be included.
+     *      
+     */ 
+    
+    // add this to list of activities of the user
+    String uid = request.getTarget().getParameter("uid");
+    SecurityToken authToken = getSecurityToken(request, uid);
+    
+    // the following modifies postedActivity - which is then returned to 
+    // the caller. 
+    // TODO the following method should be modified (or new method needed) 
+    // to return the postedActivity 
+    activitiesService.createActivity(uid, postedActivity, authToken);
+    return postedActivity;
+  }
+
+  @Override
+  public void putEntry(Activity entry, String title, Date updated,
+      List<Person> authors, String summary, Content content,
+      RequestContext request) throws ResponseContextException {
+    // TODO: Implement
+  }
+
+  /**
+   * Collection-level hoisting rules
+   */
+
+  /**
+   * The collection-level URL. Calls the getFeedIriForEntry and nulls "aid".
+   *
+   * @param request RequestContext
+   * @return The absolute request URI (includes server name, port, etc) URL
+   */
+  @Override
+  public String getHref(RequestContext request) {
+    return getFeedIriForEntry(request, "aid");
+  }
+
+  @Override
+  public String getId(RequestContext request) {
+    // TODO: what really to return for the feed ID? Better data will help.
+    return getHref(request);
+  }
+
+  // hoisting rule: atom:entry/atom:source/atom:link@rel="self" aliases
+  // "stream_url"
+  // TODO: "stream_url"
+
+  // hoisting rule: atom:entry/atom:source/atom:title aliases "stream_title"
+  // TODO: stream_title can't be accessed right here....
+  public String getTitle(RequestContext request) {
+    String routename = SocialRouteManager.getRoute(request).getName();
+    return RequestUrlTemplate.valueOf(routename).getDescription();
+  }
+
+  // hoisting rule: atom:entry/atom:author/atom:uri aliases "user_id"
+  @Override
+  public String getAuthor(RequestContext request)
+      throws ResponseContextException {
+    return request.getTarget().getParameter("uid");
+  }
+
+
+}

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

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/PersonAdapter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/PersonAdapter.java?rev=674954&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/PersonAdapter.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/atom/PersonAdapter.java Tue Jul  8 14:00:54 2008
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.shindig.social.abdera.atom;
+
+import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.social.abdera.RequestUrlTemplate;
+import org.apache.shindig.social.abdera.SocialRouteManager;
+import org.apache.shindig.social.opensocial.PeopleService;
+import org.apache.shindig.social.opensocial.model.Person;
+
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.context.ResponseContextException;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * This Collection is backed by a set of Person entities
+ * The Adapter needs People and Groups.
+ * The PeopleService comes from the base class. Groups is unimplemented.
+ */
+public class PersonAdapter extends
+    AbstractSocialEntityCollectionAdapter<Person> {
+  private static Logger logger = Logger
+      .getLogger(PersonAdapter.class.getName());
+
+  
+  /**
+   * Query the underlying model for an Person object.
+   *
+   * @param resourceName An id string that identifies a Person.
+   * @param request Abdera's RequestContext.
+   * @return An Person entity.
+   */
+  @Override
+  public Person getEntry(String resourceName, RequestContext request)
+      throws ResponseContextException {
+    String uid = request.getTarget().getParameter("uid");
+    // Get a token assuming the {uid} is the viewerid.
+    // TODO: Replace hardcoded token viewerid with a SubjectResolver.
+    SecurityToken authToken = getSecurityToken(request, uid);
+    return peopleService.getPerson(resourceName, authToken).getResponse();
+  }
+
+  /**
+   * Get's the name of the specific resource requested.
+   * There is some logic to handle some request parsing here since this
+   * adapter handles the getEntry method for two Person entries:
+   * PROFILE_OF_CONNECTION_OF_USER and PROFILE_OF_USER
+   */
+  @Override
+  protected String getResourceName(RequestContext request) {
+    switch (SocialRouteManager.getUrlTemplate(request)) {
+      case ATOM_PROFILE_OF_CONNECTION_OF_USER:
+        List<String> cids = getConnectionIds(request, request.getTarget()
+            .getParameter("uid"), securityTokenDecoder, peopleService);
+        // TODO: Improve the service apis so we can get rid of relational code.
+        for (String cid : cids) {
+          if (cid.equals(request.getTarget().getParameter("pid"))) {
+            return cid;
+          }
+        }
+        return null;
+      case ATOM_PROFILE_OF_USER:
+        return request.getTarget().getParameter("uid");
+      default:
+        // TODO: Clean this code up so we don't need this check
+        throw new UnsupportedOperationException(
+            "The person adpater was reached with an unsupported url");
+    }
+  }
+
+  /**
+   * atom:entry/atom:id aliases the "id" field. In the Atom format, it is
+   * translated into the required URI data type by prepending "urn:guid:" to the
+   * OpenSocial ID string.
+   */
+  @Override
+  public String getId(Person personObj) throws ResponseContextException {
+    return ID_PREFIX + personObj.getId();
+  }
+
+  // hoisting rule: atom:entry/atom:author/atom:uri aliases ?
+  @Override
+  public List<org.apache.abdera.model.Person> getAuthors(Person personObj,
+      RequestContext request) throws ResponseContextException {
+    org.apache.abdera.model.Person author = factory.newAuthor();
+    author.setUri(ID_PREFIX + personObj.getId());
+    return Arrays.asList(author);
+  }
+
+  /**
+   * Get the name of the entry resource (used to construct links)
+   */
+  @Override
+  public String getName(Person personObj) throws ResponseContextException {
+    return personObj.getId();
+  }
+
+  // hoisting rule: atom:entry/atom:title aliases ?
+  @Override
+  public String getTitle(Person personObj) throws ResponseContextException {
+    return personObj.getName().getUnstructured();
+  }
+
+  @Override
+  public Date getUpdated(Person personObj) throws ResponseContextException {
+    return personObj.getUpdated();
+  }
+
+  // hoisting rule: atom:entry/atom:summary aliases ?
+  @Override
+  public String getSummary(Person personObj) throws ResponseContextException {
+    return null;
+  }
+
+  // hoisting rule: atom:entry/atom:published aliases ?
+  public Long getPublished(Person personObj)
+      throws ResponseContextException {
+    // TODO: Add published element to the entry object.
+    // TODO: Switch based on output format from RFC date to epoch-based.
+    // POSTED_TIME is seconds since the epoch.
+    return null;
+  }
+
+  /**
+   * This is where some person entry format customization happens.
+   *
+   * @param request Abdera's RequestContext.
+   * @param entry The entry FOM object.
+   * @param feedIri The feed IRI that the entry came from.
+   * @param personObj The object that the entry is based on.
+   * @throws ResponseContextException
+   */
+  @Override
+  protected void addOptionalEntryDetails(RequestContext request, Entry entry,
+      IRI feedIri, Person personObj) throws ResponseContextException {
+    String link = getLink(personObj, feedIri, request);
+    // TODO: this should create links that are aware of the request format.
+    entry.addLink(link, "self", "application/atom+xml", null, null, 0);
+
+    // TODO:
+    // atom:entry/atom:published aliases ?
+  }
+
+  /**
+   * Unimplemented Data methods
+   */
+  @Override
+  public void deleteEntry(String resourceName, RequestContext request)
+      throws ResponseContextException {
+    // TODO: Auto-generated method stub
+  }
+
+  /**
+   * Query the underlying model for the list person objects.
+   *
+   * There is some logic to handle some request dispatching here since this
+   * adapter handles the getFeed method for three Person collections:
+   * PROFILES_OF_CONNECTIONS_OF_USER, PROFILES_OF_FRIENDS_OF_USER and
+   * PROFILES_IN_GROUP_OF_USER
+   *
+   * @param request RequestContext
+   * @return A List Person entities.
+   */
+  @Override
+  public Iterable<Person> getEntries(RequestContext request)
+      throws ResponseContextException {
+    String uid = request.getTarget().getParameter("uid");
+    List<String> ids;
+    switch (SocialRouteManager.getUrlTemplate(request)) {
+      case ATOM_PROFILES_OF_CONNECTIONS_OF_USER :
+        ids = getConnectionIds(request, uid, securityTokenDecoder, peopleService);
+        break;
+      case ATOM_PROFILES_OF_FRIENDS_OF_USER :
+        // TODO: Change activities service to handle the friend lookup itself
+        ids = getFriendIds(request, uid);
+        break;
+      case ATOM_PROFILES_IN_GROUP_OF_USER :
+        // TODO: add something like ids = getGroupIds(request, gid);
+        // For now, this just returns the friends.
+        ids = getFriendIds(request, uid);
+        break;
+      default:
+        // TODO: Clean this code up so we don't need this check
+        throw new UnsupportedOperationException(
+            "The person adpater was reached with an unsupported url");
+    }
+    // Get a token assuming the {uid} is the viewerid.
+    // TODO: Replace hardcoded token viewerid with a SubjectResolver.
+    SecurityToken authToken = getSecurityToken(request, uid);
+    return peopleService.getPeople(ids, PeopleService.SortOrder.name, null, 0,
+        100, null, authToken).getResponse().getItems();
+  }
+
+  @Override
+  public Person postEntry(String title, IRI id, String summary, Date updated,
+      List<org.apache.abdera.model.Person> authors, Content content,
+      RequestContext request) throws ResponseContextException {
+    // TODO: Implement
+    return null;
+  }
+
+  @Override
+  public void putEntry(Person personObj, String title, Date updated,
+      List<org.apache.abdera.model.Person> authors, String summary,
+      Content content, RequestContext request) throws ResponseContextException {
+    // TODO: Implement
+  }
+
+  /**
+   * Collection-level hoisting rules
+   */
+
+  /**
+   * The collection-level URL. Calls the getFeedIriForEntry and nulls "pid".
+   *
+   * @param request RequestContext
+   * @return The absolute request URI (includes server name, port, etc) URL
+   */
+  @Override
+  public String getHref(RequestContext request) {
+    return getFeedIriForEntry(request, "pid");
+  }
+
+  @Override
+  public String getId(RequestContext request) {
+    // TODO: what really to return for the feed ID? Better data will help.
+    return getHref(request);
+  }
+
+  public String getTitle(RequestContext request) {
+    String routename = SocialRouteManager.getRoute(request).getName();
+    return RequestUrlTemplate.valueOf(routename).getDescription();
+  }
+
+  // hoisting rule: atom:entry/atom:author/atom:uri aliases ?
+  @Override
+  public String getAuthor(RequestContext request)
+      throws ResponseContextException {
+    return request.getTarget().getParameter("uid");
+  }
+
+}

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java?rev=674954&r1=674953&r2=674954&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/JSONFilter.java Tue Jul  8 14:00:54 2008
@@ -17,8 +17,9 @@
 */
 package org.apache.shindig.social.abdera.json;
 
-import org.apache.shindig.social.abdera.AbstractSocialEntityCollectionAdapter;
+import org.apache.shindig.social.abdera.RawResponseContext;
 import org.apache.shindig.social.abdera.RequestUrlTemplate;
+import org.apache.shindig.social.abdera.SocialRouteManager;
 import org.apache.shindig.social.abdera.util.ValidRequestFilter;
 import org.apache.shindig.social.abdera.util.ValidRequestFilter.Format;
 
@@ -56,6 +57,10 @@
 
   public ResponseContext filter(RequestContext request, FilterChain chain) {
     ResponseContext resp = chain.next(request);
+    // Bypass the filter for RawResponseContext responses.
+    if (resp.getClass().equals(RawResponseContext.class)){
+      return resp;
+    }
     Format format = ValidRequestFilter.getFormatTypeFromRequest(request);
     if (format == Format.ATOM) {
       return resp;
@@ -126,7 +131,7 @@
         JSONObject json = new JSONObject();
 
         try {
-          RequestUrlTemplate url = AbstractSocialEntityCollectionAdapter
+          RequestUrlTemplate url = SocialRouteManager
               .getUrlTemplate(request);
 
           // If the type of object is Data, then we want to create a JSONObject

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/PersonJsonAdapter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/PersonJsonAdapter.java?rev=674954&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/PersonJsonAdapter.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/json/PersonJsonAdapter.java Tue Jul  8 14:00:54 2008
@@ -0,0 +1,76 @@
+/*
+ * 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.abdera.json;
+
+import com.google.inject.Inject;
+
+import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.social.ResponseItem;
+import org.apache.shindig.social.abdera.SocialRequestContext;
+import org.apache.shindig.social.abdera.SocialRouteManager;
+import org.apache.shindig.social.dataservice.GroupId;
+import org.apache.shindig.social.dataservice.RestfulCollection;
+import org.apache.shindig.social.dataservice.UserId;
+import org.apache.shindig.social.opensocial.model.Person;
+import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
+
+import java.util.concurrent.Future;
+
+public class PersonJsonAdapter extends SimpleJsonAdapter<Person> {
+
+  @Inject
+  public PersonJsonAdapter(BeanJsonConverter beanJsonConverter) {
+    super(beanJsonConverter);
+  }
+
+  @Override
+  public Future<ResponseItem<Person>> getEntity(SocialRequestContext request, SecurityToken token) {
+    String uid = request.getTarget().getParameter("uid");
+    UserId userId = UserId.fromJson(uid);
+
+    return personService.getPerson(userId, request.getFields(), token);
+  }
+
+  @Override
+  public Future<ResponseItem<RestfulCollection<Person>>> getEntities(SocialRequestContext request,
+      SecurityToken token) {
+    String uid = request.getTarget().getParameter("uid");
+    UserId userId = UserId.fromJson(uid);
+
+    GroupId groupId;
+    switch (SocialRouteManager.getUrlTemplate(request)) {
+      case JSON_PROFILES_OF_CONNECTIONS_OF_USER:
+        groupId = new GroupId(GroupId.Type.all, "all");
+        break;
+      case JSON_PROFILES_OF_FRIENDS_OF_USER:
+        // TODO: Change activities service to handle the friend lookup itself
+        groupId = new GroupId(GroupId.Type.friends, "friends");
+        break;
+      case JSON_PROFILES_IN_GROUP_OF_USER:
+        groupId = new GroupId(GroupId.Type.groupId, request.getTarget().getParameter("gid"));
+        break;
+      default:
+        // TODO: Clean this code up so we don't need this check
+        throw new UnsupportedOperationException(
+            "The person adpater was reached with an unsupported url");
+    }
+
+    return personService.getPeople(userId, groupId, request.getOrderBy(), request.getFilterBy(),
+        request.getStartIndex(), request.getCount(), request.getFields(), token);
+  }
+}