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 }