Package com.comcast.cqs.test.stress

Source Code of com.comcast.cqs.test.stress.CqsStressTester$SaxHandler

/**
* Copyright 2012 Comcast Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.comcast.cqs.test.stress;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import com.amazonaws.AmazonServiceException;
import com.comcast.cmb.common.controller.CMBControllerServlet;
import com.comcast.cmb.common.model.User;
import com.comcast.cmb.common.persistence.AbstractDurablePersistence;
import com.comcast.cmb.common.persistence.DurablePersistenceFactory;
import com.comcast.cmb.common.persistence.IUserPersistence;
import com.comcast.cmb.common.persistence.PersistenceFactory;
import com.comcast.cmb.common.persistence.UserCassandraPersistence;
import com.comcast.cmb.common.util.CMBException;
import com.comcast.cmb.common.util.CMBProperties;
import com.comcast.cmb.common.util.PersistenceException;
import com.comcast.cmb.common.util.Util;
import com.comcast.cns.io.CommunicationUtils;
import com.comcast.cqs.model.CQSMessage;
import com.comcast.cqs.persistence.ICQSMessagePersistence;
import com.comcast.cqs.util.CQSErrorCodes;

//
// some useful greps:
//
// grep -i responsetime /tmp/receiveMessage.log | grep ReceiveMessage | cut -f9- -d= > /tmp/redisTime.out
//
// grep -i responsetime /tmp/receiveMessage.log | grep ReceiveMessage | cut -f5-5 -d= > /tmp/responseTime.log
//
// grep -i responsetime /tmp/receiveMessage.log | grep ReceiveMessage |  cut -f6-6 -d= > /tmp/cassandraTime.log
//
// some useful splunks:
//
// response time for receive message operation:
//
// sourcetype=cqs action=ReceiveMessage | chart perc95(responseTimeMS) perc90(responseTimeMS) avg(responseTimeMS) median(responseTimeMS) max(responseTimeMS) perc95(redisTime) perc90(redisTime) avg(redisTime) median(redisTime) max(redisTime) perc95(CassandraTimeMS) perc90(CassandraTimeMS) avg(CassandraTimeMS) median(CassandraTimeMS) max(CassandraTimeMS)
//
// sourcetype=cqs action=ReceiveMessage | timechart avg(redisTime) avg(CassandraTimeMS) avg(responseTimeMS)
//
// manage changes in message visibility, performed once a second:
//
// sourcetype=cqs event=chechAndProcessRevisibleSet | chart avg(responseTimeMS) p95(responseTimeMS)
//
// manage hidden messages every 10 sec, look for hiddenSetSize parameter:
//
// sourcetype=cqs event=RevisibleProcessor | chart avg(responseTimeMS) p95(responseTimeMS)
//

// todo: check for message order

public class CqsStressTester {

    private static Logger logger = Logger.getLogger(CqsStressTester.class);

  static ConcurrentHashMap<Integer, AtomicInteger> timeReceiveMessageCountMap = new ConcurrentHashMap<Integer, AtomicInteger>();
  static ConcurrentHashMap<Integer, AtomicInteger> timeSendMessageCountMap = new ConcurrentHashMap<Integer, AtomicInteger>();
  static Set<String> sendMessageIdSet = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>());

    //static private ConcurrentLinkedQueue<Long> receiveLacencyMSList = new ConcurrentLinkedQueue<Long>();

    public long startTime = System.currentTimeMillis();
    final static SchemeRegistry schemeRegistry = new SchemeRegistry();
    public final static ThreadSafeClientConnManager cm;
    final static HttpClient httpClient;

    static {

       schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
       schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));

       cm = new ThreadSafeClientConnManager(schemeRegistry);
       // Increase max total connection to 200
       cm.setMaxTotal(CMBProperties.getInstance().getCNSPublisherHttpEndpointConnectionPoolSize());
       // Increase default max connection per route to 20
       cm.setDefaultMaxPerRoute(CMBProperties.getInstance().getCNSPublisherHttpEndpointConnectionsPerRouteSize());

       httpClient = new DefaultHttpClient(cm);
    }

    private List<String> queueUrls = new ArrayList<String>();
    private HashMap<String, List<Receiver>> receiverMap = new HashMap<String, List<Receiver>>();
  private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static HashMap<String, String> attributeParams = new HashMap<String, String>();
    private static AtomicInteger messageCount = new AtomicInteger(0);
    static Random rand = new Random();
    static User user = null;
    final static int revisiblePercentage = CQSStressTestProperties.getInstance().getRevisiblePercentage();

    private static void setup() throws Exception {

        attributeParams.put("MessageRetentionPeriod", "6000"); // the number of seconds when a message is available in the system - 10 hours
        attributeParams.put("VisibilityTimeout", "60"); // the number of seconds a message is hidden from the next user - 1 min

        try {
          IUserPersistence userPersistence = new UserCassandraPersistence();
          user = userPersistence.getUserByName("cqs_stress_user");

          if (user == null) {
              user = userPersistence.createUser("cqs_stress_user", "cqs_stress_user");
          }

        } catch (Exception ex) {
            logger.error("Action=setup status=exception ", ex);
        }
    }

    // This creates the specified number of queues

    private ScheduledExecutorService createQueuesAndInitializePublishersAndReceivers() throws PersistenceException, NoSuchAlgorithmException, UnsupportedEncodingException, InterruptedException {

      String fixedQueueName = "testQueue";
      int totalNumberOfQueues = CQSStressTestProperties.getInstance().getNumberOfQueues();

        String[] queueNames = CQSStressTestProperties.getInstance().getQueueNames();

        if (queueNames != null) {
        totalNumberOfQueues = queueNames.length;
      }

        ICQSMessagePersistence messagePersistence = PersistenceFactory.getCQSMessagePersistence();

        for (int i=0; i<totalNumberOfQueues; i++) {

          String queueName = fixedQueueName + rand.nextInt() + "_" + i;

          if (queueNames != null) {
          queueName = queueNames[i];
        }

          String myQueueUrl = createQueue(queueName);
      queueUrls.add(myQueueUrl);

      if (CQSStressTestProperties.getInstance().getNumberOfSendersPerQueue() > 0) {
        messagePersistence.clearQueue(myQueueUrl, 0);
      }

      logger.info("QueueUrl" + i + " = " + myQueueUrl);

      //first tickle the empty queue population by calling a receive when nothing is in the queue

      receiveMessage(myQueueUrl, 1, 100);

      Thread.sleep(500);
      }

        for (String queueUrl : queueUrls) {
      createReceivers(queueUrl);
        }

        return createSenders(queueUrls);
   }

    private ScheduledExecutorService createSenders(List<String> queueUrls) {

      int senderCount = CQSStressTestProperties.getInstance().getNumberOfSendersPerQueue();

      if (senderCount == 0) {
        return null;
      }

      int numberOfMessagesPerSec = CQSStressTestProperties.getInstance().getMessagesPerQueuePerSecond();
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(queueUrls.size()*senderCount);

    for (String queueUrl : queueUrls) {
      for (int i=0; i<senderCount; i ++) {
        scheduledExecutorService.scheduleWithFixedDelay(new MessageSender(queueUrl, i), rand.nextInt(100), 1000*senderCount/numberOfMessagesPerSec, TimeUnit.MILLISECONDS);
      }
    }

    return scheduledExecutorService;
    }

  private String generateRandomMessage(int length) {

    StringBuilder sb = new StringBuilder(length);

    Date now = new Date();
    sb.append("@").append(now.getTime()).append("*");
    sb.append(now).append("%");

    for (int i=sb.length(); i<length; i++) {
      sb.append(ALPHABET.charAt(rand.nextInt(ALPHABET.length())));
    }

    return sb.toString();
  }

  private void createReceivers(String queueUrl) {

      AbstractDurablePersistence persistence = DurablePersistenceFactory.getInstance();
      long receiverCount = CQSStressTestProperties.getInstance().getNumberOfReceiversPerQueue();
      List<Receiver> receiverListForQueue = new ArrayList<Receiver>();

      for (int i=0; i<receiverCount; i++) {
        Receiver receiver = new Receiver(queueUrl, i, persistence);
        receiver.start();
        receiverListForQueue.add(receiver);
      }

      receiverMap.put(queueUrl, receiverListForQueue);
    }

    protected void doChart(int totalMessagesSent, int totalMessagesReceived) throws IOException {

      generateChart("Send message count: Total Messages Sent=" + totalMessagesSent,  timeSendMessageCountMap, "SendMessage_Run_" + startTime, new Date(startTime), new Date());
        generateChart("Receive message count: Total Messages Received=" + totalMessagesReceived,  timeReceiveMessageCountMap, "ReceiveMessage_Run_" + startTime, new Date(startTime), new Date());
    }

    private byte[] generateChart(String title, ConcurrentHashMap<Integer, AtomicInteger> metric, String id, Date startTime, Date endTime) throws IOException {

      XYSeries series = new XYSeries(title);

      for (Entry<Integer, AtomicInteger> entry : metric.entrySet()) {
        series.add(entry.getKey().intValue(), entry.getValue().intValue());
      }

      XYSeriesCollection dataset = new XYSeriesCollection(series);

      JFreeChart chart = ChartFactory.createXYBarChart(
                "Start: " + startTime + " End: " + endTime + " Message Count: " + messageCount,
                "Test Second",
                false,
                "Number of Messages",
                dataset,
                PlotOrientation.VERTICAL,
                true,
                true,
                false
            );

      File file = new File("/tmp/" + id + ".jpeg");
      //File file = new File(getServletContext().getRealPath("WEB-INF" + "/" + id + ".jpeg"));
      ChartUtilities.saveChartAsJPEG(file, chart, 1600, 400);
      //byte b[] = Files.toByteArray(file);
      //return b;

      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      ChartUtilities.writeChartAsJPEG(bos, chart, 2400, 400);
      return bos.toByteArray();
    }
    /**
   * @param args
   */
  public static void main(String[] args) {

    try {

      CMBControllerServlet.valueAccumulator.initializeAllCounters();
          setup();
      Util.initLog4j();
      CqsStressTester tester = new CqsStressTester();
      ScheduledExecutorService scheduledExecutorService = tester.createQueuesAndInitializePublishersAndReceivers(); //will clear queues

      long totalMessagesReceived = 0;
      long totalMessagesDeleted = 0;
      long totalMessagesRevisibled = 0;
      long totalEmptyResponses = 0;
      long totalDuplicates = 0;
      long totalOutOfOrderMessages = 0;

      int testDurationSeconds = CQSStressTestProperties.getInstance().getTestDurationSeconds();
      Thread.sleep(testDurationSeconds*1000);

      if (scheduledExecutorService != null) {
        scheduledExecutorService.shutdown();
      }

      logger.info("===Sender Shutdown Triggered==");

      for (String queueUrl : tester.receiverMap.keySet()) {
          for (Receiver receiver : tester.receiverMap.get(queueUrl)) {
            receiver.setContinueThread(false);
          }
      }

      for (String queueUrl : tester.receiverMap.keySet()) {

        Set<String> messageIdMaster = new HashSet<String>();
          List<Integer> deleteTimesMaster = new ArrayList<Integer>();
          List<Long> flightTimesMaster = new ArrayList<Long>();
          List<Long> receiveTimesMaster = new ArrayList<Long>();

          for (Receiver receiver : tester.receiverMap.get(queueUrl)) {

          receiver.join();

          logger.warn("===================================================================================================================");
          logger.warn("TheadId=" + receiver.getThreadId() + " receiveMessageCount=" + receiver.getTotalMessagesReceived() + " deletedMessageCount=" + receiver.getTotalMessagesDeleted() + " revisibledMessageCount=" + receiver.getTotalMessagesRevisibled());
          logger.warn("===================================================================================================================");

          totalMessagesReceived += receiver.getTotalMessagesReceived();
          totalMessagesDeleted += receiver.getTotalMessagesDeleted();
          totalMessagesRevisibled += receiver.getTotalMessagesRevisibled();
          totalOutOfOrderMessages += receiver.getTotalOutOfOrderMessages();
          totalDuplicates += checkAndCombine(messageIdMaster, receiver.messageIds);
          //deleteTimesMaster.addAll(receiver.deleteLatencyMSList);
          //flightTimesMaster.addAll(receiver.flightTimeList);
          totalEmptyResponses += receiver.emptyResponseCount;
        }

        logger.warn("===================================================================================================================");

        Iterator<String> iter = sendMessageIdSet.iterator();

        while (iter.hasNext()) {
          logger.error("Missed message:" + iter.next());
        }

        Collections.sort(deleteTimesMaster);
        Collections.sort(flightTimesMaster);
                //receiveTimesMaster.addAll(receiveLacencyMSList);
        Collections.sort(receiveTimesMaster);

        /*logger.warn("Receive message latencies");

        if (receiveTimesMaster.size() > 0) {

          for (int i=5; i<=100; i+=5) {

            int percentileIndex = receiveTimesMaster.size()*i/100 - 1;

            if (percentileIndex < 0) {
              percentileIndex = 0;
            }

            logger.warn("" + i + "th percentile=" + receiveTimesMaster.get(percentileIndex));
          }
        }

        logger.warn("===================================================================================================================");
        logger.warn("Message flight time latencies");

        if (flightTimesMaster.size() > 0) {

          for (int i=5; i<=100; i+=5) {

            int percentileIndex = flightTimesMaster.size()*i/100 - 1;

            if (percentileIndex < 0) {
              percentileIndex = 0;
            }

            logger.warn("" + i + "th percentile=" + flightTimesMaster.get(percentileIndex));
          }
        }

        logger.warn("===================================================================================================================");
        logger.warn("Delete message latencies");

        if (deleteTimesMaster.size() > 0) {

          for (int i=5; i<=100; i+=5) {

            int percentileIndex = deleteTimesMaster.size()*i/100 - 1;

            if (percentileIndex < 0) {
              percentileIndex = 0;
            }

            logger.warn("" + i + "th percentile=" + deleteTimesMaster.get(percentileIndex));
          }
        }*/

      }

      logger.warn("===================================================================================================================");
      logger.warn("===================================================================================================================");
      logger.warn("totalMessagesSent=" + tester.messageCount.get() + " totalMessagesReceived=" + totalMessagesReceived + " totalMessagesDeleted=" + totalMessagesDeleted + " totalMessagesRevisibled=" + totalMessagesRevisibled);
      logger.warn("===================================================================================================================");
      logger.warn("totalEmptyResponses=" + totalEmptyResponses);
      logger.warn("totalDuplicates=" + totalDuplicates);
      logger.warn("totalOutOfOrderMessages=" + totalOutOfOrderMessages);
      logger.warn("totalMessagesLost=" + sendMessageIdSet.size());
      logger.warn("===================================================================================================================");
      logger.warn("totalRunTimeMillis=" + (System.currentTimeMillis()-tester.startTime) + " status=Exit");
      logger.warn("===================================================================================================================");
      logger.warn("===================================================================================================================");

    } catch (Exception e) {
      logger.error("Thread=main status=exception message=setup_failure ", e);
    } finally {
      CMBControllerServlet.valueAccumulator.deleteAllCounters();
    }
  }

  private static long checkAndCombine(Set<String> masterSet, Set<String> receivedMessageIds) {

    long totalDuplicates = 0;

    if (masterSet == null || receivedMessageIds == null) {
      return 0;
    }

    for (String messageId : receivedMessageIds) {

      if (masterSet.contains(messageId)) {
        logger.error("Action=checkAndCombine status=error message=duplicateId:" + messageId);
        totalDuplicates++;
      } else {
        masterSet.add(messageId);
      }
    }

    return totalDuplicates;
  }

    private class MessageSender implements Runnable {

    private String queueUrl;
    private String threadId;

      public MessageSender(String queueUrl, int index) {
      setQueueUrl(queueUrl);
      setThreadId(queueUrl, index);
    }

    public String getQueueUrl() {
      return queueUrl;
    }

    public void setQueueUrl(String queueUrl) {
      this.queueUrl = queueUrl;
    }

    public void setThreadId(String queueUrl, int index) {

      this.queueUrl = queueUrl;

      if (queueUrl == null || queueUrl.length() == 0) {
        return;
      }

      String queueName = queueUrl.substring(queueUrl.lastIndexOf('/') + 1);
      this.threadId = "Sender_" + queueName + "_" + index;
    }

    @Override
    public void run() {

      try {
            CMBControllerServlet.valueAccumulator.initializeAllCounters();
      } catch (Exception ex) {
              logger.error("Thread=" + threadId + " Action=setup status=exception ", ex);
      }

      int maxSendBatchSize = CQSStressTestProperties.getInstance().getSendMessageBatchSize();
      maxSendBatchSize = 1// Till we add support for send message batch

      try {

          String currentTime = "" + System.currentTimeMillis();

            long startNanoTime = System.nanoTime();
            int totalMessagesSuccessful = 0;

              for (int i = 0; i < maxSendBatchSize; i++) {

                //TBD: Make this a configurable parameter
                String messageBodyRandom = generateRandomMessage(2000);
                long index = rand.nextLong();
                String messageIndex = Thread.currentThread().getId() + "_" + index;
                sendMessageIdSet.add(messageIndex);
            String messageBody = "currentTime=" + currentTime + " messageIndex=" + messageIndex + " messagebody=message_" + currentTime + "_" + messageBodyRandom + "_" + index;

            if (sendMessage(this.queueUrl, messageBody) != null) {
              totalMessagesSuccessful++;
            }

                  logger.debug("Thread=" + threadId + " Action=Sent MessageBody '" + messageBody + "'");
              }

              //addSendMessageCount((int)((System.currentTimeMillis() - startTime)/1000), totalMessagesSuccessful);
              long endNanoTime = System.nanoTime();
              logger.info("Thread=" + threadId + " Action=SendMessageBatch latencyNano=" + (endNanoTime-startNanoTime));
        int count = messageCount.addAndGet(totalMessagesSuccessful);

        if (count % 100 == 0) {
          logger.info("event=publish queueUrl=" + getQueueUrl() + " totalCount=" + count);
        }

      } catch (AmazonServiceException ase) {
        displayServiceException("" + Thread.currentThread().getId(), "SendMessageBatch", ase);
      } finally {
        CMBControllerServlet.valueAccumulator.deleteAllCounters();
      }
    }
    }

  class Receiver extends Thread {

    private String queueUrl;
    private String threadId;
    private long totalMessagesReceived = 0;
    private long totalMessagesDeleted = 0;
    private long totalMessagesRevisibled = 0;
    private long totalOutOfOrderMessages = 0;
    private long lastMessageReceivedTime = 0;
    private boolean continueThread = true;
    private AbstractDurablePersistence persistence;
    private static final int visibilityTimeout = 600;
    private Set<String> messageIds = new HashSet<String>();
    //private List<Integer> deleteLatencyMSList = new ArrayList<Integer>();
    //private Set<Long> flightTimeList = new HashSet<Long>();
    private long emptyResponseCount = 0;

    public Receiver(String queueUrl, int index, AbstractDurablePersistence persistence) {
      setQueueUrl(queueUrl);
      setThreadId(queueUrl, index);
      setPersistence(persistence);
    }

    public String getQueueUrl() {
      return queueUrl;
    }

    public void setQueueUrl(String queueUrl) {
      this.queueUrl = queueUrl;
    }

    public void run() {

      try {
            CMBControllerServlet.valueAccumulator.initializeAllCounters();
      } catch (Exception ex) {
              logger.info("Thread=" + threadId + " Action=setup status=exception ", ex);
      }

      int maxReceiveBatchSize = CQSStressTestProperties.getInstance().getReceiveMessageBatchSize();

      try {

        int emptyCount = 0;

        while (true) {

              long startNanoTime = System.currentTimeMillis();

              List<CQSMessage> messageList = receiveMessage(this.queueUrl, maxReceiveBatchSize, visibilityTimeout);

              if (messageList == null) {
                Thread.sleep(300);
                continue;
              }

              long currentTime = System.currentTimeMillis();
            long messageFlightTime = 0;
            String messageIndex = "";

            if (messageList.size() == 0) {

                        emptyResponseCount++;
              logger.info("Thread=" + threadId + " Action=ReceiveMessage batchSize=" + maxReceiveBatchSize + " status=Empty count=" + emptyCount);

              if (!isContinueThread()) {

                          // sleep an extra second if no messages are there to account for potentially hidden messages

              Thread.sleep(1000);

                          emptyCount++;

                          if (emptyCount > 10) {
                  logger.info("Thread=" + threadId + "Action=ReceiveMessage status=Completed");
                  return;
                }
              }

            } else {

              emptyCount = 0;
              totalMessagesReceived += messageList.size();
              logger.info("Thread=" + threadId + " Action=ReceiveMessage batchSize=" + maxReceiveBatchSize + " receivedCount=" + messageList.size());
              //addReceiveMessageCount((int)((System.currentTimeMillis() - startTime)/1000), messageList.size());
            }

            int delayBetweenReceiveAndDelete = CQSStressTestProperties.getInstance().getDelayBetweenReceiveAndDeleteMS();

            if (delayBetweenReceiveAndDelete > 0) {
              Thread.sleep(delayBetweenReceiveAndDelete + rand.nextInt(40));
            }

            for (CQSMessage message: messageList) {

              String[] bodyParts = message.getBody().split(" ");

              for (String bodyPart : bodyParts) {

                String[] subParts = bodyPart.split("=");

                if (subParts[0].equals("currentTime")) {

                      long messageSendTime = Long.parseLong(subParts[1]);
                  messageFlightTime = currentTime - messageSendTime;

                  if (lastMessageReceivedTime != 0 && lastMessageReceivedTime > messageSendTime) {
                    totalOutOfOrderMessages++;
                    //logger.info("Event=MessageOutOfOrder messageId=" + messageIndex + " messageSendTime=" + messageSendTime + " lastMessageReceivedTime=" + lastMessageReceivedTime + " delta=" + Math.abs(lastMessageReceivedTime-messageSendTime));
                  }

                  lastMessageReceivedTime = messageSendTime;

                    } else if (subParts[0].equals("messageIndex")) {
                      messageIndex = subParts[1];
                    }
                  }

                  if (messageIds.contains(messageIndex)) {
                    logger.error("Action=receiveMessage status=error exception=Duplicate id: " + messageIndex);
                  } else {
                    messageIds.add(messageIndex);
                  }

                  //flightTimeList.add(messageFlightTime);

                  logger.info("Thread=" + threadId + " Action=ReceivedMessage MessageIndex=" + messageIndex + " totalTimeInFlightMillis=" + messageFlightTime);

                  startNanoTime = System.nanoTime();

                  if (revisiblePercentage > 0 && rand.nextInt(100)+1 <= revisiblePercentage) {
                        changeMessageVisibility(this.queueUrl, message.getReceiptHandle());
                        totalMessagesRevisibled += 1;
                        totalMessagesReceived -= 1;
                        messageIds.remove(messageIndex);
                    long endNanoTime = System.nanoTime();
                    logger.info("Thread=" + threadId + " Action=RevisibleMessage MessageIndex=" + messageIndex + " latencyNano=" + (endNanoTime-startNanoTime));
                  } else {
                    sendMessageIdSet.remove(messageIndex);
                    deleteMessage(this.queueUrl, message.getReceiptHandle());
                    totalMessagesDeleted += 1;
                    long endNanoTime = System.nanoTime();
                    logger.info("Thread=" + threadId + " Action=DeleteMessage MessageIndex=" + messageIndex + " latencyNano=" + (endNanoTime-startNanoTime));
                  }

                  //deleteLatencyMSList.add(new Integer((int)(endNanoTime-startNanoTime)/1000000));
                }

            int delayBetweenReceivesMS = CQSStressTestProperties.getInstance().getDelayBetweenReceivesMS();

            if (delayBetweenReceivesMS > 0) {
                  try {
              Thread.sleep(delayBetweenReceivesMS);
            } catch (InterruptedException e) {
              logger.error("Action=ReceiveMessage status=Exception ", e);
            }
                }
        }

      } catch (AmazonServiceException ase) {
        displayServiceException(threadId, "ReceiveMessage/DeleteMessage/RevisibleMessage", ase);
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        CMBControllerServlet.valueAccumulator.deleteAllCounters();
      }
    }

    public String getThreadId() {
      return threadId;
    }

    public void setThreadId(String queueUrl, int index) {

      this.queueUrl = queueUrl;

      if (queueUrl == null || queueUrl.length() == 0) {
        return;
      }

      String queueName = queueUrl.substring(queueUrl.lastIndexOf('/') + 1);
      this.threadId = "Receiver_" + queueName + "_" + index;
    }

    public long getTotalMessagesReceived() {
      return totalMessagesReceived;
    }

    public void setTotalMessagesReceived(long totalMessagesReceived) {
      this.totalMessagesReceived = totalMessagesReceived;
    }

    public long getTotalMessagesDeleted() {
      return totalMessagesDeleted;
    }

    public void setTotalMessagesDeleted(long totalMessagesDeleted) {
      this.totalMessagesDeleted = totalMessagesDeleted;
    }

    public long getTotalMessagesRevisibled() {
      return totalMessagesRevisibled;
    }

    public void setTotalMessagesRevisibled(long totalMessagesRevisibled) {
      this.totalMessagesRevisibled = totalMessagesRevisibled;
    }

    public synchronized boolean isContinueThread() {
      return continueThread;
    }

    public synchronized void setContinueThread(boolean continueThread) {
      this.continueThread = continueThread;
    }

    public AbstractDurablePersistence getPersistence() {
      return persistence;
    }

    public void setPersistence(AbstractDurablePersistence persistence) {
      this.persistence = persistence;
    }

    public long getTotalOutOfOrderMessages() {
      return this.totalOutOfOrderMessages;
    }
  }

    private void displayServiceException(String threadId, String action, AmazonServiceException ase) {
      logger.error("ThreadId=" + threadId + " Action=" + action);
        logger.error("Caught an AmazonServiceException, which means your request made it to Amazon SQS, but was rejected with an error response for some reason.");
        logger.error("Error Message=" + ase.getMessage());
        logger.error("HTTP Status Code=" + ase.getStatusCode());
        logger.error("AWS Error Code=" + ase.getErrorCode());
        logger.error("Error Type=" + ase.getErrorType());
        logger.error("Request ID=" + ase.getRequestId());
    }

    public void addReceiveMessageCount(int second, int count) {
      AtomicInteger val = null;
    timeReceiveMessageCountMap.putIfAbsent(second, new AtomicInteger(0));
    val = timeReceiveMessageCountMap.get(second);
      val.addAndGet(count);
    }

    public void addSendMessageCount(int second, int count) {
      AtomicInteger val = null;
      timeSendMessageCountMap.putIfAbsent(second, new AtomicInteger(0));
      val = timeSendMessageCountMap.get(second);
      val.addAndGet(count);
    }

    public String createQueue(String queueName) {
      Map<String, String[]> params = new HashMap<String, String[]>();
    CommunicationUtils.addParam(params,"Action", "CreateQueue");
    CommunicationUtils.addParam(params, "QueueName", queueName);
    CommunicationUtils.addParam(params, "AWSAccessKeyId", user.getAccessKey());
    CommunicationUtils.addParam(params, "Version", "2009-02-01");
    try {
      String response = send(params, CMBProperties.getInstance().getCQSServiceUrl());
      return CqsStressTester.deserialize(response, "QueueUrl").trim();
    } catch (Exception e) {
      logger.error("Action=CreateQueue status=error exception=", e);
      return null;
    }
    }

    public String sendMessage(String queueUrl, String messageBody) {
    Map<String, String[]> params = new HashMap<String, String[]>();
    CommunicationUtils.addParam(params,"Action", "SendMessage");
    CommunicationUtils.addParam(params, "MessageBody", messageBody);
    CommunicationUtils.addParam(params, "AWSAccessKeyId", user.getAccessKey());
    CommunicationUtils.addParam(params, "Version", "2009-02-01");
    try {
      String response = send(params, queueUrl);
      String messageId = CqsStressTester.deserialize(response, "MessageId");
      return (messageId!=null)?messageId.trim() : null;
    } catch (Exception e) {
      logger.error("Action=sendMessage status=error exception=", e);
      return null;
    }
    }

    public List<CQSMessage> receiveMessage(String queueUrl, int maxNoOfMessages, int visibilityTimeout) {

      // Max number of messages will be set to 1 for now
      maxNoOfMessages = 1;
    Map<String, String[]> params = new HashMap<String, String[]>();
    CommunicationUtils.addParam(params,"Action", "ReceiveMessage");
    CommunicationUtils.addParam(params, "MaxNumberOfMessages", "" + maxNoOfMessages);
    CommunicationUtils.addParam(params, "VisibilityTimeout", "" + visibilityTimeout);
    CommunicationUtils.addParam(params, "AWSAccessKeyId", user.getAccessKey());
    CommunicationUtils.addParam(params, "Version", "2009-02-01");

    try {
      long ts1 = System.currentTimeMillis();
      String response = send(params, queueUrl);
      long elapsedTime = System.currentTimeMillis() - ts1;
      logger.info("Total time spent on receiveMessage=" + elapsedTime);

      if (response.indexOf("<Body>") > 0) {
        //receiveLacencyMSList.add(elapsedTime);
      }

      return CqsStressTester.deserializeMessage(response);

    } catch (Exception e) {
      logger.error("Action=receiveMessage status=error exception=", e);
      return null;
    }
    }

    public void deleteMessage(String queueUrl, String receiptHandle) {

      Map<String, String[]> params = new HashMap<String, String[]>();
    CommunicationUtils.addParam(params,"Action", "DeleteMessage");
    CommunicationUtils.addParam(params, "ReceiptHandle", receiptHandle);
    CommunicationUtils.addParam(params, "AWSAccessKeyId", user.getAccessKey());
    CommunicationUtils.addParam(params, "Version", "2009-02-01");

    try {
      send(params, queueUrl);
    } catch (Exception e) {
      logger.error("Action=deleteMessage status=error exception=", e);
    }
    }

    public void changeMessageVisibility(String queueUrl, String receiptHandle) {

      Map<String, String[]> params = new HashMap<String, String[]>();

      CommunicationUtils.addParam(params,"Action", "ChangeMessageVisibility");
    CommunicationUtils.addParam(params, "ReceiptHandle", receiptHandle);
    int randomVisibilityTimeoutSecs = rand.nextInt(5);
    CommunicationUtils.addParam(params, "VisibilityTimeout", randomVisibilityTimeoutSecs+"");
    CommunicationUtils.addParam(params, "AWSAccessKeyId", user.getAccessKey());
    CommunicationUtils.addParam(params, "Version", "2009-02-01");

    try {
      send(params, queueUrl);
    } catch (Exception e) {
      logger.error("Action=changeMessageVisibilityTimeout status=error exception=", e);
    }
    }

    public String send(Map<String, String[]> params, String endPoint) throws Exception {

    logger.debug("event=send_cqs_message endpoint=" + endPoint);

    String url = endPoint;
    logger.debug("event=send_cqs_message url=" + url + " endpoint=" + endPoint+ "\"");

    Set<String> parameters = params.keySet();
    boolean first = true;

    for (String param: parameters) {
      if(first) {url += "?"; first=false;}
      else url += "&";
      url += URLEncoder.encode(param,"UTF-8") + "=" + URLEncoder.encode(params.get(param)[0], "UTF-8");
    }

    String resp = "";

    try {
      logger.debug("Sending request to url:" + url);
       //resp = sendHttpMessage(url);
      resp = send(url, "");
    } catch(Exception e) {
      logger.error("event=send_cqs_message endpoint=" + endPoint + " exception=" + e.toString(), e);
      throw new CMBException(CQSErrorCodes.InternalError, "internal service error");
    }
    return resp;
  }

    public String send(String endpoint, String message) throws Exception {

        logger.debug("event=send_http_request endpoint=" + endpoint + "\" message=\"" + message + "\"");

        if ((message == null) || (endpoint == null)) {
            logger.debug("event=send_http_request error_code=MissingParameters endpoint=" + endpoint + "\" message=\"" + message + "\"");
            throw new Exception("Message and Endpoint must both be set");
        }

        HttpPost httpPost = new HttpPost(endpoint);
        StringEntity stringEntity = new StringEntity(message);
        httpPost.setEntity(stringEntity);

        HttpResponse response = httpClient.execute(httpPost);
        response.getStatusLine().getStatusCode();

        HttpEntity entity = response.getEntity();

        if (entity != null) {
            InputStream instream = entity.getContent();
            InputStreamReader responseReader = new InputStreamReader(instream);
            StringBuffer responseB = new StringBuffer();

            char []arr = new char[1024];
            int size = 0;

            while ((size = responseReader.read(arr, 0, arr.length)) != -1) {
                responseB.append(arr, 0, size);
            }

            instream.close();
            return responseB.toString();
        }

        logger.error("Could not get response entity");
        System.exit(1);
        return null;
    }

  public static List<CQSMessage> deserializeMessage(String serializedMessage) {
    javax.xml.parsers.SAXParserFactory fac = new org.apache.xerces.jaxp.SAXParserFactoryImpl();
    javax.xml.parsers.SAXParser saxParser;
    SaxHandler p = new SaxHandler();
    try {
      saxParser = fac.newSAXParser();
      saxParser.parse(new ByteArrayInputStream(serializedMessage.getBytes()), p);
    } catch (ParserConfigurationException e) {
      e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }

    CQSMessage cqsMessage = null;

    try {
      if (p.getValueByKey("Body") == null) {
        return new ArrayList<CQSMessage>();
      }
      cqsMessage = new CQSMessage(p.getValueByKey("Body"), p.getAttributes());
        cqsMessage.setMessageId(p.getValueByKey("MessageId"));
      cqsMessage.setReceiptHandle(p.getValueByKey("ReceiptHandle"));
        cqsMessage.setMD5OfBody(p.getValueByKey("MD5OfBody"));
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    return java.util.Arrays.asList(cqsMessage) ;
  }

  public static String deserialize(String serialized, String key) {
    javax.xml.parsers.SAXParserFactory fac = new org.apache.xerces.jaxp.SAXParserFactoryImpl();
    javax.xml.parsers.SAXParser saxParser;
    SaxHandler p = new SaxHandler();
    try {
      saxParser = fac.newSAXParser();
      saxParser.parse(new ByteArrayInputStream(serialized.getBytes()), p);
    } catch (ParserConfigurationException e) {
      e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return p.getValueByKey(key);
  }

    private static class SaxHandler extends org.xml.sax.helpers.DefaultHandler {
        private CharArrayWriter contents = new CharArrayWriter();
        private HashMap<String, String> messageMap = new HashMap<String, String>();
        private String _name;
        private String _value;
        private HashMap<String, String> messageAttributes = new HashMap<String, String>();

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
          // clear the contents since we are in a new tag

          if (qName.equals("Message")) {
            messageMap.clear();
            messageAttributes.clear();
          }
          contents.reset();
        }

        @Override
        public void endElement(String uri, String localName, String qName) {
          if (qName.equals("Name")) {
            _name = contents.toString();
          } else if (qName.equals("Value")) {
            _value = contents.toString();
          } else if (qName.equals("Attribute")) {
            messageAttributes.put(_name, _value);
          } else if (!qName.equals("Message") && !qName.contains("Response") && !qName.contains("Result") && !qName.equals("RequestId")){
            messageMap.put(qName, contents.toString());
          }
        }

        @Override
      public void characters(char[] ch, int start, int length) {
        contents.write(ch, start, length);
        }

        String getValueByKey(String k) {
          return messageMap.get(k);
        }

        HashMap<String, String> getAttributes() {
          return messageAttributes;
        }
    }
}
TOP

Related Classes of com.comcast.cqs.test.stress.CqsStressTester$SaxHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.