/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.activemq.tool; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Arrays; import java.util.Set; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.TextMessage; import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.tool.properties.JmsClientProperties; import org.apache.activemq.tool.properties.JmsProducerProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JmsProducerClient extends AbstractJmsMeasurableClient { private static final Logger LOG = LoggerFactory.getLogger(JmsProducerClient.class); protected JmsProducerProperties client; protected MessageProducer jmsProducer; protected TextMessage jmsTextMessage; public JmsProducerClient(ConnectionFactory factory) { this(new JmsProducerProperties(), factory); } public JmsProducerClient(JmsProducerProperties clientProps, ConnectionFactory factory) { super(factory); this.client = clientProps; } public void sendMessages() throws JMSException { // Send a specific number of messages if (client.getSendType().equalsIgnoreCase(JmsProducerProperties.COUNT_BASED_SENDING)) { long sendCount = client.getSendCount(); sendCountBasedMessages(sendCount); // Send messages for a specific duration } else { long sendDuration = client.getSendDuration(); sendTimeBasedMessages(sendDuration); } } public void sendMessages(int destCount) throws JMSException { this.destCount = destCount; sendMessages(); } public void sendMessages(int destIndex, int destCount) throws JMSException { this.destIndex = destIndex; sendMessages(destCount); } public void sendCountBasedMessages(long messageCount) throws JMSException { // Parse through different ways to send messages // Avoided putting the condition inside the loop to prevent effect on performance Destination[] dest = createDestinations(destCount); // Create a producer, if none is created. if (getJmsProducer() == null) { if (dest.length == 1) { createJmsProducer(dest[0]); } else { createJmsProducer(); } } try { getConnection().start(); if (client.getMsgFileName() != null) { LOG.info("Starting to publish " + messageCount + " messages from file " + client.getMsgFileName() ); } else { LOG.info("Starting to publish " + messageCount + " messages of size " + client.getMessageSize() + " byte(s)." ); } // Send one type of message only, avoiding the creation of different messages on sending if (!client.isCreateNewMsg()) { // Create only a single message createJmsTextMessage(); // Send to more than one actual destination if (dest.length > 1) { for (int i = 0; i < messageCount; i++) { for (int j = 0; j < dest.length; j++) { getJmsProducer().send(dest[j], getJmsTextMessage()); incThroughput(); sleep(); commitTxIfNecessary(); } } // Send to only one actual destination } else { for (int i = 0; i < messageCount; i++) { getJmsProducer().send(getJmsTextMessage()); incThroughput(); sleep(); commitTxIfNecessary(); } } // Send different type of messages using indexing to identify each one. // Message size will vary. Definitely slower, since messages properties // will be set individually each send. } else { // Send to more than one actual destination if (dest.length > 1) { for (int i = 0; i < messageCount; i++) { for (int j = 0; j < dest.length; j++) { getJmsProducer().send(dest[j], createJmsTextMessage("Text Message [" + i + "]")); incThroughput(); sleep(); commitTxIfNecessary(); } } // Send to only one actual destination } else { for (int i = 0; i < messageCount; i++) { getJmsProducer().send(createJmsTextMessage("Text Message [" + i + "]")); incThroughput(); sleep(); commitTxIfNecessary(); } } } } finally { LOG.info("Finished sending"); getConnection().close(); } } public void sendTimeBasedMessages(long duration) throws JMSException { long endTime = System.currentTimeMillis() + duration; // Parse through different ways to send messages // Avoided putting the condition inside the loop to prevent effect on performance Destination[] dest = createDestinations(destCount); // Create a producer, if none is created. if (getJmsProducer() == null) { if (dest.length == 1) { createJmsProducer(dest[0]); } else { createJmsProducer(); } } try { getConnection().start(); if (client.getMsgFileName() != null) { LOG.info("Starting to publish messages from file " + client.getMsgFileName() + " for " + duration + " ms"); } else { LOG.info("Starting to publish " + client.getMessageSize() + " byte(s) messages for " + duration + " ms"); } // Send one type of message only, avoiding the creation of different messages on sending if (!client.isCreateNewMsg()) { // Create only a single message createJmsTextMessage(); // Send to more than one actual destination if (dest.length > 1) { while (System.currentTimeMillis() < endTime) { for (int j = 0; j < dest.length; j++) { getJmsProducer().send(dest[j], getJmsTextMessage()); incThroughput(); sleep(); commitTxIfNecessary(); } } // Send to only one actual destination } else { while (System.currentTimeMillis() < endTime) { getJmsProducer().send(getJmsTextMessage()); incThroughput(); sleep(); commitTxIfNecessary(); } } // Send different type of messages using indexing to identify each one. // Message size will vary. Definitely slower, since messages properties // will be set individually each send. } else { // Send to more than one actual destination long count = 1; if (dest.length > 1) { while (System.currentTimeMillis() < endTime) { for (int j = 0; j < dest.length; j++) { getJmsProducer().send(dest[j], createJmsTextMessage("Text Message [" + count++ + "]")); incThroughput(); sleep(); commitTxIfNecessary(); } } // Send to only one actual destination } else { while (System.currentTimeMillis() < endTime) { getJmsProducer().send(createJmsTextMessage("Text Message [" + count++ + "]")); incThroughput(); sleep(); commitTxIfNecessary(); } } } } finally { LOG.info("Finished sending"); getConnection().close(); } } public MessageProducer createJmsProducer() throws JMSException { jmsProducer = getSession().createProducer(null); if (client.getDeliveryMode().equalsIgnoreCase(JmsProducerProperties.DELIVERY_MODE_PERSISTENT)) { LOG.info("Creating producer to possible multiple destinations with persistent delivery."); jmsProducer.setDeliveryMode(DeliveryMode.PERSISTENT); } else if (client.getDeliveryMode().equalsIgnoreCase(JmsProducerProperties.DELIVERY_MODE_NON_PERSISTENT)) { LOG.info("Creating producer to possible multiple destinations with non-persistent delivery."); jmsProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); } else { LOG.warn("Unknown deliveryMode value. Defaulting to non-persistent."); jmsProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); } return jmsProducer; } public MessageProducer createJmsProducer(Destination dest) throws JMSException { jmsProducer = getSession().createProducer(dest); if (client.getDeliveryMode().equalsIgnoreCase(JmsProducerProperties.DELIVERY_MODE_PERSISTENT)) { LOG.info("Creating producer to: " + dest.toString() + " with persistent delivery."); jmsProducer.setDeliveryMode(DeliveryMode.PERSISTENT); } else if (client.getDeliveryMode().equalsIgnoreCase(JmsProducerProperties.DELIVERY_MODE_NON_PERSISTENT)) { LOG.info("Creating producer to: " + dest.toString() + " with non-persistent delivery."); jmsProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); } else { LOG.warn("Unknown deliveryMode value. Defaulting to non-persistent."); jmsProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); } return jmsProducer; } public MessageProducer getJmsProducer() { return jmsProducer; } public TextMessage createJmsTextMessage() throws JMSException { if (client.getMsgFileName() != null) { return loadJmsMessage(); } else { return createJmsTextMessage(client.getMessageSize()); } } public TextMessage createJmsTextMessage(int size) throws JMSException { jmsTextMessage = getSession().createTextMessage(buildText("", size)); // support for adding message headers Set<String> headerKeys = this.client.getHeaderKeys(); for (String key : headerKeys) { jmsTextMessage.setObjectProperty(key, this.client.getHeaderValue(key)); } return jmsTextMessage; } public TextMessage createJmsTextMessage(String text) throws JMSException { jmsTextMessage = getSession().createTextMessage(buildText(text, client.getMessageSize())); return jmsTextMessage; } public TextMessage getJmsTextMessage() { return jmsTextMessage; } @Override public JmsClientProperties getClient() { return client; } @Override public void setClient(JmsClientProperties clientProps) { client = (JmsProducerProperties)clientProps; } @Override protected Destination createTemporaryDestination(String destName) throws JMSException { String simpleName = getSimpleName(destName); byte destinationType = getDestinationType(destName); // when we produce to temp destinations, we publish to them as // though they were normal queues or topics if (destinationType == ActiveMQDestination.TEMP_QUEUE_TYPE) { LOG.info("Creating queue: {}", destName); return getSession().createQueue(simpleName); } else if (destinationType == ActiveMQDestination.TEMP_TOPIC_TYPE) { LOG.info("Creating topic: {}", destName); return getSession().createTopic(simpleName); } else { throw new IllegalArgumentException("Unrecognized destination type: " + destinationType); } } protected String buildText(String text, int size) { byte[] data = new byte[size - text.length()]; Arrays.fill(data, (byte) 0); return text + new String(data); } protected void sleep() { if (client.getSendDelay() > 0) { try { LOG.trace("Sleeping for " + client.getSendDelay() + " milliseconds"); Thread.sleep(client.getSendDelay()); } catch (java.lang.InterruptedException ex) { LOG.warn(ex.getMessage()); } } } /** * loads the message to be sent from the specified TextFile */ protected TextMessage loadJmsMessage() throws JMSException { try { // couple of sanity checks upfront if (client.getMsgFileName() == null) { throw new JMSException("Invalid filename specified."); } File f = new File(client.getMsgFileName()); if (f.isDirectory()) { throw new JMSException("Cannot load from " + client.getMsgFileName() + " as it is a directory not a text file."); } // try to load file StringBuffer payload = new StringBuffer(); try(FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr)) { String tmp = null; while ((tmp = br.readLine()) != null) { payload.append(tmp); } } jmsTextMessage = getSession().createTextMessage(payload.toString()); return jmsTextMessage; } catch (FileNotFoundException ex) { throw new JMSException(ex.getMessage()); } catch (IOException iox) { throw new JMSException(iox.getMessage()); } } }