001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.dbutils; 018 019 import java.lang.reflect.InvocationHandler; 020 import java.lang.reflect.Method; 021 import java.sql.ResultSet; 022 import java.sql.ResultSetMetaData; 023 import java.sql.SQLException; 024 import java.util.Arrays; 025 import java.util.Collections; 026 import java.util.Iterator; 027 028 /** 029 * MockResultSet dynamically implements the ResultSet interface. 030 */ 031 public class MockResultSet implements InvocationHandler { 032 033 /** 034 * Create a <code>MockResultSet</code> proxy object. This is equivalent to: 035 * <pre> 036 * ProxyFactory.instance().createResultSet(new MockResultSet(metaData, rows)); 037 * </pre> 038 * 039 * @param metaData 040 * @param rows A null value indicates an empty <code>ResultSet</code>. 041 */ 042 public static ResultSet create(ResultSetMetaData metaData, 043 Object[][] rows) { 044 return ProxyFactory.instance().createResultSet( 045 new MockResultSet(metaData, rows)); 046 } 047 048 private Object[] currentRow = null; 049 050 private Iterator iter = null; 051 052 private ResultSetMetaData metaData = null; 053 054 private Boolean wasNull = Boolean.FALSE; 055 056 /** 057 * MockResultSet constructor. 058 * @param metaData 059 * @param rows A null value indicates an empty <code>ResultSet</code>. 060 */ 061 public MockResultSet(ResultSetMetaData metaData, Object[][] rows) { 062 super(); 063 this.metaData = metaData; 064 this.iter = (rows == null) 065 ? Collections.EMPTY_LIST.iterator() 066 : Arrays.asList(rows).iterator(); 067 } 068 069 /** 070 * The get* methods can have an int column index or a String column name as 071 * the parameter. This method handles both cases and returns the column 072 * index that the client is trying to get at. 073 * @param args 074 * @return A column index. 075 * @throws SQLException if a database access error occurs 076 */ 077 private int columnIndex(Object[] args) throws SQLException { 078 079 if (args[0] instanceof Integer) { 080 return ((Integer) args[0]).intValue(); 081 082 } else if (args[0] instanceof String) { 083 return this.columnNameToIndex((String) args[0]); 084 085 } else { 086 throw new SQLException(args[0] + " must be Integer or String"); 087 } 088 } 089 090 /** 091 * Returns the column index for the given column name. 092 * @return A 1 based index 093 * @throws SQLException if the column name is invalid 094 */ 095 private int columnNameToIndex(String columnName) throws SQLException { 096 for (int i = 0; i < this.currentRow.length; i++) { 097 int c = i + 1; 098 if (this.metaData.getColumnName(c).equalsIgnoreCase(columnName)) { 099 return c; 100 } 101 } 102 103 throw new SQLException(columnName + " is not a valid column name."); 104 } 105 106 /** 107 * Gets the boolean value at the given column index. 108 * @param columnIndex A 1 based index. 109 * @throws SQLException if a database access error occurs 110 */ 111 protected Object getBoolean(int columnIndex) throws SQLException { 112 Object obj = this.currentRow[columnIndex - 1]; 113 this.setWasNull(obj); 114 115 try { 116 return (obj == null) 117 ? Boolean.FALSE 118 : Boolean.valueOf(obj.toString()); 119 120 } catch (NumberFormatException e) { 121 throw new SQLException(e.getMessage()); 122 } 123 } 124 125 /** 126 * Gets the byte value at the given column index. 127 * @param columnIndex A 1 based index. 128 * @throws SQLException if a database access error occurs 129 */ 130 protected Object getByte(int columnIndex) throws SQLException { 131 Object obj = this.currentRow[columnIndex - 1]; 132 this.setWasNull(obj); 133 134 try { 135 return (obj == null) 136 ? new Byte((byte) 0) 137 : Byte.valueOf(obj.toString()); 138 139 } catch (NumberFormatException e) { 140 throw new SQLException(e.getMessage()); 141 } 142 } 143 144 /** 145 * Gets the double value at the given column index. 146 * @param columnIndex A 1 based index. 147 * @throws SQLException if a database access error occurs 148 */ 149 protected Object getDouble(int columnIndex) throws SQLException { 150 Object obj = this.currentRow[columnIndex - 1]; 151 this.setWasNull(obj); 152 153 try { 154 return (obj == null) 155 ? new Double(0) 156 : Double.valueOf(obj.toString()); 157 158 } catch (NumberFormatException e) { 159 throw new SQLException(e.getMessage()); 160 } 161 } 162 163 /** 164 * Gets the float value at the given column index. 165 * @param columnIndex A 1 based index. 166 * @throws SQLException if a database access error occurs 167 */ 168 protected Object getFloat(int columnIndex) throws SQLException { 169 Object obj = this.currentRow[columnIndex - 1]; 170 this.setWasNull(obj); 171 172 try { 173 return (obj == null) ? new Float(0) : Float.valueOf(obj.toString()); 174 175 } catch (NumberFormatException e) { 176 throw new SQLException(e.getMessage()); 177 } 178 } 179 180 /** 181 * Gets the int value at the given column index. 182 * @param columnIndex A 1 based index. 183 * @throws SQLException if a database access error occurs 184 */ 185 protected Object getInt(int columnIndex) throws SQLException { 186 Object obj = this.currentRow[columnIndex - 1]; 187 this.setWasNull(obj); 188 189 try { 190 return (obj == null) 191 ? new Integer(0) 192 : Integer.valueOf(obj.toString()); 193 194 } catch (NumberFormatException e) { 195 throw new SQLException(e.getMessage()); 196 } 197 } 198 199 /** 200 * Gets the long value at the given column index. 201 * @param columnIndex A 1 based index. 202 * @throws SQLException if a database access error occurs 203 */ 204 protected Object getLong(int columnIndex) throws SQLException { 205 Object obj = this.currentRow[columnIndex - 1]; 206 this.setWasNull(obj); 207 208 try { 209 return (obj == null) ? new Long(0) : Long.valueOf(obj.toString()); 210 211 } catch (NumberFormatException e) { 212 throw new SQLException(e.getMessage()); 213 } 214 } 215 216 protected ResultSetMetaData getMetaData() throws SQLException { 217 return this.metaData; 218 } 219 220 /** 221 * Gets the object at the given column index. 222 * @param columnIndex A 1 based index. 223 * @throws SQLException if a database access error occurs 224 */ 225 protected Object getObject(int columnIndex) throws SQLException { 226 Object obj = this.currentRow[columnIndex - 1]; 227 this.setWasNull(obj); 228 return obj; 229 } 230 231 /** 232 * Gets the short value at the given column index. 233 * @param columnIndex A 1 based index. 234 * @throws SQLException if a database access error occurs 235 */ 236 protected Object getShort(int columnIndex) throws SQLException { 237 Object obj = this.currentRow[columnIndex - 1]; 238 this.setWasNull(obj); 239 240 try { 241 return (obj == null) 242 ? new Short((short) 0) 243 : Short.valueOf(obj.toString()); 244 245 } catch (NumberFormatException e) { 246 throw new SQLException(e.getMessage()); 247 } 248 } 249 250 /** 251 * Gets the String at the given column index. 252 * @param columnIndex A 1 based index. 253 * @throws SQLException if a database access error occurs 254 */ 255 protected String getString(int columnIndex) throws SQLException { 256 Object obj = this.getObject(columnIndex); 257 this.setWasNull(obj); 258 return (obj == null) ? null : obj.toString(); 259 } 260 261 public Object invoke(Object proxy, Method method, Object[] args) 262 throws Throwable { 263 264 String methodName = method.getName(); 265 266 if (methodName.equals("getMetaData")) { 267 return this.getMetaData(); 268 269 } else if (methodName.equals("next")) { 270 return this.next(); 271 272 } else if (methodName.equals("previous")) { 273 274 } else if (methodName.equals("close")) { 275 276 } else if (methodName.equals("getBoolean")) { 277 return this.getBoolean(columnIndex(args)); 278 279 } else if (methodName.equals("getByte")) { 280 return this.getByte(columnIndex(args)); 281 282 } else if (methodName.equals("getDouble")) { 283 return this.getDouble(columnIndex(args)); 284 285 } else if (methodName.equals("getFloat")) { 286 return this.getFloat(columnIndex(args)); 287 288 } else if (methodName.equals("getInt")) { 289 return this.getInt(columnIndex(args)); 290 291 } else if (methodName.equals("getLong")) { 292 return this.getLong(columnIndex(args)); 293 294 } else if (methodName.equals("getObject")) { 295 return this.getObject(columnIndex(args)); 296 297 } else if (methodName.equals("getShort")) { 298 return this.getShort(columnIndex(args)); 299 300 } else if (methodName.equals("getString")) { 301 return this.getString(columnIndex(args)); 302 303 } else if (methodName.equals("wasNull")) { 304 return this.wasNull(); 305 306 } else if (methodName.equals("isLast")) { 307 return this.isLast(); 308 309 } else if (methodName.equals("hashCode")) { 310 return new Integer(System.identityHashCode(proxy)); 311 312 } else if (methodName.equals("toString")) { 313 return "MockResultSet " + System.identityHashCode(proxy); 314 315 } else if (methodName.equals("equals")) { 316 return new Boolean(proxy == args[0]); 317 } 318 319 throw new UnsupportedOperationException("Unsupported method: " + methodName); 320 } 321 322 protected Boolean isLast() throws SQLException { 323 return this.iter.hasNext() ? Boolean.FALSE : Boolean.TRUE; 324 } 325 326 protected Boolean next() throws SQLException { 327 if (!this.iter.hasNext()) { 328 return Boolean.FALSE; 329 } else { 330 this.currentRow = (Object[]) iter.next(); 331 return Boolean.TRUE; 332 } 333 } 334 335 /** 336 * Assigns this.wasNull a Boolean value based on the object passed in. 337 * @param isNull 338 */ 339 private void setWasNull(Object isNull) { 340 this.wasNull = (isNull == null) ? Boolean.TRUE : Boolean.FALSE; 341 } 342 343 protected Boolean wasNull() throws SQLException { 344 return this.wasNull; 345 } 346 }