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) ? Collections.EMPTY_LIST.iterator()
065: : Arrays.asList(rows).iterator();
066: }
067:
068: /**
069: * The get* methods can have an int column index or a String column name as
070: * the parameter. This method handles both cases and returns the column
071: * index that the client is trying to get at.
072: * @param args
073: * @return A column index.
074: * @throws SQLException if a database access error occurs
075: */
076: private int columnIndex(Object[] args) throws SQLException {
077:
078: if (args[0] instanceof Integer) {
079: return ((Integer) args[0]).intValue();
080:
081: } else if (args[0] instanceof String) {
082: return this .columnNameToIndex((String) args[0]);
083:
084: } else {
085: throw new SQLException(args[0]
086: + " 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)
096: throws SQLException {
097: for (int i = 0; i < this .currentRow.length; i++) {
098: int c = i + 1;
099: if (this .metaData.getColumnName(c).equalsIgnoreCase(
100: columnName)) {
101: return c;
102: }
103: }
104:
105: throw new SQLException(columnName
106: + " is not a valid column name.");
107: }
108:
109: /**
110: * Gets the boolean value at the given column index.
111: * @param columnIndex A 1 based index.
112: * @throws SQLException if a database access error occurs
113: */
114: protected Object getBoolean(int columnIndex) throws SQLException {
115: Object obj = this .currentRow[columnIndex - 1];
116: this .setWasNull(obj);
117:
118: try {
119: return (obj == null) ? Boolean.FALSE : Boolean.valueOf(obj
120: .toString());
121:
122: } catch (NumberFormatException e) {
123: throw new SQLException(e.getMessage());
124: }
125: }
126:
127: /**
128: * Gets the byte value at the given column index.
129: * @param columnIndex A 1 based index.
130: * @throws SQLException if a database access error occurs
131: */
132: protected Object getByte(int columnIndex) throws SQLException {
133: Object obj = this .currentRow[columnIndex - 1];
134: this .setWasNull(obj);
135:
136: try {
137: return (obj == null) ? new Byte((byte) 0) : Byte
138: .valueOf(obj.toString());
139:
140: } catch (NumberFormatException e) {
141: throw new SQLException(e.getMessage());
142: }
143: }
144:
145: /**
146: * Gets the double value at the given column index.
147: * @param columnIndex A 1 based index.
148: * @throws SQLException if a database access error occurs
149: */
150: protected Object getDouble(int columnIndex) throws SQLException {
151: Object obj = this .currentRow[columnIndex - 1];
152: this .setWasNull(obj);
153:
154: try {
155: return (obj == null) ? new Double(0) : Double.valueOf(obj
156: .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
174: .toString());
175:
176: } catch (NumberFormatException e) {
177: throw new SQLException(e.getMessage());
178: }
179: }
180:
181: /**
182: * Gets the int value at the given column index.
183: * @param columnIndex A 1 based index.
184: * @throws SQLException if a database access error occurs
185: */
186: protected Object getInt(int columnIndex) throws SQLException {
187: Object obj = this .currentRow[columnIndex - 1];
188: this .setWasNull(obj);
189:
190: try {
191: return (obj == null) ? new Integer(0) : Integer.valueOf(obj
192: .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
210: .toString());
211:
212: } catch (NumberFormatException e) {
213: throw new SQLException(e.getMessage());
214: }
215: }
216:
217: protected ResultSetMetaData getMetaData() throws SQLException {
218: return this .metaData;
219: }
220:
221: /**
222: * Gets the object at the given column index.
223: * @param columnIndex A 1 based index.
224: * @throws SQLException if a database access error occurs
225: */
226: protected Object getObject(int columnIndex) throws SQLException {
227: Object obj = this .currentRow[columnIndex - 1];
228: this .setWasNull(obj);
229: return obj;
230: }
231:
232: /**
233: * Gets the short value at the given column index.
234: * @param columnIndex A 1 based index.
235: * @throws SQLException if a database access error occurs
236: */
237: protected Object getShort(int columnIndex) throws SQLException {
238: Object obj = this .currentRow[columnIndex - 1];
239: this .setWasNull(obj);
240:
241: try {
242: return (obj == null) ? new Short((short) 0) : Short
243: .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: "
320: + methodName);
321: }
322:
323: protected Boolean isLast() throws SQLException {
324: return this .iter.hasNext() ? Boolean.FALSE : Boolean.TRUE;
325: }
326:
327: protected Boolean next() throws SQLException {
328: if (!this .iter.hasNext()) {
329: return Boolean.FALSE;
330: } else {
331: this .currentRow = (Object[]) iter.next();
332: return Boolean.TRUE;
333: }
334: }
335:
336: /**
337: * Assigns this.wasNull a Boolean value based on the object passed in.
338: * @param isNull
339: */
340: private void setWasNull(Object isNull) {
341: this .wasNull = (isNull == null) ? Boolean.TRUE : Boolean.FALSE;
342: }
343:
344: protected Boolean wasNull() throws SQLException {
345: return this.wasNull;
346: }
347: }
|