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/02/10 14:16:17 UTC

svn commit: r1566611 - in /qpid/jms/trunk/src: main/java/org/apache/qpid/jms/impl/MessageIdHelper.java test/java/org/apache/qpid/jms/MessageIntegrationTest.java test/java/org/apache/qpid/jms/impl/MessageIdHelperTest.java

Author: robbie
Date: Mon Feb 10 13:16:17 2014
New Revision: 1566611

URL: http://svn.apache.org/r1566611
Log:
QPIDJMS-9: work on binary message-id/correlation-id handling, etc

Modified:
    qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java
    qpid/jms/trunk/src/test/java/org/apache/qpid/jms/MessageIntegrationTest.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/impl/MessageIdHelper.java
URL: http://svn.apache.org/viewvc/qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java?rev=1566611&r1=1566610&r2=1566611&view=diff
==============================================================================
--- qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java (original)
+++ qpid/jms/trunk/src/main/java/org/apache/qpid/jms/impl/MessageIdHelper.java Mon Feb 10 13:16:17 2014
@@ -64,6 +64,7 @@ public class MessageIdHelper
     private static final int AMQP_ULONG_PREFIX_LENGTH = AMQP_ULONG_PREFIX.length();
     private static final int AMQP_STRING_PREFIX_LENGTH = AMQP_STRING_PREFIX.length();
     private static final int AMQP_BINARY_PREFIX_LENGTH = AMQP_BINARY_PREFIX.length();
