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

svn commit: r656517 - in /incubator/shindig/trunk/java/social-api/src: main/java/org/apache/shindig/social/abdera/ main/java/org/apache/shindig/social/samplecontainer/ test/java/org/apache/shindig/social/abdera/

Author: doll
Date: Wed May 14 23:30:43 2008
New Revision: 656517

URL: http://svn.apache.org/viewvc?rev=656517&view=rev
Log:
SHINDIG-265
Patch from David Primmer, modified for code style fixes. This change introduces a cleaner way to write the abdera adapter classes. The next step here is to refactor the current adapter classes to use the new code.



Added:
    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
Modified:
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java
    incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/SocialApiProviderTestFixture.java

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/AbstractSocialEntityCollectionAdapter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/AbstractSocialEntityCollectionAdapter.java?rev=656517&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/AbstractSocialEntityCollectionAdapter.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/AbstractSocialEntityCollectionAdapter.java Wed May 14 23:30:43 2008
@@ -0,0 +1,222 @@
+/*
+ * 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;
+
+import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.common.SecurityTokenDecoder;
+import org.apache.shindig.common.SecurityTokenException;
+import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
+import org.apache.shindig.social.opensocial.util.BeanXmlConverter;
+
+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.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 java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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.
+ *
+ * @param <T> The entity that this is backed by.
+ */
+
+public abstract class AbstractSocialEntityCollectionAdapter<T> extends
+    AbstractEntityCollectionAdapter<T> {
+
+  protected String ID_PREFIX;
+  protected Factory factory;
+  private BeanXmlConverter beanXmlConverter;
+  private BeanJsonConverter beanJsonConverter;
+  private SecurityTokenDecoder securityTokenDecoder;
+
+  public AbstractSocialEntityCollectionAdapter() {
+    ID_PREFIX = "urn:guid:";
+    factory = new Abdera().getFactory();
+  }
+
+  private enum Format {
+    JSON("json"), ATOM("atom");
+
+    private final String displayValue;
+
+    private Format(String displayValue) {
+      this.displayValue = displayValue;
+    }
+
+    public String getDisplayValue() {
+      return displayValue;
+    }
+  }
+
+  @Inject
+  public void setConverters(BeanXmlConverter beanXmlConverter,
+      BeanJsonConverter beanJsonConverter) {
+    this.beanXmlConverter = beanXmlConverter;
+    this.beanJsonConverter = beanJsonConverter;
+  }
+
+  @Inject
+  public void setSecurityTokenDecoder(SecurityTokenDecoder
+      securityTokenDecoder) {
+    this.securityTokenDecoder = securityTokenDecoder;
+  }
+
+  protected SecurityToken getSecurityToken(RequestContext request)
+      throws SecurityTokenException {
+    String token = request.getParameter("st");
+    if (token == null || token.trim().length() == 0) {
+      throw new SecurityTokenException("Missing security token");
+    }
+    return securityTokenDecoder.createToken(token);
+  }
+
+  /**
+   * returns the format (jsoc or atom) from the RequestContext obj created by
+   * Abdera from the URL request.
+   *
+   * @param request the RequestContext obj from Abdera
+   * @return the format and default to Format.JSON
+   */
+  private Format getFormatTypeFromRequest(RequestContext request) {
+    // TODO should gracefully handle introspection if format param is missing.
+    String format = request.getTarget().getParameter("format");
+
+    if (format != null && format.equals(Format.ATOM.getDisplayValue())) {
+      return Format.ATOM;
+    } else {
+      return Format.JSON;
+    }
+  }
+
+  /**
+   * @param request RequestContext
+   * @param resourceRouteVariable The route variable for the entry. So, for a
+   *     route pattern of /:collection/:id, with "id" resourceRouteVariable this
+   *     would null out "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 = new HashMap<String, Object>();
+    params.put(resourceRouteVariable, null);
+    String uri = request.urlFor(getRoute(request).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 the request
+   * @return The Route object that matched the request.
+   */
+  public Route getRoute(RequestContext request) {
+    Object matcher = request.getTarget().getMatcher();
+    if (matcher instanceof Route) {
+      return (Route) matcher;
+    } else {
+      throw new NullPointerException();
+    }
+  }
+
+  @Override
+  public Object getContent(T entity, RequestContext request)
+      throws ResponseContextException {
+    Format format = 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 The request context
+   * @param e The entry
+   * @param feedIri The feed IRI
+   * @param entity The object that the entry is based on.
+   */
+  @Override
+  protected String addEntryDetails(RequestContext request, Entry e,
+      IRI feedIri, T entity) throws ResponseContextException {
+    String link = getLink(entity, feedIri, request);
+
+    e.addLink(link, "self", "application/atom+xml", null, null, 0);
+    e.setId(getId(entity));
+    e.setTitle(getTitle(entity));
+    e.setUpdated(getUpdated(entity));
+    e.setSummary(getSummary(entity));
+    List<Person> authors = getAuthors(entity, request);
+    if (authors != null) {
+      for (Person a : authors) {
+        e.addAuthor(a);
+      }
+    }
+    return link;
+  }
+
+  /**
+   * Unimplemented HTTP methods
+   */
+
+  @Override
+  public ResponseContext deleteEntry(RequestContext request) {
+    return null;
+  }
+
+  @Override
+  public ResponseContext postEntry(RequestContext request) {
+    return null;
+  }
+
+  @Override
+  public ResponseContext putEntry(RequestContext request) {
+    return null;
+  }
+
+  @Override
+  public ResponseContext getFeed(RequestContext request) {
+    return null;
+  }
+}

Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/ActivityAdapter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/ActivityAdapter.java?rev=656517&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/ActivityAdapter.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/ActivityAdapter.java Wed May 14 23:30:43 2008
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+import org.apache.shindig.common.BasicSecurityToken;
+import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.common.SecurityTokenException;
+import org.apache.shindig.common.crypto.BlobCrypterException;
+import org.apache.shindig.social.opensocial.ActivitiesService;
+import org.apache.shindig.social.opensocial.model.Activity;
+
+import com.google.inject.Inject;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Person;
+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;
+
+/**
+ * This Collection is backed by a set of Activity entities
+ */
+public class ActivityAdapter extends
+    AbstractSocialEntityCollectionAdapter<Activity> {
+
+  private ActivitiesService activitiesService;
+
+  @Inject
+  public ActivityAdapter(ActivitiesService activitiesService) {
+    this.activitiesService = activitiesService;
+  }
+
+  @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();
+  }
+
+  private SecurityToken getSecurityToken(RequestContext request,
+      final String viewerId) {
+    try {
+      return super.getSecurityToken(request);
+    } catch (SecurityTokenException se) {
+      // For now, if there's no st param, we'll mock one up.
+      try {
+        return new BasicSecurityToken("o", viewerId, "a", "d", "u", "m");
+      } catch (BlobCrypterException be) {
+        be.printStackTrace();
+        return null;
+      }
+    }
+  }
+
+  @Override
+  public String getId(Activity activityObj) throws ResponseContextException {
+    return 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);
+  }
+
+  @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();
+  }
+
+  @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();
+  }
+
+  /**
+   * Unimplemented Data methods
+   */
+  @Override
+  public void deleteEntry(String resourceName, RequestContext request)
+      throws ResponseContextException {
+    // TODO Auto-generated method stub
+  }
+
+  @Override
+  public Iterable<Activity> getEntries(RequestContext request)
+      throws ResponseContextException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Activity postEntry(String title, IRI id, String summary, Date updated,
+      List<Person> authors, Content content, RequestContext request)
+      throws ResponseContextException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void putEntry(Activity entry, String title, Date updated,
+      List<Person> authors, String summary, Content content,
+      RequestContext request) throws ResponseContextException {
+    // TODO Auto-generated method stub
+  }
+
+  /**
+   * 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:title aliases "stream_title"
+  // TODO stream_title can't be accessed right here....
+  public String getTitle(RequestContext request) {
+    return getRoute(request).getName();
+  }
+
+  // hoisting rule: atom:entry/atom:author/atom:uri aliases "user_id"
+  @Override
+  public String getAuthor(RequestContext request)
+      throws ResponseContextException {
+    return request.getTarget().getParameter("uid");
+  }
+}

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java?rev=656517&r1=656516&r2=656517&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/abdera/SocialApiProvider.java Wed May 14 23:30:43 2008
@@ -32,7 +32,8 @@
   private Provider<ActivitiesServiceAdapter> activitiesAdapterProvider;
   private Provider<FriendsServiceAdapter> friendsAdapterProvider;
   private Provider<DataServiceAdapter> dataAdapterProvider;
-
+  private Provider<ActivityAdapter> activityAdapterProvider;
+  
   /**
    * The CollectionAdapter enum standardizes the names and descriptions of the
    * URL templates as defined in the RESTful API spec. Each unique template has
@@ -79,12 +80,14 @@
       Provider<PeopleServiceAdapter> peopleAdapterProvider,
       Provider<FriendsServiceAdapter> friendsAdapterProvider,
       Provider<ActivitiesServiceAdapter> activitiesAdapterProvider,
-      Provider<DataServiceAdapter> dataAdapterProvider) {
+      Provider<DataServiceAdapter> dataAdapterProvider,
+      Provider<ActivityAdapter> activityAdapterProvider) {
     this.peopleAdapterProvider = peopleAdapterProvider;
     this.friendsAdapterProvider = friendsAdapterProvider;
     this.activitiesAdapterProvider = activitiesAdapterProvider;
     this.dataAdapterProvider = dataAdapterProvider;
-  }
+    this.activityAdapterProvider = activityAdapterProvider;
+    }
 
   /**
    * CollectionAdapters are provided via Guice and the RouteManager wires
@@ -109,6 +112,7 @@
     ActivitiesServiceAdapter activitiesAdapter
         = activitiesAdapterProvider.get();
     DataServiceAdapter dataAdapter = dataAdapterProvider.get();
+    ActivityAdapter activityAdapter = activityAdapterProvider.get();
 
     // Add the RouteManager that parses incoming and builds outgoing URLs
     // {uid} is assumed to be a deterministic GUID for the service
@@ -170,7 +174,7 @@
         // /activities/{uid}/@self/{aid}
         .addRoute(CollectionAdapter.ACTIVITY_OF_USER.toString(),
             BASE + "activities/:uid/@self/:aid",
-            TargetType.TYPE_ENTRY, activitiesAdapter)
+            TargetType.TYPE_ENTRY, activityAdapter)
 
 
         // AppData

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java?rev=656517&r1=656516&r2=656517&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java Wed May 14 23:30:43 2008
@@ -9,7 +9,6 @@
 
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
-
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.methods.GetMethod;
@@ -20,6 +19,8 @@
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -29,9 +30,6 @@
 import java.util.List;
 import java.util.Map;
 
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
 @Singleton
 public class XmlStateFileFetcher {
   private static final String DEFAULT_STATE_URL

Modified: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/SocialApiProviderTestFixture.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/SocialApiProviderTestFixture.java?rev=656517&r1=656516&r2=656517&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/SocialApiProviderTestFixture.java (original)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/abdera/SocialApiProviderTestFixture.java Wed May 14 23:30:43 2008
@@ -39,14 +39,17 @@
   public final Provider<DataServiceAdapter> dataProvider =
     mock(Provider.class);
   public final SocialApiProvider provider = new SocialApiProvider();
-
+  public final Provider<ActivityAdapter> activityProvider =
+    mock(Provider.class);
+  
   public SocialApiProviderTestFixture() {
     provider.setAdapters(peopleProvider, friendsProvider, activitiesProvider,
-        dataProvider);
+        dataProvider, activityProvider);
     expect(activitiesProvider.get()).andReturn(null);
     expect(peopleProvider.get()).andReturn(null);
     expect(friendsProvider.get()).andReturn(null);
     expect(dataProvider.get()).andReturn(null);
+    expect(activityProvider.get()).andReturn(null);
     org.easymock.EasyMock.replay(activitiesProvider);
     org.easymock.EasyMock.replay(peopleProvider);
     org.easymock.EasyMock.replay(friendsProvider);