/*
* 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.tests.integration.client;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicSubscriber;
import java.util.concurrent.CountDownLatch;
import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger;
import org.apache.activemq.artemis.tests.util.JMSTestBase;
import org.junit.Before;
import org.junit.Test;
public class FlowControlOnIgnoreLargeMessageBodyTest extends JMSTestBase {
IntegrationTestLogger log = IntegrationTestLogger.LOGGER;
private Topic topic;
private static int TOTAL_MESSAGES_COUNT = 20000;
private static int MSG_SIZE = 150 * 1024;
private final int CONSUMERS_COUNT = 5;
private static final String ATTR_MSG_COUNTER = "msgIdex";
protected int receiveTimeout = 10000;
private volatile boolean error = false;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
jmsServer.createTopic(true, "topicIn", "/topic/topicIn");
topic = (Topic) namingContext.lookup("/topic/topicIn");
}
@Override
protected boolean usePersistence() {
return false;
}
/**
* LoadProducer
*/
class LoadProducer extends Thread {
private final ConnectionFactory cf;
private final Topic topic;
private final int messagesCount;
private volatile boolean requestForStop = false;
private volatile boolean stopped = false;
private int sentMessages = 0;
LoadProducer(final String name,
final Topic topic,
final ConnectionFactory cf,
final int messagesCount) throws Exception {
super(name);
this.cf = cf;
this.topic = topic;
this.messagesCount = messagesCount;
}
public void sendStopRequest() {
stopped = false;
requestForStop = true;
}
public boolean isStopped() {
return stopped;
}
@Override
public void run() {
stopped = false;
Connection connection = null;
Session session = null;
MessageProducer prod;
log.info("Starting producer for " + topic + " - " + getName());
try {
connection = cf.createConnection();
session = connection.createSession(true, Session.SESSION_TRANSACTED);
prod = session.createProducer(topic);
prod.setDeliveryMode(DeliveryMode.PERSISTENT);
for (int i = 1; i <= messagesCount && !requestForStop; i++) {
if (error) {
break;
}
sentMessages++;
BytesMessage msg = session.createBytesMessage();
msg.setIntProperty(FlowControlOnIgnoreLargeMessageBodyTest.ATTR_MSG_COUNTER, i);
msg.writeBytes(new byte[FlowControlOnIgnoreLargeMessageBodyTest.MSG_SIZE]);
prod.send(msg);
if (i % 10 == 0) {
session.commit();
}
if (i % 100 == 0) {
log.info("Address " + topic + " sent " + i + " messages");
}
}
System.out.println("Ending producer for " + topic + " - " + getName() + " messages " + sentMessages);
} catch (Exception e) {
error = true;
e.printStackTrace();
} finally {
try {
session.commit();
} catch (Exception e) {
e.printStackTrace();
}
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
stopped = true;
}
public int getSentMessages() {
return sentMessages;
}
}
/**
* LoadConsumer
*/
class LoadConsumer extends Thread {
private final ConnectionFactory cf;
private final Topic topic;
private volatile boolean requestForStop = false;
private volatile boolean stopped = false;
private volatile int receivedMessages = 0;
private final int numberOfMessages;
private int receiveTimeout = 0;
private final CountDownLatch consumerCreated;
LoadConsumer(final CountDownLatch consumerCreated,
final String name,
final Topic topic,
final ConnectionFactory cf,
final int receiveTimeout,
final int numberOfMessages) {
super(name);
this.cf = cf;
this.topic = topic;
this.receiveTimeout = receiveTimeout;
this.numberOfMessages = numberOfMessages;
this.consumerCreated = consumerCreated;
}
public void sendStopRequest() {
stopped = false;
requestForStop = true;
}
public boolean isStopped() {
return stopped;
}
@Override
public void run() {
Connection connection = null;
Session session = null;
stopped = false;
requestForStop = false;
System.out.println("Starting consumer for " + topic + " - " + getName());
try {
connection = cf.createConnection();
connection.setClientID(getName());
connection.start();
session = connection.createSession(true, Session.SESSION_TRANSACTED);
TopicSubscriber subscriber = session.createDurableSubscriber(topic, getName());
consumerCreated.countDown();
int counter = 0;
while (counter < numberOfMessages && !requestForStop && !error) {
if (counter == 0) {
System.out.println("Starting to consume for " + topic + " - " + getName());
}
BytesMessage msg = (BytesMessage) subscriber.receive(receiveTimeout);
if (msg == null) {
System.out.println("Cannot get message in specified timeout: " + topic + " - " + getName());
error = true;
} else {
counter++;
if (msg.getIntProperty(FlowControlOnIgnoreLargeMessageBodyTest.ATTR_MSG_COUNTER) != counter) {
error = true;
}
}
if (counter % 10 == 0) {
session.commit();
}
if (counter % 100 == 0) {
log.info("## " + getName() + " " + topic + " received " + counter);
}
receivedMessages = counter;
}
session.commit();
} catch (Exception e) {
System.out.println("Exception in consumer " + getName() + " : " + e.getMessage());
e.printStackTrace();
} finally {
if (session != null) {
try {
session.close();
} catch (JMSException e) {
System.err.println("Cannot close session " + e.getMessage());
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
System.err.println("Cannot close connection " + e.getMessage());
}
}
}
stopped = true;
System.out.println("Stopping consumer for " + topic +
" - " +
getName() +
", received " +
getReceivedMessages());
}
public int getReceivedMessages() {
return receivedMessages;
}
}
@Test
public void testFlowControl() {
try {
LoadProducer producer = new LoadProducer("producer", topic, cf, FlowControlOnIgnoreLargeMessageBodyTest.TOTAL_MESSAGES_COUNT);
LoadConsumer[] consumers = new LoadConsumer[CONSUMERS_COUNT];
CountDownLatch latch = new CountDownLatch(CONSUMERS_COUNT);
for (int i = 0; i < consumers.length; i++) {
consumers[i] = new LoadConsumer(latch, "consumer " + i, topic, cf, receiveTimeout, FlowControlOnIgnoreLargeMessageBodyTest.TOTAL_MESSAGES_COUNT);
}
for (LoadConsumer consumer : consumers) {
consumer.start();
}
waitForLatch(latch);
producer.start();
producer.join();
for (LoadConsumer consumer : consumers) {
consumer.join();
}
String errorMessage = null;
if (producer.getSentMessages() != FlowControlOnIgnoreLargeMessageBodyTest.TOTAL_MESSAGES_COUNT) {
errorMessage = "Producer did not send defined count of messages";
} else {
for (LoadConsumer consumer : consumers) {
if (consumer.getReceivedMessages() != FlowControlOnIgnoreLargeMessageBodyTest.TOTAL_MESSAGES_COUNT) {
errorMessage = "Consumer did not send defined count of messages";
break;
}
}
}
if (errorMessage != null) {
System.err.println(" ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ");
System.err.println(errorMessage);
} else {
System.out.println(" OK ");
}
assertFalse(error);
assertNull(errorMessage);
} catch (Exception e) {
log.warn(e.getMessage(), e);
}
}
}