+    private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
 
     /**
      * Checks whether the given string begins with "ID:" prefix used to denote a JMSMessageID
@@ -144,8 +145,14 @@ public class MessageIdHelper
         }
         else if(messageId instanceof ByteBuffer)
         {
-            //TODO: implement
-            throw new UnsupportedOperationException("Support for Binary has yet to be implemented");
+            ByteBuffer dup = ((ByteBuffer)messageId).duplicate();
+
+            byte[] bytes = new byte[dup.remaining()];
+            dup.get(bytes);
+
+            String hex = convertBinaryToHexString(bytes);
+
+            return AMQP_BINARY_PREFIX + hex;
         }
         else
         {
@@ -194,27 +201,7 @@ public class MessageIdHelper
         {
             return null;
         }
-
-        if(!hasTypeEncodingPrefix(baseId))
-        {
-            //simple string, return it
-            return baseId;
-        }
-        else
-        {
-            //string encoded amqp type, decode it
-            return decode(baseId);
-        }
-    }
-
-    private Object decode(String baseId)
-    {
-        if(baseId == null)
-        {
-            return null;
-        }
-
-        if(hasAmqpUuidPrefix(baseId))
+        else if(hasAmqpUuidPrefix(baseId))
         {
             String uuidString = strip(baseId, AMQP_UUID_PREFIX_LENGTH);
             return UUID.fromString(uuidString);
@@ -230,9 +217,9 @@ public class MessageIdHelper
         }
         else if(hasAmqpBinaryPrefix(baseId))
         {
-            String binaryString = strip(baseId, AMQP_BINARY_PREFIX_LENGTH);
-            //TODO
-            throw new IllegalArgumentException("Support for Binary not yet Implented");
+            String hexString = strip(baseId, AMQP_BINARY_PREFIX_LENGTH);
+            byte[] bytes = convertHexStringToBinary(hexString);
+            return ByteBuffer.wrap(bytes);
         }
         else
         {
@@ -240,4 +227,92 @@ public class MessageIdHelper
             return baseId;
         }
     }
+
+    /**
+     * Convert the provided hex-string into a binary representation where each byte represents
+     * two characters of the hex string.
+     *
+     * The hex characters may be upper or lower case.
+     *
+     * @param hexString string to convert
+     * @return a byte array containing the binary representation
+     * @throws IllegalArgumentException if the provided String is a non-even length or contains non-hex characters
+     */
+    public byte[] convertHexStringToBinary(String hexString) throws IllegalArgumentException
+    {
+        int length = hexString.length();
+
+        //As each byte needs two characters in the hex encoding, the string must be an even length.
+        if (length % 2 != 0)
+        {
+            throw new IllegalArgumentException("The provided hex String must be an even length, but was of length " + length + ": " + hexString);
+        }
+
+        byte[] binary = new byte[length / 2];
+
+        for (int i = 0; i < length; i += 2)
+        {
+            char highBitsChar = hexString.charAt(i);
+            char lowBitsChar = hexString.charAt(i + 1);
+
+            int highBits = hexCharToInt(highBitsChar, hexString) << 4;
+            int lowBits = hexCharToInt(lowBitsChar, hexString);
+
+            binary[i / 2] = (byte) (highBits + lowBits);
+        }
+
+        return binary;
+    }
+
+    private int hexCharToInt(char ch, String orig)
+    {
+        if (ch >= '0' && ch <= '9')
+        {
+            //subtract '0' to get difference in position as an int
+            return ch - '0';
+        }
+        else if (ch >= 'A' && ch <= 'F')
+        {
+            //subtract 'A' to get difference in position as an int
+            //and then add 10 for the offset of 'A'
+            return ch - 'A' + 10;
+        }
+        else if (ch >= 'a' && ch <= 'f')
+        {
+            //subtract 'a' to get difference in position as an int
+            //and then add 10 for the offset of 'a'
+            return ch - 'a' + 10;
+        }
+
+        throw new IllegalArgumentException("The provided hex string contains non-hex character '" + ch + "': " + orig);
+    }
+
+    /**
+     * Convert the provided binary into a hex-string representation where each character
+     * represents 4 bits of the provided binary, i.e each byte requires two characters.
+     *
+     * The returned hex characters are upper-case.
+     *
+     * @param bytes binary to convert
+     * @return a String containing a hex representation of the bytes
+     */
+    public String convertBinaryToHexString(byte[] bytes)
+    {
+        //Each byte is represented as 2 chars
+        StringBuilder builder = new StringBuilder(bytes.length * 2);
+
+        for (byte b : bytes)
+        {
+            //The byte will be expanded to int before shifting, replicating the
+            //sign bit, so mask everything beyond the first 4 bits afterwards
+            int highBitsInt = (b >> 4) & 0xF;
+            //We only want the first 4 bits
+            int lowBitsInt = b & 0xF;
+
+            builder.append(HEX_CHARS[highBitsInt]);
+            builder.append(HEX_CHARS[lowBitsInt]);
+        }
+
+        return builder.toString();
+    }
 }

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=1566611&r1=1566610&r2=1566611&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 Mon Feb 10 13:16:17 2014
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertTru
 import static org.junit.Assert.assertFalse;
 
 import java.math.BigInteger;
+import java.nio.ByteBuffer;
 import java.util.Date;
 import java.util.UUID;
 
@@ -54,6 +55,7 @@ import org.apache.qpid.jms.test.testpeer
 import org.apache.qpid.jms.test.testpeer.matchers.sections.MessagePropertiesSectionMatcher;
 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.Binary;
 import org.apache.qpid.proton.amqp.DescribedType;
 import org.apache.qpid.proton.amqp.Symbol;
 import org.apache.qpid.proton.amqp.UnsignedLong;
@@ -501,12 +503,7 @@ public class MessageIntegrationTest exte
             Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
             Queue queue = session.createQueue("myQueue");
 
-            Object underlyingAmqpMessageId = messageIdForAmqpMessageClass;
-            if(underlyingAmqpMessageId instanceof BigInteger)
-            {
-                //Proton uses UnsignedLong
-                underlyingAmqpMessageId = UnsignedLong.valueOf((BigInteger)underlyingAmqpMessageId);
-            }
+            Object underlyingAmqpMessageId = classifyUnderlyingIdType(messageIdForAmqpMessageClass);
 
             PropertiesDescribedType props = new PropertiesDescribedType();
             props.setMessageId(underlyingAmqpMessageId);
