001    package com.mockrunner.mock.jms;
002    
003    import java.util.Arrays;
004    import java.util.Collections;
005    import java.util.Stack;
006    import java.util.Vector;
007    
008    import javax.jms.JMSException;
009    import javax.jms.MessageEOFException;
010    import javax.jms.MessageFormatException;
011    import javax.jms.MessageNotReadableException;
012    import javax.jms.MessageNotWriteableException;
013    import javax.jms.StreamMessage;
014    
015    import com.mockrunner.util.common.ArrayUtil;
016    
017    /**
018     * Mock implementation of JMS <code>StreamMessage</code>.
019     */
020    public class MockStreamMessage extends MockMessage implements StreamMessage
021    {
022        private Stack data;
023        
024        public MockStreamMessage()
025        {
026            data = new Stack();
027        }
028        
029        public boolean readBoolean() throws JMSException
030        {
031            if(isInWriteMode())
032            {
033                throw new MessageNotReadableException("Message is in write mode");
034            }
035            if(data.empty())
036            {
037                throw new MessageEOFException("No more data");
038            }
039            Object value = readObject();
040            if(null == value) return Boolean.valueOf(null).booleanValue();
041            if(value instanceof Boolean)
042            {
043                return ((Boolean)value).booleanValue();
044            }
045            if(value instanceof String)
046            {
047                return Boolean.valueOf((String)value).booleanValue();
048            }
049            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to boolean");
050        }
051    
052        public byte readByte() throws JMSException
053        {
054            if(isInWriteMode())
055            {
056                throw new MessageNotReadableException("Message is in write mode");
057            }
058            if(data.empty())
059            {
060                throw new MessageEOFException("No more data");
061            }
062            Object value = readObject();
063            if(null == value) return Byte.valueOf(null).byteValue();
064            if(value instanceof Byte)
065            {
066                return ((Byte)value).byteValue();
067            }
068            if(value instanceof String)
069            {
070                return Byte.valueOf((String)value).byteValue();
071            }
072            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to byte");
073        }
074    
075        public short readShort() throws JMSException
076        {
077            if(isInWriteMode())
078            {
079                throw new MessageNotReadableException("Message is in write mode");
080            }
081            if(data.empty())
082            {
083                throw new MessageEOFException("No more data");
084            }
085            Object value = readObject();
086            if(null == value) return Short.valueOf(null).shortValue();
087            if((value instanceof Byte) || (value instanceof Short))
088            {
089                return ((Number)value).shortValue();
090            }
091            if(value instanceof String)
092            {
093                return Short.valueOf((String)value).shortValue();
094            }
095            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to short");
096        }
097    
098        public char readChar() throws JMSException
099        {
100            if(isInWriteMode())
101            {
102                throw new MessageNotReadableException("Message is in write mode");
103            }
104            if(data.empty())
105            {
106                throw new MessageEOFException("No more data");
107            }
108            Object value = readObject();
109            if(null == value)
110            {
111                throw new NullPointerException();
112            }
113            if(value instanceof Character)
114            {
115                return ((Character)value).charValue();
116            }
117            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to char");
118        }
119    
120        public int readInt() throws JMSException
121        {
122            if(isInWriteMode())
123            {
124                throw new MessageNotReadableException("Message is in write mode");
125            }
126            if(data.empty())
127            {
128                throw new MessageEOFException("No more data");
129            }
130            Object value = readObject();
131            if(null == value) return Integer.valueOf(null).intValue();
132            if((value instanceof Byte) || (value instanceof Short) || (value instanceof Integer))
133            {
134                return ((Number)value).intValue();
135            }
136            if(value instanceof String)
137            {
138                return Integer.valueOf((String)value).intValue();
139            }
140            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to int");
141        }
142    
143        public long readLong() throws JMSException
144        {
145            if(isInWriteMode())
146            {
147                throw new MessageNotReadableException("Message is in write mode");
148            }
149            if(data.empty())
150            {
151                throw new MessageEOFException("No more data");
152            }
153            Object value = readObject();
154            if(null == value) return Long.valueOf(null).longValue();
155            if((value instanceof Byte) || (value instanceof Short) || (value instanceof Integer) || (value instanceof Long))
156            {
157                return ((Number)value).longValue();
158            }
159            if(value instanceof String)
160            {
161                return Long.valueOf((String)value).longValue();
162            }
163            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to long");
164        }
165    
166        public float readFloat() throws JMSException
167        {
168            if(isInWriteMode())
169            {
170                throw new MessageNotReadableException("Message is in write mode");
171            }
172            if(data.empty())
173            {
174                throw new MessageEOFException("No more data");
175            }
176            Object value = readObject();
177            if(null == value) return Float.valueOf(null).floatValue();
178            if(value instanceof Float)
179            {
180                return ((Float)value).floatValue();
181            }
182            if(value instanceof String)
183            {
184                return Float.valueOf((String)value).floatValue();
185            }
186            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to float");
187        }
188    
189        public double readDouble() throws JMSException
190        {
191            if(isInWriteMode())
192            {
193                throw new MessageNotReadableException("Message is in write mode");
194            }
195            if(data.empty())
196            {
197                throw new MessageEOFException("No more data");
198            }
199            Object value = readObject();
200            if(null == value) return Double.valueOf(null).doubleValue();
201            if((value instanceof Float) || (value instanceof Double))
202            {
203                return ((Number)value).doubleValue();
204            }
205            if(value instanceof String)
206            {
207                return Double.valueOf((String)value).doubleValue();
208            }
209            throw new MessageFormatException(value.getClass().getName() + " cannot be converted to double");
210        }
211    
212        public String readString() throws JMSException
213        {
214            if(isInWriteMode())
215            {
216                throw new MessageNotReadableException("Message is in write mode");
217            }
218            if(data.empty())
219            {
220                throw new MessageEOFException("No more data");
221            }
222            Object value = readObject();
223            if(null == value) return null;
224            if(value instanceof byte[])
225            {
226                throw new MessageFormatException(value.getClass().getName() + " cannot be converted to String");
227            }
228            return value.toString();
229        }
230    
231        public int readBytes(byte[] byteData) throws JMSException
232        {
233            if(isInWriteMode())
234            {
235                throw new MessageNotReadableException("Message is in write mode");
236            }
237            if(data.empty())
238            {
239                throw new MessageEOFException("No more data");
240            }
241            if(null == byteData) return -1;
242            if(0 == byteData.length) return 0;
243            Object value = readObject();
244            if(null == value)
245            {
246                throw new NullPointerException();
247            }
248            if(!(value instanceof byte[]))
249            {
250                throw new MessageFormatException(value.getClass().getName() + " cannot be converted to byte[]");
251            }
252            int length = Math.min(byteData.length, ((byte[])value).length);
253            System.arraycopy(value, 0, byteData, 0, length);
254            return length;
255        }
256    
257        public Object readObject() throws JMSException
258        {
259            if(isInWriteMode())
260            {
261                throw new MessageNotReadableException("Message is in write mode");
262            }
263            if(data.empty())
264            {
265                throw new MessageEOFException("No more data");
266            }
267            return data.pop();
268        }
269    
270        public void writeBoolean(boolean value) throws JMSException
271        {
272            if(!isInWriteMode())
273            {
274                throw new MessageNotWriteableException("Message is in read mode");
275            }
276            writeObject(new Boolean(value));
277        }
278    
279        public void writeByte(byte value) throws JMSException
280        {
281            if(!isInWriteMode())
282            {
283                throw new MessageNotWriteableException("Message is in read mode");
284            }
285            writeObject(new Byte(value));
286        }
287    
288        public void writeShort(short value) throws JMSException
289        {
290            if(!isInWriteMode())
291            {
292                throw new MessageNotWriteableException("Message is in read mode");
293            }
294            writeObject(new Short(value));
295        }
296    
297        public void writeChar(char value) throws JMSException
298        {
299            if(!isInWriteMode())
300            {
301                throw new MessageNotWriteableException("Message is in read mode");
302            }
303            writeObject(new Character(value));
304        }
305    
306        public void writeInt(int value) throws JMSException
307        {
308            if(!isInWriteMode())
309            {
310                throw new MessageNotWriteableException("Message is in read mode");
311            }
312            writeObject(new Integer(value));
313        }
314    
315        public void writeLong(long value) throws JMSException
316        {
317            if(!isInWriteMode())
318            {
319                throw new MessageNotWriteableException("Message is in read mode");
320            }
321            writeObject(new Long(value));
322        }
323    
324        public void writeFloat(float value) throws JMSException
325        {
326            if(!isInWriteMode())
327            {
328                throw new MessageNotWriteableException("Message is in read mode");
329            }
330            writeObject(new Float(value));
331        }
332    
333        public void writeDouble(double value) throws JMSException
334        {
335            if(!isInWriteMode())
336            {
337                throw new MessageNotWriteableException("Message is in read mode");
338            }
339            writeObject(new Double(value));
340        }
341    
342        public void writeString(String value) throws JMSException
343        {
344            if(!isInWriteMode())
345            {
346                throw new MessageNotWriteableException("Message is in read mode");
347            }
348            writeObject(value);
349        }
350    
351        public void writeBytes(byte[] data) throws JMSException
352        {
353            if(!isInWriteMode())
354            {
355                throw new MessageNotWriteableException("Message is in read mode");
356            }
357            writeObject(data);
358        }
359    
360        public void writeBytes(byte[] data, int offset, int length) throws JMSException
361        {
362            if(!isInWriteMode())
363            {
364                throw new MessageNotWriteableException("Message is in read mode");
365            }
366            if(null == data)
367            {
368                writeObject(null);
369                return;
370            }
371            writeObject(ArrayUtil.truncateArray(data, offset, length));
372        }
373    
374        public void writeObject(Object object) throws JMSException
375        {
376            if(!isInWriteMode())
377            {
378                throw new MessageNotWriteableException("Message is in read mode");
379            }
380            if(null == object)
381            {
382                data.push(object);
383                return;
384            }
385            if((object instanceof String) || (object instanceof Number) || (object instanceof Character) || (object instanceof Boolean))
386            {
387                data.push(object);
388                return;
389            }
390            if(object instanceof byte[])
391            {
392                byte[] arrayData = (byte[])((byte[])object).clone();
393                data.push(arrayData);
394                return;
395            }
396            throw new MessageFormatException(object.getClass() + " not a valid type");
397        }
398    
399        public void reset() throws JMSException
400        {
401            setReadOnly(true);
402            Collections.reverse(data);
403        }
404    
405        public void clearBody() throws JMSException
406        {
407            super.clearBody();
408            data = new Stack();
409        }
410        
411        /**
412         * Compares the underlying stream data.
413         */
414        public boolean equals(Object otherObject)
415        {
416            if(null == otherObject) return false;
417            if(!(otherObject instanceof MockStreamMessage)) return false;
418            MockStreamMessage otherMessage = (MockStreamMessage)otherObject;
419            if(data.size() != otherMessage.data.size()) return false;
420            Vector otherData = otherMessage.data;
421            if(isInWriteMode() != otherMessage.isInWriteMode())
422            {
423                otherData = new Vector(otherData);
424                Collections.reverse(otherData);
425            }
426            for(int ii = 0; ii < data.size(); ii++)
427            {
428                Object nextValue = data.get(ii);
429                Object otherValue = otherData.get(ii);
430                if(null == nextValue)
431                {
432                    if(null != otherValue) return false;
433                }
434                else if(nextValue instanceof byte[])
435                {
436                    if(null == otherValue) return false;
437                    if(!(otherValue instanceof byte[])) return false;
438                    if(!Arrays.equals((byte[])nextValue, (byte[])otherValue)) return false;
439                }
440                else
441                {
442                    if(!nextValue.equals(otherValue)) return false;
443                }
444            }
445            return true;
446        }
447    
448        public int hashCode()
449        {
450            int value = 0;
451            for(int ii = 0; ii < data.size(); ii++)
452            {
453                Object nextValue = data.get(ii);
454                if(nextValue instanceof byte[])
455                {
456                    for(int yy = 0; yy < ((byte[])nextValue).length; yy++)
457                    {
458                        value += 31 * ((byte[])nextValue)[yy];
459                    }
460                }
461                else if(nextValue != null)
462                {
463                    value += 31 * nextValue.hashCode();
464                }
465            }
466            return value;
467        }
468        
469        public Object clone()
470        {
471            MockStreamMessage message = (MockStreamMessage)super.clone();
472            message.data = new Stack();
473            for(int ii = 0; ii < data.size(); ii++)
474            {
475                Object nextValue = data.get(ii);
476                if(nextValue instanceof byte[])
477                {
478                    message.data.add(((byte[])nextValue).clone());
479                }
480                else
481                {
482                    message.data.add(nextValue);
483                }
484            }
485            return message;
486        }
487    
488        public String toString()
489        {
490            return this.getClass().getName() + ": " + data.toString();
491        }
492    }