/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.netxilia.spi.impl.storage.sql; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ListIterator; /** * MockResultSet dynamically implements the ResultSet interface. */ public class MockResultSet implements InvocationHandler { /** * Create a <code>MockResultSet</code> proxy object. This is equivalent to: * * <pre> * ProxyFactory.instance().createResultSet(new MockResultSet(metaData, rows)); * </pre> * * @param metaData * @param rows * A null value indicates an empty <code>ResultSet</code>. */ public static ResultSet create(ResultSetMetaData metaData, Object[][] rows) { return ProxyFactory.instance().createResultSet(new MockResultSet(metaData, rows)); } public static ResultSet create(Object result) { return create(MockResultSetMetaData.create(new String[] { "RESULT" }), new Object[][] { new Object[] { result } }); } public static ResultSet create() { return create(MockResultSetMetaData.create(new String[] {}), new Object[][] {}); } private Object[] currentRow = null; private ListIterator<Object[]> iter = null; private ResultSetMetaData metaData = null; private Boolean wasNull = Boolean.FALSE; /** * MockResultSet constructor. * * @param metaData * @param rows * A null value indicates an empty <code>ResultSet</code>. */ public MockResultSet(ResultSetMetaData metaData, Object[][] rows) { super(); this.metaData = metaData; if (rows == null) { List<Object[]> empty = Collections.emptyList(); this.iter = empty.listIterator(); } else { this.iter = Arrays.asList(rows).listIterator(); } } /** * The get* methods can have an int column index or a String column name as the parameter. This method handles both * cases and returns the column index that the client is trying to get at. * * @param args * @return A column index. * @throws SQLException * if a database access error occurs */ private int columnIndex(Object[] args) throws SQLException { if (args[0] instanceof Integer) { return ((Integer) args[0]).intValue(); } else if (args[0] instanceof String) { return this.columnNameToIndex((String) args[0]); } else { throw new SQLException(args[0] + " must be Integer or String"); } } /** * Returns the column index for the given column name. * * @return A 1 based index * @throws SQLException * if the column name is invalid */ private int columnNameToIndex(String columnName) throws SQLException { for (int i = 0; i < this.currentRow.length; i++) { int c = i + 1; if (this.metaData.getColumnName(c).equalsIgnoreCase(columnName)) { return c; } } throw new SQLException(columnName + " is not a valid column name."); } /** * Gets the boolean value at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected Object getBoolean(int columnIndex) throws SQLException { Object obj = this.currentRow[columnIndex - 1]; this.setWasNull(obj); try { return (obj == null) ? Boolean.FALSE : Boolean.valueOf(obj.toString()); } catch (NumberFormatException e) { throw new SQLException(e.getMessage()); } } /** * Gets the byte value at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected Object getByte(int columnIndex) throws SQLException { Object obj = this.currentRow[columnIndex - 1]; this.setWasNull(obj); try { return (obj == null) ? new Byte((byte) 0) : Byte.valueOf(obj.toString()); } catch (NumberFormatException e) { throw new SQLException(e.getMessage()); } } /** * Gets the double value at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected Object getDouble(int columnIndex) throws SQLException { Object obj = this.currentRow[columnIndex - 1]; this.setWasNull(obj); try { return (obj == null) ? new Double(0) : Double.valueOf(obj.toString()); } catch (NumberFormatException e) { throw new SQLException(e.getMessage()); } } /** * Gets the float value at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected Object getFloat(int columnIndex) throws SQLException { Object obj = this.currentRow[columnIndex - 1]; this.setWasNull(obj); try { return (obj == null) ? new Float(0) : Float.valueOf(obj.toString()); } catch (NumberFormatException e) { throw new SQLException(e.getMessage()); } } /** * Gets the int value at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected Object getInt(int columnIndex) throws SQLException { Object obj = this.currentRow[columnIndex - 1]; this.setWasNull(obj); try { return (obj == null) ? new Integer(0) : Integer.valueOf(obj.toString()); } catch (NumberFormatException e) { throw new SQLException(e.getMessage()); } } /** * Gets the long value at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected Object getLong(int columnIndex) throws SQLException { Object obj = this.currentRow[columnIndex - 1]; this.setWasNull(obj); try { return (obj == null) ? new Long(0) : Long.valueOf(obj.toString()); } catch (NumberFormatException e) { throw new SQLException(e.getMessage()); } } protected ResultSetMetaData getMetaData() throws SQLException { return this.metaData; } /** * Gets the object at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected Object getObject(int columnIndex) throws SQLException { Object obj = this.currentRow[columnIndex - 1]; this.setWasNull(obj); return obj; } /** * Gets the short value at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected Object getShort(int columnIndex) throws SQLException { Object obj = this.currentRow[columnIndex - 1]; this.setWasNull(obj); try { return (obj == null) ? new Short((short) 0) : Short.valueOf(obj.toString()); } catch (NumberFormatException e) { throw new SQLException(e.getMessage()); } } /** * Gets the String at the given column index. * * @param columnIndex * A 1 based index. * @throws SQLException * if a database access error occurs */ protected String getString(int columnIndex) throws SQLException { Object obj = this.getObject(columnIndex); this.setWasNull(obj); return (obj == null) ? null : obj.toString(); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.equals("getMetaData")) { return this.getMetaData(); } else if (methodName.equals("next")) { return this.next(); } else if (methodName.equals("previous")) { } else if (methodName.equals("close")) { this.close(); return null; } else if (methodName.equals("getBoolean")) { return this.getBoolean(columnIndex(args)); } else if (methodName.equals("getByte")) { return this.getByte(columnIndex(args)); } else if (methodName.equals("getDouble")) { return this.getDouble(columnIndex(args)); } else if (methodName.equals("getFloat")) { return this.getFloat(columnIndex(args)); } else if (methodName.equals("getInt")) { return this.getInt(columnIndex(args)); } else if (methodName.equals("getLong")) { return this.getLong(columnIndex(args)); } else if (methodName.equals("getObject")) { return this.getObject(columnIndex(args)); } else if (methodName.equals("getShort")) { return this.getShort(columnIndex(args)); } else if (methodName.equals("getString")) { return this.getString(columnIndex(args)); } else if (methodName.equals("wasNull")) { return this.wasNull(); } else if (methodName.equals("isLast")) { return this.isLast(); } else if (methodName.equals("hashCode")) { return new Integer(System.identityHashCode(proxy)); } else if (methodName.equals("toString")) { return "MockResultSet " + System.identityHashCode(proxy); } else if (methodName.equals("equals")) { return Boolean.valueOf(proxy == args[0]); } throw new UnsupportedOperationException("Unsupported method: " + methodName); } protected Boolean isLast() throws SQLException { return this.iter.hasNext() ? Boolean.FALSE : Boolean.TRUE; } protected Boolean next() throws SQLException { if (!this.iter.hasNext()) { return Boolean.FALSE; } else { this.currentRow = iter.next(); return Boolean.TRUE; } } /** * Assigns this.wasNull a Boolean value based on the object passed in. * * @param isNull */ private void setWasNull(Object isNull) { this.wasNull = (isNull == null) ? Boolean.TRUE : Boolean.FALSE; } protected Boolean wasNull() throws SQLException { return this.wasNull; } public void close() { // move back to the beginning while (iter.hasPrevious()) { iter.previous(); } } }