@@ -580,12 +577,7 @@ public class MessageIntegrationTest exte
             Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
             Queue queue = session.createQueue("myQueue");
 
-            Object underlyingAmqpCorrelationId = correlationIdForAmqpMessageClass;
-            if(underlyingAmqpCorrelationId instanceof BigInteger)
-            {
-                //Proton uses UnsignedLong
-                underlyingAmqpCorrelationId = UnsignedLong.valueOf((BigInteger)underlyingAmqpCorrelationId);
-            }
+            Object underlyingAmqpCorrelationId = classifyUnderlyingIdType(correlationIdForAmqpMessageClass);
 
             PropertiesDescribedType props = new PropertiesDescribedType();
             DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
@@ -619,13 +611,55 @@ public class MessageIntegrationTest exte
     }
 
     /**
+     * Tests that sending a message with a uuid typed correlation-id value which is a
+     * message-id results in an AMQP message with the expected encoding of the correlation-id,
+     * where the type is uuid, the "ID:" prefix of the JMSCorrelationID value is (obviously) not present, and there is
+     * no presence of the message annotation to indicate an app-specific correlation-id.
+     */
+    @Test
+    public void testSentMessageWithUUIDCorrelationId() throws Exception
+    {
+        UUID uuid = UUID.randomUUID();
+        String stringCorrelationId = MessageIdHelper.JMS_ID_PREFIX + MessageIdHelper.AMQP_UUID_PREFIX +  uuid.toString();
+        sentMessageWithCorrelationIdTestImpl(stringCorrelationId, uuid, false);
+    }
+
+    /**
+     * Tests that sending a message with a binary typed correlation-id value which is a
+     * message-id results in an AMQP message with the expected encoding of the correlation-id,
+     * where the type is binary, the "ID:" prefix of the JMSCorrelationID value is (obviously) not present, and there is
+     * no presence of the message annotation to indicate an app-specific correlation-id.
+     */
+    @Test
+    public void testSentMessageWithBinaryCorrelationId() throws Exception
+    {
+        ByteBuffer bin = ByteBuffer.wrap(new byte[]{(byte)0x01, (byte)0x23, (byte) 0xAF, (byte) 0x00});
+        String stringCorrelationId = MessageIdHelper.JMS_ID_PREFIX + MessageIdHelper.AMQP_BINARY_PREFIX +  "0123af00";
+        sentMessageWithCorrelationIdTestImpl(stringCorrelationId, bin, false);
+    }
+
+    /**
+     * Tests that sending a message with a ulong typed correlation-id value which is a
+     * message-id results in an AMQP message with the expected encoding of the correlation-id,
+     * where the type is ulong, the "ID:" prefix of the JMSCorrelationID value is (obviously) not present, and there is
+     * no presence of the message annotation to indicate an app-specific correlation-id.
+     */
+    @Test
+    public void testSentMessageWithUlongCorrelationId() throws Exception
+    {
+        BigInteger ulong = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.TEN);
+        String stringCorrelationId = MessageIdHelper.JMS_ID_PREFIX + MessageIdHelper.AMQP_ULONG_PREFIX +  ulong.toString();
+        sentMessageWithCorrelationIdTestImpl(stringCorrelationId, ulong, false);
+    }
+
+    /**
      * Tests that sending a message with a string typed correlation-id value which is a
      * message-id results in an AMQP message with the expected encoding of the correlation-id,
      * where the "ID:" prefix of the JMSCorrelationID value is not present, and there is
      * no presence of the message annotation to indicate an app-specific correlation-id.
      */
     @Test
