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 }