/**
   * Gets the activities.
   *
   * @param userId the user id
   * @param token the token
   * @param activityIds the activity ids
   * @return the activities
   */
  private List<Activity> getActivities(
      UserId userId, Set<String> activityIds, SecurityToken token) {
    StringBuilder sb = new StringBuilder();
    sb.append(ActivityDb.JPQL_FINDBY_ACTIVITIES);
    List<String> paramList = SPIUtils.toList(activityIds);
    String uid = SPIUtils.getUserList(userId, token);
    int lastPos = JPQLUtils.addInClause(sb, "a", "id", 1, paramList.size());
    sb.append(" and a.userid = ?").append(lastPos);
    lastPos++;
    paramList.add(uid);
    EntityManager entityManager = getEntityManager();

    List<Activity> a = JPQLUtils.getListQuery(entityManager, sb.toString(), paramList, null);
    entityManager.close();
    return a;
  }
  /* (non-Javadoc)
   * @see org.apache.shindig.social.opensocial.spi.ActivityService#getActivities(java.util.Set, org.apache.shindig.social.opensocial.spi.GroupId, java.lang.String, java.util.Set, org.apache.shindig.social.opensocial.spi.CollectionOptions, org.apache.shindig.auth.SecurityToken)
   */
  public Future<RestfulCollection<Activity>> getActivities(
      Set<UserId> userIds,
      GroupId groupId,
      String appId,
      Set<String> fields,
      CollectionOptions options,
      SecurityToken token)
      throws ProtocolException {

    List<Activity> plist = null;
    int lastPos = 1;

    StringBuilder sb = new StringBuilder();
    // sanitize the list to get the uid's and remove duplicates
    List<String> paramList = SPIUtils.getUserList(userIds, token);
    // select the group Id as this will drive the query
    switch (groupId.getType()) {
      case all:
        // select all contacts activity
        sb.append(ActivityDb.JPQL_FINDACTIVITY);
        JPQLUtils.addInClause(sb, "a", "userId", lastPos, paramList.size());
        sb.append(" or a.userId in (select m.person.id from GroupDb g join g.members m where ");
        lastPos = JPQLUtils.addInClause(sb, "g.owner", "id", lastPos, paramList.size());
        sb.append(")");
        break;
      case friends:
        // select all friends (subset of contacts)
        sb.append(ActivityDb.JPQL_FINDACTIVITY_BY_FRIENDS);
        lastPos = JPQLUtils.addInClause(sb, "p", "id", lastPos, paramList.size());
        sb.append(")) ");
        // TODO Group by doesn't work in HSQLDB or Derby - causes a "Not in aggregate function or
        // group by clause" jdbc exception
        // sb.append(" group by p ");
        break;
      case groupId:
        sb.append(ActivityDb.JPQL_FINDACTIVITY_BY_GROUP);
        paramList.add(groupId.getGroupId());
        lastPos += 2;
        break;
      case deleted:
        // ???
        break;
      case self:
        // select self
        sb.append(ActivityDb.JPQL_FINDACTIVITY);
        lastPos = JPQLUtils.addInClause(sb, "a", "userId", lastPos, paramList.size());
        break;
      default:
        throw new ProtocolException(HttpServletResponse.SC_BAD_REQUEST, "Group ID not recognized");
    }

    JPQLUtils.addFilterClause(sb, ActivityDb.FILTER_CAPABILITY, options, paramList);

    EntityManager entityManager = getEntityManager();

    // Get total results, that is count the total number of rows for this query
    Long totalResults = JPQLUtils.getTotalResults(entityManager, sb.toString(), paramList);
    if (options == null) options = new CollectionOptions();

    // Execute paginated query
    if (totalResults > 0) {
      JPQLUtils.addOrderClause(sb, options, "a");
      plist = JPQLUtils.getListQuery(entityManager, sb.toString(), paramList, options);
    }
    entityManager.close();
    if (plist == null) {
      plist = new ArrayList<Activity>();
    }

    // all of the above could equally have been placed into a thread to overlay the
    // db wait times.
    RestfulCollection<Activity> restCollection =
        new RestfulCollection<Activity>(
            plist, options.getFirst(), totalResults.intValue(), options.getMax());
    return ImmediateFuture.newInstance(restCollection);
  }