Example #1
0
  public static void listen() {

    if (!initialized) {

      contextQueues = new ConcurrentHashMap<String, ConcurrentLinkedQueue<AsyncContext>>();

      serverSocketChannelFactory =
          new NioServerSocketChannelFactory(
              Executors.newCachedThreadPool(), Executors.newCachedThreadPool());

      ServerBootstrap serverBootstrap = new ServerBootstrap(serverSocketChannelFactory);

      serverBootstrap.setPipelineFactory(
          new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() {
              return Channels.pipeline(new LongPollServerHandler());
            }
          });

      serverBootstrap.setOption("child.tcpNoDelay", true);
      serverBootstrap.setOption("child.keepAlive", true);

      serverBootstrap.bind(new InetSocketAddress(CMBProperties.getInstance().getCQSLongPollPort()));

      initialized = true;

      logger.info(
          "event=longpoll_receiver_service_listening port="
              + CMBProperties.getInstance().getCQSLongPollPort());
    }
  }
  @Override
  public void send() throws Exception {

    if (!CMBProperties.getInstance().getSmtpEnabled()) {
      logger.warn("event=send_email error_code=smtp_disabled endpoint=" + endpoint);
      return;
    }

    MailWrapper mailAgent = new MailWrapper();

    String msg = null;

    if (message.getMessageStructure() == CNSMessageStructure.json) {
      msg = message.getProtocolSpecificMessage(CnsSubscriptionProtocol.email_json);
    } else {
      msg = message.getMessage();
    }

    if (!rawMessageDelivery && message.getMessageType() == CNSMessageType.Notification) {
      msg =
          com.comcast.cns.util.Util.generateMessageJson(
              message, CnsSubscriptionProtocol.email_json);
    }

    logger.debug(
        "event=send_email endpoint="
            + endpoint
            + " subject=\""
            + subject
            + " message=\""
            + msg
            + "\"");

    mailAgent.postMail(
        new String[] {endpoint}, subject, msg, CMBProperties.getInstance().getSmtpReplyAddress());
  }
Example #3
0
  public CQSQueue(String name, String ownerId) {

    this.name = name;
    this.ownerUserId = ownerId;

    this.region = CMBProperties.getInstance().getRegion();

    this.setArn("arn:cmb:cqs:" + region + ":" + ownerId + ":" + name);
    String serviceUrl = CMBProperties.getInstance().getCQSServerUrl();

    if (serviceUrl != null && serviceUrl.endsWith("/")) {
      serviceUrl = serviceUrl.substring(0, serviceUrl.length() - 1);
    }

    this.setServiceEndpoint(serviceUrl);
    this.setRelativeUrl(ownerId + "/" + name);

    this.visibilityTO = CMBProperties.getInstance().getVisibilityTO();
    this.maxMsgSize = CMBProperties.getInstance().getMaxMsgSize();
    this.msgRetentionPeriod = CMBProperties.getInstance().getMsgRetentionPeriod();
    this.delaySeconds = CMBProperties.getInstance().getDelaySeconds();
  }
  @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;
  }
