View Javadoc

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