private static CnsSubscriptionProtocol getEndpointAndProtoIndexValProtocol(String composite) { String[] arr = composite.split(":"); if (arr.length < 2) { throw new IllegalArgumentException( "Bad format for EndpointAndProtocol composite. Must be of the form <protocol>:<endpoint>. Got:" + composite); } return CnsSubscriptionProtocol.valueOf(arr[0]); }
@Override public CNSSubscription getSubscription(String arn) throws Exception { // read form index to get composite col-name CmbColumnSlice<String, String> slice = cassandraHandler.readColumnSlice( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilySubscriptionsIndex, arn, null, null, 1, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); if (slice != null) { // get Column from main table String colName = slice.getColumns().get(0).getName(); CnsSubscriptionProtocol protocol = getEndpointAndProtoIndexValProtocol(colName); String endpoint = getEndpointAndProtoIndexValEndpoint(colName); CmbComposite columnName = cassandraHandler.getCmbComposite(endpoint, protocol.name()); CmbColumn<CmbComposite, String> column = cassandraHandler.readColumn( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilySubscriptions, Util.getCnsTopicArn(arn), columnName, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.COMPOSITE_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); if (column != null) { CNSSubscription s = extractSubscriptionFromColumn(column, Util.getCnsTopicArn(arn)); s.checkIsValid(); return s; } } return null; }
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; }
/** * Enumerate all subs in a topic * * @param nextToken The ARN of the last sub-returned or null is first time call. * @param topicArn * @param protocol * @param pageSize * @param hidePendingArn * @return The list of subscriptions given a topic. Note: if nextToken is provided, the returned * list will not contain it for convenience * @throws Exception */ public List<CNSSubscription> listSubscriptionsByTopic( String nextToken, String topicArn, CnsSubscriptionProtocol protocol, int pageSize, boolean hidePendingArn) throws Exception { if (nextToken != null) { if (getSubscription(nextToken) == null) { throw new SubscriberNotFoundException("Subscriber not found for arn " + nextToken); } } // read from index to get composite-col-name corresponding to nextToken CmbComposite nextTokenComposite = null; if (nextToken != null) { CmbColumnSlice<String, String> slice = cassandraHandler.readColumnSlice( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilySubscriptionsIndex, nextToken, null, null, 1, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); if (slice == null) { throw new IllegalArgumentException("Could not find any subscription with arn " + nextToken); } // get Column from main table String colName = slice.getColumns().get(0).getName(); CnsSubscriptionProtocol tokProtocol = getEndpointAndProtoIndexValProtocol(colName); String endpoint = getEndpointAndProtoIndexValEndpoint(colName); nextTokenComposite = cassandraHandler.getCmbComposite(endpoint, tokProtocol.name()); } List<CNSSubscription> l = new ArrayList<CNSSubscription>(); CNSTopic t = PersistenceFactory.getTopicPersistence().getTopic(topicArn); if (t == null) { throw new TopicNotFoundException("Resource not found."); } // read pageSize at a time CmbColumnSlice<CmbComposite, String> cols = cassandraHandler.readColumnSlice( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilySubscriptions, topicArn, nextTokenComposite, null, pageSize, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.COMPOSITE_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); if (nextToken != null && cols.size() > 0) { cols.getColumns().remove(0); } while (l.size() < pageSize) { if (cols == null || cols.size() == 0) { return l; } for (CmbColumn<CmbComposite, String> col : cols.getColumns()) { CNSSubscription sub = extractSubscriptionFromColumn(col, topicArn); // ignore invalid subscriptions coming from Cassandra try { sub.checkIsValid(); } catch (CMBException ex) { logger.error("event=invalid_subscription " + sub.toString(), ex); continue; } if (protocol != null && protocol != sub.getProtocol()) { continue; } if (hidePendingArn) { if (sub.isConfirmed()) { l.add(sub); } else { sub.setArn("PendingConfirmation"); l.add(sub); } } else { l.add(sub); } if (l.size() == pageSize) { return l; } } nextTokenComposite = cols.getColumns().get(cols.size() - 1).getName(); cols = cassandraHandler.readColumnSlice( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilySubscriptions, topicArn, nextTokenComposite, null, pageSize, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.COMPOSITE_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); if (cols.size() > 0) { cols.getColumns().remove(0); } } return l; }
@Override public CNSSubscription subscribe( String endpoint, CnsSubscriptionProtocol protocol, String topicArn, String userId) throws Exception { // subscription is unique by protocol + endpoint + topic final CNSSubscription subscription = new CNSSubscription(endpoint, protocol, topicArn, userId); CNSTopic t = PersistenceFactory.getTopicPersistence().getTopic(topicArn); if (t == null) { throw new TopicNotFoundException("Resource not found."); } // check if queue exists for cqs endpoints if (protocol.equals(CnsSubscriptionProtocol.cqs)) { CQSQueue queue = PersistenceFactory.getQueuePersistence() .getQueue(com.comcast.cqs.util.Util.getRelativeQueueUrlForArn(endpoint)); if (queue == null) { throw new CMBException( CMBErrorCodes.NotFound, "Queue with arn " + endpoint + " does not exist."); } } subscription.setArn(Util.generateCnsTopicSubscriptionArn(topicArn, protocol, endpoint)); // attempt to delete existing subscription /*Composite superColumnName = new Composite(subscription.getEndpoint(), subscription.getProtocol().name()); HSuperColumn<Composite, String, String> superCol = readColumnFromSuperColumnFamily(columnFamilySubscriptions, subscription.getTopicArn(), superColumnName, new StringSerializer(), new CompositeSerializer(), StringSerializer.get(), StringSerializer.get(), CMBProperties.getInstance().getReadConsistencyLevel()); if (superCol != null) { CNSSubscription exisitingSub = extractSubscriptionFromSuperColumn(superCol, topicArn); deleteIndexes(exisitingSub.getArn(), exisitingSub.getUserId(), exisitingSub.getToken()); deleteSuperColumn(subscriptionsTemplate, exisitingSub.getTopicArn(), superColumnName); }*/ // then set confirmation stuff and update cassandra CNSSubscription retrievedSubscription = getSubscription(subscription.getArn()); if (!CMBProperties.getInstance().getCNSRequireSubscriptionConfirmation()) { subscription.setConfirmed(true); subscription.setConfirmDate(new Date()); insertOrUpdateSubsAndIndexes(subscription, null); if (retrievedSubscription == null) { cassandraHandler.incrementCounter( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilyTopicStats, subscription.getTopicArn(), "subscriptionConfirmed", 1, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); } } else { // protocols that cannot confirm subscriptions (e.g. redisPubSub) // get an automatic confirmation here if (!protocol.canConfirmSubscription()) { subscription.setConfirmed(true); subscription.setConfirmDate(new Date()); insertOrUpdateSubsAndIndexes(subscription, null); // auto confirm subscription to cqs queue by owner } else if (protocol.equals(CnsSubscriptionProtocol.cqs)) { String queueOwner = com.comcast.cqs.util.Util.getQueueOwnerFromArn(endpoint); if (queueOwner != null && queueOwner.equals(userId)) { subscription.setConfirmed(true); subscription.setConfirmDate(new Date()); insertOrUpdateSubsAndIndexes(subscription, null); if (retrievedSubscription == null) { cassandraHandler.incrementCounter( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilyTopicStats, subscription.getTopicArn(), "subscriptionConfirmed", 1, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); } } else { // use cassandra ttl to implement expiration after 3 days insertOrUpdateSubsAndIndexes(subscription, 3 * 24 * 60 * 60); if (retrievedSubscription == null) { cassandraHandler.incrementCounter( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilyTopicStats, subscription.getTopicArn(), "subscriptionPending", 1, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); } } } else { // use cassandra ttl to implement expiration after 3 days insertOrUpdateSubsAndIndexes(subscription, 3 * 24 * 60 * 60); if (retrievedSubscription == null) { cassandraHandler.incrementCounter( AbstractDurablePersistence.CNS_KEYSPACE, columnFamilyTopicStats, subscription.getTopicArn(), "subscriptionPending", 1, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER); } } } CNSSubscriptionAttributes attributes = new CNSSubscriptionAttributes(topicArn, subscription.getArn(), userId); PersistenceFactory.getCNSAttributePersistence() .setSubscriptionAttributes(attributes, subscription.getArn()); return subscription; }
private static String getEndpointAndProtoIndexVal( String endpoint, CnsSubscriptionProtocol protocol) { return protocol.name() + ":" + endpoint; }