001    package com.mockrunner.jdbc;
002    
003    import java.util.ArrayList;
004    import java.util.Arrays;
005    import java.util.HashMap;
006    import java.util.List;
007    import java.util.Map;
008    
009    /**
010     * Abstract base class for all statement types
011     * that support out parameters, i.e. <code>CallableStatement</code>.
012     */
013    public abstract class AbstractOutParameterResultSetHandler extends AbstractParameterResultSetHandler
014    {
015        private boolean mustRegisterOutParameters = false;
016        private Map globalOutParameter = null;
017        private Map outParameterForStatement = new HashMap();
018        private Map outParameterForStatementParameters = new HashMap();
019        
020        /**
021         * Set if out parameters must be registered to be returned.
022         * The default is <code>false</code>, i.e. if there are matching
023         * out parameters prepared, they are returned even if the
024         * <code>registerOutParameter</code> methods of <code>CallableStatement</code>
025         * have not been called. If set to <code>true</code>, <code>registerOutParameter</code>
026         * must be called.
027         * @param mustOutParameterBeRegistered must out parameter be registered
028         */
029        public void setMustRegisterOutParameters(boolean mustOutParameterBeRegistered)
030        {
031            this.mustRegisterOutParameters = mustOutParameterBeRegistered;
032        }
033        
034        /**
035         * Get if out parameter must be registered to be returned.
036         * @return must out parameter be registered
037         */
038        public boolean getMustRegisterOutParameters()
039        {
040            return mustRegisterOutParameters;
041        }
042        
043        /**
044         * Returns the first out parameter <code>Map</code> that matches 
045         * the specified SQL string.
046         * Please note that you can modify the match parameters with 
047         * {@link #setCaseSensitive}, {@link #setExactMatch} and 
048         * {@link #setUseRegularExpressions}.
049         * @param sql the SQL string
050         * @return the corresponding out parameter <code>Map</code>
051         */
052        public Map getOutParameter(String sql)
053        {
054            SQLStatementMatcher matcher = new SQLStatementMatcher(getCaseSensitive(), getExactMatch(), getUseRegularExpressions());
055            List list = matcher.getMatchingObjects(outParameterForStatement, sql, true, true);
056            if(null != list && list.size() > 0)
057            {
058                return (Map)list.get(0);
059            }
060            return null;
061        }
062        
063        /**
064         * Returns the first out parameter <code>Map</code> that matches 
065         * the specified SQL string and the specified parameters. 
066         * Please note that you can modify the match parameters with 
067         * {@link #setCaseSensitive}, {@link #setExactMatch} and 
068         * {@link #setUseRegularExpressions} and the match parameters for the 
069         * specified parameter list with {@link #setExactMatchParameter}.
070         * @param sql the SQL string
071         * @param parameters the parameters
072         * @return the corresponding out parameter <code>Map</code>
073         */
074        public Map getOutParameter(String sql, Map parameters)
075        {
076            MockOutParameterWrapper wrapper = (MockOutParameterWrapper)getMatchingParameterWrapper(sql, parameters, outParameterForStatementParameters);
077            if(null != wrapper)
078            {
079                return wrapper.getOutParameter();
080            }
081            return null;
082        }
083        
084        /**
085         * Clears the out parameters.
086         */
087        public void clearOutParameter()
088        {
089            outParameterForStatement.clear();
090            outParameterForStatementParameters.clear();
091        }
092        
093        /**
094         * Returns the global out parameter <code>Map</code>.
095         * @return the global out parameter <code>Map</code>
096         */
097        public Map getGlobalOutParameter()
098        {
099            return globalOutParameter;
100        }
101        
102        /**
103         * Prepares the global out parameter <code>Map</code>.
104         * @param outParameters the global out parameter <code>Map</code>
105         */
106        public void prepareGlobalOutParameter(Map outParameters)
107        {
108            globalOutParameter = new HashMap(outParameters);
109        }
110        
111        /**
112         * Prepare an out parameter <code>Map</code> for a specified 
113         * SQL string.
114         * Please note that you can modify the match parameters with 
115         * {@link #setCaseSensitive}, {@link #setExactMatch} and 
116         * {@link #setUseRegularExpressions}.
117         * @param sql the SQL string
118         * @param outParameters the out parameter <code>Map</code>
119         */
120        public void prepareOutParameter(String sql, Map outParameters)
121        {
122            outParameterForStatement.put(sql, new HashMap(outParameters));
123        }
124        
125        /**
126         * Prepare an out parameter <code>Map</code> for a specified SQL string and
127         * the specified parameters. The specified parameters array
128         * must contain the parameters in the correct order starting with index 0 for
129         * the first parameter. Please keep in mind that parameters in
130         * <code>CallableStatement</code> objects start with 1 as the first
131         * parameter. So <code>parameters[0]</code> maps to the
132         * parameter with index 1.
133         * Please note that you can modify the match parameters with 
134         * {@link #setCaseSensitive}, {@link #setExactMatch} and 
135         * {@link #setUseRegularExpressions} and the match parameters for the 
136         * specified parameter list with {@link #setExactMatchParameter}.
137         * @param sql the SQL string
138         * @param outParameters the corresponding out parameter <code>Map</code>
139         * @param parameters the parameters
140         */
141        public void prepareOutParameter(String sql, Map outParameters, Object[] parameters)
142        {
143            prepareOutParameter(sql, outParameters, Arrays.asList(parameters));
144        }
145        
146        /**
147         * Prepare an out parameter <code>Map</code> for a specified SQL string and
148         * the specified parameters. The specified parameters array
149         * must contain the parameters in the correct order starting with index 0 for
150         * the first parameter. Please keep in mind that parameters in
151         * <code>CallableStatement</code> objects start with 1 as the first
152         * parameter. So <code>parameters.get(0)</code> maps to the
153         * parameter with index 1.
154         * Please note that you can modify the match parameters with 
155         * {@link #setCaseSensitive}, {@link #setExactMatch} and 
156         * {@link #setUseRegularExpressions} and the match parameters for the 
157         * specified parameter list with {@link #setExactMatchParameter}.
158         * @param sql the SQL string
159         * @param outParameters the corresponding out parameter <code>Map</code>
160         * @param parameters the parameters
161         */
162        public void prepareOutParameter(String sql, Map outParameters, List parameters)
163        {
164            Map params = new HashMap();
165            for(int ii = 0; ii < parameters.size(); ii++)
166            {
167                params.put(new Integer(ii + 1), parameters.get(ii));
168            }
169            prepareOutParameter(sql, outParameters,  params);
170        }
171        
172        /**
173         * Prepare an out parameter <code>Map</code> for a specified SQL string
174         * and the specified parameters. The specified parameters <code>Map</code>
175         * must contain the parameters by mapping <code>Integer</code> or
176         * <code>String</code> objects to the corresponding parameter. 
177         * An <code>Integer</code> object is the index of the parameter.
178         * A <code>String</code> is the name of the parameter.
179         * Please note that you can modify the match parameters with 
180         * {@link #setCaseSensitive}, {@link #setExactMatch} and 
181         * {@link #setUseRegularExpressions} and the match parameters for the 
182         * specified parameter list with {@link #setExactMatchParameter}.
183         * @param sql the SQL string
184         * @param outParameters the corresponding out parameter <code>Map</code>
185         * @param parameters the parameters
186         */
187        public void prepareOutParameter(String sql, Map outParameters, Map parameters)
188        {
189            List list = (List)outParameterForStatementParameters.get(sql);
190            if(null == list)
191            {
192                list = new ArrayList();
193                outParameterForStatementParameters.put(sql, list);
194            }
195            list.add(new MockOutParameterWrapper(new HashMap(outParameters), new HashMap(parameters)));
196        }
197        
198        private class MockOutParameterWrapper extends ParameterWrapper
199        {
200            private Map outParameter;
201    
202            public MockOutParameterWrapper(Map outParameter, Map parameters)
203            {
204                super(parameters);
205                this.outParameter = outParameter;
206            }
207    
208            public Map getOutParameter()
209            {
210                return outParameter;
211            }
212        }
213    }