View Javadoc

1   /*
2    * $Id: JmsMessageUtils.java 12205 2008-06-30 18:25:55Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport.jms;
12  
13  import java.io.IOException;
14  import java.io.InputStream;
15  import java.io.ObjectOutputStream;
16  import java.io.Serializable;
17  import java.util.Enumeration;
18  import java.util.Hashtable;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.Vector;
23  
24  import javax.jms.BytesMessage;
25  import javax.jms.Destination;
26  import javax.jms.JMSException;
27  import javax.jms.MapMessage;
28  import javax.jms.Message;
29  import javax.jms.MessageEOFException;
30  import javax.jms.ObjectMessage;
31  import javax.jms.Queue;
32  import javax.jms.Session;
33  import javax.jms.StreamMessage;
34  import javax.jms.TextMessage;
35  import javax.jms.Topic;
36  
37  import org.apache.commons.io.output.ByteArrayOutputStream;
38  import org.mule.util.ArrayUtils;
39  import org.mule.util.ClassUtils;
40  import org.mule.util.StringUtils;
41  
42  /**
43   * <code>JmsMessageUtils</code> contains helper method for dealing with JMS
44   * messages in Mule.
45   */
46  public class JmsMessageUtils
47  {
48      public static final char REPLACEMENT_CHAR = '_';
49  
50      /**
51       * Encode a String so that is is a valid JMS header name
52       * 
53       * @param name the String to encode
54       * @return a valid JMS header name
55       */
56      public static String encodeHeader(String name)
57      {
58          if (StringUtils.isEmpty(name))
59          {
60              throw new IllegalArgumentException("Header name to encode must not be null or empty");
61          }
62      
63          int i = 0, length = name.length();
64          while (i < length && Character.isJavaIdentifierPart(name.charAt(i)))
65          {
66              // zip through
67              i++;
68          }
69      
70          if (i == length)
71          {
72              // String is already valid
73              return name;
74          }
75          else
76          {
77              // make a copy, fix up remaining characters
78              StringBuffer sb = new StringBuffer(name);
79              for (int j = i; j < length; j++)
80              {
81                  if (!Character.isJavaIdentifierPart(sb.charAt(j)))
82                  {
83                      sb.setCharAt(j, REPLACEMENT_CHAR);
84                  }
85              }
86              return sb.toString();
87          }
88      }
89  
90      public static Message toMessage(Object object, Session session) throws JMSException
91      {
92          if (object instanceof Message)
93          {
94              return (Message)object;
95          }
96          else if (object instanceof String)
97          {
98              return session.createTextMessage((String)object);
99          }
100         else if (object instanceof Map)
101         {
102             MapMessage mMsg = session.createMapMessage();
103             Map src = (Map)object;
104 
105             for (Iterator i = src.entrySet().iterator(); i.hasNext();)
106             {
107                 Map.Entry entry = (Map.Entry)i.next();
108                 mMsg.setObject(entry.getKey().toString(), entry.getValue());
109             }
110 
111             return mMsg;
112         }
113         else if (object instanceof InputStream)
114         {
115             StreamMessage sMsg = session.createStreamMessage();	
116             InputStream temp = (InputStream)object;
117 
118             byte[] buffer = new byte[4096];
119             int len;
120 
121             try
122             {
123                 while ((len = temp.read(buffer)) != -1)
124                 {
125                     sMsg.writeBytes(buffer, 0, len);
126                 }
127             }
128             catch (IOException e)
129             {
130                 throw new JMSException("Failed to read input stream to create a stream message: " + e);
131             }
132 
133             return sMsg;
134         }
135         else if (object instanceof List)
136         {
137             StreamMessage sMsg = session.createStreamMessage();
138             List list = (List) object;
139             for (Iterator iter = list.iterator(); iter.hasNext();)
140             {
141                 sMsg.writeObject(iter.next());
142             }
143             return sMsg;
144         }
145         else if (object instanceof byte[])
146         {
147             BytesMessage bMsg = session.createBytesMessage();
148             bMsg.writeBytes((byte[])object);
149             return bMsg;
150         }
151         else if (object instanceof Serializable)
152         {
153             ObjectMessage oMsg = session.createObjectMessage();
154             oMsg.setObject((Serializable)object);
155             return oMsg;
156         }
157         else
158         {
159             throw new JMSException(
160                 "Source was not of a supported type, data must be Serializable, String, byte[], Map or InputStream, " +
161                 "but was " + ClassUtils.getShortClassName(object, "<null>"));
162         }
163     }
164 
165     public static Object toObject(Message source, String jmsSpec) throws JMSException, IOException
166     {
167         if (source instanceof ObjectMessage)
168         {
169             return ((ObjectMessage)source).getObject();
170         }
171         else if (source instanceof MapMessage)
172         {
173             Hashtable map = new Hashtable();
174             MapMessage m = (MapMessage)source;
175 
176             for (Enumeration e = m.getMapNames(); e.hasMoreElements();)
177             {
178                 String name = (String)e.nextElement();
179                 Object obj = m.getObject(name);
180                 map.put(name, obj);
181             }
182 
183             return map;
184         }
185         else if (source instanceof TextMessage)
186         {
187             return ((TextMessage)source).getText();
188         }
189         else if (source instanceof BytesMessage)
190         {
191             return toByteArray(source, jmsSpec);
192         }
193         else if (source instanceof StreamMessage)
194         {
195             Vector result = new Vector();
196             try
197             {
198                 StreamMessage sMsg = (StreamMessage)source;
199                 Object obj;
200                 while ((obj = sMsg.readObject()) != null)
201                 {
202                     result.addElement(obj);
203                 }
204             }
205             catch (MessageEOFException eof)
206             {
207                 // ignored
208             }
209             catch (Exception e)
210             {
211                 throw new JMSException("Failed to extract information from JMS Stream Message: " + e);
212             }
213             return result;
214         }
215 
216         // what else is there to do?
217         return source;
218     }
219 
220     /**
221      * @param message the message to receive the bytes from. Note this only works for
222      *            TextMessge, ObjectMessage, StreamMessage and BytesMessage.
223      * @param jmsSpec indicates the JMS API version, either
224      *            {@link JmsConstants#JMS_SPECIFICATION_102B} or
225      *            {@link JmsConstants#JMS_SPECIFICATION_11}. Any other value
226      *            including <code>null</code> is treated as fallback to
227      *            {@link JmsConstants#JMS_SPECIFICATION_102B}.
228      * @return a byte array corresponding with the message payload
229      * @throws JMSException if the message can't be read or if the message passed is
230      *             a MapMessage
231      * @throws java.io.IOException if a failure occurs while reading the stream and
232      *             converting the message data
233      */
234     public static byte[] toByteArray(Message message, String jmsSpec) throws JMSException, IOException
235     {
236         if (message instanceof BytesMessage)
237         {
238             BytesMessage bMsg = (BytesMessage)message;
239             bMsg.reset();
240 
241             if (JmsConstants.JMS_SPECIFICATION_11.equals(jmsSpec))
242             {
243                 long bmBodyLength = bMsg.getBodyLength();
244                 if (bmBodyLength > Integer.MAX_VALUE)
245                 {
246                     throw new JMSException("Size of BytesMessage exceeds Integer.MAX_VALUE; "
247                                            + "please consider using JMS StreamMessage instead");
248                 }
249 
250                 if (bmBodyLength > 0)
251                 {
252                     byte[] bytes = new byte[(int)bmBodyLength];
253                     bMsg.readBytes(bytes);
254                     return bytes;
255                 }
256                 else
257                 {
258                     return ArrayUtils.EMPTY_BYTE_ARRAY;
259                 }
260             }
261             else
262             {
263                 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
264                 byte[] buffer = new byte[4096];
265                 int len;
266 
267                 while ((len = bMsg.readBytes(buffer)) != -1)
268                 {
269                     baos.write(buffer, 0, len);
270                 }
271 
272                 if (baos.size() > 0)
273                 {
274                     return baos.toByteArray();
275                 }
276                 else
277                 {
278                     return ArrayUtils.EMPTY_BYTE_ARRAY;
279                 }
280             }
281         }
282         else if (message instanceof StreamMessage)
283         {
284             StreamMessage sMsg = (StreamMessage)message;
285             sMsg.reset();
286 
287             ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
288             byte[] buffer = new byte[4096];
289             int len;
290 
291             while ((len = sMsg.readBytes(buffer)) != -1)
292             {
293                 baos.write(buffer, 0, len);
294             }
295 
296             return baos.toByteArray();
297         }
298         else if (message instanceof ObjectMessage)
299         {
300             ObjectMessage oMsg = (ObjectMessage)message;
301             ByteArrayOutputStream baos = new ByteArrayOutputStream();
302             ObjectOutputStream os = new ObjectOutputStream(baos);
303             os.writeObject(oMsg.getObject());
304             os.flush();
305             os.close();
306             return baos.toByteArray();
307         }
308         else if (message instanceof TextMessage)
309         {
310             TextMessage tMsg = (TextMessage)message;
311             String tMsgText = tMsg.getText();
312 
313             if (null == tMsgText)
314             {
315                 // Avoid creating new instances of byte arrays, even empty ones. The
316                 // load on this part of the code can be high.
317                 return ArrayUtils.EMPTY_BYTE_ARRAY;
318             }
319             else
320             {
321                 return tMsgText.getBytes();
322             }
323         }
324         else
325         {
326             throw new JMSException("Cannot get bytes from Map Message");
327         }
328     }
329 
330     public static String getNameForDestination(Destination dest) throws JMSException
331     {
332         if (dest instanceof Queue)
333         {
334             return ((Queue)dest).getQueueName();
335         }
336         else if (dest instanceof Topic)
337         {
338             return ((Topic)dest).getTopicName();
339         }
340         else
341         {
342             return null;
343         }
344     }
345 
346     public static Message copyJMSProperties(Message from, Message to, JmsConnector connector)
347         throws JMSException
348     {
349         if (connector.supportsProperty(JmsConstants.JMS_CORRELATION_ID))
350         {
351             to.setJMSCorrelationID(from.getJMSCorrelationID());
352         }
353         if (connector.supportsProperty(JmsConstants.JMS_DELIVERY_MODE))
354         {
355             to.setJMSDeliveryMode(from.getJMSDeliveryMode());
356         }
357         if (connector.supportsProperty(JmsConstants.JMS_DESTINATION))
358         {
359             to.setJMSDestination(from.getJMSDestination());
360         }
361         if (connector.supportsProperty(JmsConstants.JMS_EXPIRATION))
362         {
363             to.setJMSExpiration(from.getJMSExpiration());
364         }
365         if (connector.supportsProperty(JmsConstants.JMS_MESSAGE_ID))
366         {
367             to.setJMSMessageID(from.getJMSMessageID());
368         }
369         if (connector.supportsProperty(JmsConstants.JMS_PRIORITY))
370         {
371             to.setJMSPriority(from.getJMSPriority());
372         }
373         if (connector.supportsProperty(JmsConstants.JMS_REDELIVERED))
374         {
375             to.setJMSRedelivered(from.getJMSRedelivered());
376         }
377         if (connector.supportsProperty(JmsConstants.JMS_REPLY_TO))
378         {
379             to.setJMSReplyTo(from.getJMSReplyTo());
380         }
381         if (connector.supportsProperty(JmsConstants.JMS_TIMESTAMP))
382         {
383             to.setJMSTimestamp(from.getJMSTimestamp());
384         }
385         if (connector.supportsProperty(JmsConstants.JMS_TYPE))
386         {
387             to.setJMSType(from.getJMSType());
388         }
389         return to;
390     }
391 
392 }