001    package com.mockrunner.jdbc;
002    
003    import java.util.ArrayList;
004    import java.util.Collection;
005    import java.util.Iterator;
006    import java.util.List;
007    import java.util.Map;
008    
009    import com.mockrunner.util.common.StringUtil;
010    
011    /**
012     * Helper class for finding matching SQL statements based on various
013     * search parameters. The search parameters are:
014     * <br>
015     * <code>caseSensitive</code> do a case sensitive match (default is <code>false</code>)
016     * <br>
017     * <code>exactMatch</code> the strings must match exactly, the parameter <code>caseSensitive</code>
018     *                         is recognized, but <code>useRegularExpression</code> is irrelevant,
019     *                         if <code>exactMatch</code> is <code>true</code> (default is <code>false</code>)
020     * <br>
021     * <code>useRegularExpression</code> use regular expressions for matching, if this parameter is
022     *                                   <code>false</code>, strings match, if one string starts with the other
023     *                                   (default is <code>false</code>)
024     */
025    public class SQLStatementMatcher
026    {
027        private boolean caseSensitive = false;
028        private boolean exactMatch = false;
029        private boolean useRegularExpressions = false;
030        
031        public SQLStatementMatcher(boolean caseSensitive, boolean exactMatch)
032        {
033            this(caseSensitive, exactMatch, false);
034        }
035        
036        public SQLStatementMatcher(boolean caseSensitive, boolean exactMatch, boolean useRegularExpressions)
037        {
038            this.caseSensitive = caseSensitive;
039            this.exactMatch = exactMatch;
040            this.useRegularExpressions = useRegularExpressions;
041        }
042        
043        /**
044         * Compares all keys in the specified <code>Map</code> with the
045         * specified query string using the method {@link #doStringsMatch}.
046         * If the strings match, the corresponding object from the <code>Map</code>
047         * is added to the resulting <code>List</code>.
048         * @param dataMap the source <code>Map</code>
049         * @param query the query string that must match the keys in <i>dataMap</i>
050         * @param queryContainsMapData only matters if <i>isExactMatch</i> is <code>false</code>,
051         *        specifies if query must be contained in the <code>Map</code> keys (<code>false</code>)
052         *        or if query must contain the <code>Map</code> keys (<code>true</code>)
053         * @return the result <code>List</code>
054         */
055        public List getMatchingObjects(Map dataMap, String query, boolean resolveCollection, boolean queryContainsMapData)
056            {
057                    if(null == query) query = "";
058                    Iterator iterator = dataMap.keySet().iterator();
059                    ArrayList resultList = new ArrayList();
060                    while(iterator.hasNext())
061                    {
062                            String nextKey = (String)iterator.next();
063                            String source, currentQuery;
064                            if(queryContainsMapData)
065                            {
066                                    source = query;
067                                    currentQuery = nextKey;
068                            }
069                            else
070                            {
071                                    source = nextKey;
072                                    currentQuery = query;
073                            }
074                            if(doStringsMatch(source, currentQuery))
075                            {
076                                    Object matchingObject = dataMap.get(nextKey);
077                                    if(resolveCollection && (matchingObject instanceof Collection))
078                                    {
079                                            resultList.addAll((Collection)matchingObject);
080                                    }
081                                    else
082                                    {
083                                            resultList.add(dataMap.get(nextKey));
084                                    }    
085                            } 
086                    }
087                    return resultList;
088            }
089        
090        /**
091         * Compares all elements in the specified <code>Collection</code> with the
092         * specified query string using the method {@link #doStringsMatch}.
093         * @param col the <code>Collections</code>
094         * @param query the query string that must match the keys in <i>col</i>
095         * @param queryContainsData only matters if <i>exactMatch</i> is <code>false</code>,
096         *        specifies if query must be contained in the <code>Collection</code> data (<code>false</code>)
097         *        or if query must contain the <code>Collection</code> data (<code>true</code>)
098         * @return <code>true</code> if <i>col</i> contains <i>query</i>, false otherwise
099         */
100        public boolean contains(Collection col, String query, boolean queryContainsData)
101        {
102            Iterator iterator = col.iterator();
103            while(iterator.hasNext())
104            {
105                String nextKey = (String)iterator.next();
106                String source, currentQuery;
107                if(queryContainsData)
108                {
109                    source = query;
110                    currentQuery = nextKey;
111                }
112                else
113                {
114                    source = nextKey;
115                    currentQuery = query;
116                }
117                if(doStringsMatch(source, currentQuery)) return true;
118            }
119            return false;
120        }
121        
122        /**
123         * Compares two strings and returns if they match. 
124         * @param query the query string that must match source
125         * @param source the source string
126         * @return <code>true</code> of the strings match, <code>false</code> otherwise
127         */
128        public boolean doStringsMatch(String source, String query)
129        {
130            if(null == source) source = "";
131            if(null == query) query = "";
132            if(useRegularExpressions && !exactMatch)
133            {
134                return doPerl5Match(source, query);
135            }
136            else
137            {
138                return doSimpleMatch(source, query);
139            }
140        }
141    
142        private boolean doSimpleMatch(String source, String query)
143        {
144            if(exactMatch)
145            {
146                return StringUtil.matchesExact(source, query, caseSensitive);
147            }
148            else
149            {
150                return StringUtil.matchesContains(source, query, caseSensitive);
151            }
152        }
153        
154        private boolean doPerl5Match(String source, String query)
155        {
156            return StringUtil.matchesPerl5(source, query, caseSensitive);
157        }
158    }