-    public void testSentMessageWithCorrelationIdString() throws Exception
+    public void testSentMessageWithStringCorrelationId() throws Exception
     {
 
         String stringCorrelationId = "ID:myTestMessageIdString";
@@ -639,13 +673,13 @@ public class MessageIntegrationTest exte
      * and the presence of the message annotation to indicate an app-specific correlation-id.
      */
     @Test
-    public void testSentMessageWithCorrelationIdStringAppSpecific() throws Exception
+    public void testSentMessageWithAppSpecificStringCorrelationId() throws Exception
     {
         String stringCorrelationId = "myTestAppSpecificString";
         sentMessageWithCorrelationIdTestImpl(stringCorrelationId, stringCorrelationId, true);
     }
 
-    private void sentMessageWithCorrelationIdTestImpl(String stringCorrelationId, Object underlyingAmqpCorrelationId, boolean appSpecific) throws Exception
+    private void sentMessageWithCorrelationIdTestImpl(String stringCorrelationId, Object correlationIdForAmqpMessageClass, boolean appSpecific) throws Exception
     {
         try(TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);)
         {
@@ -664,6 +698,7 @@ public class MessageIntegrationTest exte
 
             //Set matcher to validate the correlation-id, and the annotation
             //presence+value if it is application-specific
+            Object underlyingAmqpCorrelationId = classifyUnderlyingIdType(correlationIdForAmqpMessageClass);
             propsMatcher.withCorrelationId(equalTo(underlyingAmqpCorrelationId));
             if(appSpecific)
             {
@@ -693,6 +728,17 @@ public class MessageIntegrationTest exte
     }
 
     /**
+     * Tests that receiving a message with a string typed message-id, and then sending a message which
+     * uses the result of calling getJMSMessageID as the value for setJMSCorrelationId results in
+     * transmission of the expected AMQP message content.
+     */
+    @Test
+    public void testReceivedMessageWithStringMessageIdAndSendValueAsCorrelationId() throws Exception
+    {
+        recieveMessageIdSendCorrelationIdTestImpl("myStringMessageId");
+    }
+
+    /**
      * Tests that receiving a message with a UUID typed message-id, and then sending a message which
      * uses the result of calling getJMSMessageID as the value for setJMSCorrelationId results in
      * transmission of the expected AMQP message content.
@@ -714,6 +760,17 @@ public class MessageIntegrationTest exte
         recieveMessageIdSendCorrelationIdTestImpl(BigInteger.valueOf(123456789L));
     }
 
+    /**
+     * Tests that receiving a message with a binary typed message-id, and then sending a message which
+     * uses the result of calling getJMSMessageID as the value for setJMSCorrelationId results in
+     * transmission of the expected AMQP message content.
+     */
+    @Test
+    public void testReceivedMessageWithBinaryMessageIdAndSendValueAsCorrelationId() throws Exception
+    {
+        recieveMessageIdSendCorrelationIdTestImpl(ByteBuffer.wrap(new byte[]{(byte)0x00, (byte)0xCD, (byte) 0xEF, (byte) 0x01}));
+    }
+
     private void recieveMessageIdSendCorrelationIdTestImpl(Object idForAmqpMessageClass) throws Exception
     {
         try(TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);)
@@ -726,12 +783,7 @@ public class MessageIntegrationTest exte
             Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
             Queue queue = session.createQueue("myQueue");
 
-            Object underlyingAmqpMessageId = idForAmqpMessageClass;
-            if(underlyingAmqpMessageId instanceof BigInteger)
-            {
-                //Proton uses UnsignedLong
-                underlyingAmqpMessageId = UnsignedLong.valueOf((BigInteger)underlyingAmqpMessageId);
-            }
+            Object underlyingAmqpMessageId = classifyUnderlyingIdType(idForAmqpMessageClass);
 
             PropertiesDescribedType props = new PropertiesDescribedType();
             props.setMessageId(underlyingAmqpMessageId);
@@ -779,4 +831,22 @@ public class MessageIntegrationTest exte
             testPeer.waitForAllHandlersToComplete(3000);
         }
     }
