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 }