View Javadoc

1   /*
2    * $Id: JmsMessageUtils.java 8553 2007-09-22 19:47:56Z aperepel $
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.ClassUtils;
15  import org.mule.util.StringUtils;
16  
17  import java.io.IOException;
18  import java.io.InputStream;
19  import java.io.ObjectOutputStream;
20  import java.io.Serializable;
21  import java.util.Enumeration;
22  import java.util.Hashtable;
23  import java.util.Iterator;
24  import java.util.Map;
25  import java.util.Vector;
26  
27  import javax.jms.BytesMessage;
28  import javax.jms.Destination;
29  import javax.jms.JMSException;
30  import javax.jms.MapMessage;
31  import javax.jms.Message;
32  import javax.jms.MessageEOFException;
33  import javax.jms.ObjectMessage;
34  import javax.jms.Queue;
35  import javax.jms.Session;
36  import javax.jms.StreamMessage;
37  import javax.jms.TextMessage;
38  import javax.jms.Topic;
39  
40  import org.apache.commons.io.output.ByteArrayOutputStream;
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 byte[])
136         {
137             BytesMessage bMsg = session.createBytesMessage();
138             bMsg.writeBytes((byte[])object);
139             return bMsg;
140         }
141         else if (object instanceof Serializable)
142         {
143             ObjectMessage oMsg = session.createObjectMessage();
144             oMsg.setObject((Serializable)object);
145             return oMsg;
146         }
147         else
148         {
149             throw new JMSException(
150                 "Source was not of a supported type, data must be Serializable, String, byte[], Map or InputStream, " +
151                 "but was " + ClassUtils.getShortClassName(object, "<null>"));
152         }
153     }
154 
155     public static Object toObject(Message source, String jmsSpec) throws JMSException, IOException
156     {
157         if (source instanceof ObjectMessage)
158         {
159             return ((ObjectMessage)source).getObject();
160         }
161         else if (source instanceof MapMessage)
162         {
163             Hashtable map = new Hashtable();
164             MapMessage m = (MapMessage)source;
165 
166             for (Enumeration e = m.getMapNames(); e.hasMoreElements();)
167             {
168                 String name = (String)e.nextElement();
169                 Object obj = m.getObject(name);
170                 map.put(name, obj);
171             }
172 
173             return map;
174         }
175         else if (source instanceof TextMessage)
176         {
177             return ((TextMessage)source).getText();
178         }
179         else if (source instanceof BytesMessage)
180         {
181             return toByteArray(source, jmsSpec);
182         }
183         else if (source instanceof StreamMessage)
184         {
185             try
186             {
187                 StreamMessage sMsg = (StreamMessage)source;
188                 Vector result = new Vector();
189                 Object obj;
190                 while ((obj = sMsg.readObject()) != null)
191                 {
192                     result.addElement(obj);
193                 }
194                 return result;
195             }
196             catch (MessageEOFException eof)
197             {
198                 // ignored
199             }
200             catch (Exception e)
201             {
202                 throw new JMSException("Failed to extract information from JMS Stream Message: " + e);
203             }
204         }
205 
206         // what else is there to do?
207         return source;
208     }
209 
210     /**
211      * @param message the message to receive the bytes from. Note this only works for
212      *            TextMessge, ObjectMessage, StreamMessage and BytesMessage.
213      * @param jmsSpec indicates the JMS API version, either
214      *            {@link JmsConstants#JMS_SPECIFICATION_102B} or
215      *            {@link JmsConstants#JMS_SPECIFICATION_11}. Any other value
216      *            including <code>null</code> is treated as fallback to
217      *            {@link JmsConstants#JMS_SPECIFICATION_102B}.
218      * @return a byte array corresponding with the message payload
219      * @throws JMSException if the message can't be read or if the message passed is
220      *             a MapMessage
221      * @throws java.io.IOException if a failure occurs while reading the stream and
222      *             converting the message data
223      */
224     public static byte[] toByteArray(Message message, String jmsSpec) throws JMSException, IOException
225     {
226         if (message instanceof BytesMessage)
227         {
228             BytesMessage bMsg = (BytesMessage)message;
229             bMsg.reset();
230 
231             if (JmsConstants.JMS_SPECIFICATION_11.equals(jmsSpec))
232             {
233                 long bmBodyLength = bMsg.getBodyLength();
234                 if (bmBodyLength > Integer.MAX_VALUE)
235                 {
236                     throw new JMSException("Size of BytesMessage exceeds Integer.MAX_VALUE; "
237                                            + "please consider using JMS StreamMessage instead");
238                 }
239 
240                 if (bmBodyLength > 0)
241                 {
242                     byte[] bytes = new byte[(int)bmBodyLength];
243                     bMsg.readBytes(bytes);
244                     return bytes;
245                 }
246                 else
247                 {
248                     return ArrayUtils.EMPTY_BYTE_ARRAY;
249                 }
250             }
251             else
252             {
253                 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
254                 byte[] buffer = new byte[4096];
255                 int len;
256 
257                 while ((len = bMsg.readBytes(buffer)) != -1)
258                 {
259                     baos.write(buffer, 0, len);
260                 }
261 
262                 if (baos.size() > 0)
263                 {
264                     return baos.toByteArray();
265                 }
266                 else
267                 {
268                     return ArrayUtils.EMPTY_BYTE_ARRAY;
269                 }
270             }
271         }
272         else if (message instanceof StreamMessage)
273         {
274             StreamMessage sMsg = (StreamMessage)message;
275             sMsg.reset();
276 
277             ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
278             byte[] buffer = new byte[4096];
279             int len;
280 
281             while ((len = sMsg.readBytes(buffer)) != -1)
282             {
283                 baos.write(buffer, 0, len);
284             }
285 
286             return baos.toByteArray();
287         }
288         else if (message instanceof ObjectMessage)
289         {
290             ObjectMessage oMsg = (ObjectMessage)message;
291             ByteArrayOutputStream baos = new ByteArrayOutputStream();
292             ObjectOutputStream os = new ObjectOutputStream(baos);
293             os.writeObject(oMsg.getObject());
294             os.flush();
295             os.close();
296             return baos.toByteArray();
297         }
298         else if (message instanceof TextMessage)
299         {
300             TextMessage tMsg = (TextMessage)message;
301             String tMsgText = tMsg.getText();
302 
303             if (null == tMsgText)
304             {
305                 // Avoid creating new instances of byte arrays, even empty ones. The
306                 // load on this part of the code can be high.
307                 return ArrayUtils.EMPTY_BYTE_ARRAY;
308             }
309             else
310             {
311                 return tMsgText.getBytes();
312             }
313         }
314         else
315         {
316             throw new JMSException("Cannot get bytes from Map Message");
317         }
318     }
319 
320     public static String getNameForDestination(Destination dest) throws JMSException
321     {
322         if (dest instanceof Queue)
323         {
324             return ((Queue)dest).getQueueName();
325         }
326         else if (dest instanceof Topic)
327         {
328             return ((Topic)dest).getTopicName();
329         }
330         else
331         {
332             return null;
333         }
334     }
335 
336     public static Message copyJMSProperties(Message from, Message to, JmsConnector connector)
337         throws JMSException
338     {
339         if (connector.supportsProperty(JmsConstants.JMS_CORRELATION_ID))
340         {
341             to.setJMSCorrelationID(from.getJMSCorrelationID());
342         }
343         if (connector.supportsProperty(JmsConstants.JMS_DELIVERY_MODE))
344         {
345             to.setJMSDeliveryMode(from.getJMSDeliveryMode());
346         }
347         if (connector.supportsProperty(JmsConstants.JMS_DESTINATION))
348         {
349             to.setJMSDestination(from.getJMSDestination());
350         }
351         if (connector.supportsProperty(JmsConstants.JMS_EXPIRATION))
352         {
353             to.setJMSExpiration(from.getJMSExpiration());
354         }
355         if (connector.supportsProperty(JmsConstants.JMS_MESSAGE_ID))
356         {
357             to.setJMSMessageID(from.getJMSMessageID());
358         }
359         if (connector.supportsProperty(JmsConstants.JMS_PRIORITY))
360         {
361             to.setJMSPriority(from.getJMSPriority());
362         }
363         if (connector.supportsProperty(JmsConstants.JMS_REDELIVERED))
364         {
365             to.setJMSRedelivered(from.getJMSRedelivered());
366         }
367         if (connector.supportsProperty(JmsConstants.JMS_REPLY_TO))
368         {
369             to.setJMSReplyTo(from.getJMSReplyTo());
370         }
371         if (connector.supportsProperty(JmsConstants.JMS_TIMESTAMP))
372         {
373             to.setJMSTimestamp(from.getJMSTimestamp());
374         }
375         if (connector.supportsProperty(JmsConstants.JMS_TYPE))
376         {
377             to.setJMSType(from.getJMSType());
378         }
379         return to;
380     }
381 
382 }