+
+    private Object classifyUnderlyingIdType(Object idForAmqpMessageClass)
+    {
+        Object underlyingAmqpMessageId = idForAmqpMessageClass;
+
+        if(underlyingAmqpMessageId instanceof BigInteger)
+        {
+            //Proton uses UnsignedLong
+            underlyingAmqpMessageId = UnsignedLong.valueOf((BigInteger)underlyingAmqpMessageId);
+        }
+        else if(underlyingAmqpMessageId instanceof ByteBuffer)
+        {
+            //Proton uses Binary
+            underlyingAmqpMessageId = Binary.create((ByteBuffer)underlyingAmqpMessageId);
+        }
+
+        return underlyingAmqpMessageId;
+    }
 }

Modified: 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=1566611&r1=1566610&r2=1566611&view=diff
==============================================================================
--- qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageIdHelperTest.java (original)
+++ qpid/jms/trunk/src/test/java/org/apache/qpid/jms/impl/MessageIdHelperTest.java Mon Feb 10 13:16:17 2014
@@ -23,6 +23,7 @@ package org.apache.qpid.jms.impl;
 import static org.junit.Assert.*;
 
 import java.math.BigInteger;
+import java.nio.ByteBuffer;
 import java.util.UUID;
 
 import org.apache.qpid.jms.QpidJmsTestCase;
@@ -230,6 +231,22 @@ public class MessageIdHelperTest extends
 
     /**
      * 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_BINARY_PREFIX}.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForBinary()
+    {
+        String binaryStringMessageId = MessageIdHelper.AMQP_BINARY_PREFIX + "0123456789ABCDEF";
+        String expected = MessageIdHelper.AMQP_STRING_PREFIX + binaryStringMessageId;
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(binaryStringMessageId);
+        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}.
      */
@@ -261,10 +278,10 @@ public class MessageIdHelperTest extends
 
     /**
      * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns a string
-     * indicating an AMQP encoded Long when given a Long object.
+     * indicating an AMQP encoded ulong when given a Long object.
      */
     @Test
-    public void testToBaseMessageIdStringWithUlong()
+    public void testToBaseMessageIdStringWithLong()
     {
         Long longMessageId = Long.valueOf(123456789L);
         String expected = MessageIdHelper.AMQP_ULONG_PREFIX + longMessageId.toString();
@@ -274,9 +291,10 @@ public class MessageIdHelperTest extends
         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.
+     * indicating an AMQP encoded ulong when given a BigInteger object.
      */
     @Test
     public void testToBaseMessageIdStringWithBigInteger()
@@ -289,6 +307,24 @@ public class MessageIdHelperTest extends
         assertEquals("expected base id string was not returned", expected, baseMessageIdString);
     }
 
+
+    /**
+     * Test that {@link MessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded binary when given a ByteBuffer object.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithByteBufferBinary()
+    {
+        byte[] bytes = new byte[] { (byte)0x00, (byte)0xAB, (byte) 0x09, (byte) 0xFF};
+        ByteBuffer buf = ByteBuffer.wrap(bytes);
+
+        String expected = MessageIdHelper.AMQP_BINARY_PREFIX + "00AB09FF";
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(buf);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
     //TODO: delete this marker comment
     /**
      * Test that {@link MessageIdHelper#toIdObject(String)} returns a ulong
@@ -307,6 +343,52 @@ public class MessageIdHelperTest extends
     }
 
     /**
+     * Test that {@link MessageIdHelper#toIdObject(String)} returns binary
+     * (represented as a ByteBuffer) when given a string indicating an
+     * encoded AMQP binary id, using upper case hex characters
+     */
+    @Test
+    public void testToIdObjectWithEncodedBinaryUppercaseHexString()
+    {
+        byte[] bytes = new byte[] { (byte)0x00, (byte)0xAB, (byte) 0x09, (byte) 0xFF};
+        ByteBuffer binaryId = ByteBuffer.wrap(bytes);
+
+        String provided = MessageIdHelper.AMQP_BINARY_PREFIX + "00AB09FF";
+
+        Object idObject = _messageIdHelper.toIdObject(provided);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", binaryId, idObject);
+    }
+
+    /**
+     * Test that {@link MessageIdHelper#toIdObject(String)} returns null
+     * when given null.
+     */
+    @Test
+    public void testToIdObjectWithNull()
+    {
+        assertNull("null object should have been returned", _messageIdHelper.toIdObject(null));
+    }
+
+    /**
+     * Test that {@link MessageIdHelper#toIdObject(String)} returns binary
+     * (represented as a ByteBuffer) when given a string indicating an
+     * encoded AMQP binary id, using lower case hex characters.
+     */
+    @Test
+    public void testToIdObjectWithEncodedBinaryLowercaseHexString()
+    {
+        byte[] bytes = new byte[] { (byte)0x00, (byte)0xAB, (byte) 0x09, (byte) 0xFF};
+        ByteBuffer binaryId = ByteBuffer.wrap(bytes);
+
+        String provided = MessageIdHelper.AMQP_BINARY_PREFIX + "00ab09ff";
+
+        Object idObject = _messageIdHelper.toIdObject(provided);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", binaryId, idObject);
+    }
+
+    /**
      * Test that {@link MessageIdHelper#toIdObject(String)} returns a UUID
      * when given a string indicating an encoded AMQP uuid id.
      */
