You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ro...@apache.org on 2014/01/30 18:37:42 UTC
svn commit: r1562905 - in /qpid/jms/trunk/src:
main/java/org/apache/qpid/jms/engine/ main/java/org/apache/qpid/jms/impl/
test/java/org/apache/qpid/jms/ test/java/org/apache/qpid/jms/engine/
test/java/org/apache/qpid/jms/impl/
Author: robbie
Date: Thu Jan 30 17:37:41 2014
New Revision: 1562905
URL: http://svn.apache.org/r1562905
Log:
QPIDJMS-9: initial work on message-id (and eventually correlation-id) handling
Added:
qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java
qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageIdHelperTest.java
Modified:
qpid/jms/trunk/src/main/java/org/apache/qpid/jms/engine/AmqpMessage.java
qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/ConnectionImpl.java
qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageImpl.java
qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/SessionImpl.java
qpid/jms/trunk/src/test/java/org/apache/qpid/jms/MessageIntegrationTest.java
qpid/jms/trunk/src/test/java/org/apache/qpid/jms/engine/AmqpMessageTest.java
qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageImplTest.java
Modified: qpid/jms/trunk/src/main/java/org/apache/qpid/jms/engine/AmqpMessage.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/main/java/org/apache/qpid/jms/engine/AmqpMessage.java?rev=1562905&r1=1562904&r2=1562905&view=diff
==============================================================================
--- qpid/jms/trunk/src/main/java/org/apache/qpid/jms/engine/AmqpMessage.java (original)
+++ qpid/jms/trunk/src/main/java/org/apache/qpid/jms/engine/AmqpMessage.java Thu Jan 30 17:37:41 2014
@@ -20,16 +20,21 @@
*/
package org.apache.qpid.jms.engine;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.UnsignedByte;
import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.apache.qpid.proton.amqp.UnsignedLong;
import org.apache.qpid.proton.amqp.messaging.Accepted;
import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
@@ -426,6 +431,82 @@ public abstract class AmqpMessage
}
}
+ /**
+ * Get the MessageId.
+ *
+ * If present, the returned object may be a String, UUID,
+ * ByteBuffer (representing binary), or BigInteger (representing ulong).
+ *
+ * @return the messageId, or null if there isn't any
+ */
+ public Object getMessageId()
+ {
+ Object underlyingMessageId = _message.getMessageId();
+
+ if(underlyingMessageId instanceof Binary)
+ {
+ return ((Binary) underlyingMessageId).asByteBuffer();
+ }
+ else if(underlyingMessageId instanceof UnsignedLong)
+ {
+ return ((UnsignedLong) underlyingMessageId).bigIntegerValue();
+ }
+ else
+ {
+ return underlyingMessageId;
+ }
+ }
+
+ /**
+ * Set a string message-id value on the message.
+ */
+ public void setMessageId(String messageId)
+ {
+ setUnderlyingMessageId(messageId);
+ }
+
+ /**
+ * Set a uuid message-id value on the message.
+ */
+ public void setMessageId(UUID messageId)
+ {
+ setUnderlyingMessageId(messageId);
+ }
+
+ /**
+ * Set an ulong (represented here as a BigInteger) message-id value on the message.
+ *
+ * @param messageId the value to set
+ * @throws IllegalArgumentException if the value is not within the ulong range of [0 - 2^64)
+ */
+ public void setMessageId(BigInteger messageId) throws IllegalArgumentException
+ {
+ if(messageId.signum() == -1 || messageId.bitLength() > 64)
+ {
+ throw new IllegalArgumentException("Value \""+messageId+"\" lies outside the range [0 - 2^64).");
+ }
+
+ //TODO: add UnsignedLong.valueOf(BigInteger)?
+ setUnderlyingMessageId(UnsignedLong.valueOf(messageId.toString()));
+ }
+
+ /**
+ * Set a Binary (represented here as a ByteBuffer) message-id value on the message.
+ *
+ * @param messageId the value to set
+ */
+ public void setMessageId(ByteBuffer messageId)
+ {
+ Binary bin = Binary.create(messageId);
+
+ setUnderlyingMessageId(bin);
+ }
+
+ private void setUnderlyingMessageId(Object messageId)
+ {
+ _message.setMessageId(messageId);
+ }
+
//===== Application Properties ======
private void createApplicationProperties()
Modified: qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/ConnectionImpl.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/ConnectionImpl.java?rev=1562905&r1=1562904&r2=1562905&view=diff
==============================================================================
--- qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/ConnectionImpl.java (original)
+++ qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/ConnectionImpl.java Thu Jan 30 17:37:41 2014
@@ -63,6 +63,7 @@ public class ConnectionImpl implements C
private volatile boolean _isStarted;
private DestinationHelper _destinationHelper;
+ private MessageIdHelper _messageIdHelper;
/**
* TODO: accept a client id
@@ -97,6 +98,7 @@ public class ConnectionImpl implements C
}
_destinationHelper = new DestinationHelper();
+ _messageIdHelper = new MessageIdHelper();
}
void waitUntil(Predicate condition, long timeoutMillis) throws JmsTimeoutException, JmsInterruptedException
@@ -287,7 +289,7 @@ public class ConnectionImpl implements C
{
AmqpSession amqpSession = _amqpConnection.createSession();
- SessionImpl session = new SessionImpl(acknowledgeMode, amqpSession, this, _destinationHelper);
+ SessionImpl session = new SessionImpl(acknowledgeMode, amqpSession, this, _destinationHelper, _messageIdHelper);
stateChanged();
session.establish();
Added: qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java?rev=1562905&view=auto
==============================================================================
--- qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java (added)
+++ qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java Thu Jan 30 17:37:41 2014
@@ -0,0 +1,146 @@
+/*
+ *
+ * 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.qpid.jms.impl;
+
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Helper class for identifying and converting message-id and correlation-id strings.
+ *
+ * <p>AMQP messages allow for 4 types of message-id/correlation-id: string, binary, uuid, ulong.
+ * In order to accept or return a string representation of these for interoperability with
+ * other AMQP clients, the following encoding can be used after the "ID:" prefix used for a JMSMessageID<br/>
+ *
+ * "AMQP_BINARY:<hex representation of binary content>"<br/>
+ * "AMQP_UUID:<string representation of uuid>"<br/>
+ * "AMQP_ULONG:<string representation of ulong>"<br/>
+ * "AMQP_STRING:<string>"<br/>
+ *
+ * <p>The AMQP_STRING encoding exists only for escaping string values that happen to begin with one
+ * of the encoding prefixes (including AMQP_STRING), or for consistency of appearance. It need not be used unless necessary.
+ *
+ * <p>When setting a JMSMessageID, any value that attempts to identify itself as an encoded Binary, UUID, or ulong but cant be
+ * converted into the indicated format will default to being treated as a simple String in its entirety (including the
+ * encoding prefix). For example, "AMQP_ULONG:hello" can't be encoded as a ulong, and so the full string "AMQP_ULONG:hello"
+ * would be used as the message-id value on the AMQP message.
+ *
+ * <p>When setting a JMSCorrelationID using setJMSCorrelationID(String id), any value which begins with the "ID:" prefix of a
+ * JMSMessageID that attempts to identify itself as an encoded binary, uuid, or ulong but cant be converted into the indicated
+ * format will cause an exception to be thrown. Any JMSCorrelationID String being set which does not begin with the "ID:"
+ * prefix of a JMSMessageID will beencoded as a String in the AMQP message, regardless whether it includes the above encoding
+ * prefixes.
+ *
+ */
+public class MessageIdHelper
+{
+ public static final String AMQP_STRING_PREFIX="AMQP_STRING:";
+ public static final String AMQP_UUID_PREFIX="AMQP_UUID:";
+ public static final String AMQP_LONG_PREFIX="AMQP_LONG:";
+ public static final String AMQP_BINARY_PREFIX="AMQP_BINARY:";
+ public static final String JMS_ID_PREFIX = "ID:";
+
+ private static final int JMS_ID_PREFIX_LENGTH = JMS_ID_PREFIX.length();
+
+ /**
+ * Checks whether the given string begins with "ID:" prefix used to denote a JMSMessageID
+ *
+ * @param string the string to check
+ * @return true if and only id the string begins with "ID:"
+ */
+ public boolean hasMessageIdPrefix(String string)
+ {
+ if(string == null)
+ {
+ return false;
+ }
+
+ return string.startsWith(JMS_ID_PREFIX);
+ }
+
+ /**
+ * Returns the suffix of the given string after removing the first "ID:" prefix (if present).
+ *
+ * @param string the string to process
+ * @return the suffix, or the original String if the "ID:" prefix is not present
+ */
+ public String stripMessageIdPrefix(String id)
+ {
+ if(hasMessageIdPrefix(id))
+ {
+ return id.substring(JMS_ID_PREFIX_LENGTH);
+ }
+ else
+ {
+ return id;
+ }
+ }
+
+ public String toBaseMessageIdString(Object messageId)
+ {
+ if(messageId == null)
+ {
+ return null;
+ }
+ else if(messageId instanceof String)
+ {
+ String stringId = (String) messageId;
+
+ //If the given string has a type encoding prefix,
+ //we need to escape it as an encoded string (even if
+ //the existing encoding prefix was also for string)
+ if(hasTypeEncodingPrefix(stringId))
+ {
+ return AMQP_STRING_PREFIX + stringId;
+ }
+ else
+ {
+ return stringId;
+ }
+ }
+ else if(messageId instanceof UUID)
+ {
+ return AMQP_UUID_PREFIX + messageId.toString();
+ }
+ else if(messageId instanceof Number)
+ {
+ //TODO: use Byte/Short/Integer/Long/BigInteger check instead?
+ return AMQP_LONG_PREFIX + messageId.toString();
+ }
+ else if(messageId instanceof ByteBuffer)
+ {
+ //TODO: implement
+ throw new UnsupportedOperationException("Support for Binary has yet to be implemented");
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unsupported type provided: " + messageId.getClass());
+ }
+ }
+
+ private boolean hasTypeEncodingPrefix(String stringId)
+ {
+ return stringId.startsWith(AMQP_BINARY_PREFIX) ||
+ stringId.startsWith(AMQP_UUID_PREFIX) ||
+ stringId.startsWith(AMQP_LONG_PREFIX) ||
+ stringId.startsWith(AMQP_STRING_PREFIX);
+ }
+}
Modified: qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageImpl.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageImpl.java?rev=1562905&r1=1562904&r2=1562905&view=diff
==============================================================================
--- qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageImpl.java (original)
+++ qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageImpl.java Thu Jan 30 17:37:41 2014
@@ -19,6 +19,7 @@
package org.apache.qpid.jms.impl;
import static org.apache.qpid.jms.impl.ClientProperties.JMS_AMQP_TTL;
+import static org.apache.qpid.jms.impl.MessageIdHelper.JMS_ID_PREFIX;
import java.util.ArrayList;
import java.util.Collections;
@@ -173,15 +174,35 @@ public abstract class MessageImpl<T exte
@Override
public String getJMSMessageID() throws JMSException
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not Implemented");
+ MessageIdHelper messageIdHelper = _sessionImpl.getMessageIdHelper();
+
+ String baseIdString = messageIdHelper.toBaseMessageIdString(_amqpMessage.getMessageId());
+
+ if(baseIdString == null)
+ {
+ return null;
+ }
+ else
+ {
+ return JMS_ID_PREFIX + baseIdString;
+ }
}
@Override
public void setJMSMessageID(String id) throws JMSException
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not Implemented");
+ MessageIdHelper messageIdHelper = _sessionImpl.getMessageIdHelper();
+
+ //We permit null, but otherwise ensure that the value starts "ID:"
+ if(id != null && !messageIdHelper.hasMessageIdPrefix(id))
+ {
+ throw new QpidJmsException("Provided JMSMessageID does not have required '" + JMS_ID_PREFIX + "' prefix");
+ }
+
+ String stripped = messageIdHelper.stripMessageIdPrefix(id);
+ //TODO: convert the string if necessary, i.e. it indicates an encoded AMQP type
+
+ _amqpMessage.setMessageId(stripped);
}
@Override
Modified: qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/SessionImpl.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/SessionImpl.java?rev=1562905&r1=1562904&r2=1562905&view=diff
==============================================================================
--- qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/SessionImpl.java (original)
+++ qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/SessionImpl.java Thu Jan 30 17:37:41 2014
@@ -55,13 +55,15 @@ public class SessionImpl implements Sess
private final AmqpSession _amqpSession;
private final ConnectionImpl _connectionImpl;
private final DestinationHelper _destinationHelper;
+ private final MessageIdHelper _messageIdHelper;
- public SessionImpl(int acknowledgeMode, AmqpSession amqpSession, ConnectionImpl connectionImpl, DestinationHelper destinationHelper)
+ public SessionImpl(int acknowledgeMode, AmqpSession amqpSession, ConnectionImpl connectionImpl, DestinationHelper destinationHelper, MessageIdHelper messageIdHelper)
{
_acknowledgeMode = acknowledgeMode;
_amqpSession = amqpSession;
_connectionImpl = connectionImpl;
_destinationHelper = destinationHelper;
+ _messageIdHelper = messageIdHelper;
}
void establish() throws JmsTimeoutException, JmsInterruptedException
@@ -124,6 +126,11 @@ public class SessionImpl implements Sess
}
}
+ public MessageIdHelper getMessageIdHelper()
+ {
+ return _messageIdHelper;
+ }
+
DestinationHelper getDestinationHelper()
{
return _destinationHelper;
Modified: qpid/jms/trunk/src/test/java/org/apache/qpid/jms/MessageIntegrationTest.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/test/java/org/apache/qpid/jms/MessageIntegrationTest.java?rev=1562905&r1=1562904&r2=1562905&view=diff
==============================================================================
--- qpid/jms/trunk/src/test/java/org/apache/qpid/jms/MessageIntegrationTest.java (original)
+++ qpid/jms/trunk/src/test/java/org/apache/qpid/jms/MessageIntegrationTest.java Thu Jan 30 17:37:41 2014
@@ -25,7 +25,9 @@ import static org.junit.Assert.assertNot
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import java.math.BigInteger;
import java.util.Date;
+import java.util.UUID;
import javax.jms.Connection;
import javax.jms.Destination;
@@ -38,6 +40,7 @@ import javax.jms.TextMessage;
import javax.jms.Topic;
import org.apache.qpid.jms.impl.DestinationHelper;
+import org.apache.qpid.jms.impl.MessageIdHelper;
import org.apache.qpid.jms.test.testpeer.TestAmqpPeer;
import org.apache.qpid.jms.test.testpeer.describedtypes.sections.AmqpValueDescribedType;
import org.apache.qpid.jms.test.testpeer.describedtypes.sections.ApplicationPropertiesDescribedType;
@@ -50,6 +53,7 @@ import org.apache.qpid.jms.test.testpeer
import org.apache.qpid.jms.test.testpeer.matchers.sections.TransferPayloadCompositeMatcher;
import org.apache.qpid.jms.test.testpeer.matchers.types.EncodedAmqpValueMatcher;
import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.UnsignedLong;
import org.junit.Test;
public class MessageIntegrationTest extends QpidJmsTestCase
@@ -449,4 +453,72 @@ public class MessageIntegrationTest exte
assertEquals(timestamp, receivedMessage.getJMSExpiration());
}
}
+
+ /**
+ * Tests that receiving a message with a string typed message-id results in returning the
+ * expected value for JMSMessageId where the JMS "ID:" prefix has been added.
+ */
+ @Test
+ public void testReceivedMessageWithStringMessageIdReturnsExpectedJMSMessageID() throws Exception
+ {
+ receivedMessageWithMessageIdTestImpl("myTestMessageIdString");
+ }
+
+ /**
+ * Tests that receiving a message with a UUID typed message-id results in returning the
+ * expected value for JMSMessageId where the JMS "ID:" prefix has been added to the UUID.tostring()
+ */
+ @Test
+ public void testReceivedMessageWithUUIDMessageIdReturnsExpectedJMSMessageID() throws Exception
+ {
+ receivedMessageWithMessageIdTestImpl(UUID.randomUUID());
+ }
+
+ /**
+ * Tests that receiving a message with a UUID typed message-id results in returning the
+ * expected value for JMSMessageId where the JMS "ID:" prefix has been added to the UUID.tostring()
+ */
+ @Test
+ public void testReceivedMessageWithLongMessageIdReturnsExpectedJMSMessageID() throws Exception
+ {
+ receivedMessageWithMessageIdTestImpl(BigInteger.valueOf(123456789L));
+ }
+
+ private void receivedMessageWithMessageIdTestImpl(Object messageId) throws Exception
+ {
+ try(TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);)
+ {
+ Connection connection = _testFixture.establishConnecton(testPeer);
+ connection.start();
+
+ testPeer.expectBegin();
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Queue queue = session.createQueue("myQueue");
+
+ Object underlyingAmqpMessageId = messageId;
+ if(underlyingAmqpMessageId instanceof BigInteger)
+ {
+ //Proton uses UnsignedLong
+ underlyingAmqpMessageId = UnsignedLong.valueOf(underlyingAmqpMessageId.toString());
+ }
+
+ PropertiesDescribedType props = new PropertiesDescribedType();
+ props.setMessageId(underlyingAmqpMessageId);
+ DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+ testPeer.expectReceiverAttach();
+ testPeer.expectLinkFlowRespondWithTransfer(null, null, props, null, amqpValueNullContent);
+ testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+ Message receivedMessage = messageConsumer.receive(1000);
+ testPeer.waitForAllHandlersToComplete(3000);
+
+ assertNotNull(receivedMessage);
+ String expectedBaseIdString = new MessageIdHelper().toBaseMessageIdString(underlyingAmqpMessageId);
+
+ assertEquals("ID:" + expectedBaseIdString, receivedMessage.getJMSMessageID());
+ }
+ }
}
Modified: qpid/jms/trunk/src/test/java/org/apache/qpid/jms/engine/AmqpMessageTest.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/test/java/org/apache/qpid/jms/engine/AmqpMessageTest.java?rev=1562905&r1=1562904&r2=1562905&view=diff
==============================================================================
--- qpid/jms/trunk/src/test/java/org/apache/qpid/jms/engine/AmqpMessageTest.java (original)
+++ qpid/jms/trunk/src/test/java/org/apache/qpid/jms/engine/AmqpMessageTest.java Thu Jan 30 17:37:41 2014
@@ -22,15 +22,20 @@ package org.apache.qpid.jms.engine;
import static org.junit.Assert.*;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import org.apache.qpid.jms.QpidJmsTestCase;
import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.UnsignedByte;
import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.apache.qpid.proton.amqp.UnsignedLong;
import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
import org.apache.qpid.proton.amqp.messaging.Header;
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
@@ -47,6 +52,7 @@ public class AmqpMessageTest extends Qpi
private static final String TEST_PROP_B = "TEST_PROP_B";
private static final String TEST_VALUE_STRING_A = "TEST_VALUE_STRING_A";
private static final String TEST_VALUE_STRING_B = "TEST_VALUE_STRING_B";
+ private static final byte[] TWO_TO_64_BYTES = new byte[] { (byte) 1, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 };
private AmqpConnection _mockAmqpConnection;
private Delivery _mockDelivery;
@@ -551,6 +557,188 @@ public class AmqpMessageTest extends Qpi
assertNull(testAmqpMessage.getAbsoluteExpiryTime());
}
+ //TODO: delete this marker comment
+ @Test
+ public void testGetMessageIdIsNullOnNewMessage()
+ {
+ TestAmqpMessage testAmqpMessage = new TestAmqpMessage();
+
+ assertNull("Expected messageId to be null on new message", testAmqpMessage.getMessageId());
+ }
+
+ /**
+ * Test that setting then getting a String as the messageId returns the expected value
+ */
+ @Test
+ public void testSetGetMessageIdOnNewMessageWithString()
+ {
+ String testMessageId = "myStringMessageId";
+
+ AmqpMessage testAmqpMessage = new TestAmqpMessage();
+ testAmqpMessage.setMessageId(testMessageId);
+
+ assertEquals("Expected messageId not returned", testMessageId, testAmqpMessage.getMessageId());
+ }
+
+ /**
+ * Test that getting the messageId when using an underlying received message with a
+ * String message id returns the expected value.
+ */
+ @Test
+ public void testGetMessageIdOnReceivedMessageWithString()
+ {
+ messageIdOnReceivedMessageTestImpl("myMessageIdString");
+ }
+
+ /**
+ * Test that setting then getting a UUID as the messageId returns the expected value
+ */
+ @Test
+ public void testSetGetMessageIdOnNewMessageWithUUID()
+ {
+ UUID testMessageId = UUID.randomUUID();
+
+ AmqpMessage testAmqpMessage = new TestAmqpMessage();
+ testAmqpMessage.setMessageId(testMessageId);
+
+ assertEquals("Expected messageId not returned", testMessageId, testAmqpMessage.getMessageId());
+ }
+
+ /**
+ * Test that getting the messageId when using an underlying received message with a
+ * UUID message id returns the expected value.
+ */
+ @Test
+ public void testGetMessageIdOnReceivedMessageWithUUID()
+ {
+ messageIdOnReceivedMessageTestImpl(UUID.randomUUID());
+ }
+
+ /**
+ * Test that setting then getting a ulong messageId (using BigInteger) returns the expected value
+ */
+ @Test
+ public void testSetGetMessageIdOnNewMessageWithULong()
+ {
+ BigInteger testMessageId = BigInteger.valueOf(123456789);
+
+ AmqpMessage testAmqpMessage = new TestAmqpMessage();
+ testAmqpMessage.setMessageId(testMessageId);
+
+ assertEquals("Expected messageId not returned", testMessageId, testAmqpMessage.getMessageId());
+ }
+
+ /**
+ * Test that getting the messageId when using an underlying received message with a
+ * ulong message id (using BigInteger) returns the expected value.
+ */
+ @Test
+ public void testGetMessageIdOnReceivedMessageWithLong()
+ {
+ messageIdOnReceivedMessageTestImpl(BigInteger.valueOf(123456789L));
+ }
+
+ /**
+ * Test that attempting to set a ulong messageId (using BigInteger) with a value
+ * outwith the allowed [0 - 2^64) range results in an IAE being thrown
+ */
+ @Test
+ public void testSetMessageIdOnNewMessageWithULongOurOfRangeThrowsIAE()
+ {
+ //negative value
+ AmqpMessage testAmqpMessage = new TestAmqpMessage();
+ try
+ {
+ testAmqpMessage.setMessageId(BigInteger.valueOf(-1));
+ fail("expected exception was not thrown");
+ }
+ catch(IllegalArgumentException iae)
+ {
+ //expected
+ }
+
+ //value 1 over max
+ BigInteger aboveLimit = new BigInteger(TWO_TO_64_BYTES);
+ try
+ {
+ testAmqpMessage.setMessageId(aboveLimit);
+ fail("expected exception was not thrown");
+ }
+ catch(IllegalArgumentException iae)
+ {
+ //expected
+ }
+
+ //confirm subtracting 1 to get the max value then allows success
+ BigInteger onLimit = aboveLimit.subtract(BigInteger.ONE);
+ testAmqpMessage.setMessageId(onLimit);
+ }
+
+ /**
+ * Test that setting then getting binary as the messageId returns the expected value
+ */
+ @Test
+ public void testSetGetMessageIdOnNewMessageWithBinary()
+ {
+ ByteBuffer testMessageId = createByteBufferForBinaryId();
+
+ AmqpMessage testAmqpMessage = new TestAmqpMessage();
+ testAmqpMessage.setMessageId(testMessageId);
+
+ assertEquals("Expected messageId not returned", testMessageId, testAmqpMessage.getMessageId());
+ }
+
+ /**
+ * Test that getting the messageId when using an underlying received message with a
+ * Binary message id returns the expected ByteBuffer value.
+ */
+ @Test
+ public void testGetMessageIdOnReceivedMessageWithBinary()
+ {
+ ByteBuffer testMessageId = createByteBufferForBinaryId();
+
+ messageIdOnReceivedMessageTestImpl(testMessageId);
+ }
+
+ private void messageIdOnReceivedMessageTestImpl(Object testMessageId)
+ {
+ Object underlyingIdObject = testMessageId;
+ if(testMessageId instanceof ByteBuffer)
+ {
+ //The proton message uses a Binary wrapper for binary ids, not a ByteBuffer
+ underlyingIdObject = Binary.create((ByteBuffer) testMessageId);
+ }
+ else if(testMessageId instanceof BigInteger)
+ {
+ //The proton message uses an UnsignedLong wrapper
+ underlyingIdObject = UnsignedLong.valueOf(((BigInteger) testMessageId).toString());
+ }
+
+ Message message = Proton.message();
+
+ Properties props = new Properties();
+ props.setMessageId(underlyingIdObject);
+ message.setProperties(props);
+
+ TestAmqpMessage testAmqpMessage = new TestAmqpMessage(message, _mockDelivery, _mockAmqpConnection);
+
+ assertNotNull("Expected a messageId on received message", testAmqpMessage.getMessageId());
+
+ assertEquals("Incorrect messageId value received", testMessageId, testAmqpMessage.getMessageId());
+ }
+
+ private ByteBuffer createByteBufferForBinaryId()
+ {
+ byte length = 10;
+ byte[] idBytes = new byte[length];
+ for(int i = 0; i < length; i++)
+ {
+ idBytes[i] = (byte) (length - i);
+ }
+
+ return ByteBuffer.wrap(idBytes);
+ }
+
// ====== Message Annotations =======
@Test
Added: qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageIdHelperTest.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageIdHelperTest.java?rev=1562905&view=auto
==============================================================================
--- qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageIdHelperTest.java (added)
+++ qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageIdHelperTest.java Thu Jan 30 17:37:41 2014
@@ -0,0 +1,291 @@
+/*
+ *
+ * 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.qpid.jms.impl;
+
+import static org.junit.Assert.*;
+
+import java.math.BigInteger;
+import java.util.UUID;
+
+import org.apache.qpid.jms.QpidJmsTestCase;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MessageIdHelperTest extends QpidJmsTestCase
+{
+ private MessageIdHelper _messageIdHelper;
+
+ @Before
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _messageIdHelper = new MessageIdHelper();
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#hasMessageIdPrefix(String)} returns true for strings that begin "ID:"
+ */
+ @Test
+ public void testHasIdPrefixWithPrefix()
+ {
+ String myId = "ID:something";
+ assertTrue("'ID:' prefix should have been identified", _messageIdHelper.hasMessageIdPrefix(myId));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#hasMessageIdPrefix(String)} returns false for string beings "ID" without colon.
+ */
+ @Test
+ public void testHasIdPrefixWithIDButNoColonPrefix()
+ {
+ String myIdNoColon = "IDsomething";
+ assertFalse("'ID' prefix should not have been identified without trailing colon", _messageIdHelper.hasMessageIdPrefix(myIdNoColon));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#hasMessageIdPrefix(String)} returns false for null
+ */
+ @Test
+ public void testHasIdPrefixWithNull()
+ {
+ String nullString = null;
+ assertFalse("null string should not result in identification as having the prefix", _messageIdHelper.hasMessageIdPrefix(nullString));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#hasMessageIdPrefix(String)} returns false for strings that doesnt have "ID:" anywhere
+ */
+ @Test
+ public void testHasIdPrefixWithoutPrefix()
+ {
+ String myNonId = "something";
+ assertFalse("string without 'ID:' anywhere should not have been identified as having the prefix", _messageIdHelper.hasMessageIdPrefix(myNonId));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#hasMessageIdPrefix(String)} returns false for strings has lowercase "id:" prefix
+ */
+ @Test
+ public void testHasIdPrefixWithLowercaseID()
+ {
+ String myLowerCaseNonId = "id:something";
+ assertFalse("lowercase 'id:' prefix should not result in identification as having 'ID:' prefix", _messageIdHelper.hasMessageIdPrefix(myLowerCaseNonId));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#stripMessageIdPrefix(String)} strips "ID:" from strings that do begin "ID:"
+ */
+ @Test
+ public void testStripMessageIdPrefixWithPrefix()
+ {
+ String myIdWithoutPrefix = "something";
+ String myId = "ID:" + myIdWithoutPrefix;
+ assertEquals("'ID:' prefix should have been stripped", myIdWithoutPrefix, _messageIdHelper.stripMessageIdPrefix(myId));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#stripMessageIdPrefix(String)} only strips one "ID:" from strings that
+ * begin "ID:ID:...."
+ */
+ @Test
+ public void testStripMessageIdPrefixWithDoublePrefix()
+ {
+ String myIdWithSinglePrefix = "ID:something";
+ String myIdWithDoublePrefix = "ID:" + myIdWithSinglePrefix;
+ assertEquals("'ID:' prefix should only have been stripped once", myIdWithSinglePrefix, _messageIdHelper.stripMessageIdPrefix(myIdWithDoublePrefix));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#stripMessageIdPrefix(String)} does not alter strings that begins "ID" without a colon.
+ */
+ @Test
+ public void testStripMessageIdPrefixWithIDButNoColonPrefix()
+ {
+ String myIdNoColon = "IDsomething";
+ assertEquals("string without 'ID:' prefix should have been returned unchanged", myIdNoColon, _messageIdHelper.stripMessageIdPrefix(myIdNoColon));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#stripMessageIdPrefix(String)} returns null if given null;
+ */
+ @Test
+ public void testStripMessageIdPrefixWithNull()
+ {
+ String nullString = null;
+ assertNull("null string should have been returned", _messageIdHelper.stripMessageIdPrefix(nullString));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#stripMessageIdPrefix(String)} does not alter string that doesn't begin "ID:"
+ */
+ @Test
+ public void testStripMessageIdPrefixWithoutIDAnywhere()
+ {
+ String myNonId = "something";
+ assertEquals("string without 'ID:' anywhere should have been returned unchanged", myNonId, _messageIdHelper.stripMessageIdPrefix(myNonId));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#stripMessageIdPrefix(String)} does not alter string with lowercase "id:"
+ */
+ @Test
+ public void testStripMessageIdPrefixWithLowercaseID()
+ {
+ String myLowerCaseNonId = "id:something";
+ assertEquals("string with lowercase 'id:' prefix should have been returned unchanged", myLowerCaseNonId, _messageIdHelper.stripMessageIdPrefix(myLowerCaseNonId));
+ }
+
+ //TODO: delete this marker comment
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns null if given null
+ */
+ @Test
+ public void testToBaseMessageIdStringWithNull()
+ {
+ String nullString = null;
+ assertNull("null string should have been returned", _messageIdHelper.toBaseMessageIdString(nullString));
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} throws an IAE if given an unexpected object type.
+ */
+ @Test
+ public void testToBaseMessageIdStringThrowsIAEWithUnexpectedType()
+ {
+ try
+ {
+ _messageIdHelper.toBaseMessageIdString(new Object());
+ fail("expected exception not thrown");
+ }
+ catch(IllegalArgumentException iae)
+ {
+ //expected
+ }
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns the given
+ * basic string unchanged
+ */
+ @Test
+ public void testToBaseMessageIdStringWithString()
+ {
+ String stringMessageId = "myIdString";
+
+ String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(stringMessageId);
+ assertNotNull("null string should not have been returned", baseMessageIdString);
+ assertEquals("expected base id string was not returned", stringMessageId, baseMessageIdString);
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns a string
+ * indicating an AMQP encoded string, when the given string happens to already begin with
+ * the {@link MessageIdHelper#AMQP_UUID_PREFIX}.
+ */
+ @Test
+ public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForUUID()
+ {
+ String uuidStringMessageId = MessageIdHelper.AMQP_UUID_PREFIX + UUID.randomUUID();
+ String expected = MessageIdHelper.AMQP_STRING_PREFIX + uuidStringMessageId;
+
+ String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(uuidStringMessageId);
+ assertNotNull("null string should not have been returned", baseMessageIdString);
+ assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns a string
+ * indicating an AMQP encoded string, when the given string happens to already begin with
+ * the {@link MessageIdHelper#AMQP_LONG_PREFIXM}.
+ */
+ @Test
+ public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForLong()
+ {
+ String longStringMessageId = MessageIdHelper.AMQP_LONG_PREFIX + Long.valueOf(123456789L);
+ String expected = MessageIdHelper.AMQP_STRING_PREFIX + longStringMessageId;
+
+ String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(longStringMessageId);
+ assertNotNull("null string should not have been returned", baseMessageIdString);
+ assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns a string
+ * indicating an AMQP encoded string (effectively twice), when the given string happens to already begin with
+ * the {@link MessageIdHelper#AMQP_STRING_PREFIX}.
+ */
+ @Test
+ public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForString()
+ {
+ String stringMessageId = MessageIdHelper.AMQP_STRING_PREFIX + "myStringId";
+ String expected = MessageIdHelper.AMQP_STRING_PREFIX + stringMessageId;
+
+ String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(stringMessageId);
+ assertNotNull("null string should not have been returned", baseMessageIdString);
+ assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns a string
+ * indicating an AMQP encoded UUID when given a UUID object.
+ */
+ @Test
+ public void testToBaseMessageIdStringWithUUID()
+ {
+ UUID uuidMessageId = UUID.randomUUID();
+ String expected = MessageIdHelper.AMQP_UUID_PREFIX + uuidMessageId.toString();
+
+ String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(uuidMessageId);
+ assertNotNull("null string should not have been returned", baseMessageIdString);
+ assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns a string
+ * indicating an AMQP encoded Long when given a Long object.
+ */
+ @Test
+ public void testToBaseMessageIdStringWithLong()
+ {
+ Long longMessageId = Long.valueOf(123456789L);
+ String expected = MessageIdHelper.AMQP_LONG_PREFIX + longMessageId.toString();
+
+ String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(longMessageId);
+ assertNotNull("null string should not have been returned", baseMessageIdString);
+ assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+ }
+
+ /**
+ * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns a string
+ * indicating an AMQP encoded Long when given a BigInteger object.
+ */
+ @Test
+ public void testToBaseMessageIdStringWithBigInteger()
+ {
+ BigInteger bigIntMessageId = BigInteger.valueOf(123456789L);
+ String expected = MessageIdHelper.AMQP_LONG_PREFIX + bigIntMessageId.toString();
+
+ String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(bigIntMessageId);
+ assertNotNull("null string should not have been returned", baseMessageIdString);
+ assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+ }
+}
Modified: qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageImplTest.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageImplTest.java?rev=1562905&r1=1562904&r2=1562905&view=diff
==============================================================================
--- qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageImplTest.java (original)
+++ qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageImplTest.java Thu Jan 30 17:37:41 2014
@@ -58,6 +58,7 @@ public class MessageImplTest extends Qpi
_mockConnectionImpl = Mockito.mock(ConnectionImpl.class);
_mockSessionImpl = Mockito.mock(SessionImpl.class);
Mockito.when(_mockSessionImpl.getDestinationHelper()).thenReturn(new DestinationHelper());
+ Mockito.when(_mockSessionImpl.getMessageIdHelper()).thenReturn(new MessageIdHelper());
_testAmqpMessage = new TestAmqpMessage();
_testMessage = new TestMessageImpl(_testAmqpMessage, _mockSessionImpl, _mockConnectionImpl);
@@ -899,6 +900,130 @@ public class MessageImplTest extends Qpi
assertEquals("expected JMSPriority value to be capped at 9", 9, _testMessage.getJMSPriority());
}
+ //TODO: remove this marker comment
+ // ====== JMSMessageID =======
+
+ @Test
+ public void testGetJMSMessageIDOnNewMessage() throws Exception
+ {
+ //Should be null as it has not been set explicitly, and
+ //the message has not been sent anywhere
+ assertNull(_testMessage.getJMSMessageID());
+ }
+
+ /**
+ * Test that {@link MessageImpl#setJMSMessageID(String)} accepts null and clears an existing value
+ */
+ @Test
+ public void testSetJMSMessageIDAcceptsNull() throws Exception
+ {
+ //test setting null on fresh message is accepted
+ _testMessage.setJMSMessageID(null);
+ assertNull("JMSMessageID should still be null", _testMessage.getJMSMessageID());
+
+ //test that setting null clears an existing value
+ _testMessage.setJMSMessageID("ID:something");
+ assertNotNull("JMSMessageID should not be null anymore", _testMessage.getJMSMessageID());
+ assertNotNull("Underlying message id should not be null anymore", _testAmqpMessage.getMessageId());
+
+ _testMessage.setJMSMessageID(null);
+ assertNull("JMSMessageID should be null again", _testMessage.getJMSMessageID());
+ assertNull("Underlying message id should be null again", _testAmqpMessage.getMessageId());
+ }
+
+ /**
+ * Test that {@link MessageImpl#setJMSMessageID(String)} throws JMSException when
+ * the provided non-null value doesn't begin with "ID:".
+ */
+ @Test
+ public void testSetJMSMessageIDOnNewMessageThrowsExceptionForNonIdValues() throws Exception
+ {
+ try
+ {
+ //"ID:" is present, but in the middle instead of required prefix
+ _testMessage.setJMSMessageID("Central:ID:Included");
+ fail("Expected exception when setting non-null value without the required JMSMessageID 'ID:' prefix");
+ }
+ catch(JMSException jmse)
+ {
+ //expected
+ }
+
+ try
+ {
+ //"ID:" isn't present at all.
+ _testMessage.setJMSMessageID("MissingEntirely");
+ fail("Expected exception when setting non-null value without the required JMSMessageID 'ID:' prefix");
+ }
+ catch(JMSException jmse)
+ {
+ //expected
+ }
+
+ try
+ {
+ //Prefix exists, but with the wrong case (it must be "ID:").
+ _testMessage.setJMSMessageID("id:WrongCase");
+ fail("Expected exception when setting non-null value without the required JMSMessageID 'ID:' prefix");
+ }
+ catch(JMSException jmse)
+ {
+ //expected
+ }
+ }
+
+ /**
+ * Test that {@link MessageImpl#setJMSMessageID(String)} sets the expected value
+ * on the underlying message, i.e the JMS message ID minus the "ID:" prefix.
+ */
+ @Test
+ public void testSetJMSMessageIDSetsUnderlyingMessageWithString() throws Exception
+ {
+ String baseId = "something";
+ String jmsId = "ID:" + baseId;
+
+ _testMessage.setJMSMessageID(jmsId);
+
+ assertNotNull("Underlying message id should not be null", _testAmqpMessage.getMessageId());
+ assertEquals("Underlying message id value was not as expected", baseId, _testAmqpMessage.getMessageId());
+ }
+
+ /**
+ * Test that receiving a message with a string typed message-id value results in the
+ * expected JMSMessageID value being returned, i.e. the base string plus the JMS "ID:" prefix.
+ */
+ @Test
+ public void testGetJMSMessageIdOnRecievedMessageWithString() throws Exception
+ {
+ getJMSMessageIdOnRecievedMessageWithStringTestImpl(false);
+ }
+
+ /**
+ * Test that receiving a message with a string typed message-id value results in the
+ * expected JMSMessageID value being returned, i.e. the base string plus the JMS "ID:" prefix.
+ */
+ @Test
+ public void testGetJMSMessageIdOnRecievedMessageWithStringAlreadyContainingPrefix() throws Exception
+ {
+ getJMSMessageIdOnRecievedMessageWithStringTestImpl(true);
+ }
+
+ private void getJMSMessageIdOnRecievedMessageWithStringTestImpl(boolean prefixAlreadyExists) throws JMSException
+ {
+ String baseId = "something";
+ if(prefixAlreadyExists)
+ {
+ baseId = "ID:" + baseId;
+ }
+
+ String expectedJmsMessageId = "ID:" + baseId;
+
+ _testAmqpMessage.setMessageId(baseId);
+ _testMessage = new TestMessageImpl(_testAmqpMessage, _mockSessionImpl, _mockConnectionImpl, null);
+
+ assertEquals("expected JMSMessageID value not present", expectedJmsMessageId, _testMessage.getJMSMessageID());
+ }
+
// ====== JMS_AMQP_TTL property =======
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org