@Override
  public List<User> getApplicationFollowers(String applicationId) throws TException {
    checkAppId(applicationId);

    Statement query = createQueryForFollowersOfApp(applicationId);

    ResultSet results;

    try {
      results = cassandra.execute(query);
    } catch (Exception ex) {
      LOG.error("Failed to query for App's followed: App: [{}]", applicationId, ex);
      throw new OperationFailedException("Could not query for App's Followers: " + ex.getMessage());
    }

    List<User> followers = Lists.create();

    for (Row row : results) {
      User follower = createUserFromRow(row);
      followers.add(follower);
    }

    LOG.debug("Found {} Users followed App [{}]", followers.size(), applicationId);
    return followers;
  }
  @Override
  public List<Application> getApplicationsFollowedBy(String userId) throws TException {
    checkUserId(userId);

    Statement query = createQueryForAppsFollowedBy(userId);

    ResultSet results;

    try {
      results = cassandra.execute(query);
    } catch (Exception ex) {
      LOG.error("Failed to query Cassandra for apps followed by User: [{}]", userId, ex);
      throw new OperationFailedException(
          "Could not find apps followed by user: "******"Found {} apps followed by {}", apps.size(), userId);
    return apps;
  }
  @Override
  public boolean containsEvent(@Required String eventId, @Required User user) throws TException {
    checkEventId(eventId);
    checkUser(user);

    return this.events
        .getOrDefault(user, Lists.emptyList())
        .stream()
        .anyMatch(e -> Objects.equal(e.eventId, eventId));
  }
  @Override
  public void saveEvent(Event event, User forUser, LengthOfTime lifetime) throws TException {
    checkEvent(event);
    checkUser(forUser);
    checkLifetime(lifetime);
    User user = forUser;

    List<Event> eventsForUser = events.getOrDefault(user, Lists.create());
    eventsForUser.add(event);
    events.put(user, eventsForUser);
  }
  @Override
  public Event getEvent(String eventId, User user) throws TException {
    checkUser(user);
    checkEventId(eventId);

    return events
        .getOrDefault(user, Lists.emptyList())
        .stream()
        .filter(e -> Objects.equal(e.eventId, eventId))
        .findFirst()
        .orElseThrow(() -> new DoesNotExistException("Event does not exist"));
  }
  @Override
  public void deleteEvent(String eventId, User user) throws TException {
    checkEventId(eventId);
    checkUser(user);

    List<Event> eventsForUser =
        events
            .getOrDefault(user, Lists.emptyList())
            .stream()
            .filter(e -> !Objects.equal(e.eventId, eventId))
            .collect(toList());

    events.put(user, eventsForUser);
  }
  @Override
  public List<Event> getAllEventsFor(User user) throws TException {
    checkUser(user);

    return events.getOrDefault(user, Lists.emptyList());
  }