001    package com.mockrunner.jdbc;
002    
003    import java.io.InputStream;
004    import java.io.Reader;
005    import java.sql.SQLException;
006    import java.util.Arrays;
007    
008    import com.mockrunner.mock.jdbc.MockArray;
009    import com.mockrunner.mock.jdbc.MockBlob;
010    import com.mockrunner.mock.jdbc.MockClob;
011    import com.mockrunner.mock.jdbc.MockRef;
012    import com.mockrunner.mock.jdbc.MockStruct;
013    import com.mockrunner.util.common.ArrayUtil;
014    import com.mockrunner.util.common.MethodUtil;
015    import com.mockrunner.util.common.StreamUtil;
016    
017    /**
018     * Util class for <code>PreparedStatement</code> and <code>ResultSet</code>
019     * parameters.
020     */
021    public class ParameterUtil
022    {
023        /**
024         * Copies a parameter of a <code>PreparedStatement</code>,
025         * <code>CallableStatement</code> or <code>ResultSet</code>.
026         * <code>InputStream</code> objects, <code>Reader</code> objects 
027         * and arrays are copied into new allocated streams resp. arrays.
028         * All other objects are cloned by calling the clone method. 
029         * If the object is not cloneable, it is returned unchanged.
030         * @param source the parameter to copy
031         * @return a copy of the parameter
032         */
033        public static Object copyParameter(Object source)
034        {
035            if(null == source) return null;
036            if(source.getClass().isArray())
037            {
038                return ArrayUtil.copyArray(source);
039            }
040            if(source instanceof InputStream)
041            {
042                return StreamUtil.copyStream((InputStream)source);
043            }
044            if(source instanceof Reader)
045            {
046                return StreamUtil.copyReader((Reader)source);
047            }
048            if(source instanceof Cloneable)
049            {
050                try
051                {
052                    return MethodUtil.invoke(source, "clone");
053                }
054                catch(Exception exc)
055                {
056                    return source;
057                }
058            }
059            return source;
060        }
061        
062        /**
063         * Compares two parameters of a <code>PreparedStatement</code> or
064         * <code>CallableStatement</code>. You can use it to compare
065         * parameters of a <code>ResultSet</code>. It is used by
066         * {@link com.mockrunner.jdbc.PreparedStatementResultSetHandler}
067         * for comparing parameters specified in the <code>prepare</code>
068         * methods.
069         * Since the parameters can be of the type <code>byte[]</code>,
070         * <code>InputStream</code>, <code>Reader</code>, <code>Ref</code>,
071         * <code>Array</code>, <code>Blob</code>, <code>Clob</code> or
072         * <code>Struct</code> this method can handle these types of objects. 
073         * All other objects are compared using the <code>equals</code> method.
074         * @param source the first parameter
075         * @param target the second parameter
076         * @return <code>true</code> if <i>source</i> is equal to <i>target</i>,
077         *         <code>false</code> otherwise
078         */
079        public static boolean compareParameter(Object source, Object target)
080        {
081            if(null == source && null == target) return true;
082            if(null == source || null == target) return false;
083            if(source instanceof byte[] && target instanceof byte[])
084            {
085                return Arrays.equals((byte[])source, (byte[])target);
086            }
087            if(source instanceof InputStream && target instanceof InputStream)
088            {
089                return StreamUtil.compareStreams((InputStream)source, (InputStream)target);
090            }
091            if(source instanceof Reader && target instanceof Reader)
092            {
093                return StreamUtil.compareReaders((Reader)source, (Reader)target);
094            }
095            if(source instanceof MockRef && target instanceof MockRef)
096            {
097                return compareRef(source, target);
098            }
099            if(source instanceof MockArray && target instanceof MockArray)
100            {
101                return compareArray(source, target);
102            }
103            if(source instanceof MockBlob && target instanceof MockBlob)
104            {
105                return compareBlob(source, target);
106            }
107            if(source instanceof MockClob && target instanceof MockClob)
108            {
109                return compareClob(source, target);
110            }
111            if(source instanceof MockStruct && target instanceof MockStruct)
112            {
113                return compareStruct(source, target);
114            }
115            return source.equals(target);
116        }
117        
118        private static boolean compareClob(Object source, Object target)
119        {
120            try
121            {
122                String sourceString = ((MockClob)source).getSubString(1, (int)((MockClob)source).length());
123                String targetString = ((MockClob)target).getSubString(1, (int)((MockClob)target).length());
124                return sourceString.equals(targetString);
125            }
126            catch(SQLException exc)
127            {
128                return false;
129            }
130        }
131        
132        private static boolean compareBlob(Object source, Object target)
133        {
134            try
135            {
136                byte[] sourceArray = ((MockBlob)source).getBytes(1, (int)((MockBlob)source).length());
137                byte[] targetArray = ((MockBlob)target).getBytes(1, (int)((MockBlob)target).length());
138                return Arrays.equals(sourceArray, targetArray);
139            }
140            catch(SQLException exc)
141            {
142                return false;
143            }
144        }
145        
146        private static boolean compareArray(Object source, Object target)
147        {
148            try
149            {
150                Object[] sourceArray = ArrayUtil.convertToObjectArray(((MockArray)source).getArray());
151                Object[] targetArray = ArrayUtil.convertToObjectArray(((MockArray)target).getArray());
152                return Arrays.equals(sourceArray, targetArray);
153            }
154            catch(SQLException exc)
155            {
156                return false;
157            }
158        }
159        
160        private static boolean compareRef(Object source, Object target)
161        {
162            try
163            {
164                return ((MockRef)source).getObject().equals(((MockRef)target).getObject());
165            }
166            catch(SQLException exc)
167            {
168                return false;
169            }
170        }
171        
172        private static boolean compareStruct(Object source, Object target)
173        {
174            try
175            {
176                String sourceName = ((MockStruct)source).getSQLTypeName();
177                String targetName = ((MockStruct)target).getSQLTypeName();
178                Object[] sourceArray = ((MockStruct)source).getAttributes();
179                Object[] targetArray = ((MockStruct)target).getAttributes();
180                return (sourceName.equals(targetName)) && (Arrays.equals(sourceArray, targetArray));
181            }
182            catch(SQLException exc)
183            {
184                return false;
185            }
186        }
187    }
188