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.io.Reader; 008 import java.io.StringReader; 009 import java.io.UnsupportedEncodingException; 010 import java.io.Writer; 011 import java.sql.Clob; 012 import java.sql.SQLException; 013 014 import com.mockrunner.base.NestedApplicationException; 015 016 /** 017 * Mock implementation of <code>Clob</code>. 018 */ 019 public class MockClob implements Clob, Cloneable 020 { 021 private StringBuffer clobData; 022 private boolean wasFreeCalled; 023 024 public MockClob(String data) 025 { 026 clobData = new StringBuffer(data); 027 wasFreeCalled = false; 028 } 029 030 public long length() throws SQLException 031 { 032 return clobData.length(); 033 } 034 035 public void truncate(long len) throws SQLException 036 { 037 if(wasFreeCalled) 038 { 039 throw new SQLException("free() was called"); 040 } 041 clobData.setLength((int)len); 042 } 043 044 public InputStream getAsciiStream() throws SQLException 045 { 046 if(wasFreeCalled) 047 { 048 throw new SQLException("free() was called"); 049 } 050 try 051 { 052 return new ByteArrayInputStream(clobData.toString().getBytes("ISO-8859-1")); 053 } 054 catch(UnsupportedEncodingException exc) 055 { 056 throw new NestedApplicationException(exc); 057 } 058 } 059 060 public OutputStream setAsciiStream(long pos) throws SQLException 061 { 062 if(wasFreeCalled) 063 { 064 throw new SQLException("free() was called"); 065 } 066 return new ClobOutputStream((int)(pos - 1)); 067 } 068 069 public Reader getCharacterStream() throws SQLException 070 { 071 if(wasFreeCalled) 072 { 073 throw new SQLException("free() was called"); 074 } 075 return new StringReader(clobData.toString()); 076 } 077 078 public Reader getCharacterStream(long pos, long length) throws SQLException 079 { 080 if(wasFreeCalled) 081 { 082 throw new SQLException("free() was called"); 083 } 084 length = verifyAndFixLength(pos, (int)length); 085 return new StringReader(getSubString(pos, (int)length)); 086 } 087 088 public Writer setCharacterStream(long pos) throws SQLException 089 { 090 if(wasFreeCalled) 091 { 092 throw new SQLException("free() was called"); 093 } 094 return new ClobWriter((int)(pos - 1)); 095 } 096 097 public String getSubString(long pos, int length) throws SQLException 098 { 099 if(wasFreeCalled) 100 { 101 throw new SQLException("free() was called"); 102 } 103 length = verifyAndFixLength(pos, length); 104 return clobData.substring((int)(pos - 1), (int)(pos - 1) + length); 105 } 106 107 public int setString(long pos, String str) throws SQLException 108 { 109 return setString(pos, str, 0, str.length()); 110 } 111 112 public int setString(long pos, String str, int offset, int len) throws SQLException 113 { 114 if(wasFreeCalled) 115 { 116 throw new SQLException("free() was called"); 117 } 118 str = str.substring(offset, offset + len); 119 clobData.replace((int)(pos - 1), (int)(pos - 1) + str.length(), str); 120 return len; 121 } 122 123 public long position(String searchstr, long start) throws SQLException 124 { 125 if(wasFreeCalled) 126 { 127 throw new SQLException("free() was called"); 128 } 129 int index = clobData.toString().indexOf(searchstr, (int)(start - 1)); 130 if(-1 != index) index += 1; 131 return index; 132 } 133 134 public long position(Clob searchClob, long start) throws SQLException 135 { 136 return position(searchClob.getSubString(1, (int)searchClob.length()), start); 137 } 138 139 public void free() throws SQLException 140 { 141 wasFreeCalled = true; 142 } 143 144 /** 145 * Returns if {@link #free} has been called. 146 * @return <code>true</code> if {@link #free} has been called, 147 * <code>false</code> otherwise 148 */ 149 public boolean wasFreeCalled() 150 { 151 return wasFreeCalled; 152 } 153 154 public boolean equals(Object obj) 155 { 156 if(null == obj) return false; 157 if(!obj.getClass().equals(this.getClass())) return false; 158 MockClob other = (MockClob)obj; 159 if(wasFreeCalled != other.wasFreeCalled()) return false; 160 return clobData.toString().equals(other.clobData.toString()); 161 } 162 163 public int hashCode() 164 { 165 int hashCode = clobData.toString().hashCode(); 166 hashCode = (31 * hashCode) + (wasFreeCalled ? 31 : 62); 167 return hashCode; 168 } 169 170 public String toString() 171 { 172 return "Clob data: " + clobData.toString(); 173 } 174 175 public Object clone() 176 { 177 try 178 { 179 MockClob clone = (MockClob)super.clone(); 180 clone.clobData = new StringBuffer(clobData.toString()); 181 return clone; 182 } 183 catch(CloneNotSupportedException exc) 184 { 185 throw new NestedApplicationException(exc); 186 } 187 } 188 189 private int verifyAndFixLength(long pos, int length) 190 { 191 if(length < 0) 192 { 193 throw new IllegalArgumentException("length must be greater or equals 0"); 194 } 195 if((length + (pos - 1)) > clobData.length()) 196 { 197 return clobData.length() - (int)(pos - 1); 198 } 199 return length; 200 } 201 202 private class ClobWriter extends Writer 203 { 204 private int index; 205 206 public ClobWriter(int index) 207 { 208 this.index = index; 209 } 210 211 public void close() throws IOException 212 { 213 214 } 215 216 public void flush() throws IOException 217 { 218 219 } 220 221 public void write(char[] cbuf, int off, int len) throws IOException 222 { 223 try 224 { 225 setString(index + 1, new String(cbuf, off, len)); 226 } 227 catch(SQLException exc) 228 { 229 throw new IOException(exc.getMessage()); 230 } 231 index++; 232 } 233 } 234 235 private class ClobOutputStream extends OutputStream 236 { 237 private int index; 238 239 public ClobOutputStream(int index) 240 { 241 this.index = index; 242 } 243 244 public void write(int byteValue) throws IOException 245 { 246 byte[] bytes = new byte[] {(byte)byteValue}; 247 try 248 { 249 setString(index + 1, new String(bytes)); 250 } 251 catch(SQLException exc) 252 { 253 throw new IOException(exc.getMessage()); 254 } 255 index++; 256 } 257 } 258 }