001    package com.mockrunner.jdbc;
002    
003    import java.io.InputStream;
004    import java.io.Reader;
005    import java.util.Arrays;
006    
007    import com.mockrunner.mock.jdbc.MockResultSet;
008    import com.mockrunner.util.common.ArrayUtil;
009    import com.mockrunner.util.common.MethodUtil;
010    import com.mockrunner.util.common.StreamUtil;
011    
012    /**
013     * Util class for <code>PreparedStatement</code> and <code>ResultSet</code>
014     * parameters.
015     */
016    public class ParameterUtil
017    {
018        /**
019         * Copies a parameter of a <code>PreparedStatement</code>,
020         * <code>CallableStatement</code> or a <code>ResultSet</code> value.
021         * <code>InputStream</code> objects, <code>Reader</code> objects 
022         * and arrays are copied into new allocated streams or arrays.
023         * All other objects are cloned by calling the clone method. 
024         * If the object is not cloneable, it is returned unchanged.
025         * @param source the parameter to copy
026         * @return a copy of the parameter
027         */
028        public static Object copyParameter(Object source)
029        {
030            if(null == source) return null;
031            if(source.getClass().isArray())
032            {
033                return ArrayUtil.copyArray(source);
034            }
035            if(source instanceof InputStream)
036            {
037                return StreamUtil.copyStream((InputStream)source);
038            }
039            if(source instanceof Reader)
040            {
041                return StreamUtil.copyReader((Reader)source);
042            }
043            if(source instanceof Cloneable)
044            {
045                try
046                {
047                    return MethodUtil.invoke(source, "clone");
048                }
049                catch(Exception exc)
050                {
051                    return source;
052                }
053            }
054            return source;
055        }
056        
057        /**
058         * Compares two parameters of a <code>PreparedStatement</code> or
059         * <code>CallableStatement</code>. Can also be used to compare
060         * values of a <code>ResultSet</code>. It is used by
061         * {@link com.mockrunner.jdbc.PreparedStatementResultSetHandler}
062         * for comparing parameters specified in the <code>prepare</code>
063         * methods.
064         * Since the parameters can be of the type <code>byte[]</code>,
065         * <code>InputStream</code> and <code>Reader</code> this method handles 
066         * these types of objects. All other objects are compared using the 
067         * <code>equals</code> method. The mock versions of <code>Ref</code>,
068         * <code>Array</code>, <code>Blob</code>, <code>Clob</code> and
069         * <code>Struct</code> all provide a suitable <code>equals</code>
070         * implementation.
071         * @param source the first parameter
072         * @param target the second parameter
073         * @return <code>true</code> if <i>source</i> is equal to <i>target</i>,
074         *         <code>false</code> otherwise
075         */
076        public static boolean compareParameter(Object source, Object target)
077        {
078            if(null == source && null == target) return true;
079            if(null == source || null == target) return false;
080            if(source instanceof byte[] && target instanceof byte[])
081            {
082                return Arrays.equals((byte[])source, (byte[])target);
083            }
084            if(source instanceof InputStream && target instanceof InputStream)
085            {
086                return StreamUtil.compareStreams((InputStream)source, (InputStream)target);
087            }
088            if(source instanceof Reader && target instanceof Reader)
089            {
090                return StreamUtil.compareReaders((Reader)source, (Reader)target);
091            }
092            if(source instanceof MockResultSet && target instanceof MockResultSet)
093            {
094                return ((MockResultSet)source).isEqual((MockResultSet)target);
095            }
096            return source.equals(target);
097        }
098    }
099