private static CNSSubscription extractSubscriptionFromColumn(
      CmbColumn<CmbComposite, String> column, String topicArn) throws JSONException {

    JSONObject json = new JSONObject(column.getValue());
    CNSSubscription s = new CNSSubscription(json.getString("subArn"));

    s.setEndpoint(json.getString("endPoint"));
    s.setUserId(json.getString("userId"));

    if (json.has("confirmDate")) {
      s.setConfirmDate(new Date(json.getLong("confirmDate")));
    }

    if (json.has("requestDate")) {
      s.setRequestDate(new Date(json.getLong("requestDate")));
    }

    if (json.has("protocol")) {
      s.setProtocol(CnsSubscriptionProtocol.valueOf(json.getString("protocol")));
    }

    if (json.has("isConfirmed")) {
      s.setConfirmed(json.getBoolean("isConfirmed"));
    }

    s.setToken(json.getString("token"));

    if (json.has("authenticateOnSubscribe")) {
      s.setAuthenticateOnUnsubscribe(json.getBoolean("authenticateOnSubscribe"));
    }

    if (json.has("rawMessageDelivery")) {
      s.setRawMessageDelivery(json.getBoolean("rawMessageDelivery"));
    }

    s.setTopicArn(topicArn);

    return s;
  }
  private List<CNSSubscription> listSubscriptions(
      String nextToken, CnsSubscriptionProtocol protocol, String userId, boolean hidePendingArn)
      throws Exception {

    if (nextToken != null) {
      if (getSubscription(nextToken) == null) {
        throw new SubscriberNotFoundException("Subscriber not found for arn " + nextToken);
      }
    }

    // Algorithm is to keep reading in chunks of 100 till we've seen 500 from the nextToken-ARN
    List<CNSSubscription> l = new ArrayList<CNSSubscription>();
    // read form index to get sub-arn

    while (l.size() < 100) {

      CmbColumnSlice<String, String> slice =
          cassandraHandler.readColumnSlice(
              AbstractDurablePersistence.CNS_KEYSPACE,
              columnFamilySubscriptionsUserIndex,
              userId,
              nextToken,
              null,
              500,
              CMB_SERIALIZER.STRING_SERIALIZER,
              CMB_SERIALIZER.STRING_SERIALIZER,
              CMB_SERIALIZER.STRING_SERIALIZER);

      if (slice == null) {
        return l;
      }

      // get Column from main table
      List<CmbColumn<String, String>> cols = slice.getColumns();

      if (nextToken != null) {
        cols.remove(0);
      }

      if (cols.size() == 0) {
        return l;
      }

      for (CmbColumn<String, String> col : cols) {

        String subArn = col.getName();
        CNSSubscription subscription = getSubscription(subArn);

        if (subscription == null) {
          throw new IllegalStateException(
              "Subscriptions-user-index contains subscription-arn which doesn't exist in subscriptions-index. subArn:"
                  + subArn);
        }

        // ignore invalid subscriptions coming from Cassandra

        try {
          subscription.checkIsValid();
        } catch (CMBException ex) {
          logger.error("event=invalid_subscription " + subscription.toString(), ex);
          continue;
        }

        if (protocol != null && subscription.getProtocol() != protocol) {
          continue;
        }

        if (hidePendingArn) {
          if (subscription.isConfirmed()) {
            l.add(subscription);
          } else {
            subscription.setArn("PendingConfirmation");
            l.add(subscription);
          }
        } else {
          l.add(subscription);
        }

        if (l.size() == 100) {
          return l;
        }
      }

      nextToken = cols.get(cols.size() - 1).getName();
    }

    return l;
  }