001 package com.mockrunner.mock.jdbc;
002
003 import java.io.ByteArrayInputStream;
004 import java.io.IOException;
005 import java.io.InputStream;
006 import java.io.OutputStream;
007 import java.sql.Blob;
008 import java.sql.SQLException;
009 import java.util.ArrayList;
010 import java.util.List;
011
012 import com.mockrunner.base.NestedApplicationException;
013 import com.mockrunner.util.common.ArrayUtil;
014 import com.mockrunner.util.common.CollectionUtil;
015
016 /**
017 * Mock implementation of <code>Blob</code>.
018 */
019 public class MockBlob implements Blob, Cloneable
020 {
021 private List blobData;
022 private boolean wasFreeCalled;
023
024 public MockBlob(byte[] data)
025 {
026 blobData = ArrayUtil.getListFromByteArray(data);
027 wasFreeCalled = false;
028 }
029
030 public long length() throws SQLException
031 {
032 if(wasFreeCalled)
033 {
034 throw new SQLException("free() was called");
035 }
036 return blobData.size();
037 }
038
039 public byte[] getBytes(long pos, int length) throws SQLException
040 {
041 if(wasFreeCalled)
042 {
043 throw new SQLException("free() was called");
044 }
045 length = verifyAndFixLength(pos, length);
046 return ArrayUtil.getByteArrayFromList(blobData, (int)(pos - 1), length);
047 }
048
049 public InputStream getBinaryStream() throws SQLException
050 {
051 if(wasFreeCalled)
052 {
053 throw new SQLException("free() was called");
054 }
055 return new ByteArrayInputStream(ArrayUtil.getByteArrayFromList(blobData));
056 }
057
058 public InputStream getBinaryStream(long pos, long length) throws SQLException
059 {
060 if(wasFreeCalled)
061 {
062 throw new SQLException("free() was called");
063 }
064 length = verifyAndFixLength(pos, (int)length);
065 return new ByteArrayInputStream(ArrayUtil.getByteArrayFromList(blobData, (int)(pos - 1), (int)length));
066 }
067
068 public long position(byte[] pattern, long start) throws SQLException
069 {
070 if(wasFreeCalled)
071 {
072 throw new SQLException("free() was called");
073 }
074 byte[] data = ArrayUtil.getByteArrayFromList(blobData);
075 int index = ArrayUtil.indexOf(data, pattern, (int)(start - 1));
076 if(-1 != index) index += 1;
077 return index;
078 }
079
080 public long position(Blob pattern, long start) throws SQLException
081 {
082 return position(pattern.getBytes(1, (int)pattern.length()), start);
083 }
084
085 public int setBytes(long pos, byte[] bytes) throws SQLException
086 {
087 if(wasFreeCalled)
088 {
089 throw new SQLException("free() was called");
090 }
091 ArrayUtil.addBytesToList(bytes, blobData, (int)(pos - 1));
092 return bytes.length;
093 }
094
095 public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException
096 {
097 if(wasFreeCalled)
098 {
099 throw new SQLException("free() was called");
100 }
101 ArrayUtil.addBytesToList(bytes, offset, len, blobData, (int)(pos - 1));
102 return len;
103 }
104
105 public OutputStream setBinaryStream(long pos) throws SQLException
106 {
107 if(wasFreeCalled)
108 {
109 throw new SQLException("free() was called");
110 }
111 return new BlobOutputStream((int)(pos - 1));
112 }
113
114 public void truncate(long len) throws SQLException
115 {
116 if(wasFreeCalled)
117 {
118 throw new SQLException("free() was called");
119 }
120 blobData = CollectionUtil.truncateList(blobData, (int)len);
121 }
122
123 public void free() throws SQLException
124 {
125 wasFreeCalled = true;
126 }
127
128 /**
129 * Returns if {@link #free} has been called.
130 * @return <code>true</code> if {@link #free} has been called,
131 * <code>false</code> otherwise
132 */
133 public boolean wasFreeCalled()
134 {
135 return wasFreeCalled;
136 }
137
138 public boolean equals(Object obj)
139 {
140 if(null == obj) return false;
141 if(!obj.getClass().equals(this.getClass())) return false;
142 MockBlob other = (MockBlob)obj;
143 if(wasFreeCalled != other.wasFreeCalled()) return false;
144 return blobData.equals(other.blobData);
145 }
146
147 public int hashCode()
148 {
149 int hashCode = blobData.hashCode();
150 hashCode = (31 * hashCode) + (wasFreeCalled ? 31 : 62);
151 return hashCode;
152 }
153
154 public String toString()
155 {
156 return "Blob data: " + blobData.toString();
157 }
158
159 public Object clone()
160 {
161 try
162 {
163 MockBlob blob = (MockBlob)super.clone();
164 blob.blobData = new ArrayList(blobData);
165 return blob;
166 }
167 catch(CloneNotSupportedException exc)
168 {
169 throw new NestedApplicationException(exc);
170 }
171 }
172
173 private int verifyAndFixLength(long pos, int length)
174 {
175 if(length < 0)
176 {
177 throw new IllegalArgumentException("length must be greater or equals 0");
178 }
179 if((length + (pos - 1)) > blobData.size())
180 {
181 return blobData.size() - (int)(pos - 1);
182 }
183 return length;
184 }
185
186 private class BlobOutputStream extends OutputStream
187 {
188 private int index;
189
190 public BlobOutputStream(int index)
191 {
192 this.index = index;
193 }
194
195 public void write(int byteValue) throws IOException
196 {
197 byte[] bytes = new byte[] {(byte)byteValue};
198 ArrayUtil.addBytesToList(bytes, blobData, index);
199 index++;
200 }
201 }
202 }