@@ -366,4 +448,101 @@ public class MessageIdHelperTest extends
         assertNotNull("null object should not have been returned", idObject);
         assertEquals("expected id object was not returned", encodedUuidString, idObject);
     }
+
+    /**
+     * Test that {@link MessageIdHelper#toIdObject(String)} throws an IAE when
+     * presented with an encoded binary hex string of uneven length (after the prefix)
+     * that thus can't be converted due to each byte using 2 characters
+     */
+    @Test
+    public void testToIdObjectWithStringContainingBinaryHexThrowsIAEWithUnevenLengthString()
+    {
+        String unevenHead = MessageIdHelper.AMQP_BINARY_PREFIX + "123";
+
+        try
+        {
+            _messageIdHelper.toIdObject(unevenHead);
+            fail("expected exception was not thrown");
+        }
+        catch(IllegalArgumentException iae)
+        {
+            //expected
+            String msg = iae.getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("even length"));
+        }
+    }
+
+    /**
+     * Test that {@link MessageIdHelper#toIdObject(String)} throws an IAE when
+     * presented with an encoded binary hex string (after the prefix) that contains
+     * characters other than 0-9 and A-F and a-f, and thus can't be converted
+     */
+    @Test
+    public void testToIdObjectWithStringContainingBinaryHexThrowsIAEWithNonHexCharacters()
+    {
+
+        //char before '0'
+        char nonHexChar = '/';
+        String nonHexString = MessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
+
+        try
+        {
+            _messageIdHelper.toIdObject(nonHexString);
+            fail("expected exception was not thrown");
+        }
+        catch(IllegalArgumentException iae)
+        {
+            //expected
+            String msg = iae.getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("non-hex"));
+        }
+
+        //char after '9', before 'A'
+        nonHexChar = ':';
+        nonHexString = MessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
+
+        try
+        {
+            _messageIdHelper.toIdObject(nonHexString);
+            fail("expected exception was not thrown");
+        }
+        catch(IllegalArgumentException iae)
+        {
+            //expected
+            String msg = iae.getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("non-hex"));
+        }
+
+        //char after 'F', before 'a'
+        nonHexChar = 'G';
+        nonHexString = MessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
+
+        try
+        {
+            _messageIdHelper.toIdObject(nonHexString);
+            fail("expected exception was not thrown");
+        }
+        catch(IllegalArgumentException iae)
+        {
+            //expected
+            String msg = iae.getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("non-hex"));
+        }
+
+        //char after 'f'
+        nonHexChar = 'g';
+        nonHexString = MessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
+
+        try
+        {
+            _messageIdHelper.toIdObject(nonHexString);
+            fail("expected exception was not thrown");
+        }
+        catch(IllegalArgumentException iae)
+        {
+            //expected
+            String msg = iae.getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("non-hex"));
+        }
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org