mirror of https://github.com/apache/activemq.git
Add a configuration option to control whether properties are set on every output message or only the first one. git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1429909 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3cd8da80a6
commit
b79c9868ec
|
@ -21,9 +21,11 @@ import java.io.InputStream;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.jms.IllegalStateException;
|
import javax.jms.IllegalStateException;
|
||||||
import javax.jms.InvalidDestinationException;
|
import javax.jms.InvalidDestinationException;
|
||||||
import javax.jms.JMSException;
|
import javax.jms.JMSException;
|
||||||
|
|
||||||
import org.apache.activemq.command.ActiveMQBytesMessage;
|
import org.apache.activemq.command.ActiveMQBytesMessage;
|
||||||
import org.apache.activemq.command.ActiveMQDestination;
|
import org.apache.activemq.command.ActiveMQDestination;
|
||||||
import org.apache.activemq.command.ActiveMQMessage;
|
import org.apache.activemq.command.ActiveMQMessage;
|
||||||
|
@ -57,7 +59,7 @@ public class ActiveMQInputStream extends InputStream implements ActiveMQDispatch
|
||||||
|
|
||||||
private ProducerId producerId;
|
private ProducerId producerId;
|
||||||
private long nextSequenceId;
|
private long nextSequenceId;
|
||||||
private long timeout;
|
private final long timeout;
|
||||||
private boolean firstReceived;
|
private boolean firstReceived;
|
||||||
|
|
||||||
public ActiveMQInputStream(ActiveMQConnection connection, ConsumerId consumerId, ActiveMQDestination dest, String selector, boolean noLocal, String name, int prefetch, long timeout)
|
public ActiveMQInputStream(ActiveMQConnection connection, ConsumerId consumerId, ActiveMQDestination dest, String selector, boolean noLocal, String name, int prefetch, long timeout)
|
||||||
|
@ -155,6 +157,21 @@ public class ActiveMQInputStream extends InputStream implements ActiveMQDispatch
|
||||||
return jmsProperties;
|
return jmsProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method allows the client to receive the Stream data as unaltered ActiveMQMessage
|
||||||
|
* object which is how the split stream data is sent. Each message will contains one
|
||||||
|
* chunk of the written bytes as well as a valid message group sequence id. The EOS
|
||||||
|
* message will have a message group sequence id of -1.
|
||||||
|
*
|
||||||
|
* This method is useful for testing, but should never be mixed with calls to the
|
||||||
|
* normal stream receive methods as it will break the normal stream processing flow
|
||||||
|
* and can lead to loss of data.
|
||||||
|
*
|
||||||
|
* @return an ActiveMQMessage object that either contains byte data or an end of strem
|
||||||
|
* marker.
|
||||||
|
* @throws JMSException
|
||||||
|
* @throws ReadTimeoutException
|
||||||
|
*/
|
||||||
public ActiveMQMessage receive() throws JMSException, ReadTimeoutException {
|
public ActiveMQMessage receive() throws JMSException, ReadTimeoutException {
|
||||||
checkClosed();
|
checkClosed();
|
||||||
MessageDispatch md;
|
MessageDispatch md;
|
||||||
|
@ -285,6 +302,7 @@ public class ActiveMQInputStream extends InputStream implements ActiveMQDispatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void dispatch(MessageDispatch md) {
|
public void dispatch(MessageDispatch md) {
|
||||||
unconsumedMessages.enqueue(md);
|
unconsumedMessages.enqueue(md);
|
||||||
}
|
}
|
||||||
|
@ -294,12 +312,12 @@ public class ActiveMQInputStream extends InputStream implements ActiveMQDispatch
|
||||||
return "ActiveMQInputStream { value=" + info.getConsumerId() + ", producerId=" + producerId + " }";
|
return "ActiveMQInputStream { value=" + info.getConsumerId() + ", producerId=" + producerId + " }";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception which should get thrown if the first chunk of the stream could not read within the configured timeout
|
* Exception which should get thrown if the first chunk of the stream could not read within the configured timeout
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ReadTimeoutException extends IOException {
|
public class ReadTimeoutException extends IOException {
|
||||||
|
private static final long serialVersionUID = -3217758894326719909L;
|
||||||
|
|
||||||
public ReadTimeoutException() {
|
public ReadTimeoutException() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,13 @@ import org.apache.activemq.command.ProducerId;
|
||||||
import org.apache.activemq.command.ProducerInfo;
|
import org.apache.activemq.command.ProducerInfo;
|
||||||
import org.apache.activemq.util.IOExceptionSupport;
|
import org.apache.activemq.util.IOExceptionSupport;
|
||||||
import org.apache.activemq.util.IntrospectionSupport;
|
import org.apache.activemq.util.IntrospectionSupport;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ActiveMQOutputStream.class);
|
||||||
|
|
||||||
protected int count;
|
protected int count;
|
||||||
|
|
||||||
final byte buffer[];
|
final byte buffer[];
|
||||||
|
@ -53,6 +54,7 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
private final int priority;
|
private final int priority;
|
||||||
private final long timeToLive;
|
private final long timeToLive;
|
||||||
private boolean alwaysSyncSend = false;
|
private boolean alwaysSyncSend = false;
|
||||||
|
private boolean addPropertiesOnFirstMsgOnly = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JMS Property which is used to specify the size (in kb) which is used as chunk size when splitting the stream. Default is 64kb
|
* JMS Property which is used to specify the size (in kb) which is used as chunk size when splitting the stream. Default is 64kb
|
||||||
|
@ -91,6 +93,15 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
Map<String, String> options = new HashMap<String, String>(destination.getOptions());
|
Map<String, String> options = new HashMap<String, String>(destination.getOptions());
|
||||||
IntrospectionSupport.setProperties(this, options, "producer.");
|
IntrospectionSupport.setProperties(this, options, "producer.");
|
||||||
IntrospectionSupport.setProperties(this.info, options, "producer.");
|
IntrospectionSupport.setProperties(this.info, options, "producer.");
|
||||||
|
if (options.size() > 0) {
|
||||||
|
String msg = "There are " + options.size()
|
||||||
|
+ " producer options that couldn't be set on the producer."
|
||||||
|
+ " Check the options are spelled correctly."
|
||||||
|
+ " Unknown parameters=[" + options + "]."
|
||||||
|
+ " This producer cannot be started.";
|
||||||
|
LOG.warn(msg);
|
||||||
|
throw new ConfigurationException(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.info.setDestination(destination);
|
this.info.setDestination(destination);
|
||||||
|
@ -99,6 +110,7 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
this.connection.asyncSendPacket(info);
|
this.connection.asyncSendPacket(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
flushBuffer();
|
flushBuffer();
|
||||||
|
@ -113,6 +125,7 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
this.connection.removeOutputStream(this);
|
this.connection.removeOutputStream(this);
|
||||||
|
@ -120,6 +133,7 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public synchronized void write(int b) throws IOException {
|
public synchronized void write(int b) throws IOException {
|
||||||
buffer[count++] = (byte) b;
|
buffer[count++] = (byte) b;
|
||||||
if (count == buffer.length) {
|
if (count == buffer.length) {
|
||||||
|
@ -127,6 +141,7 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public synchronized void write(byte b[], int off, int len) throws IOException {
|
public synchronized void write(byte b[], int off, int len) throws IOException {
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
int max = Math.min(len, buffer.length - count);
|
int max = Math.min(len, buffer.length - count);
|
||||||
|
@ -142,6 +157,7 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public synchronized void flush() throws IOException {
|
public synchronized void flush() throws IOException {
|
||||||
flushBuffer();
|
flushBuffer();
|
||||||
}
|
}
|
||||||
|
@ -164,7 +180,7 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
* @throws JMSException
|
* @throws JMSException
|
||||||
*/
|
*/
|
||||||
private void send(ActiveMQMessage msg, boolean eosMessage) throws JMSException {
|
private void send(ActiveMQMessage msg, boolean eosMessage) throws JMSException {
|
||||||
if (properties != null) {
|
if (properties != null && (messageSequence == 0 || !addPropertiesOnFirstMsgOnly)) {
|
||||||
for (Iterator<String> iter = properties.keySet().iterator(); iter.hasNext();) {
|
for (Iterator<String> iter = properties.keySet().iterator(); iter.hasNext();) {
|
||||||
String key = iter.next();
|
String key = iter.next();
|
||||||
Object value = properties.get(key);
|
Object value = properties.get(key);
|
||||||
|
@ -182,6 +198,7 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
connection.send(info.getDestination(), msg, id, deliveryMode, priority, timeToLive, !eosMessage && !isAlwaysSyncSend());
|
connection.send(info.getDestination(), msg, id, deliveryMode, priority, timeToLive, !eosMessage && !isAlwaysSyncSend());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ActiveMQOutputStream { producerId=" + info.getProducerId() + " }";
|
return "ActiveMQOutputStream { producerId=" + info.getProducerId() + " }";
|
||||||
}
|
}
|
||||||
|
@ -194,4 +211,11 @@ public class ActiveMQOutputStream extends OutputStream implements Disposable {
|
||||||
this.alwaysSyncSend = alwaysSyncSend;
|
this.alwaysSyncSend = alwaysSyncSend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAddPropertiesOnFirstMsgOnly() {
|
||||||
|
return addPropertiesOnFirstMsgOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddPropertiesOnFirstMsgOnly(boolean propertiesOnFirstMsgOnly) {
|
||||||
|
this.addPropertiesOnFirstMsgOnly = propertiesOnFirstMsgOnly;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.apache.activemq.streams;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -30,9 +29,12 @@ import javax.jms.JMSException;
|
||||||
import javax.jms.Message;
|
import javax.jms.Message;
|
||||||
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
|
|
||||||
import org.apache.activemq.ActiveMQConnection;
|
import org.apache.activemq.ActiveMQConnection;
|
||||||
import org.apache.activemq.ActiveMQInputStream;
|
import org.apache.activemq.ActiveMQInputStream;
|
||||||
|
import org.apache.activemq.ActiveMQOutputStream;
|
||||||
import org.apache.activemq.JmsTestSupport;
|
import org.apache.activemq.JmsTestSupport;
|
||||||
|
import org.apache.activemq.command.ActiveMQDestination;
|
||||||
import org.apache.activemq.command.ActiveMQQueue;
|
import org.apache.activemq.command.ActiveMQQueue;
|
||||||
import org.apache.activemq.command.ActiveMQTopic;
|
import org.apache.activemq.command.ActiveMQTopic;
|
||||||
|
|
||||||
|
@ -47,7 +49,7 @@ public class JMSInputStreamTest extends JmsTestSupport {
|
||||||
private ActiveMQConnection connection2;
|
private ActiveMQConnection connection2;
|
||||||
|
|
||||||
private ActiveMQInputStream amqIn;
|
private ActiveMQInputStream amqIn;
|
||||||
|
private ActiveMQOutputStream amqOut;
|
||||||
|
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
return suite(JMSInputStreamTest.class);
|
return suite(JMSInputStreamTest.class);
|
||||||
|
@ -58,32 +60,24 @@ public class JMSInputStreamTest extends JmsTestSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initCombos() {
|
public void initCombos() {
|
||||||
addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST.QUEUE"), new ActiveMQTopic("TEST.TOPIC")});
|
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST.QUEUE"), new ActiveMQTopic("TEST.TOPIC") });
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
@Override
|
||||||
* @see TestCase#setUp()
|
|
||||||
*/
|
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
super.setAutoFail(true);
|
super.setAutoFail(true);
|
||||||
super.setUp();
|
super.setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup connection and streams
|
|
||||||
*
|
|
||||||
* @param props
|
|
||||||
* @throws JMSException
|
|
||||||
*/
|
|
||||||
private void setUpConnection(Map<String, Object> props, long timeout) throws JMSException {
|
private void setUpConnection(Map<String, Object> props, long timeout) throws JMSException {
|
||||||
connection2 = (ActiveMQConnection)factory.createConnection(userName, password);
|
connection2 = (ActiveMQConnection) factory.createConnection(userName, password);
|
||||||
connections.add(connection2);
|
connections.add(connection2);
|
||||||
OutputStream amqOut;
|
|
||||||
if (props != null) {
|
if (props != null) {
|
||||||
amqOut = connection.createOutputStream(destination, props, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE);
|
amqOut = (ActiveMQOutputStream) connection.createOutputStream(destination, props, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE);
|
||||||
} else {
|
} else {
|
||||||
amqOut = connection.createOutputStream(destination);
|
amqOut = (ActiveMQOutputStream) connection.createOutputStream(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
out = new DataOutputStream(amqOut);
|
out = new DataOutputStream(amqOut);
|
||||||
if (timeout == -1) {
|
if (timeout == -1) {
|
||||||
amqIn = (ActiveMQInputStream) connection2.createInputStream(destination);
|
amqIn = (ActiveMQInputStream) connection2.createInputStream(destination);
|
||||||
|
@ -92,9 +86,11 @@ public class JMSInputStreamTest extends JmsTestSupport {
|
||||||
}
|
}
|
||||||
in = new DataInputStream(amqIn);
|
in = new DataInputStream(amqIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see TestCase#tearDown()
|
* @see TestCase#tearDown()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
protected void tearDown() throws Exception {
|
protected void tearDown() throws Exception {
|
||||||
super.tearDown();
|
super.tearDown();
|
||||||
}
|
}
|
||||||
|
@ -113,7 +109,6 @@ public class JMSInputStreamTest extends JmsTestSupport {
|
||||||
// timeout reached, everything ok
|
// timeout reached, everything ok
|
||||||
}
|
}
|
||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for AMQ-2988
|
// Test for AMQ-2988
|
||||||
|
@ -122,7 +117,7 @@ public class JMSInputStreamTest extends JmsTestSupport {
|
||||||
String name2 = "PROPERTY_2";
|
String name2 = "PROPERTY_2";
|
||||||
String value1 = "VALUE_1";
|
String value1 = "VALUE_1";
|
||||||
String value2 = "VALUE_2";
|
String value2 = "VALUE_2";
|
||||||
Map<String,Object> jmsProperties = new HashMap<String, Object>();
|
Map<String, Object> jmsProperties = new HashMap<String, Object>();
|
||||||
jmsProperties.put(name1, value1);
|
jmsProperties.put(name1, value1);
|
||||||
jmsProperties.put(name2, value2);
|
jmsProperties.put(name2, value2);
|
||||||
setUpConnection(jmsProperties, -1);
|
setUpConnection(jmsProperties, -1);
|
||||||
|
@ -153,6 +148,53 @@ public class JMSInputStreamTest extends JmsTestSupport {
|
||||||
checkProperties(jmsProperties);
|
checkProperties(jmsProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testStreamsWithPropertiesOnlyOnFirstMessage() throws Exception {
|
||||||
|
String name1 = "PROPERTY_1";
|
||||||
|
String name2 = "PROPERTY_2";
|
||||||
|
String value1 = "VALUE_1";
|
||||||
|
String value2 = "VALUE_2";
|
||||||
|
Map<String, Object> jmsProperties = new HashMap<String, Object>();
|
||||||
|
jmsProperties.put(name1, value1);
|
||||||
|
jmsProperties.put(name2, value2);
|
||||||
|
|
||||||
|
ActiveMQDestination dest = (ActiveMQDestination) destination;
|
||||||
|
|
||||||
|
if (dest.isQueue()) {
|
||||||
|
destination = new ActiveMQQueue(dest.getPhysicalName() + "?producer.addPropertiesOnFirstMsgOnly=true");
|
||||||
|
} else {
|
||||||
|
destination = new ActiveMQTopic(dest.getPhysicalName() + "?producer.addPropertiesOnFirstMsgOnly=true");
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpConnection(jmsProperties, -1);
|
||||||
|
|
||||||
|
assertTrue(amqOut.isAddPropertiesOnFirstMsgOnly());
|
||||||
|
|
||||||
|
out.writeInt(4);
|
||||||
|
out.flush();
|
||||||
|
assertTrue(in.readInt() == 4);
|
||||||
|
out.writeFloat(2.3f);
|
||||||
|
out.flush();
|
||||||
|
assertTrue(in.readFloat() == 2.3f);
|
||||||
|
String str = "this is a test string";
|
||||||
|
out.writeUTF(str);
|
||||||
|
out.flush();
|
||||||
|
assertTrue(in.readUTF().equals(str));
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
out.writeLong(i);
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
// check properties before we try to read the stream
|
||||||
|
checkProperties(jmsProperties);
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
assertTrue(in.readLong() == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check again after read was done
|
||||||
|
checkProperties(jmsProperties);
|
||||||
|
}
|
||||||
|
|
||||||
// check if the received stream has the properties set
|
// check if the received stream has the properties set
|
||||||
// Test for AMQ-2988
|
// Test for AMQ-2988
|
||||||
private void checkProperties(Map<String, Object> jmsProperties) throws IOException {
|
private void checkProperties(Map<String, Object> jmsProperties) throws IOException {
|
||||||
|
@ -161,10 +203,9 @@ public class JMSInputStreamTest extends JmsTestSupport {
|
||||||
// we should at least have the same amount or more properties
|
// we should at least have the same amount or more properties
|
||||||
assertTrue(jmsProperties.size() <= receivedJmsProps.size());
|
assertTrue(jmsProperties.size() <= receivedJmsProps.size());
|
||||||
|
|
||||||
|
|
||||||
// check the properties to see if we have everything in there
|
// check the properties to see if we have everything in there
|
||||||
Iterator<String> propsIt = jmsProperties.keySet().iterator();
|
Iterator<String> propsIt = jmsProperties.keySet().iterator();
|
||||||
while(propsIt.hasNext()) {
|
while (propsIt.hasNext()) {
|
||||||
String key = propsIt.next();
|
String key = propsIt.next();
|
||||||
assertTrue(receivedJmsProps.containsKey(key));
|
assertTrue(receivedJmsProps.containsKey(key));
|
||||||
assertEquals(jmsProperties.get(key), receivedJmsProps.get(key));
|
assertEquals(jmsProperties.get(key), receivedJmsProps.get(key));
|
||||||
|
@ -183,6 +224,7 @@ public class JMSInputStreamTest extends JmsTestSupport {
|
||||||
}
|
}
|
||||||
final AtomicBoolean complete = new AtomicBoolean(false);
|
final AtomicBoolean complete = new AtomicBoolean(false);
|
||||||
Thread runner = new Thread(new Runnable() {
|
Thread runner = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
for (int x = 0; x < count; x++) {
|
for (int x = 0; x < count; x++) {
|
||||||
|
|
Loading…
Reference in New Issue