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