private void deleteIndexesAll(List<CNSSubscription> subscriptionList)
     throws PersistenceException {
   List<String> subArnList = new LinkedList<String>();
   List<String> userIdList = new LinkedList<String>();
   List<String> tokenList = new LinkedList<String>();
   for (CNSSubscription sub : subscriptionList) {
     subArnList.add(sub.getArn());
     userIdList.add(sub.getUserId());
     tokenList.add(sub.getToken());
   }
   cassandraHandler.deleteBatch(
       AbstractDurablePersistence.CNS_KEYSPACE,
       columnFamilySubscriptionsIndex,
       subArnList,
       null,
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER);
   cassandraHandler.deleteBatch(
       AbstractDurablePersistence.CNS_KEYSPACE,
       columnFamilySubscriptionsUserIndex,
       userIdList,
       subArnList,
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER);
   cassandraHandler.deleteBatch(
       AbstractDurablePersistence.CNS_KEYSPACE,
       columnFamilySubscriptionsTokenIndex,
       tokenList,
       subArnList,
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER);
 }
  private String getColumnValuesJSON(CNSSubscription s) throws JSONException {

    Writer writer = new StringWriter();
    JSONWriter jw = new JSONWriter(writer);
    jw = jw.object();

    if (s.getEndpoint() != null) {
      jw.key("endPoint").value(s.getEndpoint());
    }

    if (s.getToken() != null) {
      jw.key("token").value(s.getToken());
    }

    if (s.getArn() != null) {
      jw.key("subArn").value(s.getArn());
    }

    if (s.getUserId() != null) {
      jw.key("userId").value(s.getUserId());
    }

    if (s.getConfirmDate() != null) {
      jw.key("confirmDate").value(s.getConfirmDate().getTime() + "");
    }

    if (s.getProtocol() != null) {
      jw.key("protocol").value(s.getProtocol().toString());
    }

    if (s.getRequestDate() != null) {
      jw.key("requestDate").value(s.getRequestDate().getTime() + "");
    }

    jw.key("authenticateOnSubscribe").value(s.isAuthenticateOnUnsubscribe() + "");
    jw.key("isConfirmed").value(s.isConfirmed() + "");
    jw.key("rawMessageDelivery").value(s.getRawMessageDelivery() + "");

    jw.endObject();

    return writer.toString();
  }
 private void insertOrUpdateSubsAndIndexes(final CNSSubscription subscription, Integer ttl)
     throws Exception {
   subscription.checkIsValid();
   CmbComposite columnName =
       cassandraHandler.getCmbComposite(
           subscription.getEndpoint(), subscription.getProtocol().name());
   cassandraHandler.update(
       AbstractDurablePersistence.CNS_KEYSPACE,
       columnFamilySubscriptions,
       subscription.getTopicArn(),
       columnName,
       getColumnValuesJSON(subscription),
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.COMPOSITE_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER,
       ttl);
   cassandraHandler.insertRow(
       AbstractDurablePersistence.CNS_KEYSPACE,
       subscription.getArn(),
       columnFamilySubscriptionsIndex,
       getIndexColumnValues(subscription.getEndpoint(), subscription.getProtocol()),
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER,
       ttl);
   cassandraHandler.insertRow(
       AbstractDurablePersistence.CNS_KEYSPACE,
       subscription.getUserId(),
       columnFamilySubscriptionsUserIndex,
       new HashMap<String, String>() {
         {
           put(subscription.getArn(), "");
         }
       },
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER,
       ttl);
   cassandraHandler.insertRow(
       AbstractDurablePersistence.CNS_KEYSPACE,
       subscription.getToken(),
       columnFamilySubscriptionsTokenIndex,
       new HashMap<String, String>() {
         {
           put(subscription.getArn(), "");
         }
       },
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER,
       CMB_SERIALIZER.STRING_SERIALIZER,
       ttl);
 }
  @Override
  public void unsubscribe(String arn) throws Exception {

    CNSSubscription s = getSubscription(arn);

    if (s != null) {

      deleteIndexes(arn, s.getUserId(), s.getToken());
      CmbComposite columnName =
          cassandraHandler.getCmbComposite(s.getEndpoint(), s.getProtocol().name());
      cassandraHandler.delete(
          AbstractDurablePersistence.CNS_KEYSPACE,
          columnFamilySubscriptions,
          Util.getCnsTopicArn(arn),
          columnName,
          CMB_SERIALIZER.STRING_SERIALIZER,
          CMB_SERIALIZER.COMPOSITE_SERIALIZER);

      if (s.isConfirmed()) {
        cassandraHandler.decrementCounter(
            AbstractDurablePersistence.CNS_KEYSPACE,
            columnFamilyTopicStats,
            s.getTopicArn(),
            "subscriptionConfirmed",
            1,
            CMB_SERIALIZER.STRING_SERIALIZER,
            CMB_SERIALIZER.STRING_SERIALIZER);
      } else {
        cassandraHandler.decrementCounter(
            AbstractDurablePersistence.CNS_KEYSPACE,
            columnFamilyTopicStats,
            s.getTopicArn(),
            "subscriptionPending",
            1,
            CMB_SERIALIZER.STRING_SERIALIZER,
            CMB_SERIALIZER.STRING_SERIALIZER);
      }

      cassandraHandler.incrementCounter(
          AbstractDurablePersistence.CNS_KEYSPACE,
          columnFamilyTopicStats,
          s.getTopicArn(),
          "subscriptionDeleted",
          1,
          CMB_SERIALIZER.STRING_SERIALIZER,
          CMB_SERIALIZER.STRING_SERIALIZER);
    }
  }
  @Override
  public void unsubscribeAll(String topicArn) throws Exception {

    int pageSize = 1000;

    String nextToken = null;
    List<CNSSubscription> subs =
        listSubscriptionsByTopic(nextToken, topicArn, null, pageSize, false);

    // Note: for pagination to work we need the nextToken's corresponding sub to not be deleted.
    CNSSubscription nextTokenSub = null;
    while (subs.size() > 0) {
      // if retrieve subscription is less than page size, delete all index.
      if (subs.size() < pageSize) {
        deleteIndexesAll(subs);
        break;
      } else {
        // keep the last subscription for pagination purpose.
        nextTokenSub = subs.get(subs.size() - 1);
        nextToken = nextTokenSub.getArn();
        subs.remove(subs.size() - 1);
        deleteIndexesAll(subs);
        subs = listSubscriptionsByTopic(nextToken, topicArn, null, pageSize, false);
        deleteIndexes(nextTokenSub.getArn(), nextTokenSub.getUserId(), nextTokenSub.getToken());
      }
    }

    // int subscriptionConfirmedNum = (int)cassandraHandler.getCounter(CNS_KEYSPACE,
    // columnFamilyTopicStats, topicArn, "subscriptionConfirmed", CMB_SERIALIZER.STRING_SERIALIZER,
    // CMB_SERIALIZER.STRING_SERIALIZER);
    // int subscriptionPendingNum = (int)cassandraHandler.getCounter(CNS_KEYSPACE,
    // columnFamilyTopicStats, topicArn, "subscriptionPending", CMB_SERIALIZER.STRING_SERIALIZER,
    // CMB_SERIALIZER.STRING_SERIALIZER);

    cassandraHandler.incrementCounter(
        AbstractDurablePersistence.CNS_KEYSPACE,
        columnFamilyTopicStats,
        topicArn,
        "subscriptionDeleted",
        1,
        CMB_SERIALIZER.STRING_SERIALIZER,
        CMB_SERIALIZER.STRING_SERIALIZER);
    cassandraHandler.decrementCounter(
        AbstractDurablePersistence.CNS_KEYSPACE,
        columnFamilyTopicStats,
        topicArn,
        "subscriptionConfirmed",
        1,
        CMB_SERIALIZER.STRING_SERIALIZER,
        CMB_SERIALIZER.STRING_SERIALIZER);
    cassandraHandler.decrementCounter(
        AbstractDurablePersistence.CNS_KEYSPACE,
        columnFamilyTopicStats,
        topicArn,
        "subscriptionPending",
        1,
        CMB_SERIALIZER.STRING_SERIALIZER,
        CMB_SERIALIZER.STRING_SERIALIZER);

    cassandraHandler.delete(
        AbstractDurablePersistence.CNS_KEYSPACE,
        columnFamilySubscriptions,
        topicArn,
        null,
        CMB_SERIALIZER.STRING_SERIALIZER,
        CMB_SERIALIZER.STRING_SERIALIZER);
  }