Skip to content

Commit e0c5367

Browse files
committed
QPIDJMS-622 receiveBody must throw if type is Message or StreamMessage
When the next message is of type Message or StreamMessage the specification requires we throw an exception vs calling into getBody which for Message at least the specification has conflicting rules which simply returns null for all types requested. (cherry picked from commit de04f37)
1 parent dde17ee commit e0c5367

5 files changed

Lines changed: 175 additions & 7 deletions

File tree

qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
3636
import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
3737
import org.apache.qpid.jms.message.JmsMessage;
38+
import org.apache.qpid.jms.message.facade.JmsMessageFacade;
3839
import org.apache.qpid.jms.meta.JmsConsumerId;
3940
import org.apache.qpid.jms.meta.JmsConsumerInfo;
4041
import org.apache.qpid.jms.meta.JmsResource.ResourceState;
@@ -251,7 +252,16 @@ public <T> T receiveBody(Class<T> desired, long timeout) throws JMSException {
251252
try {
252253
envelope = dequeue(timeout, connection.isReceiveLocalOnly());
253254
if (envelope != null) {
254-
messageBody = envelope.getMessage().getBody(desired);
255+
final JmsMessage message = envelope.getMessage();
256+
final int messageType = message.getFacade().getJmsMsgType();
257+
258+
if (messageType == JmsMessageFacade.JMS_MESSAGE) {
259+
throw new MessageFormatException("receiveBody cannot be called on a bare Message instance.");
260+
} else if (messageType == JmsMessageFacade.JMS_STREAM_MESSAGE) {
261+
throw new MessageFormatException("receiveBody cannot be called on a StreamMessage instance.");
262+
}
263+
264+
messageBody = message.getBody(desired);
255265
}
256266
} catch (MessageFormatException mfe) {
257267
// Should behave as if receiveBody never happened in these modes.

qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMessageFacade.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,29 @@
3131
*/
3232
public interface JmsMessageFacade extends TraceableMessage {
3333

34+
public static final byte JMS_MESSAGE = 0;
35+
public static final byte JMS_OBJECT_MESSAGE = 1;
36+
public static final byte JMS_MAP_MESSAGE = 2;
37+
public static final byte JMS_BYTES_MESSAGE = 3;
38+
public static final byte JMS_STREAM_MESSAGE = 4;
39+
public static final byte JMS_TEXT_MESSAGE = 5;
40+
41+
/**
42+
* Returns a byte value that represents the message type from a know set of vales.
43+
*
44+
* <ul>
45+
* <li>jakarta.jms.Message = 0</li>
46+
* <li>jakarta.jms.ObjectMessage = 1</li>
47+
* <li>jakarta.jms.MapMessage = 2</li>
48+
* <li>jakarta.jms.BytesMessage = 3</li>
49+
* <li>jakarta.jms.StreamMessage = 4</li>
50+
* <li>jakarta.jms.TextMessage = 5</li>
51+
* </ul>
52+
*
53+
* @return a byte value that represents the message type.
54+
*/
55+
public byte getJmsMsgType();
56+
3457
/**
3558
* Returns the property names for this Message instance. The Set returned may be
3659
* manipulated by the receiver without impacting the facade, and an empty set

qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageSupport.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.nio.ByteBuffer;
2020
import java.util.Map;
2121

22+
import org.apache.qpid.jms.message.facade.JmsMessageFacade;
2223
import org.apache.qpid.proton.amqp.Symbol;
2324
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
2425
import org.apache.qpid.proton.codec.ReadableBuffer;
@@ -47,37 +48,37 @@ public final class AmqpMessageSupport {
4748
* Value mapping for JMS_MSG_TYPE which indicates the message is a generic JMS Message
4849
* which has no body.
4950
*/
50-
public static final byte JMS_MESSAGE = 0;
51+
public static final byte JMS_MESSAGE = JmsMessageFacade.JMS_MESSAGE;
5152

5253
/**
5354
* Value mapping for JMS_MSG_TYPE which indicates the message is a JMS ObjectMessage
5455
* which has an Object value serialized in its message body.
5556
*/
56-
public static final byte JMS_OBJECT_MESSAGE = 1;
57+
public static final byte JMS_OBJECT_MESSAGE = JmsMessageFacade.JMS_OBJECT_MESSAGE;
5758

5859
/**
5960
* Value mapping for JMS_MSG_TYPE which indicates the message is a JMS MapMessage
6061
* which has an Map instance serialized in its message body.
6162
*/
62-
public static final byte JMS_MAP_MESSAGE = 2;
63+
public static final byte JMS_MAP_MESSAGE = JmsMessageFacade.JMS_MAP_MESSAGE;
6364

6465
/**
6566
* Value mapping for JMS_MSG_TYPE which indicates the message is a JMS BytesMessage
6667
* which has a body that consists of raw bytes.
6768
*/
68-
public static final byte JMS_BYTES_MESSAGE = 3;
69+
public static final byte JMS_BYTES_MESSAGE = JmsMessageFacade.JMS_BYTES_MESSAGE;
6970

7071
/**
7172
* Value mapping for JMS_MSG_TYPE which indicates the message is a JMS StreamMessage
7273
* which has a body that is a structured collection of primitives values.
7374
*/
74-
public static final byte JMS_STREAM_MESSAGE = 4;
75+
public static final byte JMS_STREAM_MESSAGE = JmsMessageFacade.JMS_STREAM_MESSAGE;
7576

7677
/**
7778
* Value mapping for JMS_MSG_TYPE which indicates the message is a JMS TextMessage
7879
* which has a body that contains a UTF-8 encoded String.
7980
*/
80-
public static final byte JMS_TEXT_MESSAGE = 5;
81+
public static final byte JMS_TEXT_MESSAGE = JmsMessageFacade.JMS_TEXT_MESSAGE;
8182

8283
public static final String JMS_AMQP_TTL = "JMS_AMQP_TTL";
8384
public static final String JMS_AMQP_REPLY_TO_GROUP_ID = "JMS_AMQP_REPLY_TO_GROUP_ID";

qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/JMSConsumerIntegrationTest.java

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727

2828
import java.io.ByteArrayOutputStream;
2929
import java.io.ObjectOutputStream;
30+
import java.util.ArrayList;
3031
import java.util.Arrays;
3132
import java.util.LinkedHashMap;
33+
import java.util.List;
3234
import java.util.Map;
3335

3436
import javax.jms.IllegalStateRuntimeException;
@@ -39,6 +41,7 @@
3941
import javax.jms.MessageFormatRuntimeException;
4042
import javax.jms.MessageListener;
4143
import javax.jms.Queue;
44+
import javax.jms.StreamMessage;
4245

4346
import org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport;
4447
import org.apache.qpid.jms.test.QpidJmsTestCase;
@@ -635,4 +638,129 @@ public void testReceiveBodyBytesMessageFailsWhenWrongTypeRequested() throws Exce
635638
testPeer.waitForAllHandlersToComplete(3000);
636639
}
637640
}
641+
642+
@Test
643+
@Timeout(20)
644+
public void testReceiveBodyOnMessageFailsWhenAnyTypeRequested() throws Exception {
645+
try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
646+
JMSContext context = testFixture.createJMSContext(testPeer);
647+
648+
testPeer.expectBegin();
649+
650+
Queue queue = context.createQueue("myQueue");
651+
652+
PropertiesDescribedType properties = new PropertiesDescribedType();
653+
654+
MessageAnnotationsDescribedType msgAnnotations = null;
655+
msgAnnotations = new MessageAnnotationsDescribedType();
656+
msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.JMS_MSG_TYPE.toString(), AmqpMessageSupport.JMS_MESSAGE);
657+
658+
testPeer.expectReceiverAttach();
659+
testPeer.expectLinkFlowRespondWithTransfer(null, msgAnnotations, properties, null, null, 1);
660+
testPeer.expectDispositionThatIsAcceptedAndSettled();
661+
662+
JMSConsumer messageConsumer = context.createConsumer(queue);
663+
try {
664+
messageConsumer.receiveBody(String.class, 3000);
665+
fail("Should not read as String type");
666+
} catch (MessageFormatRuntimeException mfre) {
667+
}
668+
669+
try {
670+
messageConsumer.receiveBody(byte[].class, 3000);
671+
fail("Should not read as String type");
672+
} catch (MessageFormatRuntimeException mfre) {
673+
}
674+
675+
try {
676+
messageConsumer.receiveBody(Object.class, 3000);
677+
fail("Should not read as String type");
678+
} catch (MessageFormatRuntimeException mfre) {
679+
}
680+
681+
try {
682+
messageConsumer.receiveBody(Map.class, 3000);
683+
fail("Should not read as Map type");
684+
} catch (MessageFormatRuntimeException mfre) {
685+
}
686+
687+
final Message received = messageConsumer.receive(1000);
688+
689+
assertNotNull(received);
690+
691+
testPeer.waitForAllHandlersToComplete(3000);
692+
testPeer.expectEnd();
693+
testPeer.expectClose();
694+
695+
context.close();
696+
697+
testPeer.waitForAllHandlersToComplete(3000);
698+
}
699+
}
700+
701+
@Test
702+
@Timeout(20)
703+
public void testReceiveBodyOnStreamMessageFailsWhenAnyTypeRequested() throws Exception {
704+
try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
705+
JMSContext context = testFixture.createJMSContext(testPeer);
706+
707+
testPeer.expectBegin();
708+
709+
Queue queue = context.createQueue("myQueue");
710+
711+
List<Object> list = new ArrayList<Object>();
712+
list.add(true);
713+
list.add(false);
714+
list.add("test");
715+
716+
PropertiesDescribedType properties = new PropertiesDescribedType();
717+
718+
MessageAnnotationsDescribedType msgAnnotations = null;
719+
msgAnnotations = new MessageAnnotationsDescribedType();
720+
msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.JMS_MSG_TYPE.toString(), AmqpMessageSupport.JMS_STREAM_MESSAGE);
721+
722+
DescribedType amqpValueSectionContent = new AmqpValueDescribedType(list);
723+
724+
testPeer.expectReceiverAttach();
725+
testPeer.expectLinkFlowRespondWithTransfer(null, msgAnnotations, properties, null, amqpValueSectionContent, 1);
726+
testPeer.expectDispositionThatIsAcceptedAndSettled();
727+
728+
JMSConsumer messageConsumer = context.createConsumer(queue);
729+
try {
730+
messageConsumer.receiveBody(String.class, 3000);
731+
fail("Should not read as String type");
732+
} catch (MessageFormatRuntimeException mfre) {
733+
}
734+
735+
try {
736+
messageConsumer.receiveBody(byte[].class, 3000);
737+
fail("Should not read as String type");
738+
} catch (MessageFormatRuntimeException mfre) {
739+
}
740+
741+
try {
742+
messageConsumer.receiveBody(Object.class, 3000);
743+
fail("Should not read as String type");
744+
} catch (MessageFormatRuntimeException mfre) {
745+
}
746+
747+
try {
748+
messageConsumer.receiveBody(Map.class, 3000);
749+
fail("Should not read as Map type");
750+
} catch (MessageFormatRuntimeException mfre) {
751+
}
752+
753+
final StreamMessage received = (StreamMessage) messageConsumer.receive(1000);
754+
755+
assertNotNull(received);
756+
757+
testPeer.waitForAllHandlersToComplete(3000);
758+
testPeer.expectEnd();
759+
testPeer.expectClose();
760+
761+
context.close();
762+
763+
testPeer.waitForAllHandlersToComplete(3000);
764+
}
765+
}
638766
}

qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestMessageFacade.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.apache.qpid.jms.JmsDestination;
2929
import org.apache.qpid.jms.message.facade.JmsMessageFacade;
3030

31+
3132
/**
3233
* A test implementation of the JmsMessageFaceade that provides a generic
3334
* message instance which can be used instead of implemented in Provider specific
@@ -76,6 +77,11 @@ public JmsMsgType getMsgType() {
7677
return JmsMsgType.MESSAGE;
7778
}
7879

80+
@Override
81+
public byte getJmsMsgType() {
82+
return (byte) getMsgType().ordinal();
83+
}
84+
7985
@Override
8086
public JmsTestMessageFacade copy() {
8187
JmsTestMessageFacade copy = new JmsTestMessageFacade();

0 commit comments

Comments
 (0)