View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.jms;
8   
9   import org.mule.tck.junit4.AbstractMuleTestCase;
10  import org.mule.tck.testmodels.fruit.BananaFactory;
11  import org.mule.tck.testmodels.fruit.Orange;
12  
13  import java.io.IOException;
14  import java.io.NotSerializableException;
15  import java.io.ObjectInputStream;
16  import java.io.ObjectOutputStream;
17  import java.io.Serializable;
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.Enumeration;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import javax.jms.BytesMessage;
27  import javax.jms.JMSException;
28  import javax.jms.MapMessage;
29  import javax.jms.Message;
30  import javax.jms.MessageFormatException;
31  import javax.jms.ObjectMessage;
32  import javax.jms.Session;
33  import javax.jms.StreamMessage;
34  import javax.jms.TextMessage;
35  
36  import org.apache.activemq.command.ActiveMQBytesMessage;
37  import org.apache.activemq.command.ActiveMQMapMessage;
38  import org.apache.activemq.command.ActiveMQObjectMessage;
39  import org.apache.activemq.command.ActiveMQStreamMessage;
40  import org.apache.activemq.command.ActiveMQTextMessage;
41  import org.apache.commons.collections.IteratorUtils;
42  import org.apache.commons.collections.iterators.IteratorEnumeration;
43  import org.junit.Test;
44  
45  import static org.junit.Assert.assertEquals;
46  import static org.junit.Assert.assertNotNull;
47  import static org.junit.Assert.assertNull;
48  import static org.junit.Assert.assertSame;
49  import static org.junit.Assert.assertTrue;
50  import static org.junit.Assert.fail;
51  import static org.mockito.Matchers.anyObject;
52  import static org.mockito.Mockito.mock;
53  import static org.mockito.Mockito.times;
54  import static org.mockito.Mockito.verify;
55  import static org.mockito.Mockito.when;
56  
57  public class JmsMessageUtilsTestCase extends AbstractMuleTestCase
58  {
59  
60      public static final String ENCODING = "UTF-8";
61  
62      @Test
63      public void testHeaders()
64      {
65          // already valid headers are returned as-is, so we can assertSame
66          assertSame("identifier", JmsMessageUtils.encodeHeader("identifier"));
67          assertSame("_identifier", JmsMessageUtils.encodeHeader("_identifier"));
68          assertSame("identifier_", JmsMessageUtils.encodeHeader("identifier_"));
69          assertSame("ident_ifier", JmsMessageUtils.encodeHeader("ident_ifier"));
70  
71          assertEquals("_identifier", JmsMessageUtils.encodeHeader("-identifier"));
72          assertEquals("identifier_", JmsMessageUtils.encodeHeader("identifier-"));
73          assertEquals("ident_ifier", JmsMessageUtils.encodeHeader("ident-ifier"));
74          assertEquals("_ident_ifier_", JmsMessageUtils.encodeHeader("-ident_ifier-"));
75          assertEquals("_ident_ifier_", JmsMessageUtils.encodeHeader("-ident-ifier-"));
76      }
77  
78      @Test
79      public void testTextMessageNullContent() throws Exception
80      {
81          TextMessage mockMessage = mock(TextMessage.class);
82          when(mockMessage.getText()).thenReturn(null);
83  
84          byte[] result = JmsMessageUtils.toByteArray(mockMessage, JmsConstants.JMS_SPECIFICATION_102B,
85                                                      ENCODING);
86          assertNotNull(result);
87          assertEquals("Should return an empty byte array.", 0, result.length);
88  
89          verify(mockMessage).getText();
90      }
91  
92      @Test
93      public void testByteMessageNullContentInJmsVersion_1_0_1() throws Exception
94      {
95          BytesMessage mockMessage1 = mock(BytesMessage.class);
96          when(mockMessage1.readBytes((byte[]) anyObject())).thenReturn(-1);
97  
98          byte[] result1 = JmsMessageUtils.toByteArray(mockMessage1, JmsConstants.JMS_SPECIFICATION_102B,
99                                                       ENCODING);
100         assertNotNull(result1);
101         assertEquals("Should return an empty byte array.", 0, result1.length);
102         verify(mockMessage1).reset();
103     }
104 
105     @Test
106     public void testByteMessageNullContentInJmsVersion_1_1() throws Exception
107     {
108         BytesMessage mockMessage2 = mock(BytesMessage.class);
109         when(mockMessage2.getBodyLength()).thenReturn(Long.valueOf(0));
110 
111         byte[] result2 = JmsMessageUtils.toByteArray(mockMessage2, JmsConstants.JMS_SPECIFICATION_11,
112                                                      ENCODING);
113         assertNotNull(result2);
114         assertEquals("Should return an empty byte array.", 0, result2.length);
115         verify(mockMessage2).reset();
116     }
117 
118     @Test
119     public void testStreamMessageSerialization() throws Exception
120     {
121         Session session = mock(Session.class);
122         when(session.createStreamMessage()).thenReturn(new ActiveMQStreamMessage());
123 
124         // Creates a test list with data
125         List data = new ArrayList();
126         data.add(Boolean.TRUE);
127         data.add(new Byte("1"));
128         data.add(new Short("2"));
129         data.add(new Character('3'));
130         data.add(new Integer("4"));
131         // can't write Longs: https://issues.apache.org/activemq/browse/AMQ-1965
132         // data.add(new Long("5"));
133         data.add(new Float("6"));
134         data.add(new Double("7"));
135         data.add(new String("8"));
136         data.add(null);
137         data.add(new byte[] {9, 10});
138 
139         StreamMessage result = (StreamMessage) JmsMessageUtils.toMessage(data, session);
140 
141         // Resets so it's readable
142         result.reset();
143         assertEquals(Boolean.TRUE, result.readObject());
144         assertEquals(new Byte("1"), result.readObject());
145         assertEquals(new Short("2"), result.readObject());
146         assertEquals(new Character('3'), result.readObject());
147         assertEquals(new Integer("4"), result.readObject());
148         // can't write Longs: https://issues.apache.org/activemq/browse/AMQ-1965
149         // assertEquals(new Long("5"), result.readObject());
150         assertEquals(new Float("6"), result.readObject());
151         assertEquals(new Double("7"), result.readObject());
152         assertEquals(new String("8"), result.readObject());
153         assertNull(result.readObject());
154         assertTrue(Arrays.equals(new byte[] {9, 10}, (byte[]) result.readObject()));
155     }
156 
157     @Test(expected = MessageFormatException.class)
158     public void testStreamMessageSerializationWithInvalidType() throws Exception
159     {
160         Session session = null;
161         session = mock(Session.class);
162         when(session.createStreamMessage()).thenReturn(new ActiveMQStreamMessage());
163 
164         // Creates a test list with data
165         List data = new ArrayList();
166         data.add(new Object());
167 
168         JmsMessageUtils.toMessage(data, session);
169     }
170 
171     @Test
172     public void testMapMessageWithNullValue() throws Exception
173     {
174         String[] keys = new String[] {"key", "null"};
175         Iterator<String> keyIterator = IteratorUtils.arrayIterator(keys);
176         Enumeration<String> keyEnumeration = new IteratorEnumeration(keyIterator);
177 
178         MapMessage mockMessage1 = mock(MapMessage.class);
179         when(mockMessage1.getMapNames()).thenReturn(keyEnumeration);
180         when(mockMessage1.getObject("key")).thenReturn("value");
181         when(mockMessage1.getObject("null")).thenReturn(null);
182 
183         Object result = JmsMessageUtils.toObject(mockMessage1, JmsConstants.JMS_SPECIFICATION_11, ENCODING);
184         assertNotNull(result);
185         assertTrue(result instanceof Map);
186         Map map = (Map) result;
187         assertEquals("value", map.get("key"));
188         assertNull(map.get("null"));
189     }
190 
191     /**
192      * Tests that is able to convert a Map which only contains simple values into a
193      * MapMessage.
194      */
195     @Test
196     public void testConvertsValidMapWithSimpleValuesToMapMessage() throws JMSException
197     {
198         Session session = mock(Session.class);
199         when(session.createMapMessage()).thenReturn(new ActiveMQMapMessage());
200 
201         // Creates a test Map with data
202         Map data = new HashMap();
203         data.put("value1", new Float(4));
204         data.put("value2", new byte[] {1, 2, 3});
205         data.put("value3", "value3");
206         data.put("value4", new Double(67.9));
207         data.put("value5", true);
208         data.put("value6", null);
209 
210         Message message = JmsMessageUtils.toMessage(data, session);
211         assertTrue(message instanceof MapMessage);
212 
213         MapMessage mapMessage = (MapMessage) message;
214         assertEquals(new Float(4), mapMessage.getFloat("value1"), 0);
215         assertTrue(Arrays.equals(new byte[] {1, 2, 3}, mapMessage.getBytes("value2")));
216         assertEquals("value3", mapMessage.getString("value3"));
217         assertEquals(new Double(67.9), mapMessage.getDouble("value4"), 0);
218         assertTrue(mapMessage.getBoolean("value5"));
219         assertNull(mapMessage.getObject("value6"));
220     }
221 
222     /**
223      * Tests that is able to convert a Map which contains a serializable value into
224      * an ObjectMessage.
225      */
226     @Test
227     public void testConvertsMapWithSerializableValueIntoObjectMessage() throws Exception
228     {
229         Session session = mock(Session.class);
230         when(session.createObjectMessage()).thenReturn(new ActiveMQObjectMessage());
231 
232         // Creates a test Map containing a serializable object
233         Map data = new HashMap();
234         data.put("orange", new Orange());
235 
236         Message message = JmsMessageUtils.toMessage(data, session);
237         assertTrue(message instanceof ObjectMessage);
238 
239         ObjectMessage objectMessage = (ObjectMessage) message;
240         Map values = (Map) objectMessage.getObject();
241         assertEquals(new Orange(), values.get("orange"));
242     }
243 
244     /**
245      * Tests that trying to convert a Map which contains a non valid non serializable
246      * value throws an exception.
247      */
248     @Test
249     public void testConvertingMapIncludingNotValidNotSerializableValueThrowsException() throws Exception
250     {
251         Session session = mock(Session.class);
252         when(session.createObjectMessage()).thenReturn(new ActiveMQObjectMessage());
253 
254         // Creates a test Map containing a non serializable object
255         Map data = new HashMap();
256         data.put("notserializable", new BananaFactory());
257 
258         try
259         {
260             JmsMessageUtils.toMessage(data, session);
261             fail("Attempt to send a non-serializable object in a map should fail");
262         }
263         catch (Exception expected)
264         {
265             assertTrue(expected.getCause() instanceof NotSerializableException);
266         }
267     }
268 
269     @Test
270     public void testConvertingStringToTextMessage() throws JMSException
271     {
272         String text = "Hello world";
273 
274         Session session = mock(Session.class);
275         TextMessage textMessage = new ActiveMQTextMessage();
276         textMessage.setText(text);
277         when(session.createTextMessage(text)).thenReturn(textMessage);
278 
279         TextMessage message = (TextMessage) JmsMessageUtils.toMessage(text, session);
280         assertEquals(textMessage, message);
281         verify(session, times(1)).createTextMessage(text);
282     }
283 
284     @Test
285     public void testConvertingByteArrayToBytesMessage() throws JMSException
286     {
287         Session session = mock(Session.class);
288         when(session.createBytesMessage()).thenReturn(new ActiveMQBytesMessage());
289 
290         byte[] bytesArray = new byte[] {1, 2};
291         BytesMessage message = (BytesMessage) JmsMessageUtils.toMessage(bytesArray, session);
292 
293         // Makes the message readable
294         message.reset();
295         byte[] bytesArrayResult = new byte[(int) message.getBodyLength()];
296         int length = message.readBytes(bytesArrayResult);
297         assertEquals(2, length);
298         assertEquals(bytesArray[0], bytesArrayResult[0]);
299         assertEquals(bytesArray[1], bytesArrayResult[1]);
300     }
301 
302     @Test
303     public void testConvertingSerializableToObjectMessage() throws JMSException
304     {
305         Session session = mock(Session.class);
306         when(session.createObjectMessage()).thenReturn(new ActiveMQObjectMessage());
307 
308         final String OBJECT_ID = "id1234";
309         ObjectMessage message = (ObjectMessage) JmsMessageUtils.toMessage(new SerializableObject(OBJECT_ID),
310                                                                           session);
311 
312         Serializable serializable = message.getObject();
313         assertTrue(serializable instanceof SerializableObject);
314         assertEquals(OBJECT_ID, ((SerializableObject) serializable).id);
315     }
316 
317     @Test
318     public void testConvertingMessageToMessageReturnsSameObject() throws JMSException
319     {
320         Message original = mock(Message.class);
321         Message result = JmsMessageUtils.toMessage(original, null);
322         assertSame(original, result);
323     }
324 
325     @Test(expected = JMSException.class)
326     public void testConvertingInvalidTypeThrowsException() throws JMSException
327     {
328         JmsMessageUtils.toMessage(new Object(), null);
329     }
330 
331     /**
332      * Dummy serializable class used to test that conversion from Map to JmsMessage
333      * is OK when it includes non primitive serializable values.
334      */
335     private static class SerializableObject implements Serializable
336     {
337 
338         private static final long serialVersionUID = -4865136673252075014L;
339         private String id;
340 
341         public SerializableObject(String id)
342         {
343             this.id = id;
344         }
345 
346         private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException
347         {
348             aInputStream.defaultReadObject();
349         }
350 
351         private void writeObject(ObjectOutputStream aOutputStream) throws IOException
352         {
353             aOutputStream.defaultWriteObject();
354         }
355     }
356 }