Example #5
0
  public static void start(String mode) throws Exception {

    Util.initLog4j();
    modes = parseMode(mode);

    logger.info(
        "event=startup version="
            + CMBControllerServlet.VERSION
            + " ip="
            + InetAddress.getLocalHost().getHostAddress()
            + " io_mode="
            + CMBProperties.getInstance().getCNSIOMode()
            + " mode="
            + modes);

    if (modes.contains(Mode.Producer)) {

      CNSEndpointPublisherJobProducer.initialize();
      jobProducers =
          new CNSPublisherJobThread
              [CMBProperties.getInstance().getCNSNumEndpointPublisherJobProducers()
                  * CMBProperties.getInstance().getCNSNumPublishJobQueues()];
      int idx = 0;

      for (int i = 0;
          i < CMBProperties.getInstance().getCNSNumEndpointPublisherJobProducers();
          i++) {
        for (int k = 0; k < CMBProperties.getInstance().getCNSNumPublishJobQueues(); k++) {
          jobProducers[idx] =
              new CNSPublisherJobThread(
                  "CNSEPJobProducer-" + idx, new CNSEndpointPublisherJobProducer(), k);
          jobProducers[idx].start();
          idx++;
        }
      }
    }

    if (modes.contains(Mode.Consumer)) {

      CNSEndpointPublisherJobConsumer.initialize();
      consumers =
          new CNSPublisherJobThread
              [CMBProperties.getInstance().getCNSNumEndpointPublisherJobConsumers()
                  * CMBProperties.getInstance().getCNSNumEndpointPublishJobQueues()];
      int idx = 0;

      for (int i = 0;
          i < CMBProperties.getInstance().getCNSNumEndpointPublisherJobConsumers();
          i++) {
        for (int k = 0; k < CMBProperties.getInstance().getCNSNumEndpointPublishJobQueues(); k++) {
          consumers[idx] =
              new CNSPublisherJobThread(
                  "CNSEPJobConsumer-" + idx, new CNSEndpointPublisherJobConsumer(), k);
          consumers[idx].start();
          idx++;
        }
      }

      MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
      ObjectName name = new ObjectName("com.comcast.cns.tools:type=CNSWorkerMonitorMBean");

      if (!mbs.isRegistered(name)) {
        mbs.registerMBean(CNSWorkerMonitor.getInstance(), name);
      }
    }
  }
  @Override
  public boolean doAction(User user, AsyncContext asyncContext) throws Exception {

    CQSHttpServletRequest request = (CQSHttpServletRequest) asyncContext.getRequest();
    HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();

    CQSQueue queue = CQSCache.getCachedQueue(user, request);
    List<CQSMessage> msgList = new ArrayList<CQSMessage>();
    List<String> idList = new ArrayList<String>();
    List<CQSBatchResultErrorEntry> invalidBodyIdList = new ArrayList<CQSBatchResultErrorEntry>();

    int totalMessageSize = 0;
    int index = 1;

    String suppliedId =
        request.getParameter(this.actionName + CQSConstants.REQUEST_ENTRY + index + ".Id");
    String messageBody =
        request.getParameter(
            this.actionName + CQSConstants.REQUEST_ENTRY + index + "." + CQSConstants.MESSAGE_BODY);

    while (suppliedId != null) {

      if (!Util.isValidId(suppliedId)) {
        throw new CMBException(
            CQSErrorCodes.InvalidBatchEntryId,
            "Id "
                + suppliedId
                + " is invalid. Only alphanumeric, hyphen, and underscore are allowed. It can be at most "
                + CMBProperties.getInstance().getCQSMaxMessageSuppliedIdLength()
                + " letters long.");
      }

      if (idList.contains(suppliedId)) {
        throw new CMBException(
            CQSErrorCodes.BatchEntryIdsNotDistinct, "Id " + suppliedId + " repeated");
      }

      idList.add(suppliedId);

      if (messageBody == null || messageBody.isEmpty()) {
        invalidBodyIdList.add(
            new CQSBatchResultErrorEntry(
                suppliedId,
                true,
                "EmptyValue",
                "No value found for "
                    + this.actionName
                    + CQSConstants.REQUEST_ENTRY
                    + index
                    + "."
                    + CQSConstants.MESSAGE_BODY));
      } else if (!com.comcast.cmb.common.util.Util.isValidUnicode(messageBody)) {
        invalidBodyIdList.add(
            new CQSBatchResultErrorEntry(
                suppliedId,
                true,
                "InvalidMessageContents",
                "Invalid character was found in the message body."));
      } else {

        HashMap<String, String> attributes = new HashMap<String, String>();
        String delaySecondsStr =
            request.getParameter(
                this.actionName
                    + CQSConstants.REQUEST_ENTRY
                    + index
                    + "."
                    + CQSConstants.DELAY_SECONDS);

        if (delaySecondsStr != null) {

          Integer delaySeconds = 0;

          try {
            delaySeconds = Integer.parseInt(delaySecondsStr);
          } catch (NumberFormatException ex) {
            throw new CMBException(
                CMBErrorCodes.InvalidParameterValue, "DelaySeconds must be integer value");
          }

          if (delaySeconds < 0
              || delaySeconds > CMBProperties.getInstance().getCQSMaxMessageDelaySeconds()) {
            throw new CMBException(
                CMBErrorCodes.InvalidParameterValue,
                "DelaySeconds should be from 0 to "
                    + CMBProperties.getInstance().getCQSMaxMessageDelaySeconds());
          } else {
            attributes.put(CQSConstants.DELAY_SECONDS, "" + delaySeconds);
          }
        }

        attributes.put(CQSConstants.SENDER_ID, user.getUserId());
        attributes.put(CQSConstants.SENT_TIMESTAMP, "" + Calendar.getInstance().getTimeInMillis());
        attributes.put(CQSConstants.APPROXIMATE_RECEIVE_COUNT, "0");
        attributes.put(CQSConstants.APPROXIMATE_FIRST_RECEIVE_TIMESTAMP, "");

        CQSMessage msg = new CQSMessage(messageBody, attributes);

        msg.setSuppliedMessageId(suppliedId);
        msgList.add(msg);
      }

      if (msgList.size() > CMBProperties.getInstance().getCQSMaxMessageCountBatch()) {
        throw new CMBException(
            CQSErrorCodes.TooManyEntriesInBatchRequest,
            "Maximum number of entries per request are "
                + CMBProperties.getInstance().getCQSMaxMessageCountBatch()
                + ". You have sent "
                + msgList.size()
                + ".");
      }

      totalMessageSize += messageBody == null ? 0 : messageBody.length();

      if (totalMessageSize > CMBProperties.getInstance().getCQSMaxMessageSizeBatch()) {
        throw new CMBException(
            CQSErrorCodes.BatchRequestTooLong,
            "Batch requests cannot be longer than "
                + CMBProperties.getInstance().getCQSMaxMessageSizeBatch()
                + " bytes");
      }

      index++;

      suppliedId =
          request.getParameter(this.actionName + CQSConstants.REQUEST_ENTRY + index + ".Id");
      messageBody =
          request.getParameter(
              this.actionName
                  + CQSConstants.REQUEST_ENTRY
                  + index
                  + "."
                  + CQSConstants.MESSAGE_BODY);
    }

    if (msgList.size() == 0) {
      throw new CMBException(
          CMBErrorCodes.InvalidQueryParameter,
          "Both user supplied message Id and message body are required");
    }

    int shard = 0;

    if (queue.getNumberOfShards() > 1) {
      shard = rand.nextInt(queue.getNumberOfShards());
    }

    Map<String, String> result =
        PersistenceFactory.getCQSMessagePersistence().sendMessageBatch(queue, shard, msgList);

    try {
      CQSLongPollSender.send(queue.getArn());
    } catch (Exception ex) {
      logger.warn("event=failed_to_send_longpoll_notification", ex);
    }

    List<String> receiptHandles = new ArrayList<String>();

    for (CQSMessage message : msgList) {
      message.setMessageId(result.get(message.getSuppliedMessageId()));
      message.setReceiptHandle(result.get(message.getSuppliedMessageId()));
      receiptHandles.add(message.getReceiptHandle());
    }

    request.setReceiptHandles(receiptHandles);
    String out = CQSMessagePopulator.getSendMessageBatchResponse(msgList, invalidBodyIdList);
    writeResponse(out, response);

    CQSMonitor.getInstance().addNumberOfMessagesReceived(queue.getRelativeUrl(), msgList.size());

    return true;
  }