/*
* 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.artemis.cli.commands.messages;
import javax.jms.BytesMessage;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.artemis.utils.ReusableLatch;
public class ProducerThread extends Thread {
protected final Session session;
boolean verbose;
int messageCount = 1000;
boolean runIndefinitely = false;
Destination destination;
int sleep = 0;
boolean persistent = true;
int messageSize = 0;
int textMessageSize;
long msgTTL = 0L;
String msgGroupID = null;
int transactionBatchSize;
int transactions = 0;
final AtomicInteger sentCount = new AtomicInteger(0);
String message;
String messageText = null;
String payloadUrl = null;
byte[] payload = null;
boolean running = false;
final ReusableLatch finished = new ReusableLatch(1);
final ReusableLatch paused = new ReusableLatch(0);
public ProducerThread(Session session, Destination destination, int threadNr) {
super("Producer " + destination.toString() + ", thread=" + threadNr);
this.destination = destination;
this.session = session;
}
@Override
public void run() {
MessageProducer producer = null;
String threadName = Thread.currentThread().getName();
try {
producer = session.createProducer(destination);
producer.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
producer.setTimeToLive(msgTTL);
initPayLoad();
running = true;
System.out.println(threadName + " Started to calculate elapsed time ...\n");
long tStart = System.currentTimeMillis();
if (runIndefinitely) {
while (running) {
paused.await();
sendMessage(producer, threadName);
sentCount.incrementAndGet();
}
} else {
for (sentCount.set(0); sentCount.get() < messageCount && running; sentCount.incrementAndGet()) {
paused.await();
sendMessage(producer, threadName);
}
}
try {
session.commit();
} catch (Throwable ignored) {
}
System.out.println(threadName + " Produced: " + this.getSentCount() + " messages");
long tEnd = System.currentTimeMillis();
long elapsed = (tEnd - tStart) / 1000;
System.out.println(threadName + " Elapsed time in second : " + elapsed + " s");
System.out.println(threadName + " Elapsed time in milli second : " + (tEnd - tStart) + " milli seconds");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (finished != null) {
finished.countDown();
}
if (producer != null) {
try {
producer.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
private void sendMessage(MessageProducer producer, String threadName) throws Exception {
Message message = createMessage(sentCount.get(), threadName);
producer.send(message);
if (verbose) {
System.out.println(threadName + " Sent: " + (message instanceof TextMessage ? ((TextMessage) message).getText() : message.getJMSMessageID()));
}
if (transactionBatchSize > 0 && sentCount.get() > 0 && sentCount.get() % transactionBatchSize == 0) {
System.out.println(threadName + " Committing transaction: " + transactions++);
session.commit();
}
if (sleep > 0) {
Thread.sleep(sleep);
}
}
private void initPayLoad() {
if (messageSize > 0) {
payload = new byte[messageSize];
for (int i = 0; i < payload.length; i++) {
payload[i] = '.';
}
}
}
protected Message createMessage(int i, String threadName) throws Exception {
Message answer;
if (payload != null) {
answer = session.createBytesMessage();
((BytesMessage) answer).writeBytes(payload);
} else {
if (textMessageSize > 0) {
if (messageText == null) {
messageText = readInputStream(getClass().getResourceAsStream("demo.txt"), textMessageSize, i);
}
} else if (payloadUrl != null) {
messageText = readInputStream(new URL(payloadUrl).openStream(), -1, i);
} else if (message != null) {
messageText = message;
} else {
messageText = createDefaultMessage(i);
}
answer = session.createTextMessage(messageText);
}
if ((msgGroupID != null) && (!msgGroupID.isEmpty())) {
answer.setStringProperty("JMSXGroupID", msgGroupID);
}
answer.setIntProperty("count", i);
answer.setStringProperty("ThreadSent", threadName);
return answer;
}
private String readInputStream(InputStream is, int size, int messageNumber) throws IOException {
try (InputStreamReader reader = new InputStreamReader(is)) {
char[] buffer;
if (size > 0) {
buffer = new char[size];
} else {
buffer = new char[1024];
}
int count;
StringBuilder builder = new StringBuilder();
while ((count = reader.read(buffer)) != -1) {
builder.append(buffer, 0, count);
if (size > 0)
break;
}
return builder.toString();
} catch (IOException ioe) {
return createDefaultMessage(messageNumber);
}
}
private String createDefaultMessage(int messageNumber) {
return "test message: " + messageNumber;
}
public ProducerThread setMessageCount(int messageCount) {
this.messageCount = messageCount;
return this;
}
public int getSleep() {
return sleep;
}
public ProducerThread setSleep(int sleep) {
this.sleep = sleep;
return this;
}
public int getMessageCount() {
return messageCount;
}
public int getSentCount() {
return sentCount.get();
}
public boolean isPersistent() {
return persistent;
}
public ProducerThread setPersistent(boolean persistent) {
this.persistent = persistent;
return this;
}
public boolean isRunning() {
return running;
}
public ProducerThread setRunning(boolean running) {
this.running = running;
return this;
}
public long getMsgTTL() {
return msgTTL;
}
public ProducerThread setMsgTTL(long msgTTL) {
this.msgTTL = msgTTL;
return this;
}
public int getTransactionBatchSize() {
return transactionBatchSize;
}
public ProducerThread setTransactionBatchSize(int transactionBatchSize) {
this.transactionBatchSize = transactionBatchSize;
return this;
}
public String getMsgGroupID() {
return msgGroupID;
}
public ProducerThread setMsgGroupID(String msgGroupID) {
this.msgGroupID = msgGroupID;
return this;
}
public int getTextMessageSize() {
return textMessageSize;
}
public ProducerThread setTextMessageSize(int textMessageSize) {
this.textMessageSize = textMessageSize;
return this;
}
public int getMessageSize() {
return messageSize;
}
public ProducerThread setMessageSize(int messageSize) {
this.messageSize = messageSize;
return this;
}
public ReusableLatch getFinished() {
return finished;
}
public ProducerThread setFinished(int value) {
finished.setCount(value);
return this;
}
public String getPayloadUrl() {
return payloadUrl;
}
public ProducerThread setPayloadUrl(String payloadUrl) {
this.payloadUrl = payloadUrl;
return this;
}
public String getMessage() {
return message;
}
public ProducerThread setMessage(String message) {
this.message = message;
return this;
}
public boolean isRunIndefinitely() {
return runIndefinitely;
}
public ProducerThread setRunIndefinitely(boolean runIndefinitely) {
this.runIndefinitely = runIndefinitely;
return this;
}
public ProducerThread pauseProducer() {
this.paused.countUp();
return this;
}
public ProducerThread resumeProducer() {
this.paused.countDown();
return this;
}
public ProducerThread resetCounters() {
this.sentCount.set(0);
return this;
}
public boolean isVerbose() {
return verbose;
}
public ProducerThread setVerbose(boolean verbose) {
this.verbose = verbose;
return this;
}
}