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