001    package com.mockrunner.mock.jms;
002    
003    import java.util.Arrays;
004    import java.util.Enumeration;
005    import java.util.HashMap;
006    import java.util.Iterator;
007    import java.util.Map;
008    import java.util.Vector;
009    
010    import javax.jms.JMSException;
011    import javax.jms.MapMessage;
012    import javax.jms.MessageFormatException;
013    import javax.jms.MessageNotWriteableException;
014    
015    import com.mockrunner.util.common.ArrayUtil;
016    
017    /**
018     * Mock implementation of JMS <code>MapMessage</code>.
019     */
020    public class MockMapMessage extends MockMessage implements MapMessage
021    {
022        private Map data;
023        
024        public MockMapMessage()
025        {
026            data = new HashMap();
027        }
028    
029        public boolean getBoolean(String name) throws JMSException
030        {
031            Object value = getObject(name);
032            if(null == value)
033            {
034                return Boolean.valueOf(null).booleanValue();
035            }
036            if(value instanceof Boolean)
037            {
038                return ((Boolean)value).booleanValue();
039            }
040            if(value instanceof String)
041            {
042                return Boolean.valueOf((String)value).booleanValue();
043            }
044            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to boolean");
045        }
046    
047        public byte getByte(String name) throws JMSException
048        {
049            Object value = getObject(name);
050            if(null == value)
051            {
052                return Byte.valueOf(null).byteValue();
053            }
054            if(value instanceof Byte)
055            {
056                return ((Byte)value).byteValue();
057            }
058            if(value instanceof String)
059            {
060                return Byte.valueOf((String)value).byteValue();
061            }
062            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to byte");
063        }
064    
065        public short getShort(String name) throws JMSException
066        {
067            Object value = getObject(name);
068            if(null == value)
069            {
070                return Short.valueOf(null).shortValue();
071            }
072            if((value instanceof Byte) || (value instanceof Short))
073            {
074                return ((Number)value).shortValue();
075            }
076            if(value instanceof String)
077            {
078                return Short.valueOf((String)value).shortValue();
079            }
080            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to short");
081        }
082    
083        public char getChar(String name) throws JMSException
084        {
085            Object value = getObject(name);
086            if(null == value)
087            {
088                throw new NullPointerException();
089            }
090            if(!(value instanceof Character))
091            {
092                throw new MessageFormatException(value.getClass().getName() + " cannot be converted to char");
093            }
094            return ((Character)value).charValue();
095        }
096    
097        public int getInt(String name) throws JMSException
098        {
099            Object value = getObject(name);
100            if(null == value)
101            {
102                return Integer.valueOf(null).intValue();
103            }
104            if((value instanceof Byte) || (value instanceof Short) || (value instanceof Integer))
105            {
106                return ((Number)value).intValue();
107            }
108            if(value instanceof String)
109            {
110                return Integer.valueOf((String)value).intValue();
111            }
112            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to int");
113        }
114    
115        public long getLong(String name) throws JMSException
116        {
117            Object value = getObject(name);
118            if(null == value)
119            {
120                return Long.valueOf(null).longValue();
121            }
122            if((value instanceof Byte) || (value instanceof Short) || (value instanceof Integer) || (value instanceof Long))
123            {
124                return ((Number)value).longValue();
125            }
126            if(value instanceof String)
127            {
128                return Long.valueOf((String)value).longValue();
129            }
130            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to long");
131        }
132    
133        public float getFloat(String name) throws JMSException
134        {
135            Object value = getObject(name);
136            if(null == value)
137            {
138                return Float.valueOf(null).floatValue();
139            }
140            if(value instanceof Float)
141            {
142                return ((Float)value).floatValue();
143            }
144            if(value instanceof String)
145            {
146                return Float.valueOf((String)value).floatValue();
147            }
148            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to float");
149        }
150    
151        public double getDouble(String name) throws JMSException
152        {
153            Object value = getObject(name);
154            if(null == value)
155            {
156                return Double.valueOf(null).doubleValue();
157            }
158            if((value instanceof Double) || (value instanceof Float))
159            {
160                return ((Number)value).doubleValue();
161            }
162            if(value instanceof String)
163            {
164                return Double.valueOf((String)value).doubleValue();
165            }
166            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to double");
167        }
168    
169        public String getString(String name) throws JMSException
170        {
171            Object value = getObject(name);
172            if(null == value)
173            {
174                return null;
175            }
176            if(value instanceof byte[])
177            {
178                throw new MessageFormatException(value.getClass().getName() + " cannot be converted to String");
179            }
180            return value.toString();
181        }
182    
183        public byte[] getBytes(String name) throws JMSException
184        {
185            Object value = getObject(name);
186            if(null == value)
187            {
188                throw new NullPointerException();
189            }
190            if(!(value instanceof byte[]))
191            {
192                throw new MessageFormatException(value.getClass().getName() + " cannot be converted to byte[]");
193            }
194            return (byte[])value;
195        }
196    
197        public Object getObject(String name) throws JMSException
198        {
199            return data.get(name);
200        }
201    
202        public Enumeration getMapNames() throws JMSException
203        {
204            return new Vector(data.keySet()).elements();
205        }
206    
207        public void setBoolean(String name, boolean value) throws JMSException
208        {
209            setObject(name, new Boolean(value));
210        }
211    
212        public void setByte(String name, byte value) throws JMSException
213        {
214            setObject(name, new Byte(value));
215        }
216    
217        public void setShort(String name, short value) throws JMSException
218        {
219            setObject(name, new Short(value));
220        }
221    
222        public void setChar(String name, char value) throws JMSException
223        {
224            setObject(name, new Character(value));
225        }
226    
227        public void setInt(String name, int value) throws JMSException
228        {
229            setObject(name, new Integer(value));
230        }
231    
232        public void setLong(String name, long value) throws JMSException
233        {
234            setObject(name, new Long(value));
235        }
236    
237        public void setFloat(String name, float value) throws JMSException
238        {
239            setObject(name, new Float(value));
240        }
241    
242        public void setDouble(String name, double value) throws JMSException
243        {
244            setObject(name, new Double(value));
245        }
246    
247        public void setString(String name, String value) throws JMSException
248        {
249            setObject(name, value);
250        }
251    
252        public void setBytes(String name, byte[] byteData) throws JMSException
253        {
254            byte[] copy = (byte[])byteData.clone();
255            setObject(name, copy);
256        }
257    
258        public void setBytes(String name, byte[] byteData, int offset, int length) throws JMSException
259        {
260            if(null == byteData)
261            {
262                setObject(name, null);
263                return;
264            }
265            setBytes(name, (byte[])ArrayUtil.truncateArray(byteData, offset, length));
266        }
267    
268        public void setObject(String name, Object object) throws JMSException
269        {
270            if(!isInWriteMode())
271            {
272                throw new MessageNotWriteableException("Message is in read mode");
273            }
274            if(null == name || name.length() <= 0)
275            {
276                throw new IllegalArgumentException("Property names must not be null or empty strings");
277            }
278            if(null == object) return;
279            if((object instanceof Number) || (object instanceof Boolean) || (object instanceof Character) || (object instanceof String) || (object instanceof byte[]))
280            {
281                data.put(name, object);
282                return;
283            }
284            throw new MessageFormatException(object.getClass().getName() + " not a valid type");
285        }
286    
287        public boolean itemExists(String name) throws JMSException
288        {
289            return data.containsKey(name);
290        }
291        
292        public void clearBody() throws JMSException
293        {
294            super.clearBody();
295            data.clear();
296        }
297        
298        /**
299         * Returns a copy of the underlying data as a <code>Map</code>
300         * regardless if the message is in read or write mode. Primitives
301         * are wrapped into their corresponding type.
302         * @return the <code>Map</code> data
303         */
304        public Map getMap()
305        {
306            Map map = new HashMap();
307            copyDataToMap(map);
308            return map;
309        }
310        
311        /**
312         * Compares the underlying map data.
313         */
314        public boolean equals(Object otherObject)
315        {
316            if(null == otherObject) return false;
317            if(!(otherObject instanceof MockMapMessage)) return false;
318            MockMapMessage otherMessage = (MockMapMessage)otherObject;
319            if(data.size() != otherMessage.data.size()) return false;
320            Iterator keys = data.keySet().iterator();
321            while(keys.hasNext())
322            {
323                Object nextKey = keys.next();
324                Object nextValue = data.get(nextKey);
325                Object otherValue = otherMessage.data.get(nextKey);
326                if(null == nextValue)
327                {
328                    if(null != otherValue) return false;
329                }
330                else if(nextValue instanceof byte[])
331                {
332                    if(null == otherValue) return false;
333                    if(!(otherValue instanceof byte[])) return false;
334                    if(!Arrays.equals((byte[])nextValue, (byte[])otherValue)) return false;
335                }
336                else
337                {
338                    if(!nextValue.equals(otherValue)) return false;
339                }
340            }
341            return true;
342        }
343    
344        public int hashCode()
345        {
346            int value = 17;
347            Iterator values = data.values().iterator();
348            while(values.hasNext())
349            {
350                Object nextValue = values.next();
351                if(nextValue instanceof byte[])
352                {
353                    for(int ii = 0; ii < ((byte[])nextValue).length; ii++)
354                    {
355                        value = (31 * value) + ((byte[])nextValue)[ii];
356                    }
357                }
358                else if(nextValue != null)
359                {
360                    value = (31 * value) + nextValue.hashCode();
361                }
362            }
363            return value;
364        }
365        
366        public Object clone()
367        {
368            MockMapMessage message = (MockMapMessage)super.clone();
369            message.data = new HashMap(data.size());
370            copyDataToMap(message.data);
371            return message;
372        }
373        
374        private void copyDataToMap(Map target)
375        {
376            Iterator keys = data.keySet().iterator();
377            while(keys.hasNext())
378            {
379                Object nextKey = keys.next();
380                Object nextValue = data.get(nextKey);
381                if(nextValue instanceof byte[])
382                {
383                    target.put(nextKey, ((byte[])nextValue).clone());
384                }
385                else
386                {
387                    target.put(nextKey, nextValue);
388                }
389            }
390        }
391        
392        public String toString()
393        {
394            return this.getClass().getName() + ": " + data.toString();
395        }
396    }