{"action":"created","comment":{"url":"https://api.github.com/repos/wso2/product-mb/pulls/comments/25944676","id":25944676,"diff_hunk":"@@ -1,589 +1,317 @@\n /*\n- * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.\n- *\n- * WSO2 Inc. licenses this file to you under the Apache License,\n- * Version 2.0 (the \"License\"); you may not use this file except\n- * in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- *    http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing,\n- * software distributed under the License is distributed on an\n- * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n- * KIND, either express or implied.  See the License for the\n- * specific language governing permissions and limitations\n- * under the License.\n- */\n+*  Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.\n+*\n+*  WSO2 Inc. licenses this file to you under the Apache License,\n+*  Version 2.0 (the \"License\"); you may not use this file except\n+*  in compliance with the License.\n+*  You may obtain a copy of the License at\n+*\n+*    http://www.apache.org/licenses/LICENSE-2.0\n+*\n+* Unless required by applicable law or agreed to in writing,\n+* software distributed under the License is distributed on an\n+* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n+* KIND, either express or implied.  See the License for the\n+* specific language governing permissions and limitations\n+* under the License.\n+*/\n \n package org.wso2.mb.integration.common.clients;\n \n-import org.apache.commons.logging.Log;\n-import org.apache.commons.logging.LogFactory;\n-import org.wso2.mb.integration.common.clients.operations.queue.QueueMessageBrowser;\n-import org.wso2.mb.integration.common.clients.operations.queue.QueueMessageReceiver;\n-import org.wso2.mb.integration.common.clients.operations.queue.QueueMessageSender;\n-import org.wso2.mb.integration.common.clients.operations.topic.TopicMessagePublisher;\n-import org.wso2.mb.integration.common.clients.operations.topic.TopicMessageReceiver;\n-import org.wso2.mb.integration.common.clients.operations.utils.*;\n+\n+import org.apache.log4j.Logger;\n+import org.wso2.mb.integration.common.clients.configurations.AndesJMSClientConfiguration;\n+import org.wso2.mb.integration.common.clients.configurations.AndesJMSConsumerClientConfiguration;\n+import org.wso2.mb.integration.common.clients.configurations.AndesJMSPublisherClientConfiguration;\n+import org.wso2.mb.integration.common.clients.exceptions.AndesClientException;\n+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientOutputParser;\n import org.wso2.mb.integration.common.clients.operations.utils.AndesClientUtils;\n \n-import java.io.File;\n+import javax.jms.JMSException;\n+import javax.naming.NamingException;\n import java.io.IOException;\n import java.util.ArrayList;\n import java.util.List;\n import java.util.Map;\n-import java.util.concurrent.atomic.AtomicInteger;\n \n+/**\n+ * This class represents the Andes Client which is used to publish/consume JMS messages. The JMS\n+ * publishers and consumers are created within this class with the help of a configuration file.\n+ * This class also provides functionality which can be used to evaluate JMS message publishers and\n+ * consumers.\n+ */\n public class AndesClient {\n-    private final Log log = LogFactory.getLog(AndesClient.class);\n-\n-    private AtomicInteger queueMessageCounter = new AtomicInteger(0);\n-    private AtomicInteger topicMessageCounter = new AtomicInteger(0);\n-    public String filePathToWriteReceivedMessages = System.getProperty(\"framework.resource.location\") + File.separator +\"receivedMessages.txt\";\n-\n-    private String mode = \"\";\n-\n-    private String hostInformation = \"localhost:5673\";\n-    private String destinations = \"topic:myTopic\";\n-    private String printNumberOfMessagesPerAsString = \"1\";\n-    private String isToPrintEachMessageAsString = \"false\";\n-    private String numOfSecondsToRunAsString = \"200\";\n-    private String messageCountAsString = \"100\";\n-    private String numberOfThreadsAsString = \"1\";\n-    private String parameters = \"listener=true,ackMode=1,delayBetweenMsg=0,stopAfter=100\";\n-    private String connectionString = \"\";\n-    private int unsubscribeAfter = Integer.MAX_VALUE;\n-\n-    private String analyticOperation = \"\";\n-    private String numberOfMessagesExpectedForAnalysis = \"\";\n-\n-    private String username = \"admin\";\n-    private String password = \"admin\";\n-\n-    private String messageType = \"text\";\n-    private boolean isDurable = false;\n+    /**\n+     * The logger used to log information, warnings, errors, etc.\n+     */\n+    private static Logger log = Logger.getLogger(AndesClient.class);\n \n-    private List<QueueMessageReceiver> queueListeners = new ArrayList<QueueMessageReceiver>();\n-    private List<TopicMessageReceiver> topicListeners = new ArrayList<TopicMessageReceiver>();\n-    private List<QueueMessageSender> queueMessageSenders = new ArrayList<QueueMessageSender>();\n-    private List<TopicMessagePublisher> topicMessagePublishers = new ArrayList<TopicMessagePublisher>();\n+    /**\n+     * The delay between starting publishers or consumers\n+     */\n+    private long startDelay = 0L;\n \n-    public AndesClient(String mode, String hostInformation, String destinations, String printNumberOfMessagesPerAsString,\n-                       String isToPrintEachMessageAsString, String numOfSecondsToRunAsString, String messageCountAsString,\n-                       String numberOfThreadsAsString, String parameters, String connectionString, String username,\n-                       String password) {\n-        this(mode, hostInformation, destinations, printNumberOfMessagesPerAsString, isToPrintEachMessageAsString, numOfSecondsToRunAsString, messageCountAsString, numberOfThreadsAsString, parameters, connectionString);\n-        this.username = username;\n-        this.password = password;\n-        AndesClientUtils.initializePrintWriter(filePathToWriteReceivedMessages);\n-    }\n+    /**\n+     * The consumers that are started concurrently\n+     */\n+    List<AndesJMSConsumer> consumers = new ArrayList<AndesJMSConsumer>();\n \n-    public AndesClient(String mode, String hostInformation, String destinations, String printNumberOfMessagesPerAsString,\n-                       String isToPrintEachMessageAsString, String numOfSecondsToRunAsString, String messageCountAsString,\n-                       String numberOfThreadsAsString, String parameters, String connectionString) {\n-        this.mode = mode;\n-        this.hostInformation = hostInformation;\n-        this.destinations = destinations;\n-        this.printNumberOfMessagesPerAsString = printNumberOfMessagesPerAsString;\n-        this.isToPrintEachMessageAsString = isToPrintEachMessageAsString;\n-        this.numOfSecondsToRunAsString = numOfSecondsToRunAsString;\n-        this.messageCountAsString = messageCountAsString;\n-        this.numberOfThreadsAsString = numberOfThreadsAsString;\n-        this.parameters = parameters;\n-        this.connectionString = connectionString;\n-        AndesClientUtils.initializePrintWriter(filePathToWriteReceivedMessages);\n-    }\n+    /**\n+     * The publishers that are started concurrently\n+     */\n+    List<AndesJMSPublisher> publishers = new ArrayList<AndesJMSPublisher>();\n \n-    public AndesClient(String mode, String analiticOperation, String numberOfMessagesExpeactedForAnalysis) {\n-        this.mode = mode;\n-        this.analyticOperation = analiticOperation;\n-        this.numberOfMessagesExpectedForAnalysis = numberOfMessagesExpeactedForAnalysis;\n-        AndesClientUtils.initializePrintWriter(filePathToWriteReceivedMessages);\n+    /**\n+     * Creates a single consumer or publisher based on the configuration passed\n+     *\n+     * @param config                      The configuration.\n+     * @param createConsumersAndProducers True if the client needs to create connections, sessions\n+     *                                    and respecting receivers or consumers. False otherwise.\n+     * @throws JMSException\n+     * @throws NamingException\n+     */\n+    public AndesClient(AndesJMSClientConfiguration config, boolean createConsumersAndProducers)\n+            throws NamingException, JMSException, AndesClientException, IOException {\n+        this(config, 1, createConsumersAndProducers);\n     }\n \n-    public void startWorking() {\n-\n-        queueMessageCounter.set(0);\n-        topicMessageCounter.set(0);\n-        //mode: send/receive/browse/purge/analyse\n-        //hosts host1:port,host2:port;\n-        //destinations queue:q1,q2,q3|topic:t1,t2,t3;\n-        //printNumberOfMessagesPer 100\n-        //isToPrintEachMessage false\n-        //numOfSecondsToRun\n-        //count 1000;\n-        //numOfThreads 5;\n-        //params listener=true,durable=false,subscriptionID=sub1,file=\"\",ackMode=AUTO,delayBetweenMsg=200,stopAfter=12,ackAfterEach=300,commitAfterEach=300,rollbackAfterEach=400,unsubscribeAfter=500 (all parameters are optional)\n-        //connectionString (optional)\n-\n-        //String mode = \"receive\";\n-\n-        if (mode.equals(\"send\") || mode.equals(\"receive\")) {\n-\n-\n-/*            String hostInformation =\"localhost:5673\";\n-            String destinations = \"topic:myTopic\";\n-            String printNumberOfMessagesPerAsString = \"1\";\n-            String isToPrintEachMessageAsString = \"false\";\n-            String numOfSecondsToRunAsString = \"200\";\n-            String messageCountAsString = \"100\";\n-            String numberOfThreadsAsString = \"1\";\n-            String parameters = \"listener=true,ackMode=1,delayBetweenMsg=0,stopAfter=100\";\n-            String connectionString = \"\";*/\n-\n-            //print input information\n-            log.info(\"hosts==>\" + hostInformation);\n-            log.info(\"destinations==>\" + destinations);\n-            log.info(\"mode==>\" + mode);\n-            log.info(\"number of seconds to run==>\" + numOfSecondsToRunAsString);\n-            log.info(\"message count==>\" + messageCountAsString);\n-            log.info(\"num of threads==>\" + numberOfThreadsAsString);\n-            log.info(\"print message count per==>\" + printNumberOfMessagesPerAsString);\n-            log.info(\"is to print message==>\" + isToPrintEachMessageAsString);\n-            log.info(\"parameters==>\" + parameters);\n-            log.info(\"connectionString(optional)==>\" + connectionString);\n-\n-\n-            //decode the host information\n-            String[] hostsAndPorts = hostInformation.split(\",\");\n-\n-            //decode destinations\n-            String[] destinationList = destinations.split(\"\\\\|\");\n-\n-            String[] queues = null;\n-            String[] topics = null;\n-\n-            for (int count = 0; count < destinationList.length; count++) {\n-                String destinationString = destinationList[count];\n-                if (destinationString.startsWith(\"queue\")) {\n-                    String queueString = destinationString.split(\":\")[1];\n-                    queues = queueString.split(\",\");\n-\n-                } else if (destinationString.startsWith(\"topic\")) {\n-                    String topicString = destinationString.split(\":\")[1];\n-                    topics = topicString.split(\",\");\n-                }\n-            }\n-\n-\n-            //get mode of operation\n-            String modeOfOperation = mode;\n-\n-            //get numberOfSecondsToRun\n-            int numberOfSecondsToWaitForMessages = Integer.MAX_VALUE;\n-            if (numOfSecondsToRunAsString != null && !numOfSecondsToRunAsString.equals(\"\")) {\n-                numberOfSecondsToWaitForMessages = Integer.parseInt(numOfSecondsToRunAsString);\n-            }\n-\n-            //decode message count\n-            int messageCount = 1;\n-            if (messageCountAsString != null && !messageCountAsString.equals(\"\")) {\n-                messageCount = Integer.parseInt(messageCountAsString);\n-            }\n-            if (topics == null || topics.length == 0) {\n-                topicMessageCounter.set(messageCount);\n-            }\n-            if (queues == null || queues.length == 0) {\n-                queueMessageCounter.set(messageCount);\n-            }\n-\n-            //decode thread count\n-            int numberOfThreads = 1;\n-            if (numberOfThreadsAsString != null && !numberOfThreadsAsString.equals(\"\")) {\n-                numberOfThreads = Integer.parseInt(numberOfThreadsAsString);\n-            }\n-\n-            //decode how often we should print message count\n-            int printNumberOfMessagesPer = 1;\n-            if (printNumberOfMessagesPerAsString != null && !printNumberOfMessagesPerAsString.equals(\"\")) {\n-                printNumberOfMessagesPer = Integer.parseInt(printNumberOfMessagesPerAsString);\n-            }\n-\n-            //decode if we should print each message\n-            boolean isToPrintEachMessage = false;\n-            if (isToPrintEachMessageAsString != null && !isToPrintEachMessageAsString.equals(\"\")) {\n-                isToPrintEachMessage = Boolean.parseBoolean(isToPrintEachMessageAsString);\n-            }\n-\n-\n-\n-\n-            //decode parameters\n-            boolean isToUseListerner = true;\n-            String subscriptionID = \"\";\n-            String filePath = null;\n-            //default AUTO_ACK\n-            int ackMode = 1;\n-            int delayBetWeenMessages = 0;\n-            int stopAfter = Integer.MAX_VALUE;\n-            int ackAfterEach = Integer.MAX_VALUE;\n-            int commitAfterEach = Integer.MAX_VALUE;\n-            int rollbackAfterEach = Integer.MAX_VALUE;\n-            Long jmsExpiration = 0L; // By Default according to JMS 1.1, message expiration is only activated if this\n-            // value is larger than 0.\n-            String selectors = null;\n-            String jmsType = null;\n-\n-            String[] parameterStrings = parameters.split(\",\");\n-            for (int count = 0; count < parameterStrings.length; count++) {\n-                String[] keyValues = parameterStrings[count].split(\"=\");\n-                String key = keyValues[0];\n-                String value = keyValues[1];\n-                if (key.equals(\"\")) {\n-\n-                } else if (key.equals(\"listener\")) {\n-                    isToUseListerner = Boolean.parseBoolean(value);\n-                } else if (key.equals(\"durable\")) {\n-                    isDurable = Boolean.parseBoolean(value);\n-                } else if (key.equals(\"subscriptionID\")) {\n-                    subscriptionID = value;\n-                } else if (key.equals(\"file\")) {\n-                    filePath = value;\n-                } else if (key.equals(\"ackMode\")) {\n-                    ackMode = Integer.parseInt(value);\n-                } else if (key.equals(\"delayBetweenMsg\")) {\n-                    delayBetWeenMessages = Integer.parseInt(value);\n-                } else if (key.equals(\"stopAfter\")) {\n-                    stopAfter = Integer.parseInt(value);\n-                } else if (key.equals(\"ackAfterEach\")) {\n-                    ackAfterEach = Integer.parseInt(value);\n-                } else if (key.equals(\"commitAfterEach\")) {\n-                    commitAfterEach = Integer.parseInt(value);\n-                } else if (key.equals(\"rollbackAfterEach\")) {\n-                    rollbackAfterEach = Integer.parseInt(value);\n-                } else if (key.equals(\"unsubscribeAfter\")) {\n-                    unsubscribeAfter = Integer.parseInt(value);\n-                } else if (key.equals(\"jMSSelector\")){\n-                    selectors=value;\n-                } else if (key.equals(\"setJMSType\")) {\n-                    jmsType = value;\n-                } else if (key.equals(\"jmsExpiration\")) {\n-                    if (!value.equals(\"\")) {\n-                        jmsExpiration = Long.parseLong(value);\n-                    }\n-                }\n+    /**\n+     * The constructor used for creating multiple consumer or publishers based on the configuration\n+     * passed.\n+     *\n+     * @param config                      The configuration.\n+     * @param numberOfThreads             The amount of publishers or consumers. This amount of\n+     *                                    threads will be started.\n+     * @param createConsumersAndProducers True if the client needs to create connections, sessions\n+     *                                    and respecting receivers or consumers. False otherwise.\n+     * @throws JMSException\n+     * @throws NamingException\n+     * @throws AndesClientException\n+     */\n+    public AndesClient(AndesJMSClientConfiguration config, int numberOfThreads,\n+                       boolean createConsumersAndProducers)\n+            throws IOException, JMSException, NamingException, AndesClientException {\n+        if (0 < numberOfThreads) {\n+            if (config instanceof AndesJMSConsumerClientConfiguration) {\n+                AndesClientUtils\n+                        .initializeReceivedMessagesPrintWriter(((AndesJMSConsumerClientConfiguration) config)\n+                                                                       .getFilePathToWriteReceivedMessages());\n             }\n \n-            //*************************************************************************************************8\n-\n-\n-            //according to information start threads\n-            if (modeOfOperation.equals(\"send\")) {\n-                log.info(\"===============Sending Messages====================\");\n-                for (int count = 0; count < numberOfThreads; count++) {\n-                    int hostIndex = count % hostsAndPorts.length;\n-                    String host = hostsAndPorts[hostIndex].split(\":\")[0];\n-                    String port = hostsAndPorts[hostIndex].split(\":\")[1];\n-                    if (queues != null && queues.length != 0) {\n-                        int queueIndex = count % queues.length;\n-                        String queue = queues[queueIndex];\n-\n-                        //start a queue sender\n-                        QueueMessageSender queueMessageSender =\n-                                new QueueMessageSender(connectionString, host, port, this.username, this.password,\n-                                                       queue, queueMessageCounter, messageCount, delayBetWeenMessages,\n-                                                       filePath, printNumberOfMessagesPer, isToPrintEachMessage,\n-                                                       jmsExpiration, jmsType);\n-                        queueMessageSender.setTypeOfMessage(messageType);\n-\n-                        queueMessageSenders.add(queueMessageSender);\n-\n-                        new Thread(queueMessageSender).start();\n-\n-                    }\n-                    if (topics != null && topics.length != 0) {\n-                        int topicIndex = count % topics.length;\n-                        String topic = topics[topicIndex];\n-\n-                        //start a topic sender\n-                        TopicMessagePublisher topicMessagePublisher =\n-                                new TopicMessagePublisher(connectionString, host, port, this.username, this.password,\n-                                                          topic, topicMessageCounter, messageCount,\n-                                                          delayBetWeenMessages, filePath, printNumberOfMessagesPer,\n-                                                          isToPrintEachMessage, jmsExpiration, jmsType);\n-                        topicMessagePublishers.add(topicMessagePublisher);\n-\n-                        new Thread(topicMessagePublisher).start();\n-\n-                    }\n-\n+            for (int i = 0; i < numberOfThreads; i++) {\n+                if (config instanceof AndesJMSConsumerClientConfiguration) {\n+                    consumers\n+                            .add(new AndesJMSConsumer((AndesJMSConsumerClientConfiguration) config, createConsumersAndProducers));\n+                } else if (config instanceof AndesJMSPublisherClientConfiguration) {\n+                    publishers\n+                            .add(new AndesJMSPublisher((AndesJMSPublisherClientConfiguration) config, createConsumersAndProducers));\n                 }\n-\n-            } else if (modeOfOperation.equals(\"receive\")) {\n-\n-                log.info(\"===============Receiving Messages====================\");\n-\n-                File fileToWriteReceivedMessages = new File(filePathToWriteReceivedMessages);\n-                if (isToPrintEachMessage) {\n-                    try {\n-                        if (fileToWriteReceivedMessages.exists()) {\n-                            fileToWriteReceivedMessages.delete();\n-                        }\n-                        fileToWriteReceivedMessages.getParentFile().mkdirs();\n-                        fileToWriteReceivedMessages.createNewFile();\n-                    } catch (IOException e) {\n-                        log.info(\"Cannot create a file to append receive messages\" + e);\n-                    }\n-                }\n-                for (int count = 0; count < numberOfThreads; count++) {\n-                    int hostIndex = count % hostsAndPorts.length;\n-                    String host = hostsAndPorts[hostIndex].split(\":\")[0];\n-                    String port = hostsAndPorts[hostIndex].split(\":\")[1];\n-                    if (queues != null && queues.length != 0) {\n-                        int queueIndex = count % queues.length;\n-                        String queue = queues[queueIndex];\n-\n-                        //start a queue receiver\n-                        QueueMessageReceiver queueMessageReceiver =\n-                                new QueueMessageReceiver(connectionString, host, port, this.username, this.password,\n-                                                         queue, ackMode, isToUseListerner, queueMessageCounter,\n-                                                         delayBetWeenMessages, printNumberOfMessagesPer,\n-                                                         isToPrintEachMessage, filePathToWriteReceivedMessages,\n-                                                         stopAfter, ackAfterEach, commitAfterEach, rollbackAfterEach,\n-                                                         selectors);\n-                        queueListeners.add(queueMessageReceiver);\n-                        new Thread(queueMessageReceiver).start();\n-                    }\n-                    if (topics != null && topics.length != 0) {\n-                        int topicIndex = count % topics.length;\n-                        String topic = topics[topicIndex];\n-\n-                        //start a topic receiver\n-                        TopicMessageReceiver topicMessageReceiver =\n-                                new TopicMessageReceiver(connectionString, host, port, this.username, this.password,\n-                                                         topic, isDurable, subscriptionID, ackMode, isToUseListerner,\n-                                                         topicMessageCounter, delayBetWeenMessages,\n-                                                         printNumberOfMessagesPer, isToPrintEachMessage,\n-                                                         filePathToWriteReceivedMessages, stopAfter, unsubscribeAfter,\n-                                                         ackAfterEach, commitAfterEach, rollbackAfterEach, selectors);\n-                        topicListeners.add(topicMessageReceiver);\n-                        new Thread(topicMessageReceiver).start();\n-\n-                    }\n-                }\n-\n-            } else {\n-                log.info(\"ERROR: Unknown mode of operation\");\n-            }\n-        } else if (mode.equals(\"browse\")) {\n-\n-            /*mode browse\n-              host Name And Port localhost:5672\n-              destination myQueue\n-              print Number Of Messages Per 100\n-              is To Print Each Message false\n-              */\n-\n-            log.info(\"===============Browsing Messages====================\");\n-            //only applies to queues\n-\n-/*          String hostnameandPort =args[1];\n-            String destination = args[2];\n-            String printNumberOfMessagesPerAsString = args[3];\n-            String isToPrintEachMessageAsString = args[4];*/\n-\n-            //print input information\n-            log.info(\"mode==>\" + mode);\n-            log.info(\"host and port==>\" + hostInformation);\n-            log.info(\"destination==>\" + destinations);\n-            log.info(\"print message count per==>\" + printNumberOfMessagesPerAsString);\n-            log.info(\"is to print message==>\" + isToPrintEachMessageAsString);\n-\n-            //decode host and port\n-            String hostName = hostInformation.split(\":\")[0];\n-            String port = hostInformation.split(\":\")[1];\n-\n-            //decode how often we should print message count\n-            int printNumberOfMessagesPer = 1;\n-            if (printNumberOfMessagesPerAsString != null && !printNumberOfMessagesPerAsString.equals(\"\")) {\n-                printNumberOfMessagesPer = Integer.parseInt(printNumberOfMessagesPerAsString);\n-            }\n-\n-            //decode if we should print each message\n-            boolean isToPrintEachMessage = false;\n-            if (isToPrintEachMessageAsString != null && !isToPrintEachMessageAsString.equals(\"\")) {\n-                isToPrintEachMessage = Boolean.parseBoolean(isToPrintEachMessageAsString);\n-            }\n-\n-            int messageCount = browseQueue(hostName, port, this.username, this.password, destinations, printNumberOfMessagesPer, isToPrintEachMessage);\n-\n-            log.info(\"Browser Message Count: \" + messageCount);\n-\n-\n-        } else if (mode.equals(\"purge\")) {\n-\n-            log.info(\"===============Purging Messages====================\");\n-\n-            //only applies to queues\n-/*          String hostnameandPort =args[1];\n-            String destination = args[2];*/\n-\n-            //print input information\n-            log.info(\"mode==>\" + mode);\n-            log.info(\"host and port==>\" + hostInformation);\n-\n-            //decode host and port\n-            String hostName = hostInformation.split(\":\")[0];\n-            String port = hostInformation.split(\":\")[1];\n-\n-            //browse and get the message count\n-            int messageCount = browseQueue(hostName, port, this.username, this.password, destinations, Integer.MAX_VALUE, false);\n-\n-            //activate receiver for the queue(if specified more first one/ if specified more than one host get the first one)\n-            //start a queue receiver\n-            QueueMessageReceiver queueMessageReceiver = new QueueMessageReceiver\n-                    (\"\", hostName, port, this.username, this.password, destinations, 1, true, queueMessageCounter, 0,\n-                            Integer.MAX_VALUE, false, \"\", messageCount, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);\n-            queueListeners.add(queueMessageReceiver);\n-            new Thread(queueMessageReceiver).start();\n-\n-            topicMessageCounter.set(messageCount);\n-\n-        } else if (mode.equals(\"analyse\")) {\n-\n-            /**\n-             * mode analyse\n-             *     printMessages/printDuplicates/printMissing/printSorted/checkOrder/clearFile\n-             */\n-            String operation = analyticOperation;\n-            String numberOfMessagesSentAsString = \"\";\n-            int numberOfMessagesSent = 0;\n-\n-            if (operation.equals(\"printMissing\")) {\n-\n-                numberOfMessagesSentAsString = numberOfMessagesExpectedForAnalysis;\n-                numberOfMessagesSent = Integer.parseInt(numberOfMessagesSentAsString);\n-            }\n-\n-            //print input information\n-            log.info(\"mode==>\" + mode);\n-            log.info(\"operation==>\" + operation);\n-\n-            AndesClientOutputParser andesClientOutputParser = new AndesClientOutputParser(filePathToWriteReceivedMessages);\n-\n-            if (operation.equals(\"printMessages\")) {\n-                andesClientOutputParser.printMessagesMap();\n-            } else if (operation.equals(\"printDuplicates\")) {\n-                andesClientOutputParser.printDuplicateMessages();\n-            } else if (operation.equals(\"printMissing\")) {\n-                andesClientOutputParser.printMissingMessages(numberOfMessagesSent);\n-            } else if (operation.equals(\"printSorted\")) {\n-                andesClientOutputParser.printMessagesSorted();\n-            } else if (operation.equals(\"checkOrder\")) {\n-                log.info(\"MESSAGE ORDER PRESERVED: \" + andesClientOutputParser.checkIfMessagesAreInOrder());\n-            } else if (operation.equals(\"clearFile\")) {\n-                andesClientOutputParser.clearFile();\n-            } else {\n-                log.info(\"analyse operation not found...\");\n             }\n         } else {\n-            log.info(\"ERROR: Unknown mode of operation\");\n+            throw new AndesClientException(\"The amount of subscribers cannot be less than 1. \" +\n+                                           \"Value entered is \" + Integer.toString(numberOfThreads));\n         }\n     }\n \n-    private int browseQueue(String host, String port, String userName, String password, String destination, int printNumberOfMessagesPer, boolean isToPrintMessage) {\n-        int messageCount = 0;\n-        //create a browser - one threaded app blocking\n-        //make an enumeration and get the count\n-        QueueMessageBrowser queueMessageBrowser = new QueueMessageBrowser(host, port, userName, password, destination, printNumberOfMessagesPer, isToPrintMessage);\n-        messageCount = queueMessageBrowser.getMessageCount();\n-        return messageCount;\n-    }\n-\n-\n-    //******************************************************************************************************************\n-\n-    public void shutDownClient() {\n-\n-        if (mode.equals(\"send\")) {\n-\n-            for (QueueMessageSender qSender : queueMessageSenders) {\n-                qSender.stopSending();\n+    /**\n+     * Starts up the consumer(s) or publisher(s) to consume or publish messages.\n+     *\n+     * @throws JMSException\n+     * @throws IOException\n+     */\n+    public void startClient() throws AndesClientException, JMSException, IOException {\n+        for (AndesJMSConsumer consumer : consumers) {\n+            consumer.startClient();\n+            if (this.startDelay > 0L) {\n+                AndesClientUtils.sleepForInterval(this.startDelay);\n             }\n-            for (TopicMessagePublisher tPublisher : topicMessagePublishers) {\n-                tPublisher.stopPublishing();\n+        }\n+        for (AndesJMSPublisher publisher : publishers) {\n+            publisher.startClient();\n+            if (this.startDelay > 0L) {\n+                AndesClientUtils.sleepForInterval(this.startDelay);\n             }\n+        }\n+    }\n \n-        } else if (mode.equals(\"receive\")) {\n-\n-            for (QueueMessageReceiver qListener : queueListeners) {\n-                qListener.stopListening();\n-            }\n-            for (TopicMessageReceiver tListener : topicListeners) {\n-                tListener.stopListening();\n-            }\n+    /**\n+     * Stops the client from publishing or consuming messages.\n+     *\n+     * @throws JMSException\n+     */\n+    public void stopClient() throws JMSException {\n+        for (AndesJMSConsumer consumer : consumers) {\n+            consumer.stopClient();\n+        }\n+        for (AndesJMSPublisher publisher : publishers) {\n+            publisher.stopClient();\n+        }\n \n-        } else if (mode.equals(\"purge\")) {\n+        log.info(\"TPS:\" + this.getConsumerTPS() + \" AverageLatency:\" + this.getAverageLatency());\n+    }\n \n-            for (QueueMessageReceiver qListener : queueListeners) {\n-                qListener.stopListening();\n-            }\n+    /**\n+     * Gets the received messages for all consumers in the client.\n+     *\n+     * @return The total number of messages received for all consumers.\n+     */\n+    public long getReceivedMessageCount() {\n+        long allReceivedMessageCount = 0L;\n+        for (AndesJMSConsumer consumer : consumers) {\n+            allReceivedMessageCount = allReceivedMessageCount + consumer.getReceivedMessageCount();\n         }\n-\n+        return allReceivedMessageCount;\n     }\n \n-    public int getReceivedqueueMessagecount() {\n-        return queueMessageCounter.get();\n+    /**\n+     * Gets the average transactions per second for consumer(s).\n+     *\n+     * @return The average TPS.\n+     */\n+    public double getConsumerTPS() {\n+        double tps = 0L;\n+        for (AndesJMSConsumer consumer : consumers) {\n+            tps = tps + consumer.getConsumerTPS();\n+        }\n+        return tps / consumers.size();\n     }\n \n-    public int getReceivedTopicMessagecount() {\n-        return topicMessageCounter.get();\n+    /**\n+     * Gets the average latency for consumer(s).\n+     *\n+     * @return The average latency.\n+     */\n+    public double getAverageLatency() {\n+        double averageLatency = 0L;\n+        for (AndesJMSConsumer consumer : consumers) {\n+            averageLatency = averageLatency + consumer.getAverageLatency();\n+        }\n+        return averageLatency / consumers.size();\n     }\n \n-    public Map<Long, Integer> checkIfMessagesAreDuplicated() {\n-        org.wso2.mb.integration.common.clients.operations.utils.AndesClientUtils.flushPrintWriter();\n-        AndesClientOutputParser andesClientOutputParser = new AndesClientOutputParser(filePathToWriteReceivedMessages);\n-        return andesClientOutputParser.checkIfMessagesAreDuplicated();\n+    /**\n+     * Gets the number of messages sent by the publisher(s).\n+     *\n+     * @return The number of messages.\n+     */\n+    public long getSentMessageCount() {\n+        long allSentMessageCount = 0L;\n+        for (AndesJMSPublisher publisher : publishers) {\n+            allSentMessageCount = allSentMessageCount + publisher.getSentMessageCount();\n+        }\n+        return allSentMessageCount;\n     }\n \n-    public boolean checkIfMessagesAreInOrder() {\n-        AndesClientOutputParser andesClientOutputParser = new AndesClientOutputParser(filePathToWriteReceivedMessages);\n-        return andesClientOutputParser.checkIfMessagesAreInOrder();\n+    /**\n+     * Gets the average transactions per seconds for publisher(s). Suppressing \"UnusedDeclaration\"\n+     * as the client acts as an service.\n+     *\n+     * @return the average transactions per seconds.\n+     */\n+    @SuppressWarnings(\"UnusedDeclaration\")\n+    public double getPublisherTPS() {\n+        double tps = 0L;\n+        for (AndesJMSPublisher publisher : publishers) {\n+            tps = tps + publisher.getPublisherTPS();\n+        }\n+        return tps / publishers.size();\n     }\n \n     /**\n-     * This method return whether received messages are transacted\n+     * Gets the duplicated messages received\n      *\n-     * @param operationOccurredIndex Index of the operated message most of the time last message\n-     * @return\n+     * @return A map of message identifiers and message content.\n+     * @throws IOException\n      */\n-    public boolean transactedOperation(long operationOccurredIndex) {\n-        AndesClientOutputParser andesClientOutputParser = new AndesClientOutputParser(filePathToWriteReceivedMessages);\n-        return andesClientOutputParser.transactedOperations(operationOccurredIndex);\n+    public Map<Long, Integer> checkIfMessagesAreDuplicated()\n+            throws IOException {\n+        if (0 < consumers.size()) {\n+            AndesClientUtils.flushPrintWriters();\n+            AndesClientOutputParser andesClientOutputParser =\n+                    new AndesClientOutputParser(consumers.get(0).getConfig()","path":"modules/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesClient.java","position":739,"original_position":739,"commit_id":"fb58be1679eb9bcc789b06607f16b09fcc36cf51","original_commit_id":"fb58be1679eb9bcc789b06607f16b09fcc36cf51","user":{"login":"akalankapagoda","id":1322058,"avatar_url":"https://avatars.githubusercontent.com/u/1322058?v=3","gravatar_id":"","url":"https://api.github.com/users/akalankapagoda","html_url":"https://github.com/akalankapagoda","followers_url":"https://api.github.com/users/akalankapagoda/followers","following_url":"https://api.github.com/users/akalankapagoda/following{/other_user}","gists_url":"https://api.github.com/users/akalankapagoda/gists{/gist_id}","starred_url":"https://api.github.com/users/akalankapagoda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akalankapagoda/subscriptions","organizations_url":"https://api.github.com/users/akalankapagoda/orgs","repos_url":"https://api.github.com/users/akalankapagoda/repos","events_url":"https://api.github.com/users/akalankapagoda/events{/privacy}","received_events_url":"https://api.github.com/users/akalankapagoda/received_events","type":"User","site_admin":false},"body":"Can there be more than 1 consumer? If so do we need to check in all those consumers for message duplication instead of only checking in the 0th consumer?","created_at":"2015-03-06T13:44:02Z","updated_at":"2015-03-06T13:44:02Z","html_url":"https://github.com/wso2/product-mb/pull/32#discussion_r25944676","pull_request_url":"https://api.github.com/repos/wso2/product-mb/pulls/32","_links":{"self":{"href":"https://api.github.com/repos/wso2/product-mb/pulls/comments/25944676"},"html":{"href":"https://github.com/wso2/product-mb/pull/32#discussion_r25944676"},"pull_request":{"href":"https://api.github.com/repos/wso2/product-mb/pulls/32"}}},"pull_request":{"url":"https://api.github.com/repos/wso2/product-mb/pulls/32","id":29599255,"html_url":"https://github.com/wso2/product-mb/pull/32","diff_url":"https://github.com/wso2/product-mb/pull/32.diff","patch_url":"https://github.com/wso2/product-mb/pull/32.patch","issue_url":"https://api.github.com/repos/wso2/product-mb/issues/32","number":32,"state":"closed","locked":false,"title":"[MB-968] Refactoring Andes Client used in Test cases ","user":{"login":"hemikak","id":4398820,"avatar_url":"https://avatars.githubusercontent.com/u/4398820?v=3","gravatar_id":"","url":"https://api.github.com/users/hemikak","html_url":"https://github.com/hemikak","followers_url":"https://api.github.com/users/hemikak/followers","following_url":"https://api.github.com/users/hemikak/following{/other_user}","gists_url":"https://api.github.com/users/hemikak/gists{/gist_id}","starred_url":"https://api.github.com/users/hemikak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hemikak/subscriptions","organizations_url":"https://api.github.com/users/hemikak/orgs","repos_url":"https://api.github.com/users/hemikak/repos","events_url":"https://api.github.com/users/hemikak/events{/privacy}","received_events_url":"https://api.github.com/users/hemikak/received_events","type":"User","site_admin":false},"body":"Removed earlier Andes Client used for test cases.\r\nAdded new client for testing purposes.\r\nModified all test cases to suit the new Andes client.\r\nAdded java docs.\r\nRemoved \"test-jms\" module.","created_at":"2015-02-19T10:13:06Z","updated_at":"2015-03-06T13:44:02Z","closed_at":"2015-03-03T10:38:46Z","merged_at":"2015-03-03T10:38:46Z","merge_commit_sha":"4e8ca7d4a419e1bb874271eb03a8a0e8d45b31ce","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/wso2/product-mb/pulls/32/commits","review_comments_url":"https://api.github.com/repos/wso2/product-mb/pulls/32/comments","review_comment_url":"https://api.github.com/repos/wso2/product-mb/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wso2/product-mb/issues/32/comments","statuses_url":"https://api.github.com/repos/wso2/product-mb/statuses/fb58be1679eb9bcc789b06607f16b09fcc36cf51","head":{"label":"hemikak:user-auth","ref":"user-auth","sha":"fb58be1679eb9bcc789b06607f16b09fcc36cf51","user":{"login":"hemikak","id":4398820,"avatar_url":"https://avatars.githubusercontent.com/u/4398820?v=3","gravatar_id":"","url":"https://api.github.com/users/hemikak","html_url":"https://github.com/hemikak","followers_url":"https://api.github.com/users/hemikak/followers","following_url":"https://api.github.com/users/hemikak/following{/other_user}","gists_url":"https://api.github.com/users/hemikak/gists{/gist_id}","starred_url":"https://api.github.com/users/hemikak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hemikak/subscriptions","organizations_url":"https://api.github.com/users/hemikak/orgs","repos_url":"https://api.github.com/users/hemikak/repos","events_url":"https://api.github.com/users/hemikak/events{/privacy}","received_events_url":"https://api.github.com/users/hemikak/received_events","type":"User","site_admin":false},"repo":{"id":27819258,"name":"product-mb","full_name":"hemikak/product-mb","owner":{"login":"hemikak","id":4398820,"avatar_url":"https://avatars.githubusercontent.com/u/4398820?v=3","gravatar_id":"","url":"https://api.github.com/users/hemikak","html_url":"https://github.com/hemikak","followers_url":"https://api.github.com/users/hemikak/followers","following_url":"https://api.github.com/users/hemikak/following{/other_user}","gists_url":"https://api.github.com/users/hemikak/gists{/gist_id}","starred_url":"https://api.github.com/users/hemikak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hemikak/subscriptions","organizations_url":"https://api.github.com/users/hemikak/orgs","repos_url":"https://api.github.com/users/hemikak/repos","events_url":"https://api.github.com/users/hemikak/events{/privacy}","received_events_url":"https://api.github.com/users/hemikak/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/hemikak/product-mb","description":"","fork":true,"url":"https://api.github.com/repos/hemikak/product-mb","forks_url":"https://api.github.com/repos/hemikak/product-mb/forks","keys_url":"https://api.github.com/repos/hemikak/product-mb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hemikak/product-mb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hemikak/product-mb/teams","hooks_url":"https://api.github.com/repos/hemikak/product-mb/hooks","issue_events_url":"https://api.github.com/repos/hemikak/product-mb/issues/events{/number}","events_url":"https://api.github.com/repos/hemikak/product-mb/events","assignees_url":"https://api.github.com/repos/hemikak/product-mb/assignees{/user}","branches_url":"https://api.github.com/repos/hemikak/product-mb/branches{/branch}","tags_url":"https://api.github.com/repos/hemikak/product-mb/tags","blobs_url":"https://api.github.com/repos/hemikak/product-mb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hemikak/product-mb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hemikak/product-mb/git/refs{/sha}","trees_url":"https://api.github.com/repos/hemikak/product-mb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hemikak/product-mb/statuses/{sha}","languages_url":"https://api.github.com/repos/hemikak/product-mb/languages","stargazers_url":"https://api.github.com/repos/hemikak/product-mb/stargazers","contributors_url":"https://api.github.com/repos/hemikak/product-mb/contributors","subscribers_url":"https://api.github.com/repos/hemikak/product-mb/subscribers","subscription_url":"https://api.github.com/repos/hemikak/product-mb/subscription","commits_url":"https://api.github.com/repos/hemikak/product-mb/commits{/sha}","git_commits_url":"https://api.github.com/repos/hemikak/product-mb/git/commits{/sha}","comments_url":"https://api.github.com/repos/hemikak/product-mb/comments{/number}","issue_comment_url":"https://api.github.com/repos/hemikak/product-mb/issues/comments{/number}","contents_url":"https://api.github.com/repos/hemikak/product-mb/contents/{+path}","compare_url":"https://api.github.com/repos/hemikak/product-mb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hemikak/product-mb/merges","archive_url":"https://api.github.com/repos/hemikak/product-mb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hemikak/product-mb/downloads","issues_url":"https://api.github.com/repos/hemikak/product-mb/issues{/number}","pulls_url":"https://api.github.com/repos/hemikak/product-mb/pulls{/number}","milestones_url":"https://api.github.com/repos/hemikak/product-mb/milestones{/number}","notifications_url":"https://api.github.com/repos/hemikak/product-mb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hemikak/product-mb/labels{/name}","releases_url":"https://api.github.com/repos/hemikak/product-mb/releases{/id}","created_at":"2014-12-10T12:39:36Z","updated_at":"2015-02-07T06:40:19Z","pushed_at":"2015-03-05T13:36:31Z","git_url":"git://github.com/hemikak/product-mb.git","ssh_url":"git@github.com:hemikak/product-mb.git","clone_url":"https://github.com/hemikak/product-mb.git","svn_url":"https://github.com/hemikak/product-mb","homepage":null,"size":6074,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"wso2:master","ref":"master","sha":"b21f6471ce0b40d631f12b95fb0e92a5dda14c00","user":{"login":"wso2","id":533043,"avatar_url":"https://avatars.githubusercontent.com/u/533043?v=3","gravatar_id":"","url":"https://api.github.com/users/wso2","html_url":"https://github.com/wso2","followers_url":"https://api.github.com/users/wso2/followers","following_url":"https://api.github.com/users/wso2/following{/other_user}","gists_url":"https://api.github.com/users/wso2/gists{/gist_id}","starred_url":"https://api.github.com/users/wso2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wso2/subscriptions","organizations_url":"https://api.github.com/users/wso2/orgs","repos_url":"https://api.github.com/users/wso2/repos","events_url":"https://api.github.com/users/wso2/events{/privacy}","received_events_url":"https://api.github.com/users/wso2/received_events","type":"Organization","site_admin":false},"repo":{"id":20559227,"name":"product-mb","full_name":"wso2/product-mb","owner":{"login":"wso2","id":533043,"avatar_url":"https://avatars.githubusercontent.com/u/533043?v=3","gravatar_id":"","url":"https://api.github.com/users/wso2","html_url":"https://github.com/wso2","followers_url":"https://api.github.com/users/wso2/followers","following_url":"https://api.github.com/users/wso2/following{/other_user}","gists_url":"https://api.github.com/users/wso2/gists{/gist_id}","starred_url":"https://api.github.com/users/wso2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wso2/subscriptions","organizations_url":"https://api.github.com/users/wso2/orgs","repos_url":"https://api.github.com/users/wso2/repos","events_url":"https://api.github.com/users/wso2/events{/privacy}","received_events_url":"https://api.github.com/users/wso2/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wso2/product-mb","description":"","fork":false,"url":"https://api.github.com/repos/wso2/product-mb","forks_url":"https://api.github.com/repos/wso2/product-mb/forks","keys_url":"https://api.github.com/repos/wso2/product-mb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wso2/product-mb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wso2/product-mb/teams","hooks_url":"https://api.github.com/repos/wso2/product-mb/hooks","issue_events_url":"https://api.github.com/repos/wso2/product-mb/issues/events{/number}","events_url":"https://api.github.com/repos/wso2/product-mb/events","assignees_url":"https://api.github.com/repos/wso2/product-mb/assignees{/user}","branches_url":"https://api.github.com/repos/wso2/product-mb/branches{/branch}","tags_url":"https://api.github.com/repos/wso2/product-mb/tags","blobs_url":"https://api.github.com/repos/wso2/product-mb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wso2/product-mb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wso2/product-mb/git/refs{/sha}","trees_url":"https://api.github.com/repos/wso2/product-mb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wso2/product-mb/statuses/{sha}","languages_url":"https://api.github.com/repos/wso2/product-mb/languages","stargazers_url":"https://api.github.com/repos/wso2/product-mb/stargazers","contributors_url":"https://api.github.com/repos/wso2/product-mb/contributors","subscribers_url":"https://api.github.com/repos/wso2/product-mb/subscribers","subscription_url":"https://api.github.com/repos/wso2/product-mb/subscription","commits_url":"https://api.github.com/repos/wso2/product-mb/commits{/sha}","git_commits_url":"https://api.github.com/repos/wso2/product-mb/git/commits{/sha}","comments_url":"https://api.github.com/repos/wso2/product-mb/comments{/number}","issue_comment_url":"https://api.github.com/repos/wso2/product-mb/issues/comments{/number}","contents_url":"https://api.github.com/repos/wso2/product-mb/contents/{+path}","compare_url":"https://api.github.com/repos/wso2/product-mb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wso2/product-mb/merges","archive_url":"https://api.github.com/repos/wso2/product-mb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wso2/product-mb/downloads","issues_url":"https://api.github.com/repos/wso2/product-mb/issues{/number}","pulls_url":"https://api.github.com/repos/wso2/product-mb/pulls{/number}","milestones_url":"https://api.github.com/repos/wso2/product-mb/milestones{/number}","notifications_url":"https://api.github.com/repos/wso2/product-mb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wso2/product-mb/labels{/name}","releases_url":"https://api.github.com/repos/wso2/product-mb/releases{/id}","created_at":"2014-06-06T10:02:48Z","updated_at":"2015-03-06T11:57:14Z","pushed_at":"2015-03-06T11:57:12Z","git_url":"git://github.com/wso2/product-mb.git","ssh_url":"git@github.com:wso2/product-mb.git","clone_url":"https://github.com/wso2/product-mb.git","svn_url":"https://github.com/wso2/product-mb","homepage":null,"size":6568,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":27,"mirror_url":null,"open_issues_count":2,"forks":27,"open_issues":2,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wso2/product-mb/pulls/32"},"html":{"href":"https://github.com/wso2/product-mb/pull/32"},"issue":{"href":"https://api.github.com/repos/wso2/product-mb/issues/32"},"comments":{"href":"https://api.github.com/repos/wso2/product-mb/issues/32/comments"},"review_comments":{"href":"https://api.github.com/repos/wso2/product-mb/pulls/32/comments"},"review_comment":{"href":"https://api.github.com/repos/wso2/product-mb/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wso2/product-mb/pulls/32/commits"},"statuses":{"href":"https://api.github.com/repos/wso2/product-mb/statuses/fb58be1679eb9bcc789b06607f16b09fcc36cf